SetReadOnly causes an error when calling instanceReady from CKEditor

I am trying to set the CKEditor instance to "readOnly" after the instance is fully loaded, but I get a Javascript error: Cannot call method 'setReadOnly' of null . When I enter it, the error comes from this line in ckeditor.js in the editor.setReadOnly method: this.editable().setReadOnly(a); This means that the editor exists, but the method / attribute editable (on the CKEditor instance) is not.

Below is my code, and I will explain it a bit. My application is a combination of GWT and Backbone. CKEditor itself is created using the Backbone code, but the parent is in GWT, so when I trigger the setEnabled action.

 private native void setEnabledOnLoad(boolean enabled, String id) /*-{ CKEDITOR.on("instanceReady", function(evt) { if(evt.editor.name === id) { Namespace.trigger(Namespace.Events.SET_ENABLED, enabled); } }); }-*/; setEnabled: function(enabled) { this.editor.setReadOnly(!enabled); if(enabled){ this.editor.focusManager.focus(); } else { this.editor.focusManager.blur(); } } 

The Backbone class has a listener for Namespace.Events.SET_ENABLED that runs setEnabled .

Is there another CKEditor event that I should listen to? The instanceReady event is not displayed on editable . What am I missing?

EDIT
this.editor is created in the Backbone class render function as follows:

 this.editor = CKEDITOR.replace(this.$(this.id)[0], config); 

The reason I don't add an instanceReady listener right after I create it is because the setEnabledOnLoad function setEnabledOnLoad called in GWT before the instance is fully initialized. This is the result of having code in two places. GWT said β€œOK, create an instance”, but Backbone did not finish by the time GWT moves to the next line of code and wants to set it on / off.

+7
javascript jquery ckeditor gwt
source share
3 answers

Two years later, but here is my solution. Perhaps this will be useful to someone. As stated above, the event is fired before the editable () function is fully configured, and therefore one solution is to simply wait until it finishes before setting it to read. It may be an ugly way to do it, but it works.

  //Delayed execution - ckeditor must be properly initialized before setting readonly var retryCount = 0; var delayedSetReadOnly = function () { if (CKEDITOR.instances['bodyEditor'].editable() == undefined && retryCount++ < 10) { setTimeout(delayedSetReadOnly, retryCount * 100); //Wait a while longer each iteration } else { CKEDITOR.instances['bodyEditor'].setReadOnly(); } }; setTimeout(delayedSetReadOnly, 50); 
+7
source share

You can try to subscribe to the instanceReady event this way:

 CKEDITOR.instances.editor.on("instanceReady", onInstanceReadyHandler) 

However, an editor instance should already have been created by then (check CKEDITOR.instances in the debugger).

I am a bit confused by the difference between editable and editor . Could you display the code snippets where this.editor and this.editable assigned?

[EDITED] I think I understand what is happening. CKEDITOR is a global object, you can think of it as a class that contains all instances of CKEDITOR. Attempting to handle events using CKEDITOR.on is incorrect, you need to do this in a specific instance (for example, I showed above). I assume that "editor" is the identifier of your parent to which you want to attach the CKEDITOR instance (please correct me if I am wrong). I am not familiar with Backbone, but this is usually done with replace :

 var editorInstance = CKEDITOR.replace("editor", { on: { instanceReady: function(ev) { alert("editor is ready!"); }}}); 

Here we attach a new instance of CKEDITOR to the parent editor element and subscribe to the instanceReady event at the same time. The returned editorInstance object should provide all the APIs you may need, including setReadOnly . You can also access it through the global CKEDITOR object using the identifier of the parent element, i.e. CKEDITOR.instances.editor . Editable , on the other hand, is more likely a service object available on editor . I cannot come up with any specific case where you might need to use it directly.

+5
source share

I apologize for never updating this solution. I needed to separate the GWT function from the CKEditor behavior. So, I added a function to the GWT 'setEnabled' that is called from the parent when it wants to update the enabled state of the CKEditor.

 public void setEnabled(boolean enabled) { this.enabled = enabled; toggleCKEditorEnabled(enabled); } 

Then we changed the function above, 'setEnabledOnLoad', to be 'toggleCKEditorEnabled', which fires the SET_ENABLED event with the value enabled .

Instead of connecting the listener to a specific instance of CKEditor, I added it to the BackBone MessageEntryView class, which is the container for the CKEditor instance. In the initialize function of MessageEntryView, I added this line

 Namespace.on(Namespace.Events.SET_ENABLED, this.setEnabled); 

This only works because I have one instance of CKEditor loaded onto the screen at any given time. This problem and its solution prevented us from adding CKEditor instances to the page at a time, which we discussed before moving around and replacing our entire Backbone client.

+1
source share

All Articles