Ensure querySelector always returns null when a node is not found. Also optimize querySelector such that the matcher halts on the first result.

This commit is contained in:
Steven Orvell 2016-01-14 15:39:00 -08:00
parent 6e16619a4a
commit b9e5cce27f
3 changed files with 23 additions and 9 deletions

View File

@ -352,7 +352,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// TODO(sorvell): consider doing native QSA and filtering results. // TODO(sorvell): consider doing native QSA and filtering results.
querySelector: function(selector) { querySelector: function(selector) {
return this.querySelectorAll(selector)[0]; // match selector and halt on first result.
var result = this._query(function(n) {
return DomApi.matchesSelector.call(n, selector);
}, this.node, function(n) {
return Boolean(n);
})[0];
return result || null;
}, },
querySelectorAll: function(selector) { querySelectorAll: function(selector) {

View File

@ -139,26 +139,34 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// NOTE: `_query` is used primarily for ShadyDOM's querySelector impl, // NOTE: `_query` is used primarily for ShadyDOM's querySelector impl,
// but it's also generally useful to recurse through the element tree // but it's also generally useful to recurse through the element tree
// and is used by Polymer's styling system. // and is used by Polymer's styling system.
_query: function(matcher, node) { _query: function(matcher, node, halter) {
node = node || this.node; node = node || this.node;
var list = []; var list = [];
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, list); this._queryElements(TreeApi.Logical.getChildNodes(node), matcher,
halter, list);
return list; return list;
}, },
_queryElements: function(elements, matcher, list) { _queryElements: function(elements, matcher, halter, list) {
for (var i=0, l=elements.length, c; (i<l) && (c=elements[i]); i++) { for (var i=0, l=elements.length, c; (i<l) && (c=elements[i]); i++) {
if (c.nodeType === Node.ELEMENT_NODE) { if (c.nodeType === Node.ELEMENT_NODE) {
this._queryElement(c, matcher, list); if (this._queryElement(c, matcher, halter, list)) {
return true;
}
} }
} }
}, },
_queryElement: function(node, matcher, list) { _queryElement: function(node, matcher, halter, list) {
if (matcher(node)) { var result = matcher(node);
if (result) {
list.push(node); list.push(node);
} }
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, list); if (halter && halter(result)) {
return result;
}
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher,
halter, list);
} }
}; };

View File

@ -11,7 +11,7 @@ suite('Polymer.dom', function() {
var projected = Polymer.dom(testElement.root).querySelector('#projected'); var projected = Polymer.dom(testElement.root).querySelector('#projected');
assert.equal(projected.textContent, 'projected'); assert.equal(projected.textContent, 'projected');
var p2 = Polymer.dom(testElement).querySelector('#projected'); var p2 = Polymer.dom(testElement).querySelector('#projected');
assert.notOk(p2); assert.isNull(p2);
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject'); var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
assert.equal(rere.is, 'x-rereproject'); assert.equal(rere.is, 'x-rereproject');
var re = Polymer.dom(rere.root).querySelector('x-reproject'); var re = Polymer.dom(rere.root).querySelector('x-reproject');