我正在尝试在实例完全加载后将我的CKEditor实例设置为“readOnly”,但我收到一个Javascript错误:Cannot call method 'setReadOnly' of null
。当我深入研究时,错误来自ckeditor.js中的这一行,在editor.setReadOnly
方法中:this.editable().setReadOnly(a);
这意味着编辑器存在,但editable
方法/属性(在CKEditor实例上)没有。
下面是我的代码,我会稍微解释一下。我的应用程序是GWT和Backbone的组合。 CKEditor本身是由Backbone代码创建的,但父元素在GWT中,所以我在那里发起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();
}
}
Backbone类有Namespace.Events.SET_ENABLED
的监听器,可以触发setEnabled
。
我应该收听另一个CKEditor事件吗? instanceReady
上似乎没有editable
个活动。我错过了什么?
修改
this.editor
在Backbone类render
函数中创建,如下所示:
this.editor = CKEDITOR.replace(this.$(this.id)[0], config);
我在创建之后不立即添加instanceReady
侦听器的原因是因为在实例完全初始化之前在GWT中调用了函数setEnabledOnLoad
。这是将代码放在两个地方的结果。 GWT已经说“好了,创建了实例”,但是当GWT进入下一行代码并希望将其设置为启用/禁用时,Backbone还没有完成。
答案 0 :(得分:8)
两年后,但这是我的解决方案。也许别人会觉得它很有用。 如上所述,事件在完全设置editable()函数之前被触发,因此一种解决方案是在将其设置为只读之前等待它完成。这可能是一种丑陋的方式,但它确实有效。
//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);
答案 1 :(得分:5)
您可以尝试以这种方式订阅instanceReady
事件:
CKEDITOR.instances.editor.on("instanceReady", onInstanceReadyHandler)
但是,当时必须已创建editor
实例(在调试器中检查CKEDITOR.instances
)。
我对editable
和editor
之间的区别感到有点困惑。您能否在this.editor
和this.editable
被分配的位置显示代码片段?
[编辑] 我想我知道发生了什么。 CKEDITOR
是一个全局对象,您可以将其视为包含所有CKEDITOR实例的类。尝试使用CKEDITOR.on
处理事件是不对的,您需要在特定实例上执行此操作(如上所示)。我假设,“editor”是您想要附加CKEDITOR
实例的父元素的ID(如果我错了,请纠正我)。我不熟悉Backbone,但通常用replace完成:
var editorInstance = CKEDITOR.replace("editor", { on: {
instanceReady: function(ev) { alert("editor is ready!"); }}});
这里我们将一个新的CKEDITOR实例附加到editor
父元素,并同时订阅instanceReady
事件。返回的对象editorInstance
应该提供您可能需要的所有APIs,包括setReadOnly。您还可以使用父元素ID(即CKEDITOR
)通过全局CKEDITOR.instances.editor
对象访问它。另一方面,editable是editor上可用的服务对象。我想不出你可能需要直接使用它的任何具体情况。
答案 2 :(得分:1)
我为从未使用我的解决方案更新此内容而道歉。我需要将GWT函数与CKEditor行为进一步解耦。所以,我在GWT'setEnabled'中添加了一个函数,该函数在想要更新CKEditor对象的启用状态时从父对象调用。
public void setEnabled(boolean enabled) {
this.enabled = enabled;
toggleCKEditorEnabled(enabled);
}
然后将'setEnabledOnLoad'上面引用的函数更改为'toggleCKEditorEnabled',它触发具有enabled
值的SET_ENABLED事件。
我没有将侦听器附加到CKEditor的特定实例,而是添加到Backbone MessageEntryView类中,该类是CKEditor实例的容器。在MessageEntryView的initialize
函数中,我添加了这一行
Namespace.on(Namespace.Events.SET_ENABLED, this.setEnabled);
这只能起作用,因为我在任何给定时间都在屏幕上加载了一个CKEditor实例。这个问题及其解决方案使我们无法一次向页面添加更多CKEditor实例,这是我们在继续使用Backbone替换整个客户端之前所讨论的内容。