Ken Haynes Ken Haynes - 2 months ago 28
Javascript Question

RESOLVED: Listener Events being reset on setData and mode change, using CKEditor

Whenever my script calls setData or changes the mode ("source", "WYSIWYG"), the Listeners for the Events I have assigned, are no longer called.

Research has taught me why and I have been experimenting with suggested solutions (CKEDITOR.setData prevents attaching of events with .on function), including those from the official documentation (http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-contentDom), but none of the resolutions work for me as documented, and I have no idea why.

Has anyone else here managed to resolve this issue? If so, I would be most grateful to find out how.

We are current running version 4.5.10 of CKEditor.

Thanking you in anticipation.
Ken.

Example:

// Works until setData() is called or until the view mode is changed ("WYSIWYG", "SOURCE).

ev.editor.document.on( 'keydown', function( evt )
{
console.log("Key Down");
});

// This appears to be the recommended resolution however, this does not
// work for me even prior to setData() being called of the view mode being changed.

editor.on( 'contentDom', function() {
var editable = editor.editable();

editable.attachListener( editor.document, 'keydown', function() {
console.log("Key Down"); // Never executed
} );
} );


UPDATE: This solution (suggested by Dekel) looks to me as it should work. However, I suspect that I have not implemented it correctly so the Key Down event is not firing. Any thoughts on this:

for (var i in CKEDITOR.instances) {
CKEDITOR.instances[i].on('contentDom', function() {
CKEDITOR.instances[i].document.on('keydown', function(event) {
console.log('key down')
});
});
}


UPDATE: Full code example. The event no longer appears to fire:

<html>

<textarea name="editor1">
</textarea>

<textarea name="editor2">
</textarea>

<textarea name="editor3">
</textarea>

</html>

<script>

CKEDITOR.replace( 'editor1', {
allowedContent: true
});

CKEDITOR.replace( 'editor2', {
allowedContent: true
});

CKEDITOR.replace( 'editor3', {
allowedContent: true
});

for (var i in CKEDITOR.instances) {
CKEDITOR.instances[i].on('contentDom', function() {
CKEDITOR.instances[i].document.on('keydown', function(event) {
console.log('key down')
});
});
}

</script>


[WORKING]

for (var i in CKEDITOR.instances) {
CKEDITOR.instances[i].on('contentDom', function() {
// The variable *this* here refers to the current instance of the ckeditor
this.document.on('keydown', function(event) {
console.log('key down')
});
});


}

As Dekel pointed out: "You need to access the relevant editor, you should do it with this instead of CKEDITOR.instances[i], because the i variable will change before the call to the callback function will be made".

Answer

Took some time to understand what the problem is, but I think this is the solution that you are looking for.

You need to attach the keydown event everytime the DOM is ready. To do so - you need to listen to the contentDom event of the editor, and then to register the keydown event on the editor's document.

CKEDITOR.instances.editor1.on( 'contentDom', function() {
    CKEDITOR.instances.editor1.document.on('keydown', function(event) {
        console.log('key down')
    });
});

In this example - editor1 is the name of the ckeditor instance.

You can check this working example:
https://jsfiddle.net/gad701dc/

In case you have multiple instances you will need to loop over them and add it to each of them:

for (var i in CKEDITOR.instances) {
    CKEDITOR.instances[i].on('contentDom', function() {
        // The variable *this* here refers to the current instance of the ckeditor
        this.document.on('keydown', function(event) {
            console.log('key down')
        });
    });
}

You need to access the relevant editor, you should do it with this instead of CKEDITOR.instances[i], because the i variable will change before the call to the callback function will be made.