Skip to content

Commit

Permalink
Make sure scopeSubtree does not recurse through other ShadowRoots
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dfreedm committed May 20, 2019
1 parent 4f40589 commit 8a5c1e9
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
19 changes: 19 additions & 0 deletions lib/utils/scope-subtree.js
Expand Up @@ -9,10 +9,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
*/

import './boot.js';
import {wrap} from './wrap.js';

const ShadyDOM = window.ShadyDOM;
const ShadyCSS = window.ShadyCSS;

/**
* Return true if node scope is correct.
*
* @param {!Element} node Node to check scope
* @param {!Node} scope Scope reference
* @return {boolean} True if node is in scope
*/
function sameScope(node, scope) {
return wrap(node).getRootNode() === scope;
}

/**
* Ensure that elements in a ShadowDOM container are scoped correctly.
* This function is only needed when ShadyDOM is used and unpatched DOM APIs are used in third party code.
Expand All @@ -38,13 +50,20 @@ export function scopeSubtree(container, shouldObserve = false) {
}
// capture correct scope for container
const containerScope = ScopingShim['scopeForNode'](container);
const root = wrap(container).getRootNode();

const scopify = (node) => {
if (!sameScope(node, root)) {
return;
}
// NOTE: native qSA does not honor scoped DOM, but it is faster, and the same behavior as Polymer v1
const elements = Array.from(ShadyDOM['nativeMethods']['querySelectorAll'].call(node, '*'));
elements.push(node);
for (let i = 0; i < elements.length; i++) {
const el = elements[i];
if (!sameScope(el, root)) {
continue;
}
const currentScope = ScopingShim['currentScopeForNode'](el);
if (currentScope !== containerScope) {
if (currentScope !== '') {
Expand Down
42 changes: 42 additions & 0 deletions test/unit/styling-scoped-nopatch.html
Expand Up @@ -50,6 +50,24 @@
customElements.define('scope-subtree-element', ScopeSubtreeElement);
</script>

<script type="module">
import {Polymer, html} from '../../polymer-legacy.js';
Polymer({
is: 'scope-subtree-deep',
_template: html`
<style>
div {
border: 20px dotted orange !important;
}
</style>
<div id="target"></div>
<div id="container">
<scope-subtree-legacy id="other"></scope-subtree-legacy>
</div>
`,
});
</script>

<test-fixture id="legacy">
<template>
<scope-subtree-legacy></scope-subtree-legacy>
Expand All @@ -62,6 +80,12 @@
</template>
</test-fixture>

<test-fixture id="deep">
<template>
<scope-subtree-deep></scope-subtree-deep>
</template>
</test-fixture>

<script type="module">
import { scopeSubtree } from '../../lib/utils/scope-subtree.js';

Expand Down Expand Up @@ -127,6 +151,24 @@
assertComputed(div, '10px');
assertComputed(innerDiv, '10px');
});

suite('scopeSubtree containment', function() {
let el;
setup(function() {
el = fixture('deep');
});
test('scopeSubtree does not modify other elements\' trees', function() {
const target = el.$.target;
const container = el.$.container;
const deepContainer = el.$.other.$.container;
const deep = document.createElement('div');
deepContainer.appendChild(deep);
el.$.other.scopeSubtree(deepContainer);
el.scopeSubtree(container);
debugger;
assertComputed(deep, '10px');
});
});
});
</script>
</body>
Expand Down

0 comments on commit 8a5c1e9

Please sign in to comment.