Re: Various DOM-related wrappers (Code Worth Recommending Project)
- From: David Mark <dmark.cinsoft@xxxxxxxxx>
- Date: Tue, 11 Dec 2007 00:49:17 -0800 (PST)
On Dec 10, 11:53 pm, Peter Michaux <petermich...@xxxxxxxxx> wrote:
On Dec 10, 5:29 pm, David Mark <dmark.cins...@xxxxxxxxx> wrote:
On Dec 10, 6:37 pm, Peter Michaux <petermich...@xxxxxxxxx> wrote:
On Dec 10, 2:36 pm, David Mark <dmark.cins...@xxxxxxxxx> wrote:
On Dec 10, 2:30 pm, Peter Michaux <petermich...@xxxxxxxxx> wrote:
[snip]
Slightly similar. It doesn't completely work around the IE bug (and I
am not convinced it needs to), but it does add some value to the
implementation. The gEBCS wrapper as it stands is probably only
implementing half of what the w3c method will do. I don't think that
is necessarily a bad thing, but it may cause some confusion in that
the two branches will diverge considerably once there is a featured
w3c method. And BTW, it wouldn't hurt to add the test for it and
associated branch now (assuming we are going to wrap it.)
Wrapping an unstable and/or unimplemented spec seems to be jumping the
gun a bit.
I think it is unimplemented at the moment. I guess it may be unstable
when it is implemented in Beta versions. So that makes sense.
The tables are turned and now I want to check something you don't :-)
IE4/NN4 support 1.2 and I ignore the consequences of inadequate
feature testing for anything that came before that. That's where I
draw the line. The use of RegExp literals in this project will ensure
that NN <= 4 and IE < 4 won't parse the scripts anyway.
Ok, I'll yield. We will do less testing!
[snip]
That seems like an iffy test for a document node. It would be more
robust to test if it is not an element node (see the gEBTN wrapper.)
Please post a replacement for the above line.
See below.
ns = [];
for (i=0, ilen=els.length; i<ilen; ++i) {
Does it not make sense to use while (--i) and reverse the results
after the loop? At least for large numbers of nodes, it would seem
more efficient.
I haven't tested this system. Is it really faster? By how much?
Depends on the environment and what is happening inside the loop. In
most cases it is relatively faster.
I tested the following in Firefox
// ----------------------
var start = (new Date()).getTime();
var a = [];
var i=100000;
while (i--) {
a[i]=i;}
a.reverse();
console.log((new Date()).getTime() - start); // ~800
// ----------------------
var start = (new Date()).getTime();
var a = [];
for (var i=0; i<100000; i++) {
a[i]=i;}
console.log((new Date()).getTime() - start); // ~900
// ----------------------
The first version with reverse must be a little faster because the
memory alloted for the array does not need to be dynamically. Sound
reasonable?
It is the comparison that is faster (boolean vs. numeric comparison.)
For what it's worth, 13% more time for the forward version when the
array is huge (100000) doesn't really bother me because it would be
very unlikely to deal with an array that big in a browser scripting
task. I don't mind the reverse way but it is a little more confusing
to understand.
Right.
Would this be a more efficient test?
// Outside of the loop
re = new RegExp('(^|\\s)' + cn + '(\\s|$)')
re.test(el.className)
Using a regular expression is much slower. I tested this. It is a big
difference.
That surprises me. You could eliminate the extra string concatenation
though.
If the function is to be optimized a lot more needs to be done than
that. The CSS selector string should be compiled into a JavaScript
string which represents a function and then that function string is
evaluated. This function can be cached to be used later. This sort of
optimization is really important if selectors with several simple
selectors (e.g. div div div) because those tasks are so much more
laborious. For simple selectors it is not so important.
[snip]
Speaking of speed. I have an XPath version of this. It is tangled up
in a general-purpose query function that has a few more options (e.g.
checking for the presence of attributes.) But it wouldn't take too
much effort to untangle it and add it as a branch to this.
Please do post that! I have never looked into this but want to learn
about.
I spliced together a new version of function.
[snip]
getElementsByClassName and getElementsByCssSelector functions are both
sugar on top of what the browser offers. Given the limited scope of
what a getElementsByClassName function can do I think it would be best
to just implement it as one of the getElementsByCssSelector functions.
I think it makes sense to include it as a one-liner that calls gEBCS.
I really don't mind either way (thanks to automated testing! :D). So
you are suggesting the following in two files?
getEBCN = function(cn, d) = {
/* lots of code*/
};
getEBCS = function(s, d) = {
return getEBCN(s.substring(1), d);
};
No, exactly the opposite.
Ok.
[snip]
I haven't tested this thoroughly.
var queryXPath, resolve;
if (isFeaturedMethod(doc, 'evaluate')) {
resolve = function() { return 'http://www.w3.org/1999/xhtml';};
queryXPath = function(ancestor, tagName, className) {
var l, r, bSnapshot, docNode = (ancestor.nodeType == 9)?ancestor:
(ancestor.ownerDocument || doc);
If ancestor is from a different document and doc is used, then the doc
is not the one that contains ancestor. It seems to me this could be a
big problem if ancestor is in an XHTML document and doc is an HTML
document. Isn't it necessary to walk up the DOM from ancestor to find
it's ownerDocument?
You mean if the element node doesn't have an ownerDocument property?
I don't see that as possible in a browser that supports XPath, but I
could be wrong. Granted the || doc fallback is ambiguous.
var queryResults = [];
var queryString = ['.//', ((xmlParseMode(docNode))?'html:':''),
tagName, ((className)?"[contains(concat(' ', @class, ' '), ' " +
className + " ')]":'')].join('');
Why use join() instead of just adding the bits together with string
concatenation?
In the original query function, which accepted multiple query
parameters, this was in a loop and I thought the join would be faster.
r = docNode.evaluate(queryString, ancestor,
(xmlParseMode(docNode))?resolve:null,
global.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
Please use a 70 character line width. This is very difficult to read
and time consuming to reformat so it is readable.
l = r.snapshotLength;
while (l--) { queryResults[l] = r[l]; }
return queryResults;
};
}
var getEBCN;
var getEBCS = (function() {
var m, // regexp matches and temp var in loop
tn, // tagName in s
id, // id in s
cn, // className in s
els, // candidate elements for return
ns, // elements to return
i, // loop index
el; // temp element variable
var get = (function() {
if (typeof queryXPath != 'undefined' && typeof getEBI !=
'undefined') {
return function(d, id, tn, cn) {
if (id) {
ns = [];
el = getEBI(id);
if (el) {
if ((tn == '*' || el.tagName.toLowerCase() == tn) &&
(!cn || ((m = el.className) &&
(' '+m+' ').indexOf(' '+cn+' ') > -1))) {
ns = [el];
}
}
return ns;
}
else {
return queryXPath(d, tn, cn);
}
};
}
if (typeof getEBI != 'undefined' &&
typeof getEBTN != 'undefined' &&
// match appears first in ECMAScript in v3 so test
String.prototype.match) {
return function(d, id, tn, cn) {
// Need this because getEBI only takes document object
// as optional second argument but getEBCS takes any
// element or a document as second argument.
els = (id && (d.nodeType == 9 || (!d.nodeType && !
d.tagName))) ?
((el=getEBI(id, d)) ? [el] : [])
:
getEBTN(tn, d);
ns = [];
i = els.length;
while (i--) {
el = els[i];
// Could call an external hasClassName function but in line
// it here for efficiency. There are no cross browser issue
// with checking className.
if ((!cn ||
((m = el.className) &&
(' '+m+' ').indexOf(' '+cn+' ')>-1)) &&
// If tn != '*' then el necessarily has tagname
property.
(tn == '*' || el.tagName.toLowerCase() == tn) &&
(!id || el.id == id)) {
ns[ns.length] = el;
}
}
return ns.reverse();
};
}
})();
if (get) {
return function(s, d) {
m = s.match(/^([^#\.]+)/);
tn = m ? m[1] : '*';
m = s.match(/#([^\.]+)/);
id = m ? m[1] : null;
m = s.match(/\.([^#]+)/);
cn = m ? m[1] : null;
return get(d || doc, id, tn, cn);
};
}
})();
if (getEBCS) {
getEBCN = function(s, d) {
return getEBCS('.' + s, d);
};
}
I didn't think the code for using xpath was going to be so big. Given
Well, the actual XPath code is pretty small. It is the inline
duplication of code that has grown the gEBCS function, but that is
necessary for the branch that loops.
how big this code is I think speed profiles would be good if this is
to be recommended over the non-xpath version. I think that there won't
be too much difference for simple selectors.
It is an order or magnitude faster for all cases, but won't have a big
impact unless the fallback branch loops through lots of results (e.g.
finding className matches for any tagName.) I definitely think this
should be an alternate version. Especially if you think we will want
to provide a wrapper for gEBCS that does more than just tagNames and
classNames.
I was surprised to see that Windows Safari has XPath. So other than
IE, what modern browser doesn't have it?
I don't know.
What I would like to know is why in Prototype.js they turn off using
xpath for any browser with "AppleWebKit" in navigator.userAgent.
Who knows why they do anything? Looking through Rails tickets makes
you wonder if they know. Googling for combinations of "XPath bug",
"WebKit" and "Safari" yielded nothing. I suspect that there might be
a limitation in some older Safari version that defeats some of the
more outlandish of their supported queries, but that is just a guess.
Do
early versions of Safari have a bug in the xpath implementation. If
there is a bug, a feature test would be needed.
I agree if a bug can be confirmed.
.
- Follow-Ups:
- Re: Various DOM-related wrappers (Code Worth Recommending Project)
- From: Peter Michaux
- Re: Various DOM-related wrappers (Code Worth Recommending Project)
- References:
- Various DOM-related wrappers (Code Worth Recommending Project)
- From: David Mark
- Re: Various DOM-related wrappers (Code Worth Recommending Project)
- From: Peter Michaux
- Re: Various DOM-related wrappers (Code Worth Recommending Project)
- From: David Mark
- Re: Various DOM-related wrappers (Code Worth Recommending Project)
- From: Peter Michaux
- Re: Various DOM-related wrappers (Code Worth Recommending Project)
- From: David Mark
- Re: Various DOM-related wrappers (Code Worth Recommending Project)
- From: Peter Michaux
- Various DOM-related wrappers (Code Worth Recommending Project)
- Prev by Date: Re: Problem dealing with double quotes in InnerHTML
- Next by Date: Re: Various DOM-related wrappers (Code Worth Recommending Project)
- Previous by thread: Re: Various DOM-related wrappers (Code Worth Recommending Project)
- Next by thread: Re: Various DOM-related wrappers (Code Worth Recommending Project)
- Index(es):
Relevant Pages
|