/** * @license * Copyright (c) 2017 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 */ /** * Module to add shady DOM/shady CSS polyfill support to lit-html template * rendering. See the [[render]] method for details. * * @module shady-render * @preferred */ /** * Do not remove this comment; it keeps typedoc from misplacing the module * docs. */ import { removeNodes } from './dom.js'; import { insertNodeIntoTemplate, removeNodesFromTemplate } from './modify-template.js'; import { parts, render as litRender } from './render.js'; import { templateCaches } from './template-factory.js'; import { TemplateInstance } from './template-instance.js'; import { marker, Template } from './template.js'; export { html, svg, TemplateResult } from '../lit-html.js'; // Get a key to lookup in `templateCaches`. const getTemplateCacheKey = (type, scopeName) => `${type}--${scopeName}`; let compatibleShadyCSSVersion = true; if (typeof window.ShadyCSS === 'undefined') { compatibleShadyCSSVersion = false; } else if (typeof window.ShadyCSS.prepareTemplateDom === 'undefined') { console.warn(`Incompatible ShadyCSS version detected. ` + `Please update to at least @webcomponents/webcomponentsjs@2.0.2 and ` + `@webcomponents/shadycss@1.3.1.`); compatibleShadyCSSVersion = false; } /** * Template factory which scopes template DOM using ShadyCSS. * @param scopeName {string} */ const shadyTemplateFactory = (scopeName) => (result) => { const cacheKey = getTemplateCacheKey(result.type, scopeName); let templateCache = templateCaches.get(cacheKey); if (templateCache === undefined) { templateCache = { stringsArray: new WeakMap(), keyString: new Map() }; templateCaches.set(cacheKey, templateCache); } let template = templateCache.stringsArray.get(result.strings); if (template !== undefined) { return template; } const key = result.strings.join(marker); template = templateCache.keyString.get(key); if (template === undefined) { const element = result.getTemplateElement(); if (compatibleShadyCSSVersion) { window.ShadyCSS.prepareTemplateDom(element, scopeName); } template = new Template(result, element); templateCache.keyString.set(key, template); } templateCache.stringsArray.set(result.strings, template); return template; }; const TEMPLATE_TYPES = ['html', 'svg']; /** * Removes all style elements from Templates for the given scopeName. */ const removeStylesFromLitTemplates = (scopeName) => { TEMPLATE_TYPES.forEach((type) => { const templates = templateCaches.get(getTemplateCacheKey(type, scopeName)); if (templates !== undefined) { templates.keyString.forEach((template) => { const { element: { content } } = template; // IE 11 doesn't support the iterable param Set constructor const styles = new Set(); Array.from(content.querySelectorAll('style')).forEach((s) => { styles.add(s); }); removeNodesFromTemplate(template, styles); }); } }); }; const shadyRenderSet = new Set(); /** * For the given scope name, ensures that ShadyCSS style scoping is performed. * This is done just once per scope name so the fragment and template cannot * be modified. * (1) extracts styles from the rendered fragment and hands them to ShadyCSS * to be scoped and appended to the document * (2) removes style elements from all lit-html Templates for this scope name. * * Note,