Skip to content

Commit 9cd6b79

Browse files
committed
Merge pull request #3296 from Polymer/fix-3295
Fixes #3295. Only cache a false-y result for an element's owner shady…
2 parents 848dbb9 + 0e74810 commit 9cd6b79

File tree

4 files changed

+111
-13
lines changed

4 files changed

+111
-13
lines changed

src/lib/dom-api-shady.html

+18-5
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@
170170
if (!node) {
171171
return;
172172
}
173-
if (node._ownerShadyRoot === undefined) {
174-
var root;
173+
var root = node._ownerShadyRoot;
174+
if (root === undefined) {
175175
if (node._isShadyRoot) {
176176
root = node;
177177
} else {
@@ -183,9 +183,16 @@
183183
root = null;
184184
}
185185
}
186-
node._ownerShadyRoot = root;
186+
// memo-ize result for performance but only memo-ize a false-y
187+
// result if node is in the document. This avoids a problem where a root
188+
// can be cached while an element is inside a fragment.
189+
// If this happens and we cache the result, the value can become stale
190+
// because for perf we avoid processing the subtree of added fragments.
191+
if (root || document.documentElement.contains(node)) {
192+
node._ownerShadyRoot = root;
193+
}
187194
}
188-
return node._ownerShadyRoot;
195+
return root;
189196
},
190197

191198
_maybeDistribute: function(node) {
@@ -345,7 +352,13 @@
345352

346353
// TODO(sorvell): consider doing native QSA and filtering results.
347354
querySelector: function(selector) {
348-
return this.querySelectorAll(selector)[0];
355+
// match selector and halt on first result.
356+
var result = this._query(function(n) {
357+
return DomApi.matchesSelector.call(n, selector);
358+
}, this.node, function(n) {
359+
return Boolean(n);
360+
})[0];
361+
return result || null;
349362
},
350363

351364
querySelectorAll: function(selector) {

src/lib/dom-api.html

+15-7
Original file line numberDiff line numberDiff line change
@@ -139,26 +139,34 @@
139139
// NOTE: `_query` is used primarily for ShadyDOM's querySelector impl,
140140
// but it's also generally useful to recurse through the element tree
141141
// and is used by Polymer's styling system.
142-
_query: function(matcher, node) {
142+
_query: function(matcher, node, halter) {
143143
node = node || this.node;
144144
var list = [];
145-
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, list);
145+
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher,
146+
halter, list);
146147
return list;
147148
},
148149

149-
_queryElements: function(elements, matcher, list) {
150+
_queryElements: function(elements, matcher, halter, list) {
150151
for (var i=0, l=elements.length, c; (i<l) && (c=elements[i]); i++) {
151152
if (c.nodeType === Node.ELEMENT_NODE) {
152-
this._queryElement(c, matcher, list);
153+
if (this._queryElement(c, matcher, halter, list)) {
154+
return true;
155+
}
153156
}
154157
}
155158
},
156159

157-
_queryElement: function(node, matcher, list) {
158-
if (matcher(node)) {
160+
_queryElement: function(node, matcher, halter, list) {
161+
var result = matcher(node);
162+
if (result) {
159163
list.push(node);
160164
}
161-
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, list);
165+
if (halter && halter(result)) {
166+
return result;
167+
}
168+
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher,
169+
halter, list);
162170
}
163171

164172
};

test/smoke/owner-root.html

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
5+
<title>early owner-root</title>
6+
7+
<meta charset="utf-8">
8+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
9+
10+
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
11+
<link rel="import" href="../../polymer.html">
12+
13+
</head>
14+
<body>
15+
16+
17+
<dom-module id="x-owner-root">
18+
<template>where am I?</template>
19+
<script>
20+
Polymer({
21+
is: 'x-owner-root',
22+
23+
properties: {
24+
nug: {type: String, observer: '_nugChanged'}
25+
},
26+
27+
_nugChanged: function() {
28+
console.log(this.localName, Polymer.dom(this).getOwnerRoot());
29+
}
30+
31+
32+
});
33+
</script>
34+
</dom-module>
35+
36+
<dom-module id="x-test">
37+
<template>
38+
<template is="dom-if" if="{{foo}}">
39+
<x-owner-root nug="foo"></x-owner-root>
40+
</template>
41+
</template>
42+
<script>
43+
Polymer({
44+
is: 'x-test',
45+
attached: function() {
46+
this.foo = true;
47+
Polymer.dom.flush();
48+
var e = Polymer.dom(this.root).querySelector('x-owner-root');
49+
var r = e && Polymer.dom(e).getOwnerRoot();
50+
console.log(e, r, r === this.root);
51+
}
52+
});
53+
</script>
54+
</dom-module>
55+
56+
<x-test></x-test>
57+
58+
</body>
59+
</html>

test/unit/polymer-dom.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ suite('Polymer.dom', function() {
1111
var projected = Polymer.dom(testElement.root).querySelector('#projected');
1212
assert.equal(projected.textContent, 'projected');
1313
var p2 = Polymer.dom(testElement).querySelector('#projected');
14-
assert.notOk(p2);
14+
assert.isNull(p2);
1515
var rere = Polymer.dom(testElement.root).querySelector('x-rereproject');
1616
assert.equal(rere.is, 'x-rereproject');
1717
var re = Polymer.dom(rere.root).querySelector('x-reproject');
@@ -1207,6 +1207,24 @@ suite('Polymer.dom non-distributed elements', function() {
12071207
assert.equal(Polymer.dom(test).getOwnerRoot(), c1.root, 'getOwnerRoot incorrect for child added to element in root');
12081208
});
12091209

1210+
test('getOwnerRoot when out of tree and adding subtree', function() {
1211+
var container = document.createDocumentFragment();
1212+
var test = document.createElement('div');
1213+
container.appendChild(test);
1214+
assert.notOk(Polymer.dom(test).getOwnerRoot(), 'getOwnerRoot incorrect when not in root');
1215+
var c1 = document.createElement('x-compose');
1216+
var project = c1.$.project;
1217+
Polymer.dom(project).appendChild(container);
1218+
Polymer.dom.flush();
1219+
assert.equal(Polymer.dom(test).getOwnerRoot(), c1.root, 'getOwnerRoot incorrect for child added to element in root');
1220+
Polymer.dom(project).removeChild(test);
1221+
Polymer.dom.flush();
1222+
assert.notOk(Polymer.dom(test).getOwnerRoot(), 'getOwnerRoot incorrect for child moved from a root to no root');
1223+
Polymer.dom(project).appendChild(test);
1224+
Polymer.dom.flush();
1225+
assert.equal(Polymer.dom(test).getOwnerRoot(), c1.root, 'getOwnerRoot incorrect for child added to element in root');
1226+
});
1227+
12101228
test('getOwnerRoot, subtree', function() {
12111229
var test = document.createElement('div');
12121230
var testChild = document.createElement('div');

0 commit comments

Comments
 (0)