web-dev-qa-db-fra.com

Fire Greasemonkey script sur AJAX demande

Je travaille sur un script utilisateur et je viens de constater que le script n'est pas exécuté lorsque la page principale effectue des requêtes AJAX.

Existe-t-il un moyen de déclencher le script utilisateur à la fois lors du chargement de la page principale et lors des requêtes AJAX?

30
LooPer

La méthode intelligente pour réexécuter le code du script sur les demandes AJAX consiste à se concentrer sur les éléments clés de la page et à vérifier les modifications.

Par exemple, supposons qu'une page contienne du code HTML comme suit:

<div id="userBlather">
    <div class="comment"> Comment 1... </div> 
    <div class="comment"> Comment 2... </div> 
    ... 
</div>

et vous vouliez que le script fasse quelque chose avec chaque commentaire au moment de son entrée.

Maintenant, vous pouvez intercepter tous les appels AJAX, ou écoutez DOMSubtreeModified(obsolète), ou utilisez MutationObservers, mais ces méthodes peuvent être compliquées, difficiles et trop compliquées. 

Un moyen plus simple et plus robuste d’obtenir du contenu ajax sur une page sauvage consiste à interroger ce contenu à l’aide de la fonction waitForKeyElements ci-dessous.

Par exemple, ce script mettra en évidence les commentaires contenant "bière", comme ils le sont dans AJAX:

// ==UserScript==
// @name            _Refire on key Ajax changes
// @include         http://YOUR_SITE.com/YOUR_PATH/*
// @require         http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
// ==/UserScript==

function highlightGoodComments (jNode) {

    //***** YOUR CODE HERE *****

    if (/beer/i.test (jNode.text () ) ) {
        jNode.css ("background", "yellow");
    }
    //...
}
waitForKeyElements ("#userBlather div.comment", highlightGoodComments);

/*--- waitForKeyElements():  A utility function, for Greasemonkey scripts,
    that detects and handles AJAXed content.

    IMPORTANT: This function requires your script to have loaded jQuery.
*/
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);

    if (targetNodes  &&  targetNodes.length > 0) {
        btargetsFound   = true;
        /*--- Found target node(s).  Go through each and act if they
            are new.
        */
        targetNodes.each ( function () {
            var jThis        = $(this);
            var alreadyFound = jThis.data ('alreadyFound')  ||  false;

            if (!alreadyFound) {
                //--- Call the payload function.
                var cancelFound     = actionFunction (jThis);
                if (cancelFound)
                    btargetsFound   = false;
                else
                    jThis.data ('alreadyFound', true);
            }
        } );
    }
    else {
        btargetsFound   = false;
    }

    //--- Get the timer-control variable for this selector.
    var controlObj      = waitForKeyElements.controlObj  ||  {};
    var controlKey      = selectorTxt.replace (/[^\w]/g, "_");
    var timeControl     = controlObj [controlKey];

    //--- Now set or clear the timer as appropriate.
    if (btargetsFound  &&  bWaitOnce  &&  timeControl) {
        //--- The only condition where we need to clear the timer.
        clearInterval (timeControl);
        delete controlObj [controlKey]
    }
    else {
        //--- Set a timer, if needed.
        if ( ! timeControl) {
            timeControl = setInterval ( function () {
                    waitForKeyElements (    selectorTxt,
                                            actionFunction,
                                            bWaitOnce,
                                            iframeSelector
                                        );
                },
                300
            );
            controlObj [controlKey] = timeControl;
        }
    }
    waitForKeyElements.controlObj   = controlObj;
}

Mettre à jour:

Pour plus de commodité, waitForKeyElements() est maintenant hébergé sur GitHub .

Cette réponse montre un exemple d'utilisation de la fonction hébergée .

61
Brock Adams

Un autre moyen - plus simple et plus petit mais moins flexible - consiste à utiliser un délai JavaScript pour attendre le chargement et la fin du AJAX/jQuery. Par exemple, si le code HTML suivant a été généré dynamiquement après le premier chargement:

<div id="userBlather">
    <div class="comment"> Comment 1... </div> 
    <div class="comment"> Comment 2... </div> 
    ... 
</div>

Alors un script greasemonkey comme celui-ci pourrait le modifier:

// Wait 2 seconds for the jQuery/AJAX to finish and then modify the HTML DOM
window.setTimeout(updateHTML, 2000);

function updateHTML()
{
    var comments = document.getElementsByClassName("comment");
    for (i = 0; i < comments.length; i++)
    {
        comments[i].innerHTML = "Modified comment " + i;
    }
}

Voir les conseils ici: Sommeil/Pause/Attendre javascript

0
Mr-IDE