waitForKeyElements не ожидает загрузки данных ajax в некоторых браузерах?

В моем скрипте для Greasemonkey/Tampermonkey отлично работает в Google Chrome, но в Firefox это:

waitForKeyElements ("table#ID-rowTable tr td span._GAmD", replaceAffid);

не ждет загруженного контента AJAX.

Вот соответствующая часть моего сценария:

// ==UserScript==
// @name        ChangeProvider
// @description Change Provider Name
// @include     https://analytics.google.com/analytics/web/*
// @version     1
// @grant       GM_xmlhttpRequest
// ==/UserScript==

<snip>...

waitForKeyElements ("table#ID-rowTable tr td span._GAmD", replaceAffid);

<snip>...

function waitForKeyElements (
    selectorTxt,    /* Required: The jQuery selector string that
                        specifies the desired element(s).
                    */
    actionFunction, /* Required: The code to run when elements are
                        found. It is passed a jNode to the matched
                        element.
                    */
    bWaitOnce,      /* Optional: If false, will continue to scan for
                        new elements even after the first match is
                        found.
                    */
    iframeSelector  /* Optional: If set, identifies the iframe to
                        search.
                    */
) {
    var targetNodes, btargetsFound;

    if (typeof iframeSelector == "undefined")
        targetNodes     = $(selectorTxt);
    else
        targetNodes     = $(iframeSelector).contents ()
                                           .find (selectorTxt);

<snip>...


Полный код находится на pastebin.com.

1 ответ

Решение

Проблема (ы) в том, что:

  1. waitForKeyElements() требует jQuery.

  2. Ваш скрипт должен либо предоставить jQuery (рекомендуется), либо использовать @grant none режим и запуск на странице, которая уже использует jQuery (хрупкий способ сделать что-то, AKA "код бомбы замедленного действия").

  3. У Tampermonkey есть ошибка и возможная слабость в плане безопасности, из-за которой она не всегда правильно работает в песочнице. Это означает, что скрипт может (иногда) видеть jQuery страницы, даже когда @grant не является none. Это позволило скрипту работать в Chrome (на данный момент), но это очень рискованная вещь, от которой можно зависеть.

  4. Firefox правильно помещает " песочницу" в область видимости при использовании @grant GM_ ... поэтому скрипт не может видеть jQuery страницы.

  5. Если бы вы посмотрели на консоль браузера Firefox, вы бы увидели сообщения об ошибках, указывающие на проблему.

Решение: не используйте waitForKeyElements без @require в jQuery!
На самом деле, вам должны потребоваться обе библиотеки, как показано в этом ответе, так как он (A) работает быстрее, (B) выбирает код только один раз, когда вы устанавливаете / редактируете пользовательский скрипт, и (C) делает его чище, легче код Грока.

Таким образом, весь ваш сценарий станет примерно таким:

// ==UserScript==
// @name        GoogleAnalytics Change Provider
// @description Change Provider Name
// @include     https://analytics.google.com/analytics/web/*
// @version     1
// @require     http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant       GM_xmlhttpRequest
// ==/UserScript==
var providers = new Array ();

GM_xmlhttpRequest ( {
    method: "GET",
    url: "http://localhost:3000/api/t2_provider_list",
    onload: function (response) {
        var provider_list = JSON.parse (response.responseText);

        for (i = 0; i < provider_list.length; i++) {
            providers[provider_list[i].analytics_prefix] = provider_list[i].provider_name;
        }
        waitForKeyElements ("table#ID-rowTable tr td span._GAmD", replaceAffid);
    }
} );

/*--- replaceAffid ():  Match the fields with a given pattern 
and replace with the provider name and affid
*/
function replaceAffid () {
    console.log (providers);
    var regExp = /([a-z,A-Z,0-9]+)---([a-z,A-Z,0-9,_,-]+)/g;

    var spans = document.evaluate ("//span[contains(@class, '_GAmD') and not(contains(@class, '_GAe'))]/text()", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    console.log (spans);
    for (var i = 0; i < spans.snapshotLength; i++) {
        match = regExp.exec (spans.snapshotItem (i).textContent);

        if (match != null) {
            if (typeof providers[match[1]] === undefined) {
                // do nothing
            } else {
                spans.snapshotItem (i).textContent = "Provider: " + providers[match[1]] + " \n\r  Affid: " + match[2];
            }
        }
    }
}

Наконец, похоже, что вы вставили старую версию waitForKeyElements.
С мая 2012 года эта функция имеет следующий текст:

ВАЖНО: эта функция требует, чтобы ваш скрипт загружал jQuery.

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

Другие вопросы по тегам