Build a google chrome extension using jQuery in 90 seconds

Lately I have been following jQuery commits on github . If I look at a commit which fixes a bug then I would like to go and see the bug description. In order to do that I need to type url which would be something like this http://dev.jquery.com/ticket/6084 .

I wrote a chrome extension which would add a link to the bug at the end of commit message.

Install the extension and try it

The extension is available here . After installing the extension visit this page and you should see a link at the end of commit message.

Developing the extension and packaging it

Developing an extension on google chrome is very simple.

  1. git clone the source code of my extension or create file structure similar to this .
  2. Zip the folder contents and create jQueryBugLink.zip .
  3. Visit chrome.google.com/extensions and click on publish your extensions.
  4. Upload the zip file and publish your extension .

That’s it.

Simplest jQuery slideshow code explanation

Jonathan Snook wrote a blog titled Simplest jQuery SlideShow . Checkout the demo page .

The full JavaScript code in its entirety is given below. If you understand this code then you don’t need to read rest of the article.

$(function(){
    $('.fadein img:gt(0)').hide();
    setInterval(function(){
      $('.fadein :first-child').fadeOut()
         .next('img').fadeIn()
         .end().appendTo('.fadein');}, 
      3000);
});

appendTo removes and attaches elements

In order to understand what’s going on above, I am constructing a simple test page. Here is the html markup.

<div id='container'>
  <div class='lab'>This is div1 </div>
  <div class='lab'>This is div2 </div>
</div>

Open this page in browser and execute following command in firebug.

$('.lab:first').appendTo('#container');

Run the above command 5/6 times to see its effect. Every single time you run JavaScript the order is changing.

The order of div elements with class lab is changing because if a jQuery element is already part of document and that element is being added somewhere else then jQuery will do cut and paste and not copy and paste . Again elements that already exist in the document get plucked out of document and then they are inserted somewhere else in the document.

Back to original problem

In the original code the very first image is being plucked out of document and that image is being added to set again. In simpler terms this is what is happening. Initially the order is like this.

Image1
Image2
Image3

After the code is executed the order becomes this.

Image2
Image3
Image1

After the code is executed again then the order becomes this.

Image3
Image1
Image2

After the code is executed again then the order becomes this.

Image1
Image2
Image3

And this cycle continues forever.

Unit Testing JavaScript using Qunit . See live result and test code.

If you are in a hurry then take a look at these two links and you are done.

Introduction

Six months ago I wrote about JavaScript testing using blue-ridge, Screw.Unit, env.js and Rhino . Since then I have changed my thoughts about JavaScript testing in fundamental ways and I do not recommend writing JavaScript unit tests that would not run on an actual browser.

I could never do as good a job as Nicholas did on his blog on capturing thoughts on JavaScript unit testing. I agree with him 100%.

Since I do not recommend using rhino, what I do recommend. I like Qunit .

Getting started

Sometimes getting started is the most difficult part. There are lot of JavaScript testing tools in the market and the documentation of most of them show simple case of testing 2 + 2. That is not very helpful.

The good thing with Qunit is that if you ever want to see how to use Qunit then just look at the test code of jQuery. At the bottom of this page you will find links of other projects that user Qunit to write tests.

I don not want to look at jQuery test code. I use ruby on rails and I just want to get started

For my admin_data plugin I wrote a bunch of JavaScript tests . Take a look at them to get a feel for how to use Qunit for you ruby on rails application. Get the code from github and you can play with JavaScript test code.

Click here to see the test result for the tests written for admin_data. I have tested this test page with Firefox, Chrome, Safari, IE 6, IE 7 and IE 8 .

How jQuery selects elements using Sizzle

Introduction

jQuery’s motto is to select something and do something with it. As jQuery users, we provide the selection criteria and then we get busy with doing something with the result. This is a good thing. jQuery provides extermely simple API for selecting elements. If you are selecting ids then just prefix the name with ’#’. If you are selecting a class then prefix it with ’.’.

However it is important to understand what goes on behind the scene for many reasons. And one of the important reasons is the performance of Rich Client. As more and more web pages use more and more jQuery code, understanding of how jQuery selects elements will speed up the loading of pages.

What is a selector engine

HTML documents are full of html markups. It’s a tree like structure. Ideally speaking all the html documents should be 100% valid xml documents. However if you miss out on closing a div then browsers forgive you ( unless you have asked for strict parsing). Ultimately browser engine sees a well formed xml document. Then the browser engine renders that xml on the browser as a web page.

After a page is rendered then those xml elements are referred as DOM elements.

JavaScript is all about manipulating this tree structure (DOM elements) that browser has created in memory. A good example of manipulating the tree is command like the one give below which would hide the header element. However in order to hide the header tag, jQuery has to get to that DOM element.

jQuery('#header').hide()

The job of a selector engine is to get all the DOM elements matching the criteria provided by a user. There are many JavaScript selector engines in the market. Paul Irish has a nice article about JavaScript CSS Selector Engine timeline .

Sizzle is JavaScript selector engine developed by John Resig and is used internally in jQuery. In this article I will be showing how jQuery in conjunction with Sizzle finds elements.

Browsers help you to get to certain elements

Browsers do provide some helper functions to get to certain types of elements. For example if you want to get DOM element with id header then document.getElementById function can be used like this

document.getElementById('header')

Similarly if you want to collect all the p elements in a document then you could use following code .

document.getElementsByTagName('p')

However if you want something complex like the one given below then browsers were not much help. It was possible to walk up and down the tree however traversing the tree was tricky because of two reasons: a) DOM spec is not very intuitive b) Not all the browsers implemented DOM spec in same way.

jQuery('#header a')

Later selector API came out.

The latest version of all the major browsers support this specification including IE8. However IE7 and IE6 do not support it. This API provides querySelectorAll method which allows one to write complex selector query like document.querySelectorAll(”#score>tbody>tr>td:nth-of-type(2)” .

It means that if you are using IE8 or current version of any other modern browser then jQuery code jQuery(’#header a’) will not even hit Sizzle. That query will be served by a call to querySelectorAll .

However if you are using IE6 or IE7, Sizzle will be invoked for jQuery(’#header a’). This is one of the reasons why some apps perform much slower on IE6/7 compared to IE8 since a native browser function is much faster then elements retrieval by Sizzle.

Selection process

jQuery has a lot of optimization baked in to make things run faster. In this section I will go through some of the queries and will try to trace the route jQuery follows.

$(’#header’)

When jQuery sees that the input string is just one word and is looking for an id then jQuery invokes document.getElementById . Straight and simple. Sizzle is not invoked.

$(’#header a’) on a modern browser

f the browser supports querySelectorAll then querySelectorAll will satisfy this request. Sizzle is not invoked.

$(’.header a[href!=”hello”]’) on a modern browser

In this case jQuery will try to use querySelectorAll but the result would be an exception (atleast on firefox). The browser will throw an exception because the querySelectorAll method does not support certain selection criteria. In this case when browser throws an exception, jQuery will pass on the request to Sizzle. Sizzle not only supports css 3 selector but it goes above and beyond that.

$(’.header a’) on IE6/7

On IE6/7 querySelectorAll is not available so jQuery will pass on this request to Sizzle. Let’s see a little bit in detail how Sizzle will go about handling this case.

Sizzle gets the selector string ’.header a’. It splits the string into two parts and stores in variable called parts.

parts = ['.header', 'a']

Next step is the one which sets Sizzle apart from other selector engines. Instead of first looking for elements with class header and then going down, Sizzle starts with the outer most selector string. As per this presentation from Paul Irish YUI3 and NWMatcher also go right to left.

So in this case Sizzle starts looking for all a elements in the document. Sizzle invokes the method find. Inside the find method Sizzle attempts to find out what kind of pattern this string matches. In this case Sizzle is dealing with string a .

Here is snippet of code from Sizzle.find .

match: {
     ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
     CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
     NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
     ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
     TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
     CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
     POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
     PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
},

One by one Sizzle will go through all the match definitions. In this case since a is a valid tag, a match will be found for TAG. Next following function will be called.

TAG: function(match, context){
     return context.getElementsByTagName(match[1]);
}

Now result consists of all a elements.

Next task is to find if each of these elements has a parent element matching .header. In order to test that a call will be made to method dirCheck. In short this is what the call looks like.

dir = 'parentNode';
cur = ".header" 
checkSet = [ a www.neeraj.name, a www.google.com ] // object representation
dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML )

dirCheck method returns whether each element of checkSet passed the test. After that a call is made to method preFilter. In this method the key code is below

if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) )

For our example this is what is being checked

" header ".indexOf(" header ")

This operation is repeated for all the elements on the checkSet. Elements not matching the criteria are rejected.

More methods in Sizzle

if you dig more into Sizzle code you would see functions defined as +, > and ~ . Also you will see methods like

enabled: function(elem){
          return elem.disabled === false && elem.type !== "hidden";
    },
disabled: function(elem){
          return elem.disabled === true;
     },
checked: function(elem){
          return elem.checked === true;
     },
selected: function(elem){
          elem.parentNode.selectedIndex;
          return elem.selected === true;
     },
parent: function(elem){
          return !!elem.firstChild;
     },
empty: function(elem){
          return !elem.firstChild;
     },
has: function(elem, i, match){
          return !!Sizzle( match[3], elem ).length;
     },
header: function(elem){
          return /h\d/i.test( elem.nodeName );
     },
text: function(elem){
          return "text" === elem.type;
     },
radio: function(elem){
          return "radio" === elem.type;
     },
checkbox: function(elem){
          return "checkbox" === elem.type;
     },
file: function(elem){
          return "file" === elem.type;
     },
password: function(elem){
          return "password" === elem.type;
     },
submit: function(elem){
          return "submit" === elem.type;
     },
image: function(elem){
          return "image" === elem.type;
     },
reset: function(elem){
          return "reset" === elem.type;
     },
button: function(elem){
          return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
     },
input: function(elem){
          return /input|select|textarea|button/i.test(elem.nodeName);
     }
},

first: function(elem, i){
          return i === 0;
     },
last: function(elem, i, match, array){
          return i === array.length - 1;
     },
even: function(elem, i){
          return i % 2 === 0;
     },
odd: function(elem, i){
          return i % 2 === 1;
     },
lt: function(elem, i, match){
          return i < match[3] - 0;
     },
gt: function(elem, i, match){
          return i > match[3] - 0;
     },
nth: function(elem, i, match){
          return match[3] - 0 === i;
     },
eq: function(elem, i, match){
          return match[3] - 0 === i;
     }

I use all these methods almost daily and it was good to see how these methods are actually implemented.

Performance Implications

Now that I have little more understanding of how Sizzle works, I can better optimize my selector queries. Here are two selectors doing the same thing.

$('p.about_me .employment');

$('.about_me  p.employment'); 

Since Sizzle goes from right to left, in the first case Sizzle will pick up all the elements with the class employment and then Sizzle will try to filter that list. In the second case Sizzle will pick up only the p elements with class employment and then it will filter the list. In the second case the right most selection criteria is more specific and it will bring better performance.

So the rule with Sizzle is to go more specific on right hand side and to go less specific on left hand side. Here is another example.

$('.container :disabled');

$('.container input:disabled');

The second query will perform better because the right side query is more specific.

Inject for array

Inject is awesome. I was going through comments of this blog and learned something new today.

Given below is a case where I need to add all the numbers. One way to solve would be something like this.

ar = [[:a, 1], [:b, 2], [:c, 3]]
c = ar.inject(0) do |sum, record|
  sum += record[1]
end
puts c #=> 6

Here is another way to solve the same problem.

ar = [[:a, 1], [:b, 2], [:c, 3]]
d = ar.inject(0) do |sum, (first, second)|
  sum += second
end
puts d

The second parameter in the block is split based on pattern. If the inner array has three elements then all the three elements can be split based on pattern.

ar = [[:a, 1, 11], [:b, 2, 22], [:c, 3, 33]]
d = ar.inject(0) do |sum, (first, second, third)|
  sum += third
end
puts d #=> 66

My name is Neeraj. You can contact me at neerajdotname@gmail.com . I am also on twitter , facebook and Linkedin .

Checkout my github account for admin_data and other projects.