2013-08-22 34 views
7

我試圖在實例完全加載後將我的CKEditor實例設置爲「只讀」,但出現Javascript錯誤:Cannot call method 'setReadOnly' of null。當我深入研究時,錯誤來自ckeditor.js中的這一行,在editor.setReadOnly方法中:this.editable().setReadOnly(a);這意味着編輯器存在,但方法/屬性(在CKEditor實例上)不存在。setReadOnly在CKEditor的instanceReady上調用時會導致錯誤

下面是我的代碼,我會稍微解釋一下。我的應用程序是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(); 
    } 
} 

的骨幹類有Namespace.Events.SET_ENABLED監聽器觸發setEnabled

是否有另一個CKEditor事件我應該聽? editable上似乎沒有instanceReady事件。我錯過了什麼?

編輯
this.editor在骨幹類render功能創建這樣的:

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

的原因,我不添加instanceReady監聽它的創建後立即被因爲功能setEnabledOnLoad被稱爲GWT在實例完全初始化之前。這是兩個地方的代碼的結果。 GWT已經說過「確定,創建實例」,但Backbone在GWT進入下一行代碼並且想要將其設置爲啓用/禁用時尚未完成。

回答

5

你可以嘗試訂閱instanceReady事件是這樣的:

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

然而,editor實例必須已被創建,然後(檢查在調試器CKEDITOR.instances)。

我對editableeditor之間的差異有點困惑。您能否顯示this.editorthis.editable分配的代碼片段?

[編輯]我想我看看發生了什麼。 CKEDITOR是一個全局對象,您可以將其視爲一個包含所有CKEDITOR實例的類。試圖處理與CKEDITOR.on事件是不正確的,你需要做一個特定的實例(就像我上面顯示的)。我假設,「編輯器」是你想要附加CKEDITOR實例的父元素的ID(請糾正我,如果我錯了)。我不熟悉的骨幹,但通常它與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上可用的服務對象。我想不出任何可能需要直接使用它的具體情況。

+0

'CKEDITOR'不包含所有實例,但它也做了很多。我沒有將'instanceReady'監聽器添加到實例中的原因是因爲在實例創建之前調用了函數'setEnabledOnLoad'。這是兩個地方的代碼的結果。 GWT已經說過「確定,創建實例」,但Backbone在GWT進入下一行代碼並且想要將其設置爲啓用/禁用時尚未完成。 –

+0

我承認我缺乏關於Backbone和GWT的正確知識來進一步回答我的問題:]希望有人可以跳進去。 – Noseratio

6

兩年後,但這裏是我的解決方案。也許別人會覺得它有用。 如上所述,在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); 
+0

不能相信你必須這麼做,但上面的代碼確實有效。 –

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替換整個客戶端之前討論的內容。

相關問題