8

我试图在实例完全加载后将我的 CKEditor 实例设置为“只读”,但我收到了一个 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。我错过了什么?

EDIT
this.editor在 Backbone 类render函数中创建,如下所示:

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

我没有在instanceReady创建后立即添加侦听器的原因是因为在setEnabledOnLoad实例完全初始化之前在 GWT 中调用了该函数。这是将代码放在两个地方的结果。GWT 说“好的,创建实例”,但是当 GWT 进入下一行代码并想要将其设置为启用/禁用时,Backbone 还没有完成。

4

3 回答 3

9

两年后,但这是我的解决方案。也许其他人会发现它很有用。如上所述,事件在 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);
于 2015-11-06T09:17:30.747 回答
5

您可以尝试以这种方式订阅instanceReady事件:

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

但是,此时editor必须已经创建了实例(CKEDITOR.instances在调试器中检查)。

我对editable和之间的区别有点困惑editor。你能在哪里显示你的代码片段this.editor并被this.editable分配吗?

[编辑]我想我知道发生了什么。CKEDITOR是一个全局对象,您可以将其视为一个包含所有 CKEDITOR 实例的类。尝试处理事件CKEDITOR.on是不对的,您需要在特定实例上执行此操作(如我上面所示)。我假设,“编辑器”是您要将CKEDITOR实例附加到的父元素的 ID(如果我错了,请纠正我)。我对 Backbone 不熟悉,但通常是用replace完成的:

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

在这里,我们将 CKEDITOR 的新实例附加到editor父元素并同时订阅instanceReady事件。返回的对象editorInstance应提供您可能需要的所有API,包括setReadOnly。您还可以使用父元素 ID 通过全局CKEDITOR对象访问它,即CKEDITOR.instances.editor. 另一方面,editableeditor上可用的服务对象。我想不出您可能需要直接使用它的任何特定情况。

于 2013-08-24T04:52:06.627 回答
1

我很抱歉从未用我的解决方案更新此内容。我需要将 GWT 函数与 CKEditor 行为进一步分离。因此,我在 GWT 'setEnabled' 中添加了一个函数,当它想要更新 CKEditor 对象的启用状态时,它会从父对象调用。

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

然后将上面引用的“setEnabledOnLoad”函数更改为“toggleCKEditorEnabled”,该函数使用该enabled值触发 SET_ENABLED 事件。

我没有将侦听器附加到 CKEditor 的特定实例,而是添加到作为 CKEditor 实例容器的 Backbone MessageEntryView 类中。在initializeMessageEntryView 的函数中,我添加了这一行

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

这只有效,因为我在任何给定时间都在屏幕上加载了一个 CKEditor 实例。这个问题及其解决方案使我们无法一次向页面添加更多 CKEditor 实例,这是我们在继续使用 Backbone 替换整个客户端之前讨论的内容。

于 2016-08-01T21:41:33.363 回答