D
David Mark
Having recently added an experimental QSA add-on for My Library, I have
been warned that QSA is a bear cross-browser. I don't doubt that, but
the other assertion was that the "major" libraries have it beat (likely
in the same way they "beat" DOM traversal).
I suppose to determine if it is buggy, you have to have a baseline that
is not buggy. So I suspected that some of the "buggy" behavior and
accompanying workarounds would be mystical incantations.
The querying in jQuery 1.41 (for example), uses an oddly named variable
called "Zizzle" to abstract the two layers (QSA and some really
off-the-wall and error-filled DOM traversal).
The original Sizzle is "declared" as follows:-
window.Sizzle = Sizzle;
Well, of course it is. Some things never change.
if ( document.querySelectorAll ) {
Bad feature detection (of course). I can easily see that blowing up in
some future IE incarnation (or who knows what other browser as host
objects can do what they want on type conversion).
(function(){
var oldSizzle = Sizzle, div = document.createElement("div");
div.innerHTML = "<p class='TEST'></p>";
Same old story. Needlessly tangling up feature testing with the
notoriously flaky innerHTML property.
// Safari can't handle uppercase or unicode characters when
// in quirks mode.
Interesting observation. Just Safari? Seems more like a Webkit issue
(assuming there is an issue). And what unicode characters?
if ( div.querySelectorAll && div.querySelectorAll(".TEST").length
=== 0) {
return;
}
How about !div.querySelectorAll(".TEST").length? The strict comparison
is silly.
Sizzle = function(query, context, extra, seed){
context = context || document;
That lets out frames.
// Only use querySelectorAll on non-XML documents
No worries, it is well established that jQuery is unsuitable for
traversing (or mutating) XML documents (Resig called a punt on that
issue a few months back). So this should really read: don't use jQuery
to read or write XML documents of any kind.
// (ID selectors don't work in non-HTML documents)
if ( !seed && context.nodeType === 9 && !isXML(context) ) {
isXML? Lets see:-
var isXML = function(elem){
// documentElement is verified for cases where it doesn't yet exist
Always a good idea.
// (such as loading iframes in IE - #4833)
Interesting observation, but the understanding must be that the
documentElement may not exist, period. In other words, this is not an
IE/IFrame issue, but a gap in logic that could have been avoided long
before the observed failure.
And, of course, jQuery can't support frames anyway (see above). I
assume bits of it do, but certainly not the query engine.
var documentElement = (elem ? elem.ownerDocument || elem :
0).documentElement;
What a perfectly ludicrous (and unreadable) line of code (didn't look to
see what it was replacing). But at least it doesn't throw exceptions if
the documentElement property is missing. The telling thing is that this
is one of those "overloaded" functions that jQuery is famous for,
requiring it to discriminate between different types of host objects
(elements and documents in this case).
return documentElement ? documentElement.nodeName !== "HTML" : false;
Whatever. It certainly doesn't add up to a cross-browser XML
discriminator (and is used all over the place in a library that doesn't
really support XML). And according to the above comment about IE and
IFrames, the documentElement may be missing in some cases, but otherwise
supported, so this is tangled up as it always returns false whenever it
can't find that property.
};
Back to the query portion:-
try {
return makeArray( context.querySelectorAll(query), extra );
} catch(e){}
}
That's it, is it? One (possible) quirk worked around. I see I haven't
been missing out on much (if anything). Who would have thought that
"jdalton" would exaggerate a claim? It must be the end of the world.
return oldSizzle(query, context, extra, seed);
};
for ( var prop in oldSizzle ) {
No filter (of course). Keep this thing away from other scripts.
Sizzle[ prop ] = oldSizzle[ prop ];
}
div = null; // release memory in IE
Cargo cult. There's no circular reference to break here. I used to do
the same thing, which is likely not a coincidence.
})();
}
Okay, so how about the latest "stable" version of Prototype:-
SelectorsAPI: !!document.querySelector,
[...]
if (Prototype.BrowserFeatures.SelectorsAPI &&
document.compatMode === 'BackCompat') {
So any quirks mode.
Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){
That sounds sort of like the quirk that surfaced in jQuery.
var div = document.createElement('div'),
span = document.createElement('span');
div.id = "prototype_test_id";
span.className = 'Test';
div.appendChild(span);
var isIgnored = (div.querySelector('#prototype_test_id .test') !==
null);
div = span = null;
Another coincidence perhaps? Looks almost exactly like what I was
putting out in 2007, which showed up in jQuery in 2008 and is now being
copied by Prototype. Odd that these bums are my biggest "critics" (or
perhaps they are just jealous).
return isIgnored;
})();
I do like that pattern.
And the logic is better than jQuery's.
Still, it is testing querySelector, but using querySelectorAll for its
queries (bad object inference).
}
[...]
shouldUseSelectorsAPI: function() {
if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
Poor form.
if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;
Same.
if (!Selector._div) Selector._div = new Element('div');
The RHS is mind-bogglingly inept. How about using createElement?
They are setting up for the big finale:-
try {
Selector._div.querySelector(this.expression);
} catch(e) {
return false;
}
return true;
},
Making the try-catch a one-off is admirable. The object inference is
inexcusable. And unless I've missed something, that's it for Prototype.
So, it appears there is nearly one quirk worked around between these two
"majors". I won't confirm it as one for sure, but I do remember such an
issue with Webkit in quirks mode (unrelated to QSA), so perhaps. I'll
look into it further. I don't know why jQuery bothered as they can't
support quirks mode in IE, which makes it a waste to attempt to support
others. Not surprising given its history though.
Yes, It appears I've seriously underestimated the time and care it takes
to create a QSA adapter. I should probably just pack it in.
been warned that QSA is a bear cross-browser. I don't doubt that, but
the other assertion was that the "major" libraries have it beat (likely
in the same way they "beat" DOM traversal).
I suppose to determine if it is buggy, you have to have a baseline that
is not buggy. So I suspected that some of the "buggy" behavior and
accompanying workarounds would be mystical incantations.
The querying in jQuery 1.41 (for example), uses an oddly named variable
called "Zizzle" to abstract the two layers (QSA and some really
off-the-wall and error-filled DOM traversal).
The original Sizzle is "declared" as follows:-
window.Sizzle = Sizzle;
Well, of course it is. Some things never change.
if ( document.querySelectorAll ) {
Bad feature detection (of course). I can easily see that blowing up in
some future IE incarnation (or who knows what other browser as host
objects can do what they want on type conversion).
(function(){
var oldSizzle = Sizzle, div = document.createElement("div");
div.innerHTML = "<p class='TEST'></p>";
Same old story. Needlessly tangling up feature testing with the
notoriously flaky innerHTML property.
// Safari can't handle uppercase or unicode characters when
// in quirks mode.
Interesting observation. Just Safari? Seems more like a Webkit issue
(assuming there is an issue). And what unicode characters?
if ( div.querySelectorAll && div.querySelectorAll(".TEST").length
=== 0) {
return;
}
How about !div.querySelectorAll(".TEST").length? The strict comparison
is silly.
Sizzle = function(query, context, extra, seed){
context = context || document;
That lets out frames.
// Only use querySelectorAll on non-XML documents
No worries, it is well established that jQuery is unsuitable for
traversing (or mutating) XML documents (Resig called a punt on that
issue a few months back). So this should really read: don't use jQuery
to read or write XML documents of any kind.
// (ID selectors don't work in non-HTML documents)
if ( !seed && context.nodeType === 9 && !isXML(context) ) {
isXML? Lets see:-
var isXML = function(elem){
// documentElement is verified for cases where it doesn't yet exist
Always a good idea.
// (such as loading iframes in IE - #4833)
Interesting observation, but the understanding must be that the
documentElement may not exist, period. In other words, this is not an
IE/IFrame issue, but a gap in logic that could have been avoided long
before the observed failure.
And, of course, jQuery can't support frames anyway (see above). I
assume bits of it do, but certainly not the query engine.
var documentElement = (elem ? elem.ownerDocument || elem :
0).documentElement;
What a perfectly ludicrous (and unreadable) line of code (didn't look to
see what it was replacing). But at least it doesn't throw exceptions if
the documentElement property is missing. The telling thing is that this
is one of those "overloaded" functions that jQuery is famous for,
requiring it to discriminate between different types of host objects
(elements and documents in this case).
return documentElement ? documentElement.nodeName !== "HTML" : false;
Whatever. It certainly doesn't add up to a cross-browser XML
discriminator (and is used all over the place in a library that doesn't
really support XML). And according to the above comment about IE and
IFrames, the documentElement may be missing in some cases, but otherwise
supported, so this is tangled up as it always returns false whenever it
can't find that property.
};
Back to the query portion:-
try {
return makeArray( context.querySelectorAll(query), extra );
} catch(e){}
}
That's it, is it? One (possible) quirk worked around. I see I haven't
been missing out on much (if anything). Who would have thought that
"jdalton" would exaggerate a claim? It must be the end of the world.
return oldSizzle(query, context, extra, seed);
};
for ( var prop in oldSizzle ) {
No filter (of course). Keep this thing away from other scripts.
Sizzle[ prop ] = oldSizzle[ prop ];
}
div = null; // release memory in IE
Cargo cult. There's no circular reference to break here. I used to do
the same thing, which is likely not a coincidence.
})();
}
Okay, so how about the latest "stable" version of Prototype:-
SelectorsAPI: !!document.querySelector,
[...]
if (Prototype.BrowserFeatures.SelectorsAPI &&
document.compatMode === 'BackCompat') {
So any quirks mode.
Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){
That sounds sort of like the quirk that surfaced in jQuery.
var div = document.createElement('div'),
span = document.createElement('span');
div.id = "prototype_test_id";
span.className = 'Test';
div.appendChild(span);
var isIgnored = (div.querySelector('#prototype_test_id .test') !==
null);
div = span = null;
Another coincidence perhaps? Looks almost exactly like what I was
putting out in 2007, which showed up in jQuery in 2008 and is now being
copied by Prototype. Odd that these bums are my biggest "critics" (or
perhaps they are just jealous).
return isIgnored;
})();
I do like that pattern.
Still, it is testing querySelector, but using querySelectorAll for its
queries (bad object inference).
}
[...]
shouldUseSelectorsAPI: function() {
if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
Poor form.
if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;
Same.
if (!Selector._div) Selector._div = new Element('div');
The RHS is mind-bogglingly inept. How about using createElement?
They are setting up for the big finale:-
try {
Selector._div.querySelector(this.expression);
} catch(e) {
return false;
}
return true;
},
Making the try-catch a one-off is admirable. The object inference is
inexcusable. And unless I've missed something, that's it for Prototype.
So, it appears there is nearly one quirk worked around between these two
"majors". I won't confirm it as one for sure, but I do remember such an
issue with Webkit in quirks mode (unrelated to QSA), so perhaps. I'll
look into it further. I don't know why jQuery bothered as they can't
support quirks mode in IE, which makes it a waste to attempt to support
others. Not surprising given its history though.
Yes, It appears I've seriously underestimated the time and care it takes
to create a QSA adapter. I should probably just pack it in.