HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

querySelectorAll shim for non-IE browsers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
queryselectorallnonbrowsersforshim

Problem

Every shim I have seen for this function has used the IE-only CSS expression trick. While there's no denying it's effective, it's made useless if the browser is not IE and doesn't support querySelectorAll either.

jQuery is out of the question, since I don't want to get a whole framework just to shim one tiny little function. So I went and wrote my own. I'd like to submit it for review, which may include optimisations.

Please note that this is not a complete shim, only enough for what is frequently used:

  • tag name



  • id



  • class name



  • attribute, presence and exact value match



  • descendant combinator



  • child combinator



The code:

```
if( typeof document.querySelector == "undefined") {
document.querySelectorAll = function(sel) {
var sels = sel.split(","),
run = function(node,selector) {
var sel = selector.split(/[ >]+/), com = selector.match(/[ >]+/g) || [], s, c, ret = [node], nodes, l, i, subs, m, j, check, x, w, ok,
as;
com.unshift(" ");
while(s = sel.shift()) {
c = com.shift();
if( c) c = c.replace(/^ +| +$/g,"");
nodes = ret.slice(0);
ret = [];
l = nodes.length;
subs = s.match(/[#.[]?[a-z_-]+(?:='[^']+'|="[^"]+")?]?/gi);
m = subs.length;
for( i=0; i" ? nodes[i].children : nodes[i].getElementsByTagName("*");
if( !check) continue;
w = check.length;
for( x=0; x 0) return ret[0];
else return null;
};
if( typeof HTMLElement != "undefined") {
HTMLElement.prototype.querySelector = document.querySelector;
HTMLElement.prototype.querySelectorAll = document.querySelectorAll;
}
else {
dommods_extend.push(function() {
var a = document.getElementsByTagName("*"), l = a.length,

Solution

Overal

I am not sure which non IE-browser doesn't support querySelectorAll. Regardless, the code seems very performant, if a little Golfic ( reminds me of code golf ).

Nitpickings

If you wish this source to be maintained / debugged /reviewed by others, there are some things you can change to make that easier:

-
Declare unassigned variables last. It is easier on the eyes to know when to stop reading that long var line.

-
I am all for Spartan coding, but w,m,c (which is not a character!), l etc. just make for unmaintainable code.

-
Make your regex's constants with a meaningful name, it will make your code easier to understand.

-
Use new lines after the if condition

-
if/else branches should either both have curly braces, or both not have curly braces, dont mix

-
You could use Array.concat here:

//As is
for( i=0; i<l; i++) {
    tmp = run(this,sels[i]);
    m = tmp.length;
    for( j=0; j<m; j++) {
        ret.push(tmp[j]);
    }
}
//Replacement proposal
for( i=0; i<l; i++)
  ret.push( run(this,sels[i])  );


  • You could use a trinary here :



//As is 
if( ret.length > 0) return ret[0];
else return null
//Replacement proposal
return ret.length?ret[0]:null;


Finally

It is considered bad practice to shim in incomplete implementations, if you want to add to the HTMLElement prototype, use your own names to remove any confusion. HTMLElement.prototype.darkQuerySelector sounds so much better anyway ;)

Code Snippets

//As is
for( i=0; i<l; i++) {
    tmp = run(this,sels[i]);
    m = tmp.length;
    for( j=0; j<m; j++) {
        ret.push(tmp[j]);
    }
}
//Replacement proposal
for( i=0; i<l; i++)
  ret.push( run(this,sels[i])  );
//As is 
if( ret.length > 0) return ret[0];
else return null
//Replacement proposal
return ret.length?ret[0]:null;

Context

StackExchange Code Review Q#12444, answer score: 2

Revisions (0)

No revisions yet.