Экземпляр CKEditor уже существует

Я использую диалоги 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 ответа

Чтобы это работало, вам нужно передать логический параметр true при уничтожении экземпляра:

    var editor = CKEDITOR.instances[name];
    if (editor) { editor.destroy(true); }
    CKEDITOR.replace(name);
function loadEditor(id)
{
    var instance = CKEDITOR.instances[id];
    if(instance)
    {
        CKEDITOR.remove(instance);
    }
    CKEDITOR.replace(id);
}

У меня тоже была эта проблема, но я решил ее гораздо проще...

Я использовал класс "ckeditor" в моем скрипте jQuery как селектор, для которого я хотел бы использовать текстовые области для CKEditor. JS-скрипт ckeditor по умолчанию также использует этот класс, чтобы определить, какие текстовые области использовать для CKEditor.

Это означало конфликт между моим скриптом jQuery и скриптом ckeditor по умолчанию.

Я просто изменил класс текстовой области и моего скрипта jQuery на do_ckeditor (вы можете использовать все, кроме ckeditor), и это сработало.

Это самое простое (и единственное) решение, которое сработало для меня:

if(CKEDITOR.instances[editorName])
   delete CKEDITOR.instances[editorName];
CKEDITOR.replace(editorName);

Удаление этой записи в массиве не позволяет этой проверке безопасности формы уничтожить ваше приложение.

Уничтожить () и удалить () не работает для меня.

Возможно, это поможет вам - я сделал нечто подобное, используя jquery, за исключением того, что загружаю неизвестное количество объектов ckeditor. Мне потребовалось некоторое время, чтобы наткнуться на это - это не ясно в документации.

function loadEditors() {
    var $editors = $("textarea.ckeditor");
    if ($editors.length) {
        $editors.each(function() {
            var editorID = $(this).attr("id");
            var instance = CKEDITOR.instances[editorID];
            if (instance) { instance.destroy(true); }
            CKEDITOR.replace(editorID);
        });
    }
}

И вот что я запускаю, чтобы получить контент от редакторов:

    var $editors = $("textarea.ckeditor");
    if ($editors.length) {
        $editors.each(function() {
            var instance = CKEDITOR.instances[$(this).attr("id")];
            if (instance) { $(this).val(instance.getData()); }
        });
    }

ОБНОВЛЕНИЕ: я изменил свой ответ, чтобы использовать правильный метод -.destroy(). .remove() должен быть внутренним и был неправильно задокументирован в какой-то момент.

var e= CKEDITOR.instances['sample'];
e.destroy();
e= null;

У меня была похожая проблема, когда мы делали несколько экземпляров CKeditor для контента, загружаемого через ajax.

CKEDITOR.remove ()

Хранит DOM в памяти и не удаляет все привязки.

CKEDITOR.instance [instance_id].destroy()

Дала ошибку i.contentWindow ошибка всякий раз, когда я создаю новый экземпляр с новыми данными из ajax. Но это было только до тех пор, пока я не понял, что уничтожаю экземпляр после очистки DOM.

Используйте destroy(), пока экземпляр и его DOM присутствуют на странице, тогда он прекрасно работает.

Для запросов AJAX,

 for(k in CKEDITOR.instances){
    var instance = CKEDITOR.instances[k];
    instance.destroy()
 }
  CKEDITOR.replaceAll();

этот фрагмент удаляет все экземпляры из документа. Затем создает новые экземпляры.

Вы можете удалить любой экземпляр ckeditor, удалив метод ckeditor. Экземпляр будет идентификатором или именем текстовой области.

if (CKEDITOR.instances[instance_name]) {
    CKEDITOR.remove(CKEDITOR.instances[instance_name]);
}

i.contentWindow is null Кажется, ошибка возникает при вызове команды destroy для экземпляра редактора, который был привязан к текстовой области, которой больше нет в DOM.

CKEDITORY.destroy принимает параметр noUpdate,

APIdoc утверждает:

Если экземпляр заменяет элемент DOM, этот параметр указывает, следует ли обновлять элемент содержимым экземпляра.

Итак, чтобы избежать ошибки, либо вызовите destroy перед удалением элемента textarea из DOM, либо вызовите destory (true), чтобы избежать попытки обновить несуществующий элемент DOM.

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

(используя версию 3.6.2 с адаптером jQuery)

Вот что сработало для меня:

for(name in CKEDITOR.instances)
{
  CKEDITOR.instances[name].destroy()
}
CKEDITOR.instances = new Array();

Я использую это перед своими звонками, чтобы создать экземпляр (по одному на страницу загрузки). Не уверен, как это влияет на обработку памяти, а что нет. Это будет работать, только если вы хотите заменить все экземпляры на странице.

У меня была такая же проблема с экземплярами, я искал везде, и, наконец, эта реализация работает для меня:



    //set my instance id on a variable

    myinstance = CKEDITOR.instances['info'];

    //check if my instance already exist

    if (myinstance) { 
        CKEDITOR.remove(info)
    }

    //call ckeditor again

    $('#info').ckeditor({
        toolbar: 'Basic',
        entities: false,
        basicEntities: false
    });

Я подготовил свое собственное решение на основе всех приведенных выше кодов.

      $("textarea.ckeditor")
      .each(function () {

                var editorId = $(this).attr("id");

                try {    
                    var instance = CKEDITOR.instances[editorId];
                    if (instance) { instance.destroy(true); }

                }
                catch(e) {}
                finally {
                    CKEDITOR.replace(editorId);
                }
            });

Это прекрасно работает для меня.

Иногда после AJAX-запроса возникает неправильная структура DOM. Для установки:

<div id="result">
   <div id="result>
   //CONTENT
   </div>
</div>

Это также вызовет проблему, и ckEditor не будет работать. Поэтому убедитесь, что у вас правильная структура DOM.

Действительно, удаление класса.ckeditor из вашего кода решает проблему. Большинство из нас следовали примеру интеграции с jQuery из документации ckeditor:

$('.jquery_ckeditor')
.ckeditor( function() { /* callback code */ }, { skin : 'office2003' } );

и подумал "... может быть, я могу просто избавиться или".jquery_'часть ".

Я тратил свое время на настройку функции обратного вызова (потому что {skin:'office2003'} действительно работал), в то время как проблема исходила из других источников.

Я думаю, что в документации следует упомянуть, что использование "ckeditor" в качестве имени класса не рекомендуется, потому что это зарезервированное ключевое слово.

Приветствия.

Я решил переименовать все экземпляры вместо уничтожения / замены - поскольку иногда загруженный AJAX-экземпляр на самом деле не заменяет тот, что находится в ядре страницы... он сохраняет больше в ОЗУ, но при этом меньше конфликтует.

    if (CKEDITOR && CKEDITOR.instances) {
        for (var oldName in CKEDITOR.instances) {
            var newName = "ajax"+oldName;
            CKEDITOR.instances[newName] = CKEDITOR.instances[oldName];
            CKEDITOR.instances[newName].name = newName;
            delete CKEDITOR.instances[oldName];
        }
    }

Удалить class="ckeditor", это могло бы вызвать инициализацию ckeditor

У меня эта функция работает в CKEditor версии 4.4.5, у нее нет утечек памяти

 function CKEditor_Render(CkEditor_id) {
        var instance = CKEDITOR.instances[CkEditor_id];
        if (CKEDITOR.instances.instance) {
            CKEDITOR.instances.instance.destroy();
        }
        CKEDITOR.replace(CkEditor_id);
    }

// вызываем эту функцию, как показано ниже

var id = 'ckeditor'; // Id of your textarea

CKEditor_Render(id);

Я узнал, что

удалить CKEDITOR.instances[editorName];

сам по себе фактически удалил экземпляр. ВСЕ другие методы, которые я читал и видел, включая то, что было найдено здесь в stackru от его пользователей, не работали для меня.

В моей ситуации я использую ajax-вызов, чтобы вытащить копию содержимого, обернутого вокруг и. Проблема заключается в том, что я использую событие jQuery .live для привязки ссылки "Редактировать этот документ", а затем применяю экземпляр ckeditor после успешной загрузки ajax. Это означает, что когда я щелкаю по другой ссылке на ссылку с другим событием.live, я должен использовать delete CKEDITOR.instances[editorName] как часть моей задачи очистки окна содержимого (удержания формы), а затем повторной выборки содержимого, удерживаемого в базе данных или другом ресурсе.

У меня такая же проблема с диалогом jQuery.

Зачем уничтожать экземпляр, если вы просто хотите удалить предыдущие данные?

function clearEditor(id)
{
  var instance = CKEDITOR.instances[id];
  if(instance)
  {
    instance.setData( '' );
  }
}

Я нахожусь в ситуации, когда мне нужно управлять этими диалоговыми окнами, каждый из которых должен иметь встроенный в них диалог. И так бывает, что текстовые области имеют одинаковый идентификатор. (обычно это очень плохая практика, но у меня есть 2 jqGrids, один из назначенных элементов и другой из неназначенных элементов.) Они имеют почти идентичную конфигурацию. Таким образом, я использую общий код для настройки обоих.

Поэтому, когда я загружаю диалог для добавления строк или их редактирования из jqGrid; Я должен удалить все экземпляры CKEDITOR во всех текстовых областях.

$('textarea').each(function()
{
    try 
    {
        if(CKEDITOR.instances[$(this)[0].id] != null)
        {
            CKEDITOR.instances[$(this)[0].id].destroy();
        }
    }
    catch(e)
    {

    }
});

Это зациклит все текстовые области, и если есть экземпляр CKEDITOR, то уничтожьте его.

В качестве альтернативы, если вы используете чистый JQuery:

$('textarea').each(function()
{
    try 
    {
        $(this).ckeditorGet().destroy();
    }
    catch(e)
    {

    }
});

У меня была точно такая же проблема, как у Джекбобера. Я использовал динамическую загрузку форм в диалогах jquery, а затем прикреплял различные виджеты (средства выбора даты, ckeditors и т. Д.). И я попробовал все решения, указанные выше, ни одно из них не сработало для меня.

По какой-то причине ckeditor только прикрепил первый раз, когда я загрузил форму, во второй раз я получил точно такое же сообщение об ошибке, которое сделал jackboberg.

Я проанализировал свой код и обнаружил, что если вы прикрепите ckeditor в "воздухе", то есть, пока содержимое формы еще не помещено в диалог, ckeditor не будет правильно прикреплять свои привязки. Это связано с тем, что ckeditor подключен в "воздухе", во второй раз, когда вы подключаете его в "воздухе"... poof... выдается ошибка, поскольку первый экземпляр не был должным образом удален из 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

Это довольно просто. В моем случае я запустил приведенный ниже метод 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

       });

Вот и все. Я надеюсь, что это поможет вам.

Ура, Сириш.

Попробуй это:

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

Для тех, кто использует "адаптер" jquery и имеет проблемы (как я), супер хакерское, но работающее решение - сделать что-то вроде этого:

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

Это устраняет проблему с тем, что текст редактора не будет виден при следующем открытии диалога. Я понимаю, что это очень хакерски, но, учитывая, что большинство из них будут использоваться для инструментов администратора, я не думаю, что это настолько серьезная проблема, как обычно... и это работает, так что, надеюсь, это спасет кого-то время;)

У меня была та же проблема, когда я получал исключение нулевой ссылки, и слово "нуль" будет отображаться в редакторе. Я попробовал несколько решений, включая обновление редактора до 3.4.1, но безрезультатно.

Я закончил тем, что отредактировал источник. Примерно в строке от 416 до 426 в _source\plugins\wysiwygarea\plugin.js есть фрагмент, подобный следующему:

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

В FF, по крайней мере, 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
...

Текст отображается последовательно в модальных диалогах.

Это полностью рабочий код для jquery .load() api и ckeditor, в моем случае я загружаю страницу с ckeditor в div с некоторыми эффектами jquery. Я надеюсь, что это поможет вам.

 $(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')" >

Чтобы поддерживать динамическую (Ajax) загрузку форм (без обновления страницы между ними), которые содержат текстовые области с одинаковыми (одна и та же форма вызывается снова) или разными идентификаторами (ранее выгруженная форма) и преобразовывать их в элементы 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 совпадать с исходным содержимым textarea. Вызывает мерцание при использовании. Если вы можете избежать его использования, сделайте это..

Я столкнулся с этой же проблемой, и проблема заключалась в том, что плагин wordcount занимал слишком много времени для инициализации. Более 30 секунд Пользователь щелкает в представлении, отображающем ckeditor, затем отменяет, тем самым ajax-загрузка новой страницы в DOM. Плагин жаловался, потому что iframe или все, на что указывает contentWindow, уже не было видно, когда он был готов добавить себя в contentWindow. Вы можете убедиться в этом, щелкнув по своему виду, а затем подождать, пока в правом нижнем углу редактора появится Количество слов. Если вы отмените сейчас, у вас не будет проблем. Если вы не ждете этого, вы получите ошибку i.contentWindow is null. Чтобы это исправить, просто удалите плагин:

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

Если вам нужен счетчик слов, зарегистрируйтесь для добавления и редактирования событий в редакторе с помощью функции, которая считает слова.

CKeditor 4.2.1

Здесь есть много ответов, но для меня мне нужно что-то большее (немного грязное, поэтому, если кто-то может улучшить, пожалуйста, сделайте). Для меня МОДАЛИ, где моя проблема.

Я рендерил CKEditor в модальном режиме, используя Foundation. В идеале я бы уничтожил редактора после закрытия, однако я не хотел связываться с Фондом.

Я вызвал удаление, я попытался удалить и другой метод, но с этим я наконец и остановился.

Я использовал textarea для заполнения не DIVs.

Мое решение

//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']
                    ]
                };
    }
Другие вопросы по тегам