diff --git a/.devcontainer.json b/.devcontainer.json new file mode 100644 index 0000000..3c90ed8 --- /dev/null +++ b/.devcontainer.json @@ -0,0 +1,42 @@ +{ + "name": "Swiss Army Knife Development", + + // Open the sub-folder with the source code + "workspaceFolder": "/workspaces/swiss-army-knife-card", + +// See https://aka.ms/vscode-remote/devcontainer.json for format details. + "remoteUser": "vscode", + "appPort": ["6000:6000", "9123:8123"], +// "postCreateCommand": "yarn install && sudo container install", +// "runArgs": ["-v", "${localWorkspaceFolder}/.devcontainer/www:/config/www"], + "customizations/vscode/extensions": [ + "github.vscode-pull-request-github", + "eamodio.gitlens", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "bierner.lit-html", + "runem.lit-plugin", + "davidanson.vscode-markdownlint", + "redhat.vscode-yaml", + "msjsdiag.debugger-for-chrome", + "yzhang.markdown-all-in-one" + ], + "customizations/vscode/settings": { + "files.eol": "\n", + "editor.tabSize": 2, + "terminal.integrated.shell.linux": "/bin/bash", + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "files.trimTrailingWhitespace": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "markdown.extension.toc.githubCompatibility": true, + "files.watcherExclude": { + "**/.git/objects/**": true, + "**/.git/subtree-cache/**": true, + "**/node_modules/**": true, + "**/.hg/store/**": true, + "**/.rpt2_cache/**": true + } + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..e952eaf --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,42 @@ +{ + "name": "Swiss Army Knife Development", + + // Open the sub-folder with the source code + "workspaceFolder": "/workspaces/swiss-army-knife-card", + +// See https://aka.ms/vscode-remote/devcontainer.json for format details. + "remoteUser": "vscode", + "appPort": ["5000:5000", "9123:8123"], +// "postCreateCommand": "yarn install && sudo container install", +// "runArgs": ["-v", "${localWorkspaceFolder}/.devcontainer/www:/config/www"], + "customizations/vscode/extensions": [ + "github.vscode-pull-request-github", + "eamodio.gitlens", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "bierner.lit-html", + "runem.lit-plugin", + "davidanson.vscode-markdownlint", + "redhat.vscode-yaml", + "msjsdiag.debugger-for-chrome", + "yzhang.markdown-all-in-one" + ], + "customizations/vscode/settings": { + "files.eol": "\n", + "editor.tabSize": 2, + "terminal.integrated.shell.linux": "/bin/bash", + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "files.trimTrailingWhitespace": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "markdown.extension.toc.githubCompatibility": true, + "files.watcherExclude": { + "**/.git/objects/**": true, + "**/.git/subtree-cache/**": true, + "**/node_modules/**": true, + "**/.hg/store/**": true, + "**/.rpt2_cache/**": true + } + } +} diff --git a/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 0000000..50446ae --- /dev/null +++ b/.eslintrc.yaml @@ -0,0 +1,99 @@ +extends: airbnb-base +parserOptions: + ecmaVersion: 2022 + sourceType: module +ignorePatterns: + - /distjs/* + - /dist/* + - /src/swiss-army-knife-card.js +rules: + no-else-return: 0 + no-underscore-dangle: 0 + nonblock-statement-body-position: 0 + # curly checks for all {} after if for instance + curly: 0 + no-return-assign: 0 + consistent-return: 0 + no-mixed-operators: 0 + class-methods-use-this: 0 + no-nested-ternary: 0 + camelcase: 0 + # Added for convenience to check eslint... + # Settings handled: + no-param-reassign: 0 + max-len: + - warn + - code: 220 + ignoreComments: true + eqeqeq: 1 + brace-style: 1 + # - Prevent warnings in logging and multiple params on one line + function-call-argument-newline: 0 + function-paren-newline: 0 + # - Allow i++ / i-- in for loops + no-plusplus: + - warn + - allowForLoopAfterthoughts: true + no-irregular-whitespace: 0 + no-bitwise: + - warn + - allow: + - "~" + # - Disable .js import warnings + import/extensions: 0 + # - Allow the use of console.() + no-console: 0 + # - Allow for calling .hasOwnProperty for instance directly + no-prototype-builtins: 0 + # - Allow as-needed function names + func-names: + - warn + - as-needed + # - Just let me index arrays and get data from them + prefer-destructuring: 0 + # - For now, keep using things like isNaN() as Number.isNan() is incompatible. + # Ignore the eslint advice to replace them. As a result everything crashes... + no-restricted-globals: 0 + # Ignore identiation for now + indent: 0 + no-unreachable: 0 + # THINGS THAT MUST BE HANDLED LATER... + # - This is a thing from the segmented-arc, the only file with errors/warnings! + # - Status as of 2023.05.06 13:00 + block-scoped-var: 0 + vars-on-top: 0 + no-var: 0 + no-redeclare: 0 + no-setter-return: 0 + no-multi-assign: 0 + no-empty: 0 + no-unused-vars: 0 + prefer-const: 0 + no-lonely-if: 0 + no-shadow: 0 + no-loop-func: 0 + # Settings handled and NOT occuring anymore! + no-undef: 2 + no-use-before-define: 1 + no-case-declarations: 1 + no-inner-declarations: 1 + array-callback-return: 1 + max-classes-per-file: 1 + no-new-func: 1 + no-constant-condition: 1 + default-case: 1 + default-case-last: 1 + operator-assignment: 1 + no-sequences: 1 + no-restricted-syntax: 1 + no-unused-expressions: 1 + no-useless-escape: 1 + import/no-unresolved: 1 + no-template-curly-in-string: 1 + # Settings disabled for now, until handled + +globals: + browser: true + window: true + Event: true + customElements: true diff --git a/.gitignore b/.gitignore index 12cd4a4..1f49730 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ swiss-army-knife-card.js-from-src swiss-army-knife-card.js-from-src2 2022.07.16 swiss-army-knife-card.js 2022.07.16 swiss-army-knife-card.js +node_modules +*.js.map + + diff --git a/dist/swiss-army-knife-card-bundle.js b/dist/swiss-army-knife-card-bundle.js new file mode 100644 index 0000000..3728130 --- /dev/null +++ b/dist/swiss-army-knife-card-bundle.js @@ -0,0 +1,11576 @@ +/** + * @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 + */ +/** + * True if the custom elements polyfill is in use. + */ +const isCEPolyfill = typeof window !== 'undefined' && + window.customElements != null && + window.customElements.polyfillWrapFlushCallback !== + undefined; +/** + * Reparents nodes, starting from `start` (inclusive) to `end` (exclusive), + * into another container (could be the same container), before `before`. If + * `before` is null, it appends the nodes to the container. + */ +const reparentNodes = (container, start, end = null, before = null) => { + while (start !== end) { + const n = start.nextSibling; + container.insertBefore(start, before); + start = n; + } +}; +/** + * Removes nodes, starting from `start` (inclusive) to `end` (exclusive), from + * `container`. + */ +const removeNodes = (container, start, end = null) => { + while (start !== end) { + const n = start.nextSibling; + container.removeChild(start); + start = n; + } +}; + +/** + * @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 + */ +/** + * An expression marker with embedded unique key to avoid collision with + * possible text in templates. + */ +const marker = `{{lit-${String(Math.random()).slice(2)}}}`; +/** + * An expression marker used text-positions, multi-binding attributes, and + * attributes with markup-like text values. + */ +const nodeMarker = ``; +const markerRegex = new RegExp(`${marker}|${nodeMarker}`); +/** + * Suffix appended to all bound attribute names. + */ +const boundAttributeSuffix = '$lit$'; +/** + * An updatable Template that tracks the location of dynamic parts. + */ +class Template { + constructor(result, element) { + this.parts = []; + this.element = element; + const nodesToRemove = []; + const stack = []; + // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null + const walker = document.createTreeWalker(element.content, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false); + // Keeps track of the last index associated with a part. We try to delete + // unnecessary nodes, but we never want to associate two different parts + // to the same index. They must have a constant node between. + let lastPartIndex = 0; + let index = -1; + let partIndex = 0; + const { strings, values: { length } } = result; + while (partIndex < length) { + const node = walker.nextNode(); + if (node === null) { + // We've exhausted the content inside a nested template element. + // Because we still have parts (the outer for-loop), we know: + // - There is a template in the stack + // - The walker will find a nextNode outside the template + walker.currentNode = stack.pop(); + continue; + } + index++; + if (node.nodeType === 1 /* Node.ELEMENT_NODE */) { + if (node.hasAttributes()) { + const attributes = node.attributes; + const { length } = attributes; + // Per + // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap, + // attributes are not guaranteed to be returned in document order. + // In particular, Edge/IE can return them out of order, so we cannot + // assume a correspondence between part index and attribute index. + let count = 0; + for (let i = 0; i < length; i++) { + if (endsWith(attributes[i].name, boundAttributeSuffix)) { + count++; + } + } + while (count-- > 0) { + // Get the template literal section leading up to the first + // expression in this attribute + const stringForPart = strings[partIndex]; + // Find the attribute name + const name = lastAttributeNameRegex.exec(stringForPart)[2]; + // Find the corresponding attribute + // All bound attributes have had a suffix added in + // TemplateResult#getHTML to opt out of special attribute + // handling. To look up the attribute value we also need to add + // the suffix. + const attributeLookupName = name.toLowerCase() + boundAttributeSuffix; + const attributeValue = node.getAttribute(attributeLookupName); + node.removeAttribute(attributeLookupName); + const statics = attributeValue.split(markerRegex); + this.parts.push({ type: 'attribute', index, name, strings: statics }); + partIndex += statics.length - 1; + } + } + if (node.tagName === 'TEMPLATE') { + stack.push(node); + walker.currentNode = node.content; + } + } + else if (node.nodeType === 3 /* Node.TEXT_NODE */) { + const data = node.data; + if (data.indexOf(marker) >= 0) { + const parent = node.parentNode; + const strings = data.split(markerRegex); + const lastIndex = strings.length - 1; + // Generate a new text node for each literal section + // These nodes are also used as the markers for node parts + for (let i = 0; i < lastIndex; i++) { + let insert; + let s = strings[i]; + if (s === '') { + insert = createMarker(); + } + else { + const match = lastAttributeNameRegex.exec(s); + if (match !== null && endsWith(match[2], boundAttributeSuffix)) { + s = s.slice(0, match.index) + match[1] + + match[2].slice(0, -boundAttributeSuffix.length) + match[3]; + } + insert = document.createTextNode(s); + } + parent.insertBefore(insert, node); + this.parts.push({ type: 'node', index: ++index }); + } + // If there's no text, we must insert a comment to mark our place. + // Else, we can trust it will stick around after cloning. + if (strings[lastIndex] === '') { + parent.insertBefore(createMarker(), node); + nodesToRemove.push(node); + } + else { + node.data = strings[lastIndex]; + } + // We have a part for each match found + partIndex += lastIndex; + } + } + else if (node.nodeType === 8 /* Node.COMMENT_NODE */) { + if (node.data === marker) { + const parent = node.parentNode; + // Add a new marker node to be the startNode of the Part if any of + // the following are true: + // * We don't have a previousSibling + // * The previousSibling is already the start of a previous part + if (node.previousSibling === null || index === lastPartIndex) { + index++; + parent.insertBefore(createMarker(), node); + } + lastPartIndex = index; + this.parts.push({ type: 'node', index }); + // If we don't have a nextSibling, keep this node so we have an end. + // Else, we can remove it to save future costs. + if (node.nextSibling === null) { + node.data = ''; + } + else { + nodesToRemove.push(node); + index--; + } + partIndex++; + } + else { + let i = -1; + while ((i = node.data.indexOf(marker, i + 1)) !== -1) { + // Comment node has a binding marker inside, make an inactive part + // The binding won't work, but subsequent bindings will + // TODO (justinfagnani): consider whether it's even worth it to + // make bindings in comments work + this.parts.push({ type: 'node', index: -1 }); + partIndex++; + } + } + } + } + // Remove text binding nodes after the walk to not disturb the TreeWalker + for (const n of nodesToRemove) { + n.parentNode.removeChild(n); + } + } +} +const endsWith = (str, suffix) => { + const index = str.length - suffix.length; + return index >= 0 && str.slice(index) === suffix; +}; +const isTemplatePartActive = (part) => part.index !== -1; +// Allows `document.createComment('')` to be renamed for a +// small manual size-savings. +const createMarker = () => document.createComment(''); +/** + * This regex extracts the attribute name preceding an attribute-position + * expression. It does this by matching the syntax allowed for attributes + * against the string literal directly preceding the expression, assuming that + * the expression is in an attribute-value position. + * + * See attributes in the HTML spec: + * https://www.w3.org/TR/html5/syntax.html#elements-attributes + * + * " \x09\x0a\x0c\x0d" are HTML space characters: + * https://www.w3.org/TR/html5/infrastructure.html#space-characters + * + * "\0-\x1F\x7F-\x9F" are Unicode control characters, which includes every + * space character except " ". + * + * So an attribute is: + * * The name: any character except a control character, space character, ('), + * ("), ">", "=", or "/" + * * Followed by zero or more space characters + * * Followed by "=" + * * Followed by zero or more space characters + * * Followed by: + * * Any character except space, ('), ("), "<", ">", "=", (`), or + * * (") then any non-("), or + * * (') then any non-(') + */ +const lastAttributeNameRegex = +// eslint-disable-next-line no-control-regex +/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/; + +/** + * @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 + */ +const walkerNodeFilter = 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */; +/** + * Removes the list of nodes from a Template safely. In addition to removing + * nodes from the Template, the Template part indices are updated to match + * the mutated Template DOM. + * + * As the template is walked the removal state is tracked and + * part indices are adjusted as needed. + * + * div + * div#1 (remove) <-- start removing (removing node is div#1) + * div + * div#2 (remove) <-- continue removing (removing node is still div#1) + * div + * div <-- stop removing since previous sibling is the removing node (div#1, + * removed 4 nodes) + */ +function removeNodesFromTemplate(template, nodesToRemove) { + const { element: { content }, parts } = template; + const walker = document.createTreeWalker(content, walkerNodeFilter, null, false); + let partIndex = nextActiveIndexInTemplateParts(parts); + let part = parts[partIndex]; + let nodeIndex = -1; + let removeCount = 0; + const nodesToRemoveInTemplate = []; + let currentRemovingNode = null; + while (walker.nextNode()) { + nodeIndex++; + const node = walker.currentNode; + // End removal if stepped past the removing node + if (node.previousSibling === currentRemovingNode) { + currentRemovingNode = null; + } + // A node to remove was found in the template + if (nodesToRemove.has(node)) { + nodesToRemoveInTemplate.push(node); + // Track node we're removing + if (currentRemovingNode === null) { + currentRemovingNode = node; + } + } + // When removing, increment count by which to adjust subsequent part indices + if (currentRemovingNode !== null) { + removeCount++; + } + while (part !== undefined && part.index === nodeIndex) { + // If part is in a removed node deactivate it by setting index to -1 or + // adjust the index as needed. + part.index = currentRemovingNode !== null ? -1 : part.index - removeCount; + // go to the next active part. + partIndex = nextActiveIndexInTemplateParts(parts, partIndex); + part = parts[partIndex]; + } + } + nodesToRemoveInTemplate.forEach((n) => n.parentNode.removeChild(n)); +} +const countNodes = (node) => { + let count = (node.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */) ? 0 : 1; + const walker = document.createTreeWalker(node, walkerNodeFilter, null, false); + while (walker.nextNode()) { + count++; + } + return count; +}; +const nextActiveIndexInTemplateParts = (parts, startIndex = -1) => { + for (let i = startIndex + 1; i < parts.length; i++) { + const part = parts[i]; + if (isTemplatePartActive(part)) { + return i; + } + } + return -1; +}; +/** + * Inserts the given node into the Template, optionally before the given + * refNode. In addition to inserting the node into the Template, the Template + * part indices are updated to match the mutated Template DOM. + */ +function insertNodeIntoTemplate(template, node, refNode = null) { + const { element: { content }, parts } = template; + // If there's no refNode, then put node at end of template. + // No part indices need to be shifted in this case. + if (refNode === null || refNode === undefined) { + content.appendChild(node); + return; + } + const walker = document.createTreeWalker(content, walkerNodeFilter, null, false); + let partIndex = nextActiveIndexInTemplateParts(parts); + let insertCount = 0; + let walkerIndex = -1; + while (walker.nextNode()) { + walkerIndex++; + const walkerNode = walker.currentNode; + if (walkerNode === refNode) { + insertCount = countNodes(node); + refNode.parentNode.insertBefore(node, refNode); + } + while (partIndex !== -1 && parts[partIndex].index === walkerIndex) { + // If we've inserted the node, simply adjust all subsequent parts + if (insertCount > 0) { + while (partIndex !== -1) { + parts[partIndex].index += insertCount; + partIndex = nextActiveIndexInTemplateParts(parts, partIndex); + } + return; + } + partIndex = nextActiveIndexInTemplateParts(parts, partIndex); + } + } +} + +/** + * @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 + */ +const directives = new WeakMap(); +/** + * Brands a function as a directive factory function so that lit-html will call + * the function during template rendering, rather than passing as a value. + * + * A _directive_ is a function that takes a Part as an argument. It has the + * signature: `(part: Part) => void`. + * + * A directive _factory_ is a function that takes arguments for data and + * configuration and returns a directive. Users of directive usually refer to + * the directive factory as the directive. For example, "The repeat directive". + * + * Usually a template author will invoke a directive factory in their template + * with relevant arguments, which will then return a directive function. + * + * Here's an example of using the `repeat()` directive factory that takes an + * array and a function to render an item: + * + * ```js + * html`` + * ``` + * + * When `repeat` is invoked, it returns a directive function that closes over + * `items` and the template function. When the outer template is rendered, the + * return directive function is called with the Part for the expression. + * `repeat` then performs it's custom logic to render multiple items. + * + * @param f The directive factory function. Must be a function that returns a + * function of the signature `(part: Part) => void`. The returned function will + * be called with the part object. + * + * @example + * + * import {directive, html} from 'lit-html'; + * + * const immutable = directive((v) => (part) => { + * if (part.value !== v) { + * part.setValue(v) + * } + * }); + */ +const directive = (f) => ((...args) => { + const d = f(...args); + directives.set(d, true); + return d; +}); +const isDirective = (o) => { + return typeof o === 'function' && directives.has(o); +}; + +/** + * @license + * Copyright (c) 2018 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 + */ +/** + * A sentinel value that signals that a value was handled by a directive and + * should not be written to the DOM. + */ +const noChange = {}; +/** + * A sentinel value that signals a NodePart to fully clear its content. + */ +const nothing = {}; + +/** + * @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 + */ +/** + * An instance of a `Template` that can be attached to the DOM and updated + * with new values. + */ +class TemplateInstance { + constructor(template, processor, options) { + this.__parts = []; + this.template = template; + this.processor = processor; + this.options = options; + } + 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() { + // There are a number of steps in the lifecycle of a template instance's + // DOM fragment: + // 1. Clone - create the instance fragment + // 2. Adopt - adopt into the main document + // 3. Process - find part markers and create parts + // 4. Upgrade - upgrade custom elements + // 5. Update - set node, attribute, property, etc., values + // 6. Connect - connect to the document. Optional and outside of this + // method. + // + // We have a few constraints on the ordering of these steps: + // * We need to upgrade before updating, so that property values will pass + // through any property setters. + // * We would like to process before upgrading so that we're sure that the + // cloned fragment is inert and not disturbed by self-modifying DOM. + // * We want custom elements to upgrade even in disconnected fragments. + // + // Given these constraints, with full custom elements support we would + // prefer the order: Clone, Process, Adopt, Upgrade, Update, Connect + // + // But Safari does not implement CustomElementRegistry#upgrade, so we + // can not implement that order and still have upgrade-before-update and + // upgrade disconnected fragments. So we instead sacrifice the + // process-before-upgrade constraint, since in Custom Elements v1 elements + // must not modify their light DOM in the constructor. We still have issues + // when co-existing with CEv0 elements like Polymer 1, and with polyfills + // that don't strictly adhere to the no-modification rule because shadow + // DOM, which may be created in the constructor, is emulated by being placed + // in the light DOM. + // + // The resulting order is on native is: Clone, Adopt, Upgrade, Process, + // Update, Connect. document.importNode() performs Clone, Adopt, and Upgrade + // in one step. + // + // The Custom Elements v1 polyfill supports upgrade(), so the order when + // polyfilled is the more ideal: Clone, Process, Adopt, Upgrade, Update, + // Connect. + const fragment = isCEPolyfill ? + this.template.element.content.cloneNode(true) : + document.importNode(this.template.element.content, true); + const stack = []; + const parts = this.template.parts; + // 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 partIndex = 0; + let nodeIndex = 0; + let part; + let node = walker.nextNode(); + // Loop through all the nodes and parts of a template + while (partIndex < parts.length) { + part = parts[partIndex]; + if (!isTemplatePartActive(part)) { + this.__parts.push(undefined); + partIndex++; + continue; + } + // Progress the tree walker until we find our next part's node. + // Note that multiple parts may share the same node (attribute parts + // on a single element), so this loop may not run at all. + while (nodeIndex < part.index) { + nodeIndex++; + if (node.nodeName === 'TEMPLATE') { + stack.push(node); + walker.currentNode = node.content; + } + if ((node = walker.nextNode()) === null) { + // We've exhausted the content inside a nested template element. + // Because we still have parts (the outer for-loop), we know: + // - There is a template in the stack + // - The walker will find a nextNode outside the template + walker.currentNode = stack.pop(); + node = walker.nextNode(); + } + } + // We've arrived at our part's node. + if (part.type === 'node') { + const part = this.processor.handleTextExpression(this.options); + part.insertAfterNode(node.previousSibling); + this.__parts.push(part); + } + else { + this.__parts.push(...this.processor.handleAttributeExpressions(node, part.name, part.strings, this.options)); + } + partIndex++; + } + if (isCEPolyfill) { + document.adoptNode(fragment); + customElements.upgrade(fragment); + } + return fragment; + } +} + +/** + * @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 + */ +/** + * Our TrustedTypePolicy for HTML which is declared using the html template + * tag function. + * + * That HTML is a developer-authored constant, and is parsed with innerHTML + * before any untrusted expressions have been mixed in. Therefor it is + * considered safe by construction. + */ +const policy = window.trustedTypes && + trustedTypes.createPolicy('lit-html', { createHTML: (s) => s }); +const commentMarker = ` ${marker} `; +/** + * The return type of `html`, which holds a Template and the values from + * interpolated expressions. + */ +class TemplateResult { + constructor(strings, values, type, processor) { + this.strings = strings; + this.values = values; + this.type = type; + this.processor = processor; + } + /** + * Returns a string of HTML used to create a `