Monthly Archives: November 2012

Bookmarkets

You might have seen the Pinterest button, its an interesting concept that’s been around for a while in the way of Greesemonkey scripts, but it took pinterest to really execute it well for it to be used by your average web user.

The idea is simple really, instead of adding  a URL to your bookmarks, you instead add some JavaScript that is run once the button is clicked. All the major browsers support this.

The first thing the JavaScript does it to load an external script into the current page, something like this:

javascript:void((function()%7Bvar e=document.createElement('script');e.setAttribute('type','text/javascript');e.setAttribute('charset','UTF-8');e.setAttribute('src','http://somesite/somescript.js?r='+Math.random()*99999999);document.body.appendChild(e)%7D)()); 

 

It’s a little messy, so I’ll explain the concepts. First a new script tag is created on the current page that the user is viewing. The script tag is set to load up an externally controlled script.

This script contains the real power. Some observations might be:

1. This script also creates a new script tag to load in any dependencies, the thing to watch out for here is that it might take some time for the script to load, so you need to use the tag’s script.onreadystatechange event before you try to execute any code.

2. You want to be careful on what resources you do load, remember that your loading into an unknown page, this page may already have a version of jQuery loaded which might cause conflicts.

3. The Pinterest scripts look at all of the images on the current page and arrange them nicely. Your scripts can load scripts via jsonp which can be used to load personalised information.

4. You need to be specific with your CSS on any UI you create. Since your loading into an unknown page which may have a number of styles already defined. Expect to spend most of your time addressing these types of issues.

OK, some code for a template:

(function (wind, doc) {
    var lw = {
        init: function () {

            var style = doc.createElement('link');
            style.rel = 'stylesheet';
            style.href = 'http://somesite/uicss.css';
            
	   document.getElementsByTagName('head')[0].appendChild(style);

            
            this.getScript('http://somesite/jquery1.8.2.js', function (itm) {

                if (typeof jQuery == 'undefined') {

                    // Super failsafe - still somehow failed...

                } else {
    
                    getScript('http://somesite/anotherdependency.js', function (itm) {

                        //all real work done here

                    });
                        

                }

            });

        },

        getScript: function (url, success) {

            var script = document.createElement('script');
            script.src = url;

            var head = document.getElementsByTagName('head')[0],
		    done = false;

            // Attach handlers for all browsers
            script.onload = script.onreadystatechange = function () {

                if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {

                    done = true;

                    // callback function provided as param
                    success(this);

                    script.onload = script.onreadystatechange = null;
                    head.removeChild(script);

                };

            };

            head.appendChild(script);

        },



        loadData: function (data) {
           

            


        }
    };

    
    window.loadData = lw.loadData;
    window.getScript = lw.getScript;

    lw.init();

   

})(window, document);