diff --git a/CHANGELOG b/CHANGELOG index 3f8b16f..59f5020 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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] diff --git a/src/selector.js b/src/selector.js index d98d099..3880b1d 100644 --- a/src/selector.js +++ b/src/selector.js @@ -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 diff --git a/test/unit/selector.html b/test/unit/selector.html index baa6ba2..90a33b6 100644 --- a/test/unit/selector.html +++ b/test/unit/selector.html @@ -61,7 +61,7 @@