My TinyMCE AJAX Implementation: autosave plugin vs. isDirty() (aka Fixing the Tweak)

TinyMCE LogoYes I know, here I am back again with yet another TinyMCE tweak, but this one’s really nice to know too … 😉

In the beginning : Pimp your form with some AJAX!

As you might have read before, I’ve developed a simple method to save the data of a TinyMCE instance via an AJAX call. As I’ve written before, the method is built around the tinyMCE.triggerSave function:

  • Call a tinyMCE.triggerSave(false,true), so that the content of the editor get placed back into the textarea the editor is replacing
  • Get the value of that textarea
  • Send that value over XHR to the server

In code, that would be something like this (using prototype here):

[js]// note that this is a demofunction and it stands alone. In a real implementation this would be placed into an object by using the Object Literal Notation 😉
function saveIt() {

// triggerSave first!
tinyMCE.triggerSave(false,true);

// get the value of the textarea (which now has updated content)
var toSend = escape($F(‘myTextarea’));

// make the AJAX call
new Ajax.Request(
“/backend.php”, {
method : “post”,
postBody : “data=” + toSend + “&action=save”,
onSuccess : function(t, json) {
// your code here
}
}
);
}[/js]

Now simply hook that a button and set its onclick event to perform the saveIt(); and all should work fine. Not that hard at all.

Erm okay, I already knew that …

Hold your horses, the best is yet to come! As the backend I’ve written supports multiple languages, thus multiple instances of TinyMCE are present, a user might easily forget to save the page before navigating away as only 1 language at a time is shown.

TinyMCE Multilanguage

To prevent the user of not saving changes, the autosave plugin TinyMCE provides comes in handy. This plugin gives the user a warning if they made modifications to a editor instance but didn’t submit them. A nice tweak in the config if I say so myself and above all $userComplaintsAboutNotHavingSavedChanges--; 🙂

Okay, but I knew that too …

Yeah I know. But what you don’t know is that things turn evil when combining both of the above! 1 plus 1 apparently does not equal 2 in this case 🙁

Aha, now you’ve got me interested

So I added the autosave plugin to the TinyMCE init and started editing some content. Clicked the close button of my browser (I could have clicked a link to an other page too, I know) and – this is expected behavior – the autosave plugin indeed jumped in: “Are you sure you want to navigate …”.

TinyMCE Autosave Notice

Clicked Cancel, clicked my button labeled Save, saw the AJAX call passing by with a successful response (thank you Firebug!), and then tried again closing my browser tab. To my surprise the autosave plugin jumped in again. Hmmz, that ain’t right. Resaved the data and checked the database to see if the changes were made too but no go, the autosave plugin kept jumping in.

Dirty aye?

So I started debugging and after a quick dive into the TinyMCE Wiki and quick look at the autosave plugin code I found out that – internally – TinyMCE keeps track if an instance is dirty or not. Dirty? Yeah, dirty! After then hitting the TinyMCE API I found out that dirty defines if the editor instance has been modified or not and that this can be checked by calling the isDirty() function on a TinyMCE instance.

After realizing that TinyMCE does not provide a function to reset the dirty status of an instance, I decided to code it myself. The raw TinyMCE source of the isDirty(); function along with the autosave plugin code were a jumpstart as I only had to combine some little bits an pieces to end up with the little piece of code below. Note that this piece of code should be placed into the onSuccess function of the previously mentioned Ajax.Request.

[js]// as the content has been saved, TinyMCE may not return true on isDirty() … this is the fix!
for (n in tinyMCE.instances) {

// get current item
inst = tinyMCE.instances[n];

// is not an instance? ABORT I SAY!
if (!tinyMCE.isInstance(inst)) continue;

// it’s an instance : set startContent and give a polish (set not dirty)
inst.startContent = tinyMCE.trim(inst.getBody().innerHTML);
inst.isNotDirty = true;
}

tinyMCE.triggerNodeChange(false, true); // this is needed?[/js]

Not quite sure if that last call to triggerNodeChange is needed but I’m using it anyway, as it appeard in the code of the autosave plugin.

Hereby the question/hint to the TinyMCE developers to implement a resetDirty(); or unDirty(); function into the main core as this might come in handy to some 😉

Hope this post saved you some troubles 😉

B!

Join the Conversation

5 Comments

Leave a comment

Leave a Reply to Johan Ronsse Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.