2

I have a basic greasemonkey script shown below, in which I want to run some code every time an AJAX request is sent by the website I'm running the script on.

I'm using the ajaxSuccess jQuery handler and it's not being fired. I suspect this might be because the AJAX requests are being sent with the global flag set to false (see http://docs.jquery.com/Ajax_Events). Is there some better way to achieve this that will work even when global is set to false?

Code:

// ==UserScript==
// @name           MyTestScript
// @require        http://code.jquery.com/jquery-1.7.1.min.js
// @namespace      NRA
// @include        http://www.mysamplewebsite.com/view/*
// ==/UserScript==

$(document).ajaxSuccess(function(e, xhr) {
    alert("ajax success hit!");
    // I will do my other handling here
});

Thanks

Sean Chapman
  • 322
  • 1
  • 10

2 Answers2

3

The jQuery in your userscript runs in a separate environment from the page's jQuery.

You need to intercept the page's AJAX calls so you can use either (A) unsafeWindow or (B) Inject your script.

(A) unsafeWindow looks like:

unsafeWindow.$(document).ajaxSuccess(function(e, xhr) {
    alert("ajax success hit!");
    // I will do my other handling here
});


(B) Script injection looks like:

function scriptWrapper () {

    //--- Intercept Ajax
    $('body').ajaxSuccess (
        function (event, requestData) {
            alert ("ajax success hit!");
            doStuffWithAjax (requestData);
        }
    );

    function doStuffWithAjax (requestData) {
        console.log ('doStuffWithAjax: ', requestData.responseText);
    }

    //--- DO YOUR OTHER STUFF HERE.
    console.log ('Doing stuff outside Ajax.');
}

function addJS_Node (text, s_URL, funcToRun) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ    = D.getElementsByTagName('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}

addJS_Node (null, null, scriptWrapper);


Note that in both cases, you must be conscious that data does not flow from page scope back to GM scope easily -- be careful about mixing the two.

One workaround, for transmitting data across the sandbox, can be found in this answer.

Community
  • 1
  • 1
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • Tried both of these methods and unfortunately they didn't work. I'm not sure where I'm going wrong. Do you have any other ideas I could try? – Sean Chapman Mar 02 '12 at 20:06
  • I use both of these approaches; they work fine. Edit your question (or start a new question) to describe **how** it doesn't work for you and **link to the target page**. Greasemonkey scripts are always highly page specific. ... If the code that doesn't work for you is not **exactly** as shown above, start a new question that shows the exact code you are using, but don't forget the link to the target page. As for other ideas, intercepting AJAx is seldom the best approach, but that's what you asked about. It's usually better to monitor specific nodes on the target page. Post a new Q for that. – Brock Adams Mar 02 '12 at 21:13
  • Okay I will do, thanks. I am essentially trying to monitor a DIV element to see if it's CSS changes. I'm trying to check that everytime an AJAX event occurs, which seemed like the only way to do it without a timer. – Sean Chapman Mar 02 '12 at 22:16
  • The timer approach, if applicable to your page, is normally simpler and more robust that the intercept-AJAX approach. It all depends on what the end goal is. – Brock Adams Mar 03 '12 at 05:46
1

It could have something to do with the greasemonkey sandboxing.

http://greasemonkey.mozdev.org/authoring.html

Sometimes, you will want to access the global variables in the content document. For example, maybe the content document defines a function which you want to call. In these cases, you can access the content document's global scope with the unsafeWindow variable. Just be aware that accessing the members of this variable means that content scripts can detect your script and potentially interfere with it if they choose.

I.e. document in the greasemonkey script may not be the same as document in the actual web page, so you might have to use unsafeWindow.document or something.

Or maybe jQuery's ajax methods simply don't work in greasemonkey without alteration (requiring special override of XHR objects)...

E.g. http://www.monperrus.net/martin/greasemonkey+jquery+and+xmlhttprequest+together

and http://ryangreenberg.com/archives/2010/03/greasemonkey_jquery.php

... JQuery AJAX in Greasemonkey then looks like:

$.ajax({
  url: '/p/',// this even works for cross-domain requests by default
  xhr: function(){return new GM_XHR();},
  type: 'POST',
  success: function(val){
  .... 
  }
});
Paul Grime
  • 14,970
  • 4
  • 36
  • 58