Greasemonkey comes in incredibly handy (especially when your job forces you to use ill-conceived internal web applications). However, ever since I tinkered around with jQuery, I can’t imagine trying to grease a page without that functional goodness. I therefore decided to use jQuery in my Greasemonkey scripts, and that turned out to be just a little more complicated than I thought it would be.

The first thing that pops up in Google is Joan Piedra’s solution, where he provides a userscript that downloads jQuery from jquery.com every time. That’s not exactly the solution I had in mind since I didn’t want to download jQuery every time the script ran, so I searched some more and found this post by Sean Catchpole about how to patch jQuery to get rid of a loading problem. I downloaded his userscript and everything seemed to work great for me until I tried to use siblings(), children(), or parents(). Then Firefox would complain about ‘jQuery’ not being defined and script would halt.

I searched through the code and found where these functions are being declared:

jQuery.each({
    parent: "a.parentNode",
    parents: "jQuery.parents(a)",
    next: "jQuery.nth(a,2,'nextSibling')",
    prev: "jQuery.nth(a,2,'previousSibling')",
    siblings: "jQuery.sibling(a.parentNode.firstChild,a)",
    children: "jQuery.sibling(a.firstChild)" 
}, function(i,n){
    jQuery.fn[ i ] = function(a) {
        var ret = jQuery.map(this,n);
        if ( a && typeof a == "string" )
            ret = jQuery.multiFilter(a,ret);
        return this.pushStack( ret );
    };
});

Each of these pairs of function names and strings is passed to the map function:

map: function(elems, fn) {
    // If a string is passed in for the function, make a function
    // for it (a handy shortcut)
    if ( typeof fn == "string" ) {
        fn = new Function("a","return " + fn);
    }

    var result = [];

    // Go through the array, translating each of the items to their
    // new value (or values).
    for ( var i = 0, el = elems.length; i < el; i++ ) {
        var val = fn(elems[i],i);

        if ( val !== null && val != undefined ) {
            if ( val.constructor != Array ) val = [val];
            result = result.concat( val );
        }
    }

    return result;
}

The script was crashing on the line that declares the new Function object inside the first if-statement. 4 out of 5 of those functions above reference the jQuery object. I couldn’t find out why the jQuery object didn’t exist in the scope of the new Function object, so I just gave up on that and started trying different but functionally equivalent replacements for that line of code. I finally found something that worked:

fn = eval("function(a) { return " + fn + " };");

It turned out that I really didn’t need those functions for what I was working on, but it’s still nice to know that jQuery now works completely (as far as I know) with Greasemonkey.