The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,860 other subscribers

Workaround for “embedding” external scripts in JavaScript bookmarklets (thanks @ben_alman).

Posted by jpluimers on 2025/03/25

Bookmarklets are basically URLs that execute a JavaScript function.

Sometimes you want to rely on external JavaScript files (for instance jQuery), but Bookmarklets themselves cannot do that.

Bookmarklets can modify the current page though, and use those to load a script, wait until it is loaded, then continue executing.

Often that is OK as you want to operate the Bookmarklet on that page anyway, but be careful though that you do not mess up the page by loading an incompatible script: test, test, test!

I mentioned Ben Alman (formerly [Wayback/Archive] Ben Alman (@cowboy), now [Wayback/Archive] “Cowboy” Ben Alman (@ben_alman)) in my blogs earlier, but did not detailed much. Time to do that now:

His old post is [Wayback/Archive] Ben Alman » jQuery Bookmarklet Generator which starts with

This would probably actually be better called “Run some arbitrary code that requires jQuery, loading a minimum required version of [Wayback/Archive] jQuery first (but only if necessary), affecting the host page as little as possible Bookmarklet Generator” but that wasn’t nearly as catchy as “jQuery Bookmarklet Generator” so I’m going to stick with that.

The source code is in [Wayback/Archive] benalman.com/code/javascript/jquery/jquery.ba-run-code-bookmarklet.js and uses the [Wayback/Archive] Window: load event – Web APIs | MDN (named onload) from [Wayback/Archive] HTMLScriptElement – Web APIs | MDN (named script).

A generator front-end is at [Wayback/Archive] Ben Alman » Run jQuery Code Bookmarklet » Generate and points to a few other interesting sites as well.

The cool thing about the front-end is that it is parameterised as demonstrated by [Wayback/Archive] Ben Alman » Run jQuery Code Bookmarklet » Generate (alert example) which generates the code to execute alert('existing: '+(window.jQuery?jQuery.fn.jquery:'N/A')+', loaded: '+(L?$.fn.jquery:'N/A'));, and then generates this:

javascript:(function(e,a,g,h,f,c,b,d){if(!(f=e.jQuery)||g>f.fn.jquery||h(f)){c=a.createElement("script");c.type="text/javascript";c.src="http://ajax.googleapis.com/ajax/libs/jquery/"+g+"/jquery.min.js";c.onload=c.onreadystatechange=function(){if(!b&&(!(d=this.readyState)||d=="loaded"||d=="complete")){h((f=e.jQuery).noConflict(1),b=1);f(c).remove()}};a.documentElement.childNodes[0].appendChild(c)}})(window,document,"1.3.2",function($,L){alert('existing: '+(window.jQuery?jQuery.fn.jquery:%27N/A%27)+%27,%20loaded:%20%27+(L?$.fn.jquery:%27N/A%27));});

Or expanded (thanks [Wayback/Archive] Online JavaScript beautifier!)

javascript: (function(e, a, g, h, f, c, b, d) {
    if (!(f = e.jQuery) || g > f.fn.jquery || h(f)) {
        c = a.createElement("script");
        c.type = "text/javascript";
        c.src = "http://ajax.googleapis.com/ajax/libs/jquery/" + g + "/jquery.min.js";
        c.onload = c.onreadystatechange = function() {
            if (!b && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
                h((f = e.jQuery).noConflict(1), b = 1);
                f(c).remove()
            }
        };
        a.documentElement.childNodes[0].appendChild(c)
    }
})(window, document, "1.3.2", function($, L) {
    alert('existing: ' + (window.jQuery ? jQuery.fn.jquery : % 27 N / A % 27) + % 27, % 20 loaded: % 20 % 27 + (L ? $.fn.jquery : % 27 N / A % 27));
});

Parameters:

  • e = window
  • a = document
  • g = required_version
  • h = callback
  • f = $
  • c = script_uri
  • b = done
  • d = readystate

I have made the most important lines bold to emphasise what they accomplish:

  1. create a new script element with a type attribute of  text/javascript and a src attribute to the right javascript URI
  2. pointing the onload and onreadystatechange attributes to capture the load and readystatechange events so that the callback can be called when the document readyState is loaded or complete.
  3. add the script element to the current document (which will then start try loading the script and eventually fire the above events upon success).

Via

  1. [Wayback/Archive] embed javascript file in bookmarklet – Google Search
  2. [Wayback/Archive] How to create a bookmarklet with an external js file. (2011-05) based on:
  3. [Wayback/Archive] Create Bookmarklets – The Right Way (2011-02)

The last two use this bit of code that does not wait for loading which means the Bookmarklet can continue while the script is not loaded yet, then fails:

javascript: (function () {
    var jsCode = document.createElement('script');
    jsCode.setAttribute('src', 'https://path/to/external/file.js');                
  document.body.appendChild(jsCode);
 }());

That’s a bummer as [Wayback/Archive] HTMLScriptElement: dynamically importing scripts – Web APIs | MDN has had the correct example for this for a very long time (at least 2013, but I think even earlier on prior links):

function loadError(oError) {
  throw new URIError(`The script ${oError.target.src} didn't load correctly.`);
}

function prefixScript(url, onloadFunction) {
  const newScript = document.createElement("script");
  newScript.onerror = loadError;
  if (onloadFunction) { newScript.onload = onloadFunction; }
  document.currentScript.parentNode.insertBefore(newScript, document.currentScript);
  newScript.src = url;
}

Related

My earlier blog posts:

Links mentioned by Ben Alman:

--jeroen

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.