27
votes

I have a custom-written CMS that uses CKEditor *(FCKEditor v3) for editing content. I'm also using the jQuery Validation plugin to check all fields for error prior to AJAX-based submission. I'm using the serialize() function to passing the data to the PHP backend.

Problem is, serialize manages to grab all fields correctly, except for the actual content typed in CKEditor. Like every other WYSIWYG editor, this one too overlays an iframe over an existing textbox. And serialize ignores the iframe and looks only into the textbox for content, which, of course, it doesn't find, thus returning a blank content body.

My approach to this is to create a hook onto the onchange event of CKEditor and concurrently update the textbox (CKEDITOR.instances.[textboxname].getData() returns the content) or some other hidden field with any changes made in the editor.

However, since CKEditor is still in it's beta stage and severely lacks documentation, I can't find a suitable API call that'll enable me to do so.

Does anyone have any idea on how to go about this?

11
I've figured out as far as grabbing the content from the iframe: $( '#cke_contents_body iframe' ).contents().find( 'body' ).html()... the closest directly addressable element being a td with the id, 'cke_contents_body'. CKEditor wraps the iframe with this td.miCRoSCoPiC_eaRthLinG
Still to go.. a way to auto update the textbox with the data by hooking onto a change event of CKEditor. Any ideas? Anyone?miCRoSCoPiC_eaRthLinG
New CKEditor version has resolved this problemIvan

11 Answers

36
votes

Another generic solutions to this would be to run the following whenever you try to submit the form

for ( instance in CKEDITOR.instances )
            CKEDITOR.instances[instance].updateElement();

This will force all CKEDITOR instances in the form to update their respective fields

7
votes

I've just released a CKEditor plugin for jQuery which will take care of all this in the background without any extra code: http://www.fyneworks.com/jquery/CKEditor/

6
votes

I have also been trying to fix this problem today. I realised that the reason the above code isnt working for me is because the CKEditor instance isnt ready yet when the document property is referenced. So you have to call the "instanceReady" event and within that the document's events can be used, because prior to that it just doesnt exist.

This example might work for you:

CKEDITOR.instances["editor1"].on("instanceReady", function()
{
//set keyup event
this.document.on("keyup", CK_jQ);

 //and paste event
this.document.on("paste", CK_jQ);
});

function CK_jQ()
{

    CKEDITOR.tools.setTimeout( function()
    { 
        $("#editor1").val(CKEDITOR.instances.editor1.getData()); 
    }, 0);
}
3
votes

This should do it...

CKEDITOR.instances["editor1"].document.on('keydown', function(event)
{
    CKEDITOR.tools.setTimeout( function()
    { 
        $("#editor1").val(CKEDITOR.instances.editor1.getData()); 
    }, 0);
});

CKEDITOR.instances["editor1"].document.on('paste', function(event)
{
    CKEDITOR.tools.setTimeout( function()
    { 
        $("#editor1").val(CKEDITOR.instances.editor1.getData()); 
    }, 0);
});

edit: added section to update textbox after pastes, too...

2
votes

I had success with this:

console.log(CKEDITOR.instances.editor1.getData());
1
votes

I took a slightly different approach I figured it would be better to use ckeditor's update function and since keyup was being used the timeout wasn't needed

CKEDITOR.instances["editor1"].on("instanceReady", function()
{
//set keyup event
this.document.on("keyup", CK_jQ);

 //and paste event
this.document.on("paste", CK_jQ);
}

function CK_jQ()
{
   CKEDITOR.instances.editor1.updateElement(); 
}
1
votes

Wouldn't it be better to do just this:

CKEDITOR.instances.editor1.on('contentDom', function() {
          CKEDITOR.instances.editor1.document.on('keyup', function(event) {/*your instructions*/});
        });

ref: http://cksource.com/forums/viewtopic.php?f=11&t=18286

1
votes

The contentDom event worked for me and not the instanceReady... I would really like to know what the events ae, but I assume they are proprietary...

var editor = CKEDITOR.replace('editor');

CKEDITOR.instances.editor.on("instanceReady", function(){
    this.on('contentDom', function() {
        this.document.on('keydown', function(event) {
            CKEDITOR.tools.setTimeout( function(){ 
                $(".seldiv").html(CKEDITOR.instances.editor.getData()); 
            }, 1);
        });
    });
    this.on('contentDom', function() {
        this.document.on('paste', function(event) {
            CKEDITOR.tools.setTimeout( function(){ 
                $(".seldiv").html(CKEDITOR.instances.editor.getData()); 
            }, 1);
        });
    });
    edits_clix();
    var td = setTimeout("ebuttons()", 1);
})
1
votes

CKEDITOR.instances.wc_content1.getData() will return the ckeditor data
CKEDITOR.instances.wc_content1.setData() will set the ckeditor data

0
votes

I think the user was asking about serializing, I was struggling serializing a form to submit and it was giving me a lot of issues.

This is what worked for me:

$(document).ready(function() {
$('#form').submit(function(){
if ( CKEDITOR.instances.editor1.getData() == '' ){
    alert( 'There is no data available' );//an alert just to check if its working
}else{
    var editor_data = CKEDITOR.instances.editor1.getData();
    $("#editor1").val(editor_data); //at this point i give the value to the textarea
    $.ajax({ 
                    //do your ajax here  

                     });

        }
return false;
    });
 });
0
votes

I solved this problem with the current version: http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.js

After line 55 this.submit( function( event ) { - i added this code:

if (typeof CKEDITOR !== "undefined") {
    for ( instance in CKEDITOR.instances )
        CKEDITOR.instances[instance].updateElement();
}