2011-11-26 21 views
27

私はユーザースクリプトを作成していますが、メインページがAJAXリクエストを行ったときにスクリプトが実行されていないことがわかりました。AJAXリクエストのFire Greasemonkeyスクリプト

メインページの読み込みとAJAXリクエストの両方でユーザースクリプトを起動する方法はありますか?

答えて

56

AJAXリクエストでスクリプトのコードを再実行するスマートな方法は、ページのキービットに集中して変更をチェックすることです。

例えば

は、そのようなページに含まれるHTMLを考える:

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

とあなたはそれが入って来たよう各コメントに何かをするスクリプトを望んでいた

今、あなたはでしインターセプトすべてのAJAX。電話番号 または DOMSubtreeModified (廃止予定)のいずれかを受信するか、MutationObserverを使用してください。ただし、これらの方法は扱いにくく、細かく複雑すぎることがあります。

野生のページでajax-ifiedコンテンツを取得するための、より簡単で堅牢な方法は、下記のwaitForKeyElements機能を使用してそれをポーリングすることです。例えば

として、彼らは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; 
} 

更新:

便宜上、waitForKeyElements()は今hosted on GitHubです。

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

+0

Iお詫び申し上げますが、エラーは実際にはあなたの関数ではなく、zeroclipboardにあります。私がデバッグ中に発見した興味深いのは、 'bWaitOnce'が' true'に設定されているとコードが実際に2回発火し、意図的であるかどうかわからないことです。 – RozzA

+0

@RozzA、私はそれを実証するコードに興味があります。コードの一部は、設計上2回(または何度も)発射することがあります。しかし、 'actionFunction'は与えられたノードごとに1回だけ起動するべきです。 –

+0

@BrockAdams、なぜ 'setInterval'ではなく' MutationObserver'ですか? –

0

もう1つの方法 - より簡単で小さくても柔軟性が低い - JavaScriptの遅延を使用して、AJAX/jQueryが読み込まれて終了するのを待つことです。以下のHTMLを動的に最初のロード後に生成された場合たとえば、:

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

次に、このようなGreasemonkeyのスクリプトは、それを変更することができるだろう。ここ

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

参照ガイダンス:Sleep/Pause/Wait in Javascript

関連する問題