Dreamstime

Saturday 18 July 2015

When Keystrokes Triggered Nothing In Raven/RavenPlus


I was suppose to publish this post on 28th May 2015. Little did I know then that Google had planned to shutdown the ClientLogin authentication protocol on that faithful day. Obviously, my attempts to publish this blog post failed. If only they had published a notification on my Blogger dashboard (something that I login to everyday) rather then at their developer blogs and forums (something that I did not access until recently).

But irrespective, I still maintain that this is still the most difficult bug fix in Zoundry Raven/RavenPlus for me, despite my work on OAuth2 over the last couple of weeks.

The blog post follows below.


This must have been the most difficult bug fix for Zoundry Raven/RavenPlus so far. With variables to track and multiple levels of inheritance for certain Python Classes, pretty soon I got confused while tracing through the code. I have to virtually see the code in my sleep before I finally figured out the root cause of this problem: variables not being reset correctly after clicking the "Save" button within the editor. A very common programming mistake, if I may add.

I can only think of 2 states that the Raven/RavenPlus editor could be in at any one time - "Content NOT Modified" or "Content Modified". In the "Content NOT Modified" state, the "Save" button is disabled. Make any changes, by keying something on the keyboard for example, will change the editor from the "Content NOT Modified" to the "Content Modified" state. This should trigger an event to enable the "Save" button. Click on the "Save" button and the state will change back to "Content NOT Modified" from "Content Modified" - and disabling the "Save" button at the same time.

However, I have encountered a number of times when keying in something on the keyboard triggered nothing while editing. The "Save" button remains disabled no matter how many times I banged on the keyboard.

Reproducing The Problem

There are 2 ways to reproduce this problem.

First Method

  1. Open up the Raven/RavenPlus editor. Stay in the "Design" tab and key in something via the keyboard into the blog content area.

  2. Switch to the "XHTML" tab. Key in something via the keyboard into the body of the XHTML area. Click the "Save" button - the "Save" button should become disabled after the successful save.

  3. Switch back to the "Design" tab. Key in something via the keyboard (again into the blog content area). Noticed that the "Save" button remains disabled despite the changes that were made.

Second Method

The Second Method is the reverse of the First mentioned above.

  1. Open up the Raven/RavenPlus editor. Switch to the "XHTML" tab. Key in something via the keyboard into the XHTML area (example: <p>this is a test. this is a test.</p>).

  2. Switch to the "Design" tab. Key in something via the keyboard into the blog content area. Then click the "Save" button - the "Save" button should become disabled after the successful save.

  3. Switch back to "XHTML" tab again. Key in something via the keyboard again into the XHTML area. Noticed that the "Save" button remains disabled despite the changes that were made.

The Fix

In the editor window, two tabs are available for editing blog posts - the "Design" and the "XHTML" tab. After clicking the "Save" button, in the old code, only the variables in the Python class/object for the ACTIVE tab gets reset - when in actual fact it should be reset for both tabs.

Clicking the "Save" button will call the "save" function in the class "ZBlogPostEditor" in the file "zoundry\blogapp\ui\editors\blogeditor.py". All I did for this fix is to add 4 additional lines of code, while removing none, in this function. These 4 additional lines are in essence instructions that can be found in the function "modelSaved", in the class "ZBlogPostContentEditorBase" in the file "zoundry\blogapp\ui\editors\blogeditorctrls\basecontenteditor.py". What I have done, in effect, was to juggle the code around so that variables that were used as flags to track the state of the editor got reset correctly on both the "Design" and "XHTML" tabs.

To comply with the naming and coding standards, I have to define 2 new functions in the class "ZBlogPostContentEditorBase" in the file "zoundry\blogapp\ui\editors\blogeditorctrls\basecontenteditor.py", namely "setContentModified" and "getContentEditControl".

The Source Code

Here is the source code to the changes (in RED) that I have made. Two files are required to be modified.

1. File: "zoundry\blogapp\ui\editors\blogeditor.py"


These are the changes that have to be made to the function "save" in the class "ZBlogPostEditor":


==== BEGIN ====


    def save(self):
        self._clearRecoverySnapshot()
        # Flush data from UI controls to document model
        self._updateModel()
        portableFilesCopies = self._checkForNonPortableFiles()
        # save model document to data store
        self.model.saveDocument()


        # Chuah TC   19th April 2015
        #
        # We need to call the function "setContentModified(False)" for both
        # the "Design" and "XHTML" tab as otherwise, the "Save" button will
        # misbehave (i.e. it won't be enabled even though modifications
        # have been made in the editor area).
        #
        self.xhtmlContentEditor.setContentModified(False)
        self.wysiwygContentEditor.setContentModified(False)
        # I think we need to "clearState()" for both "Design" and "XHTML" tabs too -
        # previously called from ZBlogPostContentEditorBase.modelSaved() in file
        # basecontenteditor.py for one of the tabs only.
        self.xhtmlContentEditor.getContentEditControl().clearState()
        self.wysiwygContentEditor.getContentEditControl().clearState()
        # Chuah TC   19th April 2015


        self.getActiveContentEditor().modelSaved()
        self.setDirty(False)
        
        if portableFilesCopies:
            # refresh editor UI if files were copies to the portable profile resource store
            self.getActiveContentEditor().refreshUI()            
    # end save()

==== END ====


2. File: "zoundry\blogapp\ui\editors\blogeditorctrls\basecontenteditor.py"


In the class "ZBlogPostContentEditorBase", add 2 additional functions:


==== BEGIN ====


    # Chuah TC   19th April 2015
    def setContentModified(self, modified):
        self._setContentModified(modified)
    # Chuah TC   19th April 2015


    # Chuah TC   19th April 2015
    def getContentEditControl(self):
        return self._getContentEditControl()
    # end getContentEditControl
    # Chuah TC   19th April 2015

==== END ====


And these are the changes (in RED) to the function "modelSaved", also in the class "ZBlogPostContentEditorBase".


==== BEGIN ====


    def modelSaved(self):
          
        # Chuah TC  19th April 2015
        #
        # This function is called from only one place, at class ZBlogPostEditor.save() in
        # file blogeditor.py. So moved the code "self._setContentModified(False)" and
        # "self._getContentEditControl().clearState()", below, to where it is called.
        #
        # See ZBlogPostEditor.save() in file blogeditor.py for explanation.
        # 
        # Chuah TC  19th April 2015

        # --- The old code that I have disabled - Chuah TC   19th April 2015 ---
        # --- START ---
        # model was saved to data store.
        # Clear dirty flag so that onContentModified() handler can set the flag in the model
        # self._setContentModified(False)
        # Clear flags (such as 'content modified') in the content editor
        # (eg. ZMSHTMLBlogPostEditControl via ZBlogPostWysiwygContentEditor)
        # self._getContentEditControl().clearState()
        # --- END ---

          
        # Refresh widget UI.
        self.metaDataWidget.refreshUI()
    # end modelSaved()

==== END ====










2 comments:

  1. Ok, thanks, I understand this, but with this fix can I post in blooger with ZR or still not?

    ReplyDelete
    Replies
    1. This fix is at the editor level and has nothing to do with publishing. So to answer your question: No.

      Delete