Replacing CKEditor on the Fly While Enabling Save Button Using jQuery

I was working on a project yesterday when I encountered the need to have DIVs change into text editors upon double-click. It was fairly easy since I was using CKEditor as a rich-text editor and there was an example on the CKEditor website on how to do that. The DIV to be replaced by CKEditor looks like this:

[html]
<div class="editable">
<h3>Part 1</h3>
<p>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras et ipsum quis mi
semper accumsan. Integer pretium dui id massa. Suspendisse in nisl sit amet urna
rutrum imperdiet. Nulla eu tellus. Donec ante nisi, ullamcorper quis, fringilla
nec, sagittis eleifend, pede. Nulla commodo interdum massa. Donec id metus. Fusce
eu ipsum. Suspendisse auctor. Phasellus fermentum porttitor risus.
</p>
</div>
[/html]

While the script on the demo page looks like this:

[javascript]
window.onload = function()
{
// Listen to the double click event.
if ( window.addEventListener )
document.body.addEventListener( ‘dblclick’, onDoubleClick, false );
else if ( window.attachEvent )
document.body.attachEvent( ‘ondblclick’, onDoubleClick );
};

function onDoubleClick( ev )
{
// Get the element which fired the event. This is not necessarily the
// element to which the event has been attached.
var element = ev.target || ev.srcElement;
// Find out the div that holds this element.
var name;
do
{
element = element.parentNode;
}
while ( element && ( name = element.nodeName.toLowerCase() ) && ( name != ‘div’ || element.className.indexOf( ‘editable’ ) == -1 ) && name != ‘body’ )
if ( name == ‘div’ && element.className.indexOf( ‘editable’ ) != -1 )
replaceDiv( element );
}
var editor;
function replaceDiv( div )
{
if ( editor )
editor.destroy();
editor = CKEDITOR.replace( div );
}
[/javascript]

I have to say that the code works well. But the project that I’m doing uses jQuery, so I had to convert the above script to utilize it. Please take note that this project uses the included jQuery adapter.

The downside of the code above is that the Save button only works if it is inside a FORM element. If the CKEditor is not within a form, then the Save button will be disabled automatically. So after knowing this, many of you, including me, will just wrap the whole div inside a form and try to test out the Save button.

[html highlight=”1,12″]
<form action="actionpage" method="post">
<div class="editable">
<h3>Part 1</h3>
<p>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras et ipsum quis mi
semper accumsan. Integer pretium dui id massa. Suspendisse in nisl sit amet urna
rutrum imperdiet. Nulla eu tellus. Donec ante nisi, ullamcorper quis, fringilla
nec, sagittis eleifend, pede. Nulla commodo interdum massa. Donec id metus. Fusce
eu ipsum. Suspendisse auctor. Phasellus fermentum porttitor risus.
</p>
</div>
</form>
[/html]

To our surprise, the button is still disabled! After a few seconds of pondering, we will find out that the culprit lies within our HTML code. Come to think of it, according to the documentation, CKEditor works like a textarea inside our form and just submit the contents of our editor as such. Also, the Save button works just like a Submit button, which in turn, pass the content of our CKEditor to the form. But wait, we don’t have a textarea! Yes, if you used the HTML code above, our CKEditor was a div and not a textarea, so logically, a form cannot submit the value from a div, which in turn, makes our Save button disabled.

Some of you probably opted to replace the DIV from your HTML to a textarea but figured out it would defeat the purpose of editing on the fly. Others probably will hack into the CKEditor to create a new Save button that will do everything that they wanted to! But I thought, why not just change the DOM of the document so a textarea could be inserted to the form, then just replace the textarea into CKEditor instead of the div. Well, I think it was a better idea instead of creating a new plugin. Here’s a how I did it:

[javascript]
/** Here are the global variables **/
var ceditor; //This is for our CKEditor editor
var divcontent=""; //This will save the contents of our div (Not really necessary, just for illustration purposes)

//I wanted it to execute after the DOM is ready.
$(document).ready(function(){
//Handle the doubleclick event for the div
$(".editable").dblclick(function(){

//Destroy first our editor if it exists
if(ceditor)
{
$(ceditor).ckeditorGet().destroy();
}

divcontent = $(this).html(); //Save the content of our div (Stored it in a variable just for clarity)

//Insert the textarea inside the div with the contents of our div as it’s value
$(this).html("<textarea name=’txtArea’>"+divcontent+"");

//Time to replace the textarea to a CKEditor editor
//Notice that it’s not using the jQuery adapter’s method since it doesn’t modify the textarea’s value upon submission of the form
//It’s better to use the native CKEditor in this case
ceditor =  CKEDITOR.replace($(this).children("textarea").get(0));
});
});
[/javascript]

Works fine for me, the Save button is now enabled and can submit the form just fine. If we double-click on another div, the previously edited div retains the modified text on the DOM. So what if if we want to cancel the editing of a div by double-clicking outside the editor and upon canceling, rolls back to the previous value of the div? Fairly easy, especially if all you have to do is copy-paste:

[javascript]
/** Here are the global variables **/
var ceditor; //This is for our CKEditor editor
var ceditor_container; //Saves the container of our editor (DIV).
var divcontent=""; //This will save the contents of our div

//I wanted it to execute after the DOM is ready.
$(document).ready(function(){
//Stop bubbling of event, so the handler for double-clicking the body doesn’t executed
event.stopPropagation();

//Handle the doubleclick event for the div
$(".editable").dblclick(function(){

//Destroy first our editor if it exists then rollback the previous value of our div
if(ceditor)
{
$(ceditor).ckeditorGet().destroy();
$(ceditor_container).html(divcontent);
}

divcontent = $(this).html(); //Save the content of our div so we can rollback later

//Insert the textarea inside the div with the contents of our div as it’s value
$(this).html("<textarea name=’txtArea’>"+divcontent+"");

//Time to replace the textarea to a CKEditor editor
ceditor =  CKEDITOR.replace($(this).children("textarea").get(0));

//Save the div container for retrieval later
ceditor_container = $(this);
});

//Handle double-click from anywhere on the page.
$("body").dblclick(function(){
//Destroy the editor and rollback the previous value
if(ceditor)
{
$(ceditor).ckeditorGet().destroy();
ceditor = null; //Set it to null since upon the destroying the CKEditor, the value of the variable is not destroyed (not destroyed by reference)
$(ceditor_container).html(divcontent);
}
});
});
[/javascript]

What do you think about the code? I hastily modified the code from the project I was working on, like variable names, etc. Notify me if you found some errors.