2011-11-26 16 views
27

Sto lavorando a uno script utente e ho appena scoperto che lo script non viene eseguito quando la pagina principale effettua richieste AJAX.Fire Greasemonkey script su richiesta AJAX

C'è un modo per attivare lo script utente sia sul caricamento della pagina principale che sulle richieste AJAX?

risposta

56

Il modo intelligente per rieseguire il codice dello script su richieste AJAX, è di concentrarsi sui bit chiave della pagina e controllare le modifiche.

Ad esempio, supponiamo che una pagina contenuta HTML in questo modo:

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

e si voleva lo script di fare qualcosa con ogni commento come è venuto in

Ora è poteva intercettare tutto AJAX. chiama, o ascolta per DOMSubtreeModified (obsoleto), o usa MutationObserver s, ma questi metodi possono diventare complicati, complicati e eccessivamente complicati.

Un modo più semplice e più robusto per ottenere un contenuto corretto su una pagina wild consiste nel collegarlo utilizzando qualcosa come la funzione waitForKeyElements, di seguito.

Ad esempio, questo script metterà in evidenza i commenti che contengono "birra", come AJAX-in:

// ==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; 
} 

Aggiornamento:

Per comodità, waitForKeyElements() è ora hosted on GitHub.

This answer shows an example of how to use the hosted function.

+0

I chiedi scusa, gli errori si trovano effettivamente nella zeroclipboard, non nella tua funzione. Una cosa interessante che ho scoperto durante il debug è che se 'bWaitOnce' è impostato su' true' il codice viene effettivamente attivato due volte, non è sicuro che sia intenzionale o no – RozzA

+0

@RozzA, sarei interessato a vedere il codice che lo dimostra. Parti del codice possono essere attivate due volte (o molte volte) - in base alla progettazione. Ma il 'actionFunction' dovrebbe sparare solo una volta per un dato nodo. –

+0

@BrockAdams, perché 'setInterval' e non' MutationObserver'? –

0

Un altro modo - più semplice e più piccolo ma meno flessibile - consiste nell'usare un ritardo in JavaScript per attendere il caricamento e il completamento di AJAX/jQuery. Ad esempio, se la seguente HTML è stato generato dinamicamente dopo il primo carico:

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

Poi uno script Greasemonkey come questo sarebbe in grado di modificarlo:

// 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; 
    } 
} 

See guida qui: Sleep/Pause/Wait in Javascript

Problemi correlati