@suyouwanggang/p-ui
Version:
`p-ui`是一套使用原生`Web Components`规范开发的跨框架UI组件库,基于`lit-elment`库开发。 [github项目地址](https://github.com/suyouwanggang/p-ui)
1,530 lines (1,307 loc) • 462 kB
JavaScript
import _classCallCheck from '@babel/runtime/helpers/classCallCheck';
import _createClass from '@babel/runtime/helpers/createClass';
import _possibleConstructorReturn from '@babel/runtime/helpers/possibleConstructorReturn';
import _getPrototypeOf from '@babel/runtime/helpers/getPrototypeOf';
import _get from '@babel/runtime/helpers/get';
import _inherits from '@babel/runtime/helpers/inherits';
import _typeof from '@babel/runtime/helpers/typeof';
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import _regeneratorRuntime from '@babel/runtime/regenerator';
import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator';
import _wrapNativeSuper from '@babel/runtime/helpers/wrapNativeSuper';
/**
* @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.
*/
var 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.
*/
var reparentNodes = function reparentNodes(container, start) {
var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var before = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
while (start !== end) {
var n = start.nextSibling;
container.insertBefore(start, before);
start = n;
}
};
/**
* Removes nodes, starting from `start` (inclusive) to `end` (exclusive), from
* `container`.
*/
var removeNodes = function removeNodes(container, start) {
var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
while (start !== end) {
var 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.
*/
var marker = "{{lit-".concat(String(Math.random()).slice(2), "}}");
/**
* An expression marker used text-positions, multi-binding attributes, and
* attributes with markup-like text values.
*/
var nodeMarker = "<!--".concat(marker, "-->");
var markerRegex = new RegExp("".concat(marker, "|").concat(nodeMarker));
/**
* Suffix appended to all bound attribute names.
*/
var boundAttributeSuffix = '$lit$';
/**
* An updatable Template that tracks the location of dynamic parts.
*/
var Template = function Template(result, element) {
_classCallCheck(this, Template);
this.parts = [];
this.element = element;
var nodesToRemove = [];
var stack = []; // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null
var 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.
var lastPartIndex = 0;
var index = -1;
var partIndex = 0;
var strings = result.strings,
length = result.values.length;
while (partIndex < length) {
var 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()) {
var attributes = node.attributes;
var _length = attributes.length; // 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.
var count = 0;
for (var 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
var stringForPart = strings[partIndex]; // Find the attribute name
var 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.
var attributeLookupName = name.toLowerCase() + boundAttributeSuffix;
var attributeValue = node.getAttribute(attributeLookupName);
node.removeAttribute(attributeLookupName);
var statics = attributeValue.split(markerRegex);
this.parts.push({
type: 'attribute',
index: index,
name: 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 */
) {
var data = node.data;
if (data.indexOf(marker) >= 0) {
var parent = node.parentNode;
var _strings = data.split(markerRegex);
var 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 (var _i = 0; _i < lastIndex; _i++) {
var insert = void 0;
var s = _strings[_i];
if (s === '') {
insert = createMarker();
} else {
var 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) {
var _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: 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 {
var _i2 = -1;
while ((_i2 = node.data.indexOf(marker, _i2 + 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 (var _i3 = 0, _nodesToRemove = nodesToRemove; _i3 < _nodesToRemove.length; _i3++) {
var n = _nodesToRemove[_i3];
n.parentNode.removeChild(n);
}
};
var endsWith = function endsWith(str, suffix) {
var index = str.length - suffix.length;
return index >= 0 && str.slice(index) === suffix;
};
var isTemplatePartActive = function isTemplatePartActive(part) {
return part.index !== -1;
}; // Allows `document.createComment('')` to be renamed for a
// small manual size-savings.
var createMarker = function createMarker() {
return 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-(')
*/
var 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
*/
var 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) {
var content = template.element.content,
parts = template.parts;
var walker = document.createTreeWalker(content, walkerNodeFilter, null, false);
var partIndex = nextActiveIndexInTemplateParts(parts);
var part = parts[partIndex];
var nodeIndex = -1;
var removeCount = 0;
var nodesToRemoveInTemplate = [];
var currentRemovingNode = null;
while (walker.nextNode()) {
nodeIndex++;
var 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(function (n) {
return n.parentNode.removeChild(n);
});
}
var countNodes = function countNodes(node) {
var count = node.nodeType === 11
/* Node.DOCUMENT_FRAGMENT_NODE */
? 0 : 1;
var walker = document.createTreeWalker(node, walkerNodeFilter, null, false);
while (walker.nextNode()) {
count++;
}
return count;
};
var nextActiveIndexInTemplateParts = function nextActiveIndexInTemplateParts(parts) {
var startIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1;
for (var i = startIndex + 1; i < parts.length; i++) {
var 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) {
var refNode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var content = template.element.content,
parts = template.parts; // 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;
}
var walker = document.createTreeWalker(content, walkerNodeFilter, null, false);
var partIndex = nextActiveIndexInTemplateParts(parts);
var insertCount = 0;
var walkerIndex = -1;
while (walker.nextNode()) {
walkerIndex++;
var 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
*/
var directives = new WeakMap();
var isDirective = function 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.
*/
var noChange = {};
/**
* A sentinel value that signals a NodePart to fully clear its content.
*/
var nothing = {};
/**
* An instance of a `Template` that can be attached to the DOM and updated
* with new values.
*/
var TemplateInstance =
/*#__PURE__*/
function () {
function TemplateInstance(template, processor, options) {
_classCallCheck(this, TemplateInstance);
this.__parts = [];
this.template = template;
this.processor = processor;
this.options = options;
}
_createClass(TemplateInstance, [{
key: "update",
value: function update(values) {
var i = 0;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = this.__parts[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var part = _step.value;
if (part !== undefined) {
part.setValue(values[i]);
}
i++;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = this.__parts[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _part = _step2.value;
if (_part !== undefined) {
_part.commit();
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
}, {
key: "_clone",
value: function _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.
var fragment = isCEPolyfill ? this.template.element.content.cloneNode(true) : document.importNode(this.template.element.content, true);
var stack = [];
var parts = this.template.parts; // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null
var walker = document.createTreeWalker(fragment, 133
/* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */
, null, false);
var partIndex = 0;
var nodeIndex = 0;
var part;
var 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') {
var _part2 = this.processor.handleTextExpression(this.options);
_part2.insertAfterNode(node.previousSibling);
this.__parts.push(_part2);
} else {
var _this$__parts;
(_this$__parts = this.__parts).push.apply(_this$__parts, _toConsumableArray(this.processor.handleAttributeExpressions(node, part.name, part.strings, this.options)));
}
partIndex++;
}
if (isCEPolyfill) {
document.adoptNode(fragment);
customElements.upgrade(fragment);
}
return fragment;
}
}]);
return TemplateInstance;
}();
/**
* 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.
*/
var policy = window.trustedTypes && trustedTypes.createPolicy('lit-html', {
createHTML: function createHTML(s) {
return s;
}
});
var commentMarker = " ".concat(marker, " ");
/**
* The return type of `html`, which holds a Template and the values from
* interpolated expressions.
*/
var TemplateResult =
/*#__PURE__*/
function () {
function TemplateResult(strings, values, type, processor) {
_classCallCheck(this, TemplateResult);
this.strings = strings;
this.values = values;
this.type = type;
this.processor = processor;
}
/**
* Returns a string of HTML used to create a `<template>` element.
*/
_createClass(TemplateResult, [{
key: "getHTML",
value: function getHTML() {
var l = this.strings.length - 1;
var html = '';
var isCommentBinding = false;
for (var i = 0; i < l; i++) {
var s = this.strings[i]; // For each binding we want to determine the kind of marker to insert
// into the template source before it's parsed by the browser's HTML
// parser. The marker type is based on whether the expression is in an
// attribute, text, or comment position.
// * For node-position bindings we insert a comment with the marker
// sentinel as its text content, like <!--{{lit-guid}}-->.
// * For attribute bindings we insert just the marker sentinel for the
// first binding, so that we support unquoted attribute bindings.
// Subsequent bindings can use a comment marker because multi-binding
// attributes must be quoted.
// * For comment bindings we insert just the marker sentinel so we don't
// close the comment.
//
// The following code scans the template source, but is *not* an HTML
// parser. We don't need to track the tree structure of the HTML, only
// whether a binding is inside a comment, and if not, if it appears to be
// the first binding in an attribute.
var commentOpen = s.lastIndexOf('<!--'); // We're in comment position if we have a comment open with no following
// comment close. Because <-- can appear in an attribute value there can
// be false positives.
isCommentBinding = (commentOpen > -1 || isCommentBinding) && s.indexOf('-->', commentOpen + 1) === -1; // Check to see if we have an attribute-like sequence preceding the
// expression. This can match "name=value" like structures in text,
// comments, and attribute values, so there can be false-positives.
var attributeMatch = lastAttributeNameRegex.exec(s);
if (attributeMatch === null) {
// We're only in this branch if we don't have a attribute-like
// preceding sequence. For comments, this guards against unusual
// attribute values like <div foo="<!--${'bar'}">. Cases like
// <!-- foo=${'bar'}--> are handled correctly in the attribute branch
// below.
html += s + (isCommentBinding ? commentMarker : nodeMarker);
} else {
// For attributes we use just a marker sentinel, and also append a
// $lit$ suffix to the name to opt-out of attribute-specific parsing
// that IE and Edge do for style and certain SVG attributes.
html += s.substr(0, attributeMatch.index) + attributeMatch[1] + attributeMatch[2] + boundAttributeSuffix + attributeMatch[3] + marker;
}
}
html += this.strings[l];
return html;
}
}, {
key: "getTemplateElement",
value: function getTemplateElement() {
var template = document.createElement('template');
var value = this.getHTML();
if (policy !== undefined) {
// this is secure because `this.strings` is a TemplateStringsArray.
// TODO: validate this when
// https://github.com/tc39/proposal-array-is-template-object is
// implemented.
value = policy.createHTML(value);
}
template.innerHTML = value;
return template;
}
}]);
return TemplateResult;
}();
/**
* A TemplateResult for SVG fragments.
*
* This class wraps HTML in an `<svg>` tag in order to parse its contents in the
* SVG namespace, then modifies the template to remove the `<svg>` tag so that
* clones only container the original fragment.
*/
var SVGTemplateResult =
/*#__PURE__*/
function (_TemplateResult) {
_inherits(SVGTemplateResult, _TemplateResult);
function SVGTemplateResult() {
_classCallCheck(this, SVGTemplateResult);
return _possibleConstructorReturn(this, _getPrototypeOf(SVGTemplateResult).apply(this, arguments));
}
_createClass(SVGTemplateResult, [{
key: "getHTML",
value: function getHTML() {
return "<svg>".concat(_get(_getPrototypeOf(SVGTemplateResult.prototype), "getHTML", this).call(this), "</svg>");
}
}, {
key: "getTemplateElement",
value: function getTemplateElement() {
var template = _get(_getPrototypeOf(SVGTemplateResult.prototype), "getTemplateElement", this).call(this);
var content = template.content;
var svgElement = content.firstChild;
content.removeChild(svgElement);
reparentNodes(content, svgElement.firstChild);
return template;
}
}]);
return SVGTemplateResult;
}(TemplateResult);
var isPrimitive = function isPrimitive(value) {
return value === null || !(_typeof(value) === 'object' || typeof value === 'function');
};
var isIterable = function isIterable(value) {
return Array.isArray(value) || // eslint-disable-next-line @typescript-eslint/no-explicit-any
!!(value && value[Symbol.iterator]);
};
/**
* Writes attribute values to the DOM for a group of AttributeParts bound to a
* single attribute. The value is only set once even if there are multiple parts
* for an attribute.
*/
var AttributeCommitter =
/*#__PURE__*/
function () {
function AttributeCommitter(element, name, strings) {
_classCallCheck(this, AttributeCommitter);
this.dirty = true;
this.element = element;
this.name = name;
this.strings = strings;
this.parts = [];
for (var i = 0; i < strings.length - 1; i++) {
this.parts[i] = this._createPart();
}
}
/**
* Creates a single part. Override this to create a differnt type of part.
*/
_createClass(AttributeCommitter, [{
key: "_createPart",
value: function _createPart() {
return new AttributePart(this);
}
}, {
key: "_getValue",
value: function _getValue() {
var strings = this.strings;
var l = strings.length - 1;
var parts = this.parts; // If we're assigning an attribute via syntax like:
// attr="${foo}" or attr=${foo}
// but not
// attr="${foo} ${bar}" or attr="${foo} baz"
// then we don't want to coerce the attribute value into one long
// string. Instead we want to just return the value itself directly,
// so that sanitizeDOMValue can get the actual value rather than
// String(value)
// The exception is if v is an array, in which case we do want to smash
// it together into a string without calling String() on the array.
//
// This also allows trusted values (when using TrustedTypes) being
// assigned to DOM sinks without being stringified in the process.
if (l === 1 && strings[0] === '' && strings[1] === '') {
var v = parts[0].value;
if (_typeof(v) === 'symbol') {
return String(v);
}
if (typeof v === 'string' || !isIterable(v)) {
return v;
}
}
var text = '';
for (var i = 0; i < l; i++) {
text += strings[i];
var part = parts[i];
if (part !== undefined) {
var _v = part.value;
if (isPrimitive(_v) || !isIterable(_v)) {
text += typeof _v === 'string' ? _v : String(_v);
} else {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _v[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var t = _step.value;
text += typeof t === 'string' ? t : String(t);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}
}
text += strings[l];
return text;
}
}, {
key: "commit",
value: function commit() {
if (this.dirty) {
this.dirty = false;
this.element.setAttribute(this.name, this._getValue());
}
}
}]);
return AttributeCommitter;
}();
/**
* A Part that controls all or part of an attribute value.
*/
var AttributePart =
/*#__PURE__*/
function () {
function AttributePart(committer) {
_classCallCheck(this, AttributePart);
this.value = undefined;
this.committer = committer;
}
_createClass(AttributePart, [{
key: "setValue",
value: function setValue(value) {
if (value !== noChange && (!isPrimitive(value) || value !== this.value)) {
this.value = value; // If the value is a not a directive, dirty the committer so that it'll
// call setAttribute. If the value is a directive, it'll dirty the
// committer if it calls setValue().
if (!isDirective(value)) {
this.committer.dirty = true;
}
}
}
}, {
key: "commit",
value: function commit() {
while (isDirective(this.value)) {
var directive = this.value;
this.value = noChange;
directive(this);
}
if (this.value === noChange) {
return;
}
this.committer.commit();
}
}]);
return AttributePart;
}();
/**
* A Part that controls a location within a Node tree. Like a Range, NodePart
* has start and end locations and can set and update the Nodes between those
* locations.
*
* NodeParts support several value types: primitives, Nodes, TemplateResults,
* as well as arrays and iterables of those types.
*/
var NodePart =
/*#__PURE__*/
function () {
function NodePart(options) {
_classCallCheck(this, NodePart);
this.value = undefined;
this.__pendingValue = undefined;
this.options = options;
}
/**
* Appends this part into a container.
*
* This part must be empty, as its contents are not automatically moved.
*/
_createClass(NodePart, [{
key: "appendInto",
value: function appendInto(container) {
this.startNode = container.appendChild(createMarker());
this.endNode = container.appendChild(createMarker());
}
/**
* Inserts this part after the `ref` node (between `ref` and `ref`'s next
* sibling). Both `ref` and its next sibling must be static, unchanging nodes
* such as those that appear in a literal section of a template.
*
* This part must be empty, as its contents are not automatically moved.
*/
}, {
key: "insertAfterNode",
value: function insertAfterNode(ref) {
this.startNode = ref;
this.endNode = ref.nextSibling;
}
/**
* Appends this part into a parent part.
*
* This part must be empty, as its contents are not automatically moved.
*/
}, {
key: "appendIntoPart",
value: function appendIntoPart(part) {
part.__insert(this.startNode = createMarker());
part.__insert(this.endNode = createMarker());
}
/**
* Inserts this part after the `ref` part.
*
* This part must be empty, as its contents are not automatically moved.
*/
}, {
key: "insertAfterPart",
value: function insertAfterPart(ref) {
ref.__insert(this.startNode = createMarker());
this.endNode = ref.endNode;
ref.endNode = this.startNode;
}
}, {
key: "setValue",
value: function setValue(value) {
this.__pendingValue = value;
}
}, {
key: "commit",
value: function commit() {
if (this.startNode.parentNode === null) {
return;
}
while (isDirective(this.__pendingValue)) {
var directive = this.__pendingValue;
this.__pendingValue = noChange;
directive(this);
}
var value = this.__pendingValue;
if (value === noChange) {
return;
}
if (isPrimitive(value)) {
if (value !== this.value) {
this.__commitText(value);
}
} else if (value instanceof TemplateResult) {
this.__commitTemplateResult(value);
} else if (value instanceof Node) {
this.__commitNode(value);
} else if (isIterable(value)) {
this.__commitIterable(value);
} else if (value === nothing) {
this.value = nothing;
this.clear();
} else {
// Fallback, will render the string representation
this.__commitText(value);
}
}
}, {
key: "__insert",
value: function __insert(node) {
this.endNode.parentNode.insertBefore(node, this.endNode);
}
}, {
key: "__commitNode",
value: function __commitNode(value) {
if (this.value === value) {
return;
}
this.clear();
this.__insert(value);
this.value = value;
}
}, {
key: "__commitText",
value: function __commitText(value) {
var node = this.startNode.nextSibling;
value = value == null ? '' : value; // If `value` isn't already a string, we explicitly convert it here in case
// it can't be implicitly converted - i.e. it's a symbol.
var valueAsString = typeof value === 'string' ? value : String(value);
if (node === this.endNode.previousSibling && node.nodeType === 3
/* Node.TEXT_NODE */
) {
// If we only have a single text node between the markers, we can just
// set its value, rather than replacing it.
// TODO(justinfagnani): Can we just check if this.value is primitive?
node.data = valueAsString;
} else {
this.__commitNode(document.createTextNode(valueAsString));
}
this.value = value;
}
}, {
key: "__commitTemplateResult",
value: function __commitTemplateResult(value) {
var template = this.options.templateFactory(value);
if (this.value instanceof TemplateInstance && this.value.template === template) {
this.value.update(value.values);
} else {
// Make sure we propagate the template processor from the TemplateResult
// so that we use its syntax extension, etc. The template factory comes
// from the render function options so that it can control template
// caching and preprocessing.
var instance = new TemplateInstance(template, value.processor, this.options);
var fragment = instance._clone();
instance.update(value.values);
this.__commitNode(fragment);
this.value = instance;
}
}
}, {
key: "__commitIterable",
value: function __commitIterable(value) {
// For an Iterable, we create a new InstancePart per item, then set its
// value to the item. This is a little bit of overhead for every item in
// an Iterable, but it lets us recurse easily and efficiently update Arrays
// of TemplateResults that will be commonly returned from expressions like:
// array.map((i) => html`${i}`), by reusing existing TemplateInstances.
// If _value is an array, then the previous render was of an
// iterable and _value will contain the NodeParts from the previous
// render. If _value is not an array, clear this part and make a new
// array for NodeParts.
if (!Array.isArray(this.value)) {
this.value = [];
this.clear();
} // Lets us keep track of how many items we stamped so we can clear leftover
// items from a previous render
var itemParts = this.value;
var partIndex = 0;
var itemPart;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = value[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var item = _step2.value;
// Try to reuse an existing part
itemPart = itemParts[partIndex]; // If no existing part, create a new one
if (itemPart === undefined) {
itemPart = new NodePart(this.options);
itemParts.push(itemPart);
if (partIndex === 0) {
itemPart.appendIntoPart(this);
} else {
itemPart.insertAfterPart(itemParts[partIndex - 1]);
}
}
itemPart.setValue(item);
itemPart.commit();
partIndex++;
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
if (partIndex < itemParts.length) {
// Truncate the parts array so _value reflects the current state
itemParts.length = partIndex;
this.clear(itemPart && itemPart.endNode);
}
}
}, {
key: "clear",
value: function clear() {
var startNode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.startNode;
removeNodes(this.startNode.parentNode, startNode.nextSibling, this.endNode);
}
}]);
return NodePart;
}();
/**
* Implements a boolean attribute, roughly as defined in the HTML
* specification.
*
* If the value is truthy, then the attribute is present with a value of
* ''. If the value is falsey, the attribute is removed.
*/
var BooleanAttributePart =
/*#__PURE__*/
function () {
function BooleanAttributePart(element, name, strings) {
_classCallCheck(this, BooleanAttributePart);
this.value = undefined;
this.__pendingValue = undefined;
if (strings.length !== 2 || strings[0] !== '' || strings[1] !== '') {
throw new Error('Boolean attributes can only contain a single expression');
}
this.element = element;
this.name = name;
this.strings = strings;
}
_createClass(BooleanAttributePart, [{
key: "setValue",
value: function setValue(value) {
this.__pendingValue = value;
}
}, {
key: "commit",
value: function commit() {
while (isDirective(this.__pendingValue)) {
var directive = this.__pendingValue;
this.__pendingValue = noChange;
directive(this);
}
if (this.__pendingValue === noChange) {
return;
}
var value = !!this.__pendingValue;
if (this.value !== value) {
if (value) {
this.element.setAttribute(this.name, '');
} else {
this.element.removeAttribute(this.name);
}
this.value = value;
}
this.__pendingValue = noChange;
}
}]);
return BooleanAttributePart;
}();
/**
* Sets attribute values for PropertyParts, so that the value is only set once
* even if there are multiple parts for a property.
*
* If an expression controls the whole property value, then the value is simply
* assigned to the property under control. If there are string literals or
* multiple expressions, then the strings are expressions are interpolated into
* a string first.
*/
var PropertyCommitter =
/*#__PURE__*/
function (_AttributeCommitter) {
_inherits(PropertyCommitter, _AttributeCommitter);
function PropertyCommitter(element, name, strings) {
var _this;
_classCallCheck(this, PropertyCommitter);
_this = _possibleConstructorReturn(this, _getPrototypeOf(PropertyCommitter).call(this, element, name, strings));
_this.single = strings.length === 2 && strings[0] === '' && strings[1] === '';
return _this;
}
_createClass(PropertyCommitter, [{
key: "_createPart",
value: function _createPart() {
return new PropertyPart(this);
}
}, {
key: "_getValue",
value: function _getValue() {
if (this.single) {
return this.parts[0].value;
}
return _get(_getPrototypeOf(PropertyCommitter.prototype), "_getValue", this).call(this);
}
}, {
key: "commit",
value: function commit() {
if (this.dirty) {
this.dirty = false; // eslint-disable-next-line @typescript-eslint/no-explicit-any
this.element[this.name] = this._getValue();
}
}
}]);
return PropertyCommitter;
}(AttributeCommitter);
var PropertyPart =
/*#__PURE__*/
function (_AttributePart) {
_inherits(PropertyPart, _AttributePart);
function PropertyPart() {
_classCallCheck(this, PropertyPart);
return _possibleConstructorReturn(this, _getPrototypeOf(PropertyPart).apply(this, arguments));
}
return PropertyPart;
}(AttributePart); // Detect event listener options support. If the `capture` property is read
// from the options object, then options are supported. If not, then the third
// argument to add/removeEventListener is interpreted as the boolean capture
// value so we should only pass the `capture` property.
var eventOptionsSupported = false; // Wrap into an IIFE because MS Edge <= v41 does not support having try/catch
// blocks right into the body of a module
(function () {
try {
var options = {
get capture() {
eventOptionsSupported = true;
return false;
}
}; // eslint-disable-next-line @typescript-eslint/no-explicit-any
window.addEventListener('test', options, options); // eslint-disable-next-line @typescript-eslint/no-explicit-any
window.removeEventListener('test', options, options);
} catch (_e) {// event options not supported
}
})();
var EventPart =
/*#__PURE__*/
function () {
function EventPart(element, eventName, eventContext) {
var _this2 = this;
_classCallCheck(this, EventPart);
this.value = undefined;
this.__pendingValue = undefined;
this.element = element;
this.eventName = eventName;
this.eventContext = eventContext;
this.__boundHandleEvent = function (e) {
return _this2.handleEvent(e);
};
}
_createClass(EventPart, [{
key: "setValue",
value: function setValue(value) {
this.__pendingValue = value;
}
}, {
key: "commit",
value: function commit() {
while (isDirective(this.__pendingValue)) {
var directive = this.__pendingValue;
this.__pendingValue = noChange;
directive(this);
}
if (this.__pendingValue === noChange) {
return;
}
var newListener = this.__pendingValue;
var oldListener = this.value;
var shouldRemoveListener = newListener == null || oldListener != null && (newListener.capture !== oldListener.capture || newListener.once !== oldListener.once || newListener.passive !== oldListener.passive);
var shouldAddListener = newListener != null && (oldListener == null || shouldRemoveListener);
if (shouldRemoveListener) {
this.element.removeEventListener(this.eventName, this.__boundHandleEvent, this.__options);
}
if (shouldAddListener) {
this.__options = getOptions(newListener);
this.element.addEventListener(this.eventName, this.__boundHandleEvent, this.__options);
}
this.value = newListener;
this.__pendingValue = noChange;
}
}, {
key: "handleEvent",
value: function handleEvent(event) {
if (typeof this.value === 'function') {
this.value.call(this.eventContext || this.element, event);
} else {
this.value.handleEvent(event);
}
}
}]);
return EventPart;
}(); // We copy options because of the inconsistent behavior of browsers when reading
// the third argument of add/removeEventListener. IE11 doesn't support options
// at all. Chrome 41 only reads `capture` if the argument is an object.
var getOptions = function getOptions(o) {
return o && (eventOptionsSupported ? {
capture: o.capture,
passive: o.passive,
once: o.once
} : o.capture);
};
/**
* @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
*/
/