UNPKG

lit-html

Version:

HTML template literals in JavaScript

95 lines 4 kB
/** * @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 */ import { isCEPolyfill } from './dom.js'; import { isTemplatePartActive } from './template.js'; /** * An instance of a `Template` that can be attached to the DOM and updated * with new values. */ export class TemplateInstance { constructor(template, processor, getTemplate) { this._parts = []; this.template = template; this.processor = processor; this._getTemplate = getTemplate; } update(values) { let i = 0; for (const part of this._parts) { if (part !== undefined) { part.setValue(values[i]); } i++; } for (const part of this._parts) { if (part !== undefined) { part.commit(); } } } _clone() { // When using the Custom Elements polyfill, clone the node, rather than // importing it, to keep the fragment in the template's document. This // leaves the fragment inert so custom elements won't upgrade and // potentially modify their contents by creating a polyfilled ShadowRoot // while we traverse the tree. const fragment = isCEPolyfill ? this.template.element.content.cloneNode(true) : document.importNode(this.template.element.content, true); const parts = this.template.parts; let partIndex = 0; let nodeIndex = 0; const _prepareInstance = (fragment) => { // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be // null const walker = document.createTreeWalker(fragment, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false); let node = walker.nextNode(); // Loop through all the nodes and parts of a template while (partIndex < parts.length && node !== null) { const part = parts[partIndex]; // Consecutive Parts may have the same node index, in the case of // multiple bound attributes on an element. So each iteration we either // increment the nodeIndex, if we aren't on a node with a part, or the // partIndex if we are. By not incrementing the nodeIndex when we find a // part, we allow for the next part to be associated with the current // node if neccessasry. if (!isTemplatePartActive(part)) { this._parts.push(undefined); partIndex++; } else if (nodeIndex === part.index) { if (part.type === 'node') { const part = this.processor.handleTextExpression(this._getTemplate); part.insertAfterNode(node); this._parts.push(part); } else { this._parts.push(...this.processor.handleAttributeExpressions(node, part.name, part.strings)); } partIndex++; } else { nodeIndex++; if (node.nodeName === 'TEMPLATE') { _prepareInstance(node.content); } node = walker.nextNode(); } } }; _prepareInstance(fragment); return fragment; } } //# sourceMappingURL=template-instance.js.map