Skip to content

Instantly share code, notes, and snippets.

@kafene
Created July 16, 2014 11:32
Show Gist options
  • Save kafene/f62e8446f1fe79beee1b to your computer and use it in GitHub Desktop.
Save kafene/f62e8446f1fe79beee1b to your computer and use it in GitHub Desktop.

Loading bookmarklets with jQuery

I looked at a lot of solutions for this and here's what I've come up with:

(function getjQuery(callback) {
    if ('complete' === document.readyState) {
        var script = document.createElement('script');
        var target = document.documentElement;
        script.src = '//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
        script.async = false;
        script.onload = function () {
            target.removeChild(script);
            callback(jQuery.noConflict(true));
        };
        target.appendChild(script);
    } else {
        window.addEventListener('load', function () {
            getjQuery(callback);
        });
    }
})(function ($) {
    // Your code here...
});

Many scripts try to detect if jQuery is already loaded, and some go further and check if the loaded version is the version they want. I think this is bad: though exceedingly unlikely, a site could inject malicious code somewhere into the jQuery object, or even for whatever reason have a global variable set to something like jQuery = false.

I say let's grab our own version. And the version I load is the latest 1.x release from Google's CDN. Since the 1.x branch is in a sort of maintenance-mode, I guess it's unlikely to get many breaking changes in the future. It will probably last on Google's CDN for a long time, though. Once you've finalized functionality it would be wise to pick a full version number and use that. Since we're loading from one of the most popular CDNs for jQuery, chances are, the browser already has the script cached, so it won't need to be downloaded anyway.

Since bookmarklets are almost always written expecting a fully usable document, I've named the calling function and wrapped it in a check that the document's readyState is 'complete', and if it's not, add's a window.onload event to re-run the script.

I set the script async to false, again because the site's scripts should already be loaded, and it saves setting up an onreadystatechange listener for the script. The onload event can be used instead. I've heard some places that onload might not be as backwards-compatible as using onreadystatechange, so if you need old versions of browsers to work, try refactoring it to use the onreadystatechange event. I've had no issues in the latest versions of the usual candidates (Firefox and Chrome).

Once the script is loaded, I immediately remove the script tag from the DOM, so as not to alter the generated source code much. I don't know that there's a great reason to be doing this, but it doesn't hurt, and it leaves the DOM in the same state it was before calling, so it's likely to prevent issues with some few sites. Even though the script tag is removed, window.jQuery remains.

The last thing to do is just call the callback function, sending jQuery as the sole argument. I use jQuery.noConflict(true) to restore the previous values of window.jQuery and window.$, even if they were undefined. This is another thing I saw often overlooked in others' bookmarklets. My objective is to make clicking it provide jQuery to the callback function and execute that code, without causing any side effects, and I think this method achieves that pretty well. I'm using it myself "in production" (read: on my personal computers), and will certainly report any issues I come across with this method.

I don't feel that such simple code needs a license, so for anyone who wants to alter/redistribute it, consider it Unlicensed (see: http://unlicense.org) and in the public domain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment