2013-08-22 4 views
7

Ich versuche, meine CKEditor-Instanz zu "readOnly" zu setzen, nachdem die Instanz vollständig geladen wurde, aber ich bekomme einen Javascript-Fehler: Cannot call method 'setReadOnly' of null. Wenn ich drüber nachdenke, kommt der Fehler von dieser Zeile in der ckeditor.js innerhalb der editor.setReadOnly Methode: this.editable().setReadOnly(a); Das bedeutet, dass der Editor existiert, aber die editable Methode/Attribut (auf der CKEditor-Instanz) nicht.setReadOnly verursacht Fehler beim Aufruf von instanceReady von CKEditor

Unten ist mein Code, und ich werde es ein wenig erklären. Meine App ist eine Kombination aus GWT und Backbone. Der CKEditor selbst wird durch den Backbone-Code erstellt, aber das übergeordnete Element befindet sich in GWT, daher initiiere ich dort die Aktion setEnabled.

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(); 
    } 
} 

Die Backbone-Klasse hat einen Hörer für Namespace.Events.SET_ENABLED die setEnabled auslöst.

Gibt es ein anderes CKEditor-Ereignis, auf das ich achten sollte? Es scheint kein instanceReady Ereignis auf editable zu sein. Was vermisse ich?

EDIT
this.editor in der Backbone-Klasse render Funktion wie folgt erstellt:

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

Der Grund, warum ich nicht hinzufügen, die instanceReady Zuhörer direkt nach ihrer Erstellung wird, weil die Funktion setEnabledOnLoad heißt in GWT, bevor die Instanz vollständig initialisiert wurde. Dies ist ein Ergebnis des Codes an zwei Stellen. GWT hat "ok, erstelle die Instanz" gesagt, aber Backbone ist noch nicht fertig, wenn GWT zur nächsten Codezeile geht und sie aktivieren/deaktivieren möchte.

Antwort

5

könnten Sie versuchen, instanceReady Ereignis abonnieren möchte auf diese Weise:

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

jedoch die editor Instanz bereits dann erstellt worden sein (inspizieren CKEDITOR.instances im Debugger).

Ich bin etwas verwirrt über den Unterschied zwischen editable und editor. Könnten Sie die Fragmente Ihres Codes zeigen, wo und this.editable zugewiesen bekommen?

[EDITED] Ich denke, ich sehe, was vor sich geht. CKEDITOR ist ein globales Objekt, Sie können es sich als eine Klasse vorstellen, die alle CKEDITOR-Instanzen enthält. Versuche, Ereignisse mit CKEDITOR.on zu behandeln, ist nicht richtig, Sie müssen es auf einer bestimmten Instanz (wie ich oben gezeigt habe) tun. Ich nehme an, "editor" ist die ID Ihres übergeordneten Elements, das Sie an eine CKEDITOR Instanz anhängen möchten (bitte korrigieren Sie mich, wenn ich falsch liege). Ich bin nicht vertraut mit Rückgrat, aber in der Regel ist es geschaffen mit replace:

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

Hier legen wir eine neue Instanz von CKEditor zum editor Elternelement und abonnieren Sie die instanceReady Veranstaltung zur gleichen Zeit. Das zurückgegebene Objekt editorInstance sollte alle benötigten APIs einschließlich setReadOnly enthalten. Sie könnten auch über das globale CKEDITOR-Objekt unter Verwendung der Elternelement-ID, d. H. CKEDITOR.instances.editor, darauf zugreifen.Auf der anderen Seite ist editable eher ein Serviceobjekt, das auf editor verfügbar ist. Ich kann mir keinen speziellen Fall vorstellen, in dem Sie es möglicherweise direkt verwenden müssen.

+0

'CKEDITOR' hält alle Instanzen, aber es tut auch viel mehr. Der Grund, dass ich den 'instanceReady'-Listener nicht zur Instanz hinzufüge, liegt darin, dass die Funktion' setEnabledOnLoad' aufgerufen wird, bevor die Instanz erstellt wurde. Dies ist ein Ergebnis des Codes an zwei Stellen. GWT hat "ok, erstelle die Instanz" gesagt, aber Backbone ist noch nicht fertig, wenn GWT zur nächsten Codezeile geht und sie aktivieren/deaktivieren möchte. –

+0

Ich gebe zu, dass mir das richtige Wissen über Backbone und GWT fehlt, um meine Antwort weiter zu beantworten:] Hoffentlich kann jemand hineinspringen. – Noseratio

6

Zwei Jahre später, aber hier ist meine Lösung. Vielleicht findet es jemand anders nützlich. Wie oben erwähnt, wird das Ereignis scheinbar ausgelöst, bevor die editierbare() Funktion vollständig eingerichtet ist, und daher ist eine Lösung, einfach darauf zu warten, dass es beendet wird, bevor es auf Nur-Lesen gesetzt wird. Dies kann ein hässlicher Weg sein, aber es funktioniert.

 //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); 
+0

Ich kann nicht glauben, dass Sie das tun müssen, aber der obige Code funktioniert. –

1

Ich entschuldige mich für die Aktualisierung nie mit meiner Lösung. Ich musste die GWT-Funktion weiter vom CKEditor-Verhalten entkoppeln. Also habe ich eine Funktion in GWT 'setEnabled' hinzugefügt, die vom übergeordneten Objekt aufgerufen wird, wenn der aktivierte Zustand des CKEditor-Objekts aktualisiert werden soll.

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

verändert dann die Funktion oben ‚setEnabledOnLoad‘ ‚bezeichnet toggleCKEditorEnabled‘ werden, die das SET_ENABLED Ereignis mit dem enabled Wert auslöst.

Anstatt den Listener an die spezifische Instanz von CKEditor anzuhängen, fügte ich der Backbone MessageEntryView-Klasse hinzu, die der Container der CKEditor-Instanz ist. In der initialize Funktion des MessageEntryView, habe ich diese Zeile

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

Dies funktioniert nur, weil ich eine Instanz von CKEditor auf dem Bildschirm zu einem bestimmten Zeitpunkt geladen haben. Dieses Problem und seine Lösung hinderten uns daran, mehr CKEditor-Instanzen gleichzeitig auf der Seite hinzufügen zu können, was wir besprochen haben, bevor wir fortfahren und unseren gesamten Client durch Backbone ersetzen.