CSS specificity in JavaScript
Any JavaScript library worth its salt has a CSS selector engine, powering, amongst other things, an event system. I wanted to extend the idea of CSS specificity to events, so callbacks registered against the same element would be invoked in the order of their selector’s specificity, not the order in which the callbacks were registered.
For example, in Ignite 0.12, these two callbacks would be fired one after the other:
ignite.event.add('a','click',func1);ignite.event.add('a.foo','click','func2');
For an anchor with the “foo” class, both selectors match, therefore func1 will fire, followed by func2. You must change the order of registration to change the callback sequence, which is obviously not feasible when dealing with modular code.
Instead, Ignite’s Event module 0.13 will fire common callbacks in order of specificity. This means you can insert a callback anywhere in the invocation sequence from any point in your code.
The code
So, just in case you ever needed to calculate a CSS specificity value (don’t all shout out at once), here’s a small JavaScript object to do just that:
var selector={specificity:function(s){ // accepts a single selectors=s.replace(/\([^\)]+\)/,"");return parseInt([/#[\d\w-_]+/g,/[\.:\[][^\.:\[+>]+/g,/(^|[\s\+>])\w+/g].map(function(p){var m=s.match(p);return m ? m.length.toString(16) : 0;}).join(''),16);},sort:function(s){ // accepts an array of selectorsreturn s.sort(function(a,b){a=selector.specificity(a), b=selector.specificity(b);return a < b ? 1 : (a > b) ? -1 : 0;});}};
The selector.specificity() function returns a value corresponding to the CSS specificity. Because the values are arbitrary (in this case, they are calculated on a hex system to incorporate lengthier selectors), you can use selector.sort() to sort a series of selectors by their specificity.
var a=["p span","#foo","div + ol li",];selector.sort(a); // => ["#foo", "div + ol li", "p span"]
Thanks a million for this. Save me lots of time!
November 20th, 2009 at 4:20 pmCheers,
Maureen