CKEditor实例已经存在。

99

我正在使用jQuery对话框呈现通过AJAX获取的表单。在某些表单中,我使用CKEditor来处理文本区域。编辑器在第一次加载时显示得很好。

当用户取消对话框时,我会删除内容,以便它们在稍后的请求中重新加载。问题是,一旦对话框重新加载,CKEditor就会声称编辑器已经存在。

uncaught exception: [CKEDITOR.editor] The instance "textarea_name" already exists.

这个API包含一个销毁现有编辑器的方法,我看到有些人声称这是一个解决方案:

if (CKEDITOR.instances['textarea_name']) {
CKEDITOR.instances['textarea_name'].destroy();
}
CKEDITOR.replace('textarea_name');

这对我来说不起作用,因为我收到了一个新的错误:

TypeError: Result of expression 'i.contentWindow' [null] is not an object.

这个错误似乎发生在“destroy()”而不是“replace()”。是否有人遇到过这种情况并找到了不同的解决方法?

是否可以“重新渲染”现有的编辑器,而不是销毁和替换它?

更新:这里还有一个问题涉及相同的问题,但他提供了可下载的测试案例

32个回答

1

移除 class="ckeditor",它可能会触发 ckeditor 的初始化。


0

试试这个:

for (name in CKEDITOR.instances)
{
    CKEDITOR.instances[name].destroy(true);
}

0

我曾经遇到过同样的问题,我收到了一个空引用异常并且在编辑器中显示了“null”字样。我尝试了一些解决方案,包括将编辑器升级到3.4.1版本,但都没有成功。

最终我不得不编辑源代码。在_source\plugins\wysiwygarea\plugin.js文件的第416至426行左右,有一个类似于以下的代码片段:

iframe = CKEDITOR.dom.element.createFromHtml( '&lt;iframe' + ... + '></iframe>' );

在 Firefox 中,iframe 在需要时并没有完全实例化。因此,我使用了 setTimeout 函数来包围该行之后的其余函数内容:
iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' + ... + '></iframe>' );
setTimeout(function()
{ 
    // Running inside of Firefox chrome the load event doesn't bubble like in a normal page (#5689)
    ...
}, 1000);

};

// The script that launches the bootstrap logic on 'domReady', so the document
...

现在文本在模态对话框中呈现一致。


0
为了支持动态(Ajax)加载包含具有相同ID(重新调用相同表单)或不同ID(以前未加载的表单)的文本区域并将它们转换为CKEditor元素的表单(无需页面刷新),我使用JQuery适配器执行以下操作:
在页面完成每个传递要转换的文本区域的Ajax调用后,我调用以下函数:
setupCKeditor()

这看起来像这样(它假设要将您的文本区域转换为 RTE 的 class="yourCKClass"):

    /* Turns textAreas into TinyMCE Rich Text Editors where
 * class: tinymce applied to textarea.
 */
function setupCKeditor(){

    // define editor configuration      
    var config = {skin : 'kama'};

    // Remove and recreate any existing CKEditor instances
    var count = 0;
    if (CKEDITOR.instances !== 'undefined') {
        for(var i in CKEDITOR.instances) {

            var oEditor   = CKEDITOR.instances[i];
            var editorName = oEditor.name;

             // Get the editor data.
            var data = $('#'+editorName).val();

            // Check if current instance in loop is the same as the textarea on current page
            if ($('textarea.yourCKClass').attr('id') == editorName) {
                if(CKEDITOR.instances[editorName]) {

                    // delete and recreate the editor
                    delete CKEDITOR.instances[editorName];
                    $('#'+editorName).ckeditor(function() { },config);
                    count++;

                }
            }   


        }
    }

    // If no editor's exist in the DOM, create any that are needed.             
    if (count == 0){

        $('textarea.yourCKClass').each( function(index) {

                var editorName = $(this).attr('id');
                $('#'+editorName).ckeditor(function() { $('#'+editorName).val(data); },config);

            });

    }


}

我应该提到这一行:
$('#'+editorName).ckeditor(function() { $('#'+editorName).val(data); },config);

可以(而且应该)简单地写成:

$('#'+editorName).ckeditor(function() { },config);

然而,我发现编辑器在加载后通常会显示正确的内容,然后清空所需内容的编辑器。因此,带有回调代码的那行强制CKEditor内容与源文本区域内容相同。使用时会导致闪烁。如果可以避免使用它,请这样做。


0

CKeditor 4.2.1

这里有很多答案,但对我来说,我需要更多的东西(有点肮脏,如果有人能改进,请务必这样做)。 对我来说,MODAL是我的问题。

我在模态中使用Foundation渲染了CKEditor。 理想情况下,我会在关闭时销毁编辑器,但我不想干扰Foundation。

我调用了delete,我尝试了remove和另一种方法,但这是我最终解决的方法。

我使用文本区域来填充而不是DIV。

我的解决方案

//hard code the DIV removal (due to duplication of CKeditors on page however they didn't work)

    $("#cke_myckeditorname").remove();


     if (CKEDITOR.instances['myckeditorname']) {
                delete CKEDITOR.instances['myckeditorname'];
                CKEDITOR.replace('myckeditorname', GetCKEditorSettings());
            } else {
                CKEDITOR.replace('myckeditorname', GetCKEditorSettings());
            }

这是我的方法来返回我特定的格式,但你可能不想要。

    function GetCKEditorSettings()
    {
       return {
                    linkShowAdvancedTab: false,
                    linkShowTargetTab: false,
                    removePlugins: 'elementspath,magicline',
                    extraAllowedContent: 'hr blockquote div',
                    fontSize_sizes: 'small/8px;normal/12px;large/16px;larger/24px;huge/36px;',
                    toolbar: [
                        ['FontSize'],
                        ['Bold', 'Italic', 'Underline', '-', 'NumberedList', 'BulletedList', '-', 'Link', 'Unlink'],
                        ['Smiley']
                    ]
                };
    }

0

我和jackboberg有着完全相同的问题。我正在使用动态表单加载到jquery对话框中,然后附加各种小部件(日期选择器、ckeditor等)。 我尝试了上面提到的所有解决方案,但都没有起作用。

由于某种原因,ckeditor只在第一次加载表单时附加,第二次我得到了与jackboberg完全相同的错误消息。

我分析了我的代码,并发现如果您在“半空中”附加ckeditor,也就是说,在表单内容还没有放置到对话框中时,ckeditor不会正确地附加其绑定。这是因为ckeditor是在“半空中”附加的,第二次您在“半空中”附加它...噼啪声...一个错误被抛出,因为第一个实例没有从DOM中正确地删除。

这是导致错误的代码:

var $content = $(r.content); // jQuery can create DOM nodes from html text gotten from <xhr response> - so called "mid-air" DOM creation
$('.rte-field',$content).ckeditor(function(){});
$content.dialog();

这是有效的修复方法:

var $content = $(r.content).dialog(); // first create dialog
$('.rte-field',$content).ckeditor(function(){}); // then attach ckeditor widget

0
很简单。在我的情况下,我运行了以下 jQuery 方法,在页面加载期间销毁 ckeditor 实例。这解决了问题 -
JQuery 方法 -
function resetCkEditorsOnLoad(){

    for(var i in CKEDITOR.instances) {
        editor = CKEDITOR.instances[i];
            editor.destroy();
            editor = null;
    }
}

$(function() {

            $(".form-button").button();
    $(".button").button();

    resetCkEditorsOnLoad(); // CALLING THE METHOD DURING THE PAGE LOAD

            .... blah.. blah.. blah.... // REST OF YOUR BUSINESS LOGIC GOES HERE

       });

就是这样。希望能对你有所帮助。

祝好, Sirish。


0

对于那些使用jQuery“适配器”并遇到问题的人(就像我一样),一个超级hackish但有效的解决方案是这样做:

// content editor plugin
(function($){
    $.fn.contentEditor = function( params ) {
        var xParams = $.extend({}, $.fn.contentEditor.defaultParams, params);
        return this.each( function() {   
            var $editor = $(this);
            var $params = $.extend({}, xParams, $editor.data());

            // if identifier is set, detect type based on identifier in $editor
            if( $params.identifier.type ) {
                $params.type = $editor.find($params.identifier.type).val();
            }

            $editor.data('type', $params.type);

            // edit functionality
            editButton = $('<button>Edit Content</button>').on('click',function(){
                // content container
                var $cc = $('#' + $editor.data('type'));

                // editor window
                var $ew = $('<form class="editorWindow" />');
                $ew.appendTo('body');

                // editor content
                $ec = $('<textarea name="editorContent" />').val($cc.html());
                $ec.appendTo($ew);
                $ec.ckeditor();


                //$ec.ckeditorGet().setMode('source');


                $ew.dialog({
                    "autoOpen": true,
                    "modal": true,
                    "draggable": false,
                    "resizable": false,
                    "width": 850,
                    "height": 'auto',
                    "title": "Content Editor",
                    "buttons": { 
                        'Save': function() {                            
                            $cc.html( $ec.val() );
                            $ec.ckeditorGet().destroy(); 
                            $ew.remove();
                        },
                        'Cancel / Close': function() { 

                            $ec.ckeditorGet().destroy();                        
                            $ew.remove();
                        }
                    },
                    'close': function() {
                        $ec.ckeditorGet().destroy(); 
                    },
                    'open': function() {
                        $ew.find('a.cke_button_source').click();

                        setTimeout(function(){
                            $ew.find('a.cke_button_source.cke_on').click();
                        }, 500);
                    }
                });

                return false;
            });

            editButton.appendTo( $editor );

        });
    }

    // set default option values
    $.fn.contentEditor.defaultParams = {
        'identifier': {
            'type': 'input[name="type"]'
        }
    };   

})(jQuery);   

$(function(){

    $('form.contentEditor').contentEditor();

});

关键点在于这部分:
                'open': function() {
                    $ew.find('a.cke_button_source').click();

                    setTimeout(function(){
                        $ew.find('a.cke_button_source.cke_on').click();
                    }, 500);
                }

这个修复了编辑器文本下次打开对话框时不可见的问题。我意识到这非常hackish,但考虑到大多数这些将用于管理员工具,我认为这不像通常那样重要..而且这有效,希望能节省某人的时间 😉


0

我遇到了完全相同的问题,问题在于 wordcount 插件初始化时间太长了。超过30秒。用户会点击进入显示 ckeditor 的视图,然后取消,从而将新页面 ajax 加载到 dom 中。插件会抱怨,因为 iframe 或者 contentWindow 指向的内容已经不再可见,当它准备将自己添加到 contentWindow 时。您可以通过点击进入您的视图,然后等待 Word Count 出现在编辑器右下角来验证这一点。如果您现在取消,就不会有问题。如果您不等待它,您将收到 i.contentWindow 为空的错误。要修复它,只需放弃该插件:

if (CKEDITOR.instances['textarea_name']) 
{
   CKEDITOR.instances['textarea_name'].destroy();
}
CKEDITOR.replace('textarea_name', { removePlugins: "wordcount" } );

如果您需要一个单词计数器,可以在编辑器上注册粘贴和键盘松开事件,并使用一个计算单词的函数。

0
这是关于jquery .load() api和ckeditor的完整工作代码,我在我的情况下将带有ckeditor的页面加载到带有一些jquery效果的div中。希望它能对你有所帮助。
 $(function() {
            runEffect = function(fileload,lessonid,act) {
            var selectedEffect = 'drop';
            var options = {};
            $( "#effect" ).effect( selectedEffect, options, 200, callback(fileload,lessonid,act) );
        };
        function callback(fileload,lessonid,act) {
            setTimeout(function() {//load the page in effect div
                $( "#effect" ).load(fileload,{lessonid:lessonid,act:act});
                 $("#effect").show( "drop", 
                          {direction: "right"}, 200 );
                $("#effect").ajaxComplete(function(event, XMLHttpRequest, ajaxOptions) {
                    loadCKeditor(); //call the function after loading page
                });
            }, 100 );   
        };

        function loadCKeditor()
        {//you need to destroy  the instance if already exist
            if (CKEDITOR.instances['introduction']) 
            {
                CKEDITOR.instances['introduction'].destroy();
            }
            CKEDITOR.replace('introduction').getSelection().getSelectedText();
        }
    });

===================== button for call the function ================================

<input type="button" name="button" id="button" onclick="runEffect('lesson.php','','add')" >

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接