prototype: Optimize Selector#match and Element#match for simple selectors. Closes #9082.
This commit is contained in:
parent
a529bcf590
commit
82bedcee84
@ -1,5 +1,7 @@
|
||||
*SVN*
|
||||
|
||||
* Optimize Selector#match and Element#match for simple selectors. Closes #9082. [Andrew Dupont]
|
||||
|
||||
* Remove the dependency on Element.ClassNames from Element#addClassName/removeClassName/toggleClassName, and deprecate Element.ClassNames. Closes #9073. [Tobie Langel]
|
||||
|
||||
* Make Element#wrap accept a second argument for setting attributes on the wrapper. Allow wrapping elements which are not part of the document. Closes #9071. [Tobie Langel]
|
||||
|
@ -74,7 +74,39 @@ Selector.prototype = {
|
||||
},
|
||||
|
||||
match: function(element) {
|
||||
return this.findElements(document).include(element);
|
||||
this.tokens = [];
|
||||
|
||||
var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
|
||||
var le, p, m;
|
||||
|
||||
while (e && le !== e && (/\S/).test(e)) {
|
||||
le = e;
|
||||
for (var i in ps) {
|
||||
p = ps[i];
|
||||
if (m = e.match(p)) {
|
||||
// use the Selector.assertions methods unless the selector
|
||||
// is too complex.
|
||||
if (as[i]) {
|
||||
this.tokens.push([i, Object.clone(m)]);
|
||||
e = e.replace(m[0], '');
|
||||
} else {
|
||||
// reluctantly do a document-wide search
|
||||
// and look for a match in the array
|
||||
return this.findElements(document).include(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var match = true, name, matches;
|
||||
for (var i = 0, token; token = this.tokens[i]; i++) {
|
||||
name = token[0], matches = token[1];
|
||||
if (!Selector.assertions[name](element, matches)) {
|
||||
match = false; break;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
@ -223,6 +255,30 @@ Object.extend(Selector, {
|
||||
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
|
||||
},
|
||||
|
||||
// for Selector.match and Element#match
|
||||
assertions: {
|
||||
tagName: function(element, matches) {
|
||||
return matches[1].toUpperCase() == element.tagName.toUpperCase();
|
||||
},
|
||||
|
||||
className: function(element, matches) {
|
||||
return Element.hasClassName(element, matches[1]);
|
||||
},
|
||||
|
||||
id: function(element, matches) {
|
||||
return element.id === matches[1];
|
||||
},
|
||||
|
||||
attrPresence: function(element, matches) {
|
||||
return Element.hasAttribute(element, matches[1]);
|
||||
},
|
||||
|
||||
attr: function(element, matches) {
|
||||
var nodeValue = Element.readAttribute(element, matches[1]);
|
||||
return Selector.operators[matches[2]](nodeValue, matches[3]);
|
||||
}
|
||||
},
|
||||
|
||||
handlers: {
|
||||
// UTILITY FUNCTIONS
|
||||
// joins two collections
|
||||
|
@ -61,7 +61,7 @@
|
||||
</div> <!-- #level1 -->
|
||||
|
||||
<div id="dupContainer">
|
||||
<span id="dupL1">
|
||||
<span id="dupL1" class="span_foo span_bar">
|
||||
<span id="dupL2">
|
||||
<span id="dupL3">
|
||||
<span id="dupL4">
|
||||
@ -198,6 +198,26 @@
|
||||
assertElementMatches(Selector.findElement($('list').descendants(), 'li#item_3'), 'li');
|
||||
assertEqual(undefined, Selector.findElement($('list').descendants(), 'em'));
|
||||
}},
|
||||
|
||||
testElementMatch: function() {with(this) {
|
||||
var span = $('dupL1');
|
||||
// tests that should pass
|
||||
assert(span.match('span'));
|
||||
assert(span.match('span#dupL1'));
|
||||
assert(span.match('div > span'), 'child combinator');
|
||||
assert(span.match('#dupContainer span'), 'descendant combinator');
|
||||
assert(span.match('#dupL1'), 'ID only');
|
||||
assert(span.match('span.span_foo'), 'class name 1');
|
||||
assert(span.match('span.span_bar'), 'class name 2');
|
||||
assert(span.match('span:first-child'), 'first-child pseudoclass');
|
||||
|
||||
assert(!span.match('span.span_wtf'), 'bogus class name');
|
||||
assert(!span.match('#dupL2'), 'different ID');
|
||||
assert(!span.match('div'), 'different tag name');
|
||||
assert(!span.match('span span'), 'different ancestry');
|
||||
assert(!span.match('span > span'), 'different parent');
|
||||
assert(!span.match('span:nth-child(5)'), 'different pseudoclass');
|
||||
}},
|
||||
|
||||
testSelectorWithSpaceInAttributeValue: function() {with(this) {
|
||||
assertEnumEqual([$('with_title')], $$('cite[title="hello world!"]'));
|
||||
|
Loading…
Reference in New Issue
Block a user