2011-11-26 2 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 기능과 같은 것을 사용하여 폴링하는 것입니다.

// ==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입니다 그들은 AJAX-같이

예를 들어,이 스크립트는 "맥주"를 포함 의견을 강조 할 것이다.

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

+0

I

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

는이 같은 그리스 몽키 스크립트를 수정할 수있을 것입니다 죄송합니다. 실제로 오류는 zeroclipboard가 아니라 사용자의 기능입니다. 디버깅하는 동안 발견 한 흥미로운 점은'bWaitOnce'가'true'로 설정되면 코드가 실제로 두 번 실행됩니다. 의도적인지 또는 확실하지 않은 것입니까 – RozzA

+0

@RozzA, 나는 이것을 보여주는 코드를 보게됩니다. 코드의 일부는 설계 상 두 번 (또는 여러 번) 실행될 수 있습니다. 그러나'actionFunction'은 지정된 노드 당 한 번만 발생해야합니다. –

+0

@BrockAdams, 왜'setInterval'이 아니라'MutationObserver'입니까? –

0

더 간단하고 작지만 유연성이 떨어지는 또 다른 방법은 JavaScript 시간 지연을 사용하여 AJAX/jQuery를로드하고 마치는 것을 기다리는 것입니다. 다음 HTML을 동적으로 첫 번째로드 후 생성 된 경우 예를 들어, :

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

관련 문제