Создание пользовательского интерфейса jQuery для сортировки в iframe

На странице у меня есть iframe. В этом iframe есть набор элементов, которые мне нужно сортировать. Все Javascript запускаются на родительской странице. Я могу получить доступ к списку в документе iframe и создать сортировку с помощью контекста:

var ifrDoc = $( '#iframe' ).contents();

$( '.sortable', ifrDoc ).sortable( { cursor: 'move' } );

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

Пример: http://robertadamray.com/sortable-test.html

Итак, есть ли способ достичь того, что я хочу сделать - желательно без необходимости взломать код jQuery UI?

Ответ 1

Динамически добавить jQuery и jQuery UI в iframe (demo):

$('iframe')
    .load(function() {
        var win = this.contentWindow,
            doc = win.document,
            body = doc.body,
            jQueryLoaded = false,
            jQuery;

        function loadJQueryUI() {
            body.removeChild(jQuery);
            jQuery = null;

            win.jQuery.ajax({
                url: 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js',
                dataType: 'script',
                cache: true,
                success: function () {
                    win.jQuery('.sortable').sortable({ cursor: 'move' });
                }
            });
        }

        jQuery = doc.createElement('script');

        // based on https://gist.github.com/getify/603980
        jQuery.onload = jQuery.onreadystatechange = function () {
            if ((jQuery.readyState && jQuery.readyState !== 'complete' && jQuery.readyState !== 'loaded') || jQueryLoaded) {
                return false;
            }
            jQuery.onload = jQuery.onreadystatechange = null;
            jQueryLoaded = true;
            loadJQueryUI();
        };

        jQuery.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js';
        body.appendChild(jQuery);
    })
    .prop('src', 'iframe-test.html');

Обновление: Andrew Ingram правильно, что пользовательский интерфейс jQuery хранит и использует ссылки на window и document для страницы, на которой пользовательский интерфейс jQuery загружен. Загружая jQuery/jQuery UI в iframe, он имеет правильные ссылки (для iframe, а не внешнего документа) и работает как ожидалось.


Обновление 2: Исходный фрагмент кода имел тонкую проблему: порядок выполнения динамических тегов script не гарантируется. Я обновил его, чтобы пользовательский интерфейс jQuery загружался после того, как jQuery готов.

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

Ответ 2

Играя со своим javascript немного, Campaign Monitor решает это, в основном имея пользовательскую версию jQuery UI. Они изменили ui.mouse и ui.sortable, чтобы заменить ссылки на документ и окно с кодом, который получает документ и окно для рассматриваемого элемента. document становится this.element[0].ownerDocument

и у них есть пользовательская функция jQuery, называемая window(), которая позволяет им заменить window на this.element.window() или аналогичную.

Ответ 3

Я не знаю, почему ваш код не работает. Похоже, должно быть.

Итак, вот два альтернативных способа реализации этой функции:

  • Если вы можете изменить iframe

    Переместите JavaScript из родительского документа в iframe-test.html. Это может быть самым чистым способом, поскольку он соединяет JavaScript с элементами, на которых он фактически выполняется.

    http://dl.dropbox.com/u/3287783/snippets/rarayiframe/sortable-test.html

  • Если вы управляете только родительским документом

    Используйте метод jQuery.load() для извлечения содержимого вместо HTML iframe.

    http://dl.dropbox.com/u/3287783/snippets/rarayiframe2/sortable-test.html

Ответ 4

Вместо того, чтобы загружать jQuery и jQueryUI внутри iFrame и оценивать взаимодействия jQueryUI как в родительском, так и в дочернем - вы можете просто вывести события мыши в родительский документ:

var ifrDoc = $( '#iframe' ).contents();

$('.sortable', ifrDoc).on('mousemove mouseup', function (event) {
    $(parent.document).trigger(event);
});

Таким образом вы можете оценить весь свой Javascript в контексте родительского документа.