Виджет JS (с использованием Jquery), конфликтующий с Prototype на хост-странице

Я предоставляю виджет Javascript другим сайтам, и мое использование Jquery в виджете конфликтует с использованием Prototype хост-сайтом.

Вы можете увидеть конфликт в действии здесь: http://www.phillyrealestateadvocate.idxco.com/idx/8572/results.php?lp=100000&hp=500000&sqFt=0&bd=2&ba=0&searchSubmit=&city%5B%5D=131< /а>

В правой части страницы нажмите зеленую кнопку «Задать вопрос» — появится всплывающее окно, и как только вы откроете всплывающее окно, в консоль JS начнут поступать ошибки «неверная длина массива» (и не t stop.) После этого всплывающее окно не может закрыться, но его можно перетаскивать. Код/контент во всплывающем окне находится в iframe, поэтому он по-прежнему работает нормально, но всплывающее окно просто не закрывается.

Firebug выдает мне следующую ошибку: invalid array length в Prototype.js, но когда я раскрываю ее для деталей, в ней есть ссылки на jquery.min.js, поэтому это заставило меня поверить, что они конфликтуют.

Код моего виджета полностью находится в анонимной функции и загружает Jquery, используя модель, описанную здесь Алексом Марандоном: http://alexmarandon.com/articles/web_widget_jquery/

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

Вот начало моего скрипта виджета, который содержит ссылки на jquery.min.js и jqueryui:

    (function() {

        // Localize jQuery variable
        var jQuery;

        /******** Load jQuery if not present *********/
        if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.6.2') 
        {
            var script_tag = document.createElement('script');
            script_tag.setAttribute("type","text/javascript");
            script_tag.setAttribute("src",
                "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js");
            script_tag.onload = scriptLoadHandler;
            script_tag.onreadystatechange = function () { // Same thing but for IE
                if (this.readyState == 'complete' || this.readyState == 'loaded') {
                    scriptLoadHandler();
                }
            };
            // Try to find the head, otherwise default to the documentElement
            (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
        } 
        else 
        {
            $.getScript( "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js" , 
                function()
                {
                    // The jQuery version on the window is the one we want to use
                    jQuery = window.jQuery;
                    main();
                }
            );
        }

        /******** Called once jQuery has loaded ******/
        function scriptLoadHandler() 
        {
            $.getScript( "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js" , 
                function()
                {
                    // Restore $ and window.jQuery to their previous values and store the
                    // new jQuery in our local jQuery variable
                    jQuery = window.jQuery.noConflict(true);
                    main(); 
                }
            );
        }

        /******** Our main function ********/
        function main() 
        { 

           // Do a bunch of stuff here

    }

})(); // We call our anonymous function immediately

Любая помощь приветствуется!

Изменить: теперь у меня есть пользовательский интерфейс Jquery непосредственно в виджете, поэтому я полностью исключил вызовы getScript. К сожалению, это не решило конфликт. Вот новый код:

(function() {

    // Localize jQuery variable
    var jQuery, 

    /******** Load jQuery if not present *********/
    if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.6.2') 
    {
        var script_tag = document.createElement('script');
        script_tag.setAttribute("type","text/javascript");
        script_tag.setAttribute("src", "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js");
        script_tag.onload = scriptLoadHandler;
        script_tag.onreadystatechange = function () { // Same thing but for IE
            if (this.readyState == 'complete' || this.readyState == 'loaded') {
                scriptLoadHandler();
            }
        };
        // Try to find the head, otherwise default to the documentElement
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
    } 
    else 
    {
        jQuery = window.jQuery;
        main();
    }

    /******** Called once jQuery has loaded ******/
    function scriptLoadHandler() 
    {
        jQuery = window.jQuery.noConflict(true);
        main(); 
    }

    /******** Our main function ********/
    function main() 
    { 

person Wemmick    schedule 10.10.2011    source источник


Ответы (2)


Проблема в том, что Prototype переопределяет метод Array.shift по умолчанию, что не является полностью совместимым. jQuery ожидает поведения по умолчанию.

На самом деле это не вызывает проблем только с jQuery, когда ваша страница загружается, вы получаете аналогичную ошибку, вызванную вызовом shift в сценарии curfon-yui.js, загруженном на эту страницу.

Давайте попробуем это в Firebug без загруженного Prototype:

  >>> [].shift()
  undefined

Теперь на вашей странице:

>>> [].shift()
RangeError: invalid array length
this[i]=this[i+1];this.length--;return...ct).join(': ');}).join(', ')+'}>';}} 

Очевидно, вы не единственный, у кого есть эта проблема: http://tommysetiawan.com/post/7887390641/jquery-and-prototype-conflict-array-shift

К сожалению, NoConflict в jQuery не поможет. Похоже, что проблема решена в более поздних версиях Prototype, поэтому, если у вас есть какой-либо контроль над главной страницей, обновление версии Prototype может помочь. Тот факт, что он уже вызывает ошибки с другим скриптом, может быть хорошим аргументом, чтобы убедить владельца этой страницы исправить это. В противном случае вам может потребоваться изменить виджет, чтобы он не вызывал Array.shift, или вы даже можете попытаться исправить Array.shift таким образом, чтобы это исправилось.

person Alex Marandon    schedule 12.10.2011

Вы должны определить jQuery.noConflict() сразу после function scriptLoadHandler(){. В настоящее время вы вызываете noConflict() после загрузки подключаемого модуля пользовательского интерфейса, что уже слишком поздно.

var hasLoaded = false;
function scriptLoadHandler() 
    {
        if(hasLoaded) return;
        hasLoaded = true;
        window.jQuery = jQuery.noConflict(true);
        jQuery.getScript( "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js" , 
            function(){
                main(); 
            }
        );
    }

Обновление: добавлено hasLoaded для предотвращения двойного выполнения кода.

person Rob W    schedule 10.10.2011
comment
Итак, я только что попробовал это, но теперь Firebug говорит, что jQuery не определен (в строке noConflict) - person Wemmick; 11.10.2011
comment
Ваш загрузчик неисправен, обновите ответ, чтобы исправить это. - person Rob W; 11.10.2011
comment
Я не мог заставить это работать с помощью getScript после noConflict, поэтому я вставил код пользовательского интерфейса jQuery в код самого виджета. Если кто-то может увидеть, что я делаю неправильно, я хотел бы услышать это! - person Wemmick; 11.10.2011