Skip to content

Commit 8a5c1e9

Browse files
committed
Make sure scopeSubtree does not recurse through other ShadowRoots
Polymer v1 implementation of `scopeSubtree` actually only added scoping classes, and thus would have most of the effect of stopping at ShadowRoot boundaries. This change is more consistent with Polymer v1 behavior, without a weird intersection of styling behavior.
1 parent 4f40589 commit 8a5c1e9

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

lib/utils/scope-subtree.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
99
*/
1010

1111
import './boot.js';
12+
import {wrap} from './wrap.js';
1213

1314
const ShadyDOM = window.ShadyDOM;
1415
const ShadyCSS = window.ShadyCSS;
1516

17+
/**
18+
* Return true if node scope is correct.
19+
*
20+
* @param {!Element} node Node to check scope
21+
* @param {!Node} scope Scope reference
22+
* @return {boolean} True if node is in scope
23+
*/
24+
function sameScope(node, scope) {
25+
return wrap(node).getRootNode() === scope;
26+
}
27+
1628
/**
1729
* Ensure that elements in a ShadowDOM container are scoped correctly.
1830
* This function is only needed when ShadyDOM is used and unpatched DOM APIs are used in third party code.
@@ -38,13 +50,20 @@ export function scopeSubtree(container, shouldObserve = false) {
3850
}
3951
// capture correct scope for container
4052
const containerScope = ScopingShim['scopeForNode'](container);
53+
const root = wrap(container).getRootNode();
4154

4255
const scopify = (node) => {
56+
if (!sameScope(node, root)) {
57+
return;
58+
}
4359
// NOTE: native qSA does not honor scoped DOM, but it is faster, and the same behavior as Polymer v1
4460
const elements = Array.from(ShadyDOM['nativeMethods']['querySelectorAll'].call(node, '*'));
4561
elements.push(node);
4662
for (let i = 0; i < elements.length; i++) {
4763
const el = elements[i];
64+
if (!sameScope(el, root)) {
65+
continue;
66+
}
4867
const currentScope = ScopingShim['currentScopeForNode'](el);
4968
if (currentScope !== containerScope) {
5069
if (currentScope !== '') {

test/unit/styling-scoped-nopatch.html

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,24 @@
5050
customElements.define('scope-subtree-element', ScopeSubtreeElement);
5151
</script>
5252

53+
<script type="module">
54+
import {Polymer, html} from '../../polymer-legacy.js';
55+
Polymer({
56+
is: 'scope-subtree-deep',
57+
_template: html`
58+
<style>
59+
div {
60+
border: 20px dotted orange !important;
61+
}
62+
</style>
63+
<div id="target"></div>
64+
<div id="container">
65+
<scope-subtree-legacy id="other"></scope-subtree-legacy>
66+
</div>
67+
`,
68+
});
69+
</script>
70+
5371
<test-fixture id="legacy">
5472
<template>
5573
<scope-subtree-legacy></scope-subtree-legacy>
@@ -62,6 +80,12 @@
6280
</template>
6381
</test-fixture>
6482

83+
<test-fixture id="deep">
84+
<template>
85+
<scope-subtree-deep></scope-subtree-deep>
86+
</template>
87+
</test-fixture>
88+
6589
<script type="module">
6690
import { scopeSubtree } from '../../lib/utils/scope-subtree.js';
6791

@@ -127,6 +151,24 @@
127151
assertComputed(div, '10px');
128152
assertComputed(innerDiv, '10px');
129153
});
154+
155+
suite('scopeSubtree containment', function() {
156+
let el;
157+
setup(function() {
158+
el = fixture('deep');
159+
});
160+
test('scopeSubtree does not modify other elements\' trees', function() {
161+
const target = el.$.target;
162+
const container = el.$.container;
163+
const deepContainer = el.$.other.$.container;
164+
const deep = document.createElement('div');
165+
deepContainer.appendChild(deep);
166+
el.$.other.scopeSubtree(deepContainer);
167+
el.scopeSubtree(container);
168+
debugger;
169+
assertComputed(deep, '10px');
170+
});
171+
});
130172
});
131173
</script>
132174
</body>

0 commit comments

Comments
 (0)