The Anatomy of a JavaScript Bookmarklet

I think of bookmarklets as a way to greasemonkey patch a webpage with custom JavaScript not approved by the author of the website you are visiting. Bookmarklets are a bit of JavaScript that you save as a bookmark and when visiting a page, if you click on that bookmark, the JavaScript will run on the context of the current page that is being viewed. This allows you to modify the current page in ways that the original author did not think off or allow. In essence, bookmarklets are a way to extend, modify, and enhance sites you are visiting.

Common examples of bookmarklets are the Amazon Universal Wishlist, Tumblr share bookmarklet, and DZone submission bookmarklet. In the case of the Amazon bookmarklet, when you click the bookmarked JavaScript a new frame dialog pops up that allows you to select an image from the current page, add a price, and title and then add that product description to your Amazon wishlist. The Tumblr and Dzone bookmarklets help in submitting the current page to their respective services as a social bookmark.

Bookmarks are not new, they have been around since JavaScript was first introduced, but it is a technique that opens a lot of opportunities for a power users. Bookmarklets allows your users to submit information to your service about and from whichever website they are visiting.

Here is the hello world example of a bookmarklet.

javascript:alert('hello, world!');

Type the above code snippet in the location bar of your browser and click enter! You should have seen the alert dialog pop up with the correct greeting. That is your first bookmarklet.

To allow users to save the JavaScript bookmark as a bookmarklet into their favorites or bookmark toolbar you will need to create a link. Here is an example of a link with a bookmarklet.

<a href="javascript:alert('hello, world!');">Say Hello</a>

Now that we have the mechanics of a bookmarklet down, lets go over some practical scenarios. In the examples listed above, the bookmarklet simply loads an additional JavaScript source file that acts as the main application which in turn may load additional resources such as images and CSS files. Once all the resources have been loaded, from the main JavaScript source file, you can invoke the necessary methods.

Here is an example of the JavaScript bookmarklet which will load the secondary JavaScript main application source file. This bookmarklet simply acts as a loader. Notice that for the actual bookmarlet, the JavaScript needs to be escaped and obfuscated into a single line.

(
  function(){
    var w=window,
        u='<url TO MAIN SCRIPT>',
        l=w.location,
        d=w.document,
        s=d.createElement('script'),
        e=encodeURIComponent,
        x='undefined';

    function g(){
      if(d.readyState && d.readyState!='complete'){
        setTimeout(g,200);
      }else{
        if(typeof MainApp==x) {
          s.setAttribute('src',u+'.js');
          d.body.appendChild(s);
        }
        
        function f(){
          if(typeof MainApp==x){
            setTimeout(f,200)
          }else {
            MainApp.show();
          }
        }

        f();
      }
    }
    g();
  }()
)

Again, you need to obfuscate the above JavaScript into a bookmarklet by removing all non-essential white spaces and line breaks. The bookmarklet should all fit in a single line in the href of a HTML link. That said, lets explain the above bookmarklet a bit. The first thing that will happen is that the a new HTML script tag will be created for the main JavaScript source file. The script will set timeouts until the additional script file has been downloaded, interpreted, and the MainApp object is defined. Once the MapApp object has been defined you can invoke the custom code that will run in the browser in the context of the current web page. The MainApp object is defined in the JavaScript file which was loaded by the bookmarklet.

For completeness sake, here is a simplified trivial example of the main JavaScript source file.

var MainApp = function(){
  var greetings = function(message) {
    alert(message);
  }
  
  return {
    show: function() {
      greetings('Hello, World');
    }
  }
}();

Remember that the main JavaScript source file can load additional resources, ask for user input, and post data back to your server. It runs in the context of the current page you are visiting and has access to all elements in the DOM. In my opinion, bookmarlets are the easiest way to enhance a page without using a browser plugin or extension.


2 Responses to “The Anatomy of a JavaScript Bookmarklet”

Leave a Reply