es5-lit-html
Version:
An ES5 transpiled version of lit-html
213 lines (176 loc) • 8.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TemplateInstance = void 0;
var _dom = require("./dom.js");
var _template = require("./template.js");
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/**
* 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 dooes 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 = _dom.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 (!(0, _template.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 (_dom.isCEPolyfill) {
document.adoptNode(fragment);
customElements.upgrade(fragment);
}
return fragment;
}
}]);
return TemplateInstance;
}();
exports.TemplateInstance = TemplateInstance;