UNPKG

@polymer/polymer

Version:

The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to

97 lines (90 loc) 3.33 kB
/** @license Copyright (c) 2019 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */ 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. * This can happen in noPatch mode or when specialized APIs like ranges or tables are used to mutate DOM. * * @param {!Element} container Container element to scope * @param {boolean=} shouldObserve if true, start a mutation observer for added nodes to the container * @return {?MutationObserver} Returns a new MutationObserver on `container` if `shouldObserve` is true. */ export function scopeSubtree(container, shouldObserve = false) { // If using native ShadowDOM, abort if (!ShadyDOM || !ShadyCSS) { return null; } // ShadyCSS handles DOM mutations when ShadyDOM does not handle scoping itself if (!ShadyDOM['handlesDynamicScoping']) { return null; } const ScopingShim = ShadyCSS['ScopingShim']; // if ScopingShim is not available, abort if (!ScopingShim) { return null; } // 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 !== '') { ScopingShim['unscopeNode'](el, currentScope); } ScopingShim['scopeNode'](el, containerScope); } } }; // scope everything in container scopify(container); if (shouldObserve) { const mo = new MutationObserver((mxns) => { for (let i = 0; i < mxns.length; i++) { const mxn = mxns[i]; for (let j = 0; j < mxn.addedNodes.length; j++) { const addedNode = mxn.addedNodes[j]; if (addedNode.nodeType === Node.ELEMENT_NODE) { scopify(addedNode); } } } }); mo.observe(container, {childList: true, subtree: true}); return mo; } else { return null; } }