128 lines
5.0 KiB
JavaScript
128 lines
5.0 KiB
JavaScript
/**
|
|
* @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 shady-render
|
|
*/
|
|
import { isTemplatePartActive } from './template.js';
|
|
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)
|
|
*/
|
|
export 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.
|
|
*/
|
|
export 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);
|
|
}
|
|
}
|
|
}
|
|
//# sourceMappingURL=modify-template.js.map
|