108 lines
5.2 KiB
JavaScript
108 lines
5.2 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
|
|
*/
|
|
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
var m = o[Symbol.asyncIterator], i;
|
|
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
};
|
|
import { createMarker, directive, NodePart } from '../lit-html.js';
|
|
/**
|
|
* A directive that renders the items of an async iterable[1], appending new
|
|
* values after previous values, similar to the built-in support for iterables.
|
|
*
|
|
* Async iterables are objects with a [Symbol.asyncIterator] method, which
|
|
* returns an iterator who's `next()` method returns a Promise. When a new
|
|
* value is available, the Promise resolves and the value is appended to the
|
|
* Part controlled by the directive. If another value other than this
|
|
* directive has been set on the Part, the iterable will no longer be listened
|
|
* to and new values won't be written to the Part.
|
|
*
|
|
* [1]: https://github.com/tc39/proposal-async-iteration
|
|
*
|
|
* @param value An async iterable
|
|
* @param mapper An optional function that maps from (value, index) to another
|
|
* value. Useful for generating templates for each item in the iterable.
|
|
*/
|
|
export const asyncAppend = directive((value, mapper) => async (part) => {
|
|
var e_1, _a;
|
|
if (!(part instanceof NodePart)) {
|
|
throw new Error('asyncAppend can only be used in text bindings');
|
|
}
|
|
// If we've already set up this particular iterable, we don't need
|
|
// to do anything.
|
|
if (value === part.value) {
|
|
return;
|
|
}
|
|
part.value = value;
|
|
// We keep track of item Parts across iterations, so that we can
|
|
// share marker nodes between consecutive Parts.
|
|
let itemPart;
|
|
let i = 0;
|
|
try {
|
|
for (var value_1 = __asyncValues(value), value_1_1; value_1_1 = await value_1.next(), !value_1_1.done;) {
|
|
let v = value_1_1.value;
|
|
// Check to make sure that value is the still the current value of
|
|
// the part, and if not bail because a new value owns this part
|
|
if (part.value !== value) {
|
|
break;
|
|
}
|
|
// When we get the first value, clear the part. This lets the
|
|
// previous value display until we can replace it.
|
|
if (i === 0) {
|
|
part.clear();
|
|
}
|
|
// As a convenience, because functional-programming-style
|
|
// transforms of iterables and async iterables requires a library,
|
|
// we accept a mapper function. This is especially convenient for
|
|
// rendering a template for each item.
|
|
if (mapper !== undefined) {
|
|
// This is safe because T must otherwise be treated as unknown by
|
|
// the rest of the system.
|
|
v = mapper(v, i);
|
|
}
|
|
// Like with sync iterables, each item induces a Part, so we need
|
|
// to keep track of start and end nodes for the Part.
|
|
// Note: Because these Parts are not updatable like with a sync
|
|
// iterable (if we render a new value, we always clear), it may
|
|
// be possible to optimize away the Parts and just re-use the
|
|
// Part.setValue() logic.
|
|
let itemStartNode = part.startNode;
|
|
// Check to see if we have a previous item and Part
|
|
if (itemPart !== undefined) {
|
|
// Create a new node to separate the previous and next Parts
|
|
itemStartNode = createMarker();
|
|
// itemPart is currently the Part for the previous item. Set
|
|
// it's endNode to the node we'll use for the next Part's
|
|
// startNode.
|
|
itemPart.endNode = itemStartNode;
|
|
part.endNode.parentNode.insertBefore(itemStartNode, part.endNode);
|
|
}
|
|
itemPart = new NodePart(part.options);
|
|
itemPart.insertAfterNode(itemStartNode);
|
|
itemPart.setValue(v);
|
|
itemPart.commit();
|
|
i++;
|
|
}
|
|
}
|
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
finally {
|
|
try {
|
|
if (value_1_1 && !value_1_1.done && (_a = value_1.return)) await _a.call(value_1);
|
|
}
|
|
finally { if (e_1) throw e_1.error; }
|
|
}
|
|
});
|
|
//# sourceMappingURL=async-append.js.map
|