lit-html
Version:
HTML template literals in JavaScript
91 lines • 3.59 kB
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
*/
import { directive, NodePart, removeNodes, reparentNodes } from '../lit-html.js';
const keyMapCache = new WeakMap();
function cleanMap(part, key, map) {
if (!part.startNode.parentNode) {
map.delete(key);
}
}
export function repeat(items, keyFnOrTemplate, template) {
let keyFn;
if (arguments.length === 2) {
template = keyFnOrTemplate;
}
else if (arguments.length === 3) {
keyFn = keyFnOrTemplate;
}
return directive((part) => {
let keyMap = keyMapCache.get(part);
if (keyMap === undefined) {
keyMap = new Map();
keyMapCache.set(part, keyMap);
}
const container = part.startNode.parentNode;
let index = -1;
let currentMarker = part.startNode.nextSibling;
for (const item of items) {
let result;
let key;
try {
++index;
result = template(item, index);
key = keyFn ? keyFn(item) : index;
}
catch (e) {
console.error(e);
continue;
}
// Try to reuse a part
let itemPart = keyMap.get(key);
if (itemPart === undefined) {
// TODO(justinfagnani): We really want to avoid manual marker creation
// here and instead use something like part.insertBeforePart(). This
// requires a little refactoring, like iterating through values and
// existing parts like NodePart#_setIterable does. We can also remove
// keyMapCache and use part._value instead.
// But... repeat() is badly in need of rewriting, so we'll do this for
// now and revisit soon.
const marker = document.createComment('');
const endNode = document.createComment('');
container.insertBefore(marker, currentMarker);
container.insertBefore(endNode, currentMarker);
itemPart = new NodePart(part.templateFactory);
itemPart.insertAfterNode(marker);
if (key !== undefined) {
keyMap.set(key, itemPart);
}
}
else if (currentMarker !== itemPart.startNode) {
// Existing part in the wrong position
const end = itemPart.endNode.nextSibling;
if (currentMarker !== end) {
reparentNodes(container, itemPart.startNode, end, currentMarker);
}
}
else {
// else part is in the correct position already
currentMarker = itemPart.endNode.nextSibling;
}
itemPart.setValue(result);
itemPart.commit();
}
// Cleanup
if (currentMarker !== part.endNode) {
removeNodes(container, currentMarker, part.endNode);
keyMap.forEach(cleanMap);
}
});
}
//# sourceMappingURL=repeat.js.map