jQuery UI, AJAX и CKEditor — CKEditor загружается только в первый раз

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

Решение, представленное во второй ссылке, по-видимому, решает мою проблему, но удаление эффектов масштабирования отображения/скрытия не требуется для правильного создания экземпляра CKEditor. Обязательно найдется гораздо лучшая альтернатива разрешению этого конфликта.

Моя проблема:

Когда я открываю свою страницу и нажимаю кнопку редактирования, появляется диалоговое окно jQueryUI, загружает свои данные через ajax, а затем я пытаюсь заменить текстовую область, добавленную в диалоговое окно, экземпляром CKEditor. При первой загрузке страницы диалог работает без сучка и задоринки. Я могу изменять данные в редакторе, сохранять данные формы и продолжать жить дальше. Однако, если я закрою диалоговое окно, а затем открою его снова, редактор больше не будет включен. Кнопки по-прежнему имеют эффекты наведения и кликабельны, но ничего не делают. Текстовая область редактора отключена и установлена ​​на "style: visibility: hidden; display: none;". Почти вся информация, которую я могу найти по этой проблеме, была получена много лет назад, и исправления включают использование функций/методов, которые больше не существуют или не применимы.

Поток управления

Я открываю страницу, содержащую текстовую ссылку «Редактировать обновление», которая вызывает мою функцию Javascript openEditTicketUpdateDialog.

function openEditTicketUpdateDialog(tup_id, url)
    {
        simplePost(null, url, new Callback
        (
            function onSuccess(data)
            {
                $('#editticketupdatedialog').dialog('option', 'buttons',
                [
                    {
                        text: 'Save Edits',
                        click: function()
                        {
                            // Save the Update info
                            var formData = {
                                tup_update: CKEDITOR.instances.tup_update_edit.getData(),
                                tup_internal: +$('#tup_internal_edit').is(":checked"),
                                tup_important: +$('#tup_important_edit').is(":checked")
                            };

                            simplePost(formData, data['submitRoute'], new Callback
                            (
                                function onSuccess(data)
                                {
                                    $('#update-' + tup_id).html(data.input['tup_update']);
                                    $('#updateflags-' + tup_id).html(data.flags);
                                    $('#editticketupdatedialog').dialog('close');
                                },
                                function onFail(errors)
                                {
                                    console.log(errors);
                                }
                            ));
                        }
                    },
                    {
                        text: 'Cancel',
                        click: function()
                        {
                            $(this).dialog("close");
                        }
                    }
                ]);

                $('#editticketupdatedialog').dialog('option', 'title', data['title']);
                $('#editticketupdatedialog').html(data['view']);
                $('#editticketupdatedialog').dialog('open');

                destroyEditor('tup_update_edit');

                console.log('CKEDITOR.status: ' + CKEDITOR.status);
                createEditor('tup_update_edit');

            },
            function onFail(errors)
            {
                console.log(errors);
            }
        ));
    }

Эта функция использует три вспомогательные функции: simplePost, destroyEditor и createEditor.

function simplePost(data, url, callback)
{
    post(data, url, true, false, callback);
}

function createEditor(name)
{
    console.log('Create editor: ' + name);
    console.log('Current Instance: ');
    console.log(CKEDITOR.instances.name);

    if (CKEDITOR.status == 'loaded')
    {
        CKEDITOR.replace(name,
        {
            customConfig: '/js/ckeditor/custom/configurations/standard_config.js'
        });
    }
    else
    {
        CKEDITOR.on('load', createEditor(name));
        CKEDITOR.loadFullCore && CKEDITOR.loadFullCore();
    }

    console.log('After instance created: ');
    var instance = CKEDITOR.instances.name;
    console.log(instance);
}

function destroyEditor(name)
{
    console.log('Destroy editor: ' + name);
    console.log('Current Instance: ');
    console.log(CKEDITOR.instances.name);

    if (CKEDITOR.instances.name)
    {
        console.log('Instance exists - destroying...');
        CKEDITOR.instances.name.destroy();
        $('#' + name).off().remove();
    }

    console.log('After instance removed: ');
    var instance = CKEDITOR.instances.name;
    console.log(instance);
}

Этот метод создания экземпляра CKEditor взят из здесь. Этот метод уничтожения экземпляра CKEditor взят из здесь.

Как видите, openEditTicketUpdateDialog запускает AJAX-вызов моей функции getEditUpdateForm через маршруты Laravel.

public function getEditUpdateForm($tup_id, $update_number)
{
    $update = Update::find($tup_id);

    $data = [
        'title' => 'Editing update #' . $update_number . ' of ticket #' . $update->tup_ticket,
        'view' => View::make('tickets.ticketupdate-edit')
            ->with('update', $update)
            ->render(),
        'submitRoute' => route('tickets/update/submit', $tup_id)
    ];

    return Response::json(array('status' => 1, 'data' => $data));
}

Отсюда возвращается статус 1 и вызывается функция onSuccess. Я пытался добавить вызовы создания/удаления перед вызовом $('#editticketupdatedialog').dialog('open');, но безрезультатно. Я также пробовал несколько других решений, которые я обнаружил, которые включают взломанные реализации функций и атрибутов Dialog jQueryUI: _allowInteraction и moveToTop. Первоначально мне удалось решить эту проблему в первый раз, когда она возникла, вызвав эту функцию перед выполнением CKEDITOR.replace:

function enableCKEditorInDialog()
{
    $.widget( "ui.dialog", $.ui.dialog, {
    /**
    * jQuery UI v1.11+ fix to accommodate CKEditor (and other iframed content) inside a dialog
    * @see http://bugs.jqueryui.com/ticket/9087
    * @see http://dev.ckeditor.com/ticket/10269
    */
    _allowInteraction: function( event ) {
        return this._super( event ) ||

        // addresses general interaction issues with iframes inside a dialog
        event.target.ownerDocument !== this.document[ 0 ] ||

        // addresses interaction issues with CKEditor's dialog windows and iframe-based dropdowns in IE
        !!$( event.target ).closest( ".cke_dialog, .cke_dialog_background_cover, .cke" ).length;
    }
    });
}

После обновления до Laravel 5 и внесения нескольких других изменений на стороне сервера это исправление больше не работает. Мне удалось решить мою проблему, удалив свойства отображения/скрытия из моего диалогового окна. Я бы очень предпочел не удалять эти свойства, так как половина аргументов в пользу наличия диалога — это эстетика анимации. Вот моя инициализация диалога.

$('#editticketupdatedialog').dialog({
    modal: true,
    draggable: false,
    minWidth: 722,
    autoOpen: false,
    show:
    {
        effect: "scale",
        duration: 200
    },
    hide:
    {
        effect: "scale",
        duration: 200
    },
    closeOnEscape: true
});

Когда у меня включены эти анимации, в первый раз, когда я использую диалог, он работает отлично. Во второй раз я получаю ошибку TypeError: this.getWindow(...).$ is undefined - ckeditor.js:83:18 в консоли JS, которая относится к этой строке:

function(a)
{
    var d = this.getWindow().$.getComputedStyle(this.$,null);

    return d ? d.getPropertyValue(a) : ""
}

Подведение итогов

Моя главная цель здесь — найти решение этой проблемы, не удаляя анимацию диалогового окна jQueryUI. Я не уверен, на кого указать пальцем, так как я действительно не могу определить, связана ли проблема с CKEditor, jQueryUI или моей реализацией.


person Aaron St. Clair    schedule 03.03.2015    source источник


Ответы (1)


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

Моя инициализация выглядит следующим образом:

$('#editticketupdatedialog').dialog({
    modal: true,
    draggable: false,
    minWidth: 722,
    autoOpen: false,
    show:
    {
        effect: "scale",
        duration: 200
    },
    hide:
    {
        effect: "scale",
        duration: 200
    },
    closeOnEscape: true,
    open: function()
    {
        $(this).parent().promise().done(function ()
        {
            destroyEditor('tup_update_edit');

            console.log('CKEDITOR.status: ' + CKEDITOR.status);
            createEditor('tup_update_edit');
        });
    }
});
person Aaron St. Clair    schedule 03.03.2015