
Using jQuery and GitHub to Create a Bookmarklet
Last week I wanted to create a bookmarklet that displayed the W3C Navigation Timing API. I had our design team create a UI for the bookmarklet and investigate the Timing API and then built a prototype of the application. Then next step was to figure out how to turn the prototype in to a working bookmarklet; so I looked at dozen or so bookmarklets but did not like the approach any took to creating them.
Development Approach
I took a different approach to building the bookmarklet. The only components to my booklet are; jQuery, ViewJS(the new jquery templates) and GitHub. Why this approach? Looking at the other bookmarklets, they all had things about them i did not like:
- Need to hand build the DOM
- Hosting the bookmarklet was a pain
- The way the JavaScript was compiled into a single file was not easy to maintain
So how does this bookmarklet’s architecture resolve these problems?
Bookmarklet link
The bookmarklet link is very simple and calls out to an external JavaScript file. The nice thing about this is that you can test this approach in any webpage before moving it to the bookmarklet.
javascript:(function(){ var w3cnavjs=document.createElement('SCRIPT'); w3cnavjs.type='text/javascript'; w3cnavjs.src='https://yottaa.github.com/NavigationTimingBookmarklet/bookmarklet.js'; document.getElementsByTagName('head')[0].appendChild(w3cnavjs); })();
The code for the bookmarklet (
bookmarklet.js) does only a few things:
- Captures the W3C NavigationTiming Data
- Encodes it into a JSON String
- Creates an iframe and passes the data to the iframe in the hash
$(document.body).append(' <iframe id="w3c-nav-iframe" style="padding: 0px; position: absolute; top: 10px; right: 10px; z-index: 999999999;" frameborder="0" scrolling="no" width="350px" height="660px"></iframe> '); //Add the data as the hash. The iframe will pull the data. $('#w3c-nav-iframe').attr('src', "https://yottaa.github.com/NavigationTimingBookmarklet/w3c-nav-bookmarklet.html#"+JSON.stringify(data));
Why use an iframe?
I tried several ways to do this. Ideally I would not need to use an iframe however because the template was loaded from a file on the server it caused a cross domain issue. I needed to retrieve the template from yottaa.github.com domain, which will always be different from the webpages domain. Even through the bookmarklet is not part of the page, when executed it runs with in the webpages domain and thus Ajax calls to load resources from yottaa.github.com fail.
Yes, I could have encoded the HTML into a string and embedded it in the JavaScript but this would have increased the maintenance cost of the bookmarklet. If I wanted to change any UI elements or add a new feature, changing the minified HTML string would have been worse than building the DOM structure by JavaScript alone.
One other important reason I choose the iframe was I did not need to embed all my JavaScript into a single file. When the browser loaded, I could just use the “script” tags to load my JavaScript files.
My iframe
The source of my iframe is “w3c-nav-bookmarklet.html” which when loaded will run the following code:
$(document).ready(function(){ //Need to pull off the "#" from the string var data = window.location.hash.substring(1); //if the string is empty that means there is no data and //the browser does not support the API. if (data != ""){ data = JSON.parse(data); showW3cNavPerformanceData(data); }else{ $(document.body).html($("#w3c-nav-bookmarklet-notsupported").render({})); } });
The final phase of the bookmarklet is handed over to
$.render(); function and the bookmarklet UI is displayed using a template. This greatly simplifies the development of the UI, and means I can concentrate on the features. Why is this simpler? Because it allows me to just use HTML in its natural form and let the
$.render(); function insert the data UI where it needs to go. This approach is not a good choice for everyone but for me it works.
<div class="section"> <div class="leftBox height1"> Redirect </div> <div class="rightBox"> <div class="timingName"> Redirect Start </div> <div class="timingData"> <!-- This will be replaced with the data --> </div> </div> </div>
Why use GitHub to host?
Even though I am the CTO of Yottaa, deploying stuff into production is not easy; it requires working with our operations team or setting up a separate server environment. The bookmarklet requires no server side other than serving files… so i figured using GitHub pages would simplify everything.
Now when I want to release a new version I can just push the code into my gh-pages branch and the new version will automatically be deployed. No need for a separate deployment script for the website.
Navigation Timing Bookmarklet Tips
Clear Cache
Once you have the bookmarklet in your toolbar it will be cached by the browser. The first time I made a change bookmarklet, it took about 15-30 minutes to figure this out. Damn it! After I realized this, I just kept the “Clear Browsing Data…” page open in chrome and hit the button. It was not only the JavaScript but all resources that were loaded being cached.
Setting up github pages
This was fairly straightforward; I just followed the instructions here. My branching strategy for the project is different from my other repositories. In this project, I use the “gh-pages” branch as the master/production branch and use the “master” branch as my development branch.
Build Prototype
The prototype was key; I could easily mock up the UI and test it out without needing to move work with the bookmarklet approach until after it worked.
Templates & jsRender
jsRender is the next version of jQuery Templates and it works awesome. I was very surprised when I could just embed my stylesheet in the template and it worked. The UI for the bookmarklet was very simple also so the template engine easily handled it. One feature that would be great; is the ability for jsRender to load a template from a file on the server.
Feel free to fork the bookmarklet (https://github.com/Yottaa/NavigationTimingBookmarklet)