@tko/binding.template 4.0.0-beta1.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/foreach.js +5 -11
- package/dist/foreach.js.map +2 -2
- package/dist/index.cjs +1052 -806
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +5 -11
- package/dist/index.js.map +2 -2
- package/dist/index.mjs +5 -11
- package/dist/index.mjs.map +2 -2
- package/dist/nativeTemplateEngine.js +8 -15
- package/dist/nativeTemplateEngine.js.map +2 -2
- package/dist/templateEngine.js +16 -20
- package/dist/templateEngine.js.map +3 -3
- package/dist/templateSources.js +69 -68
- package/dist/templateSources.js.map +2 -2
- package/dist/templating.js +128 -86
- package/dist/templating.js.map +2 -2
- package/helpers/dummyTemplateEngine.ts +94 -100
- package/package.json +7 -8
- package/LICENSE +0 -22
package/dist/templating.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// @tko/binding.template 🥊 4.0.0
|
|
1
|
+
// @tko/binding.template 🥊 4.0.0 ESM
|
|
2
|
+
"use strict";
|
|
2
3
|
import {
|
|
3
4
|
virtualElements,
|
|
4
5
|
fixUpContinuousNodeArray,
|
|
@@ -17,23 +18,11 @@ import {
|
|
|
17
18
|
bindingEvent,
|
|
18
19
|
bindingContext as BindingContextConstructor
|
|
19
20
|
} from "@tko/bind";
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
} from "
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
dependencyDetection,
|
|
26
|
-
unwrap,
|
|
27
|
-
observable,
|
|
28
|
-
isObservableArray
|
|
29
|
-
} from "@tko/observable";
|
|
30
|
-
import {
|
|
31
|
-
templateEngine
|
|
32
|
-
} from "./templateEngine";
|
|
33
|
-
import {
|
|
34
|
-
anonymousTemplate as AnonymousTemplate
|
|
35
|
-
} from "./templateSources";
|
|
36
|
-
var _templateEngine;
|
|
21
|
+
import { computed } from "@tko/computed";
|
|
22
|
+
import { isObservable, dependencyDetection, unwrap, observable, isObservableArray } from "@tko/observable";
|
|
23
|
+
import { templateEngine } from "./templateEngine";
|
|
24
|
+
import { anonymousTemplate as AnonymousTemplate } from "./templateSources";
|
|
25
|
+
let _templateEngine;
|
|
37
26
|
const cleanContainerDomDataKey = domData.nextKey();
|
|
38
27
|
export function setTemplateEngine(tEngine) {
|
|
39
28
|
if (tEngine !== void 0 && !(tEngine instanceof templateEngine)) {
|
|
@@ -44,7 +33,7 @@ export function setTemplateEngine(tEngine) {
|
|
|
44
33
|
function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {
|
|
45
34
|
let node;
|
|
46
35
|
let nextInQueue = firstNode;
|
|
47
|
-
|
|
36
|
+
const firstOutOfRangeNode = virtualElements.nextSibling(lastNode);
|
|
48
37
|
while (nextInQueue && (node = nextInQueue) !== firstOutOfRangeNode) {
|
|
49
38
|
nextInQueue = virtualElements.nextSibling(node);
|
|
50
39
|
action(node, nextInQueue);
|
|
@@ -52,15 +41,15 @@ function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {
|
|
|
52
41
|
}
|
|
53
42
|
function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext, afterBindingCallback) {
|
|
54
43
|
if (continuousNodeArray.length) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
44
|
+
let firstNode = continuousNodeArray[0];
|
|
45
|
+
let lastNode = continuousNodeArray[continuousNodeArray.length - 1];
|
|
46
|
+
const parentNode = firstNode.parentNode;
|
|
47
|
+
const provider = koOptions.bindingProviderInstance;
|
|
48
|
+
const preprocessNode = provider.preprocessNode;
|
|
60
49
|
if (preprocessNode) {
|
|
61
50
|
invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {
|
|
62
|
-
|
|
63
|
-
|
|
51
|
+
const nodePreviousSibling = node.previousSibling;
|
|
52
|
+
const newNodes = preprocessNode.call(provider, node);
|
|
64
53
|
if (newNodes) {
|
|
65
54
|
if (node === firstNode) {
|
|
66
55
|
firstNode = newNodes[0] || nextNodeInRange;
|
|
@@ -82,12 +71,12 @@ function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingConte
|
|
|
82
71
|
}
|
|
83
72
|
}
|
|
84
73
|
invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
|
|
85
|
-
if (node.nodeType ===
|
|
74
|
+
if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.COMMENT_NODE) {
|
|
86
75
|
applyBindings(bindingContext, node).then(afterBindingCallback);
|
|
87
76
|
}
|
|
88
77
|
});
|
|
89
78
|
invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
|
|
90
|
-
if (node.nodeType ===
|
|
79
|
+
if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.COMMENT_NODE) {
|
|
91
80
|
memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
|
|
92
81
|
}
|
|
93
82
|
});
|
|
@@ -99,14 +88,14 @@ function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
|
|
|
99
88
|
}
|
|
100
89
|
function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options, afterBindingCallback) {
|
|
101
90
|
options = options || {};
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
91
|
+
const firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
|
|
92
|
+
const templateDocument = (firstTargetNode || template || {}).ownerDocument;
|
|
93
|
+
const templateEngineToUse = options.templateEngine || _templateEngine;
|
|
94
|
+
const renderedNodesArray = templateEngineToUse.renderTemplate(template, bindingContext, options, templateDocument);
|
|
106
95
|
if (typeof renderedNodesArray.length !== "number" || renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType !== "number") {
|
|
107
96
|
throw new Error("Template engine must return an array of DOM nodes");
|
|
108
97
|
}
|
|
109
|
-
|
|
98
|
+
let haveAddedNodesToParent = false;
|
|
110
99
|
switch (renderMode) {
|
|
111
100
|
case "replaceChildren":
|
|
112
101
|
virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
|
|
@@ -148,20 +137,34 @@ export function renderTemplate(template, dataOrBindingContext, options, targetNo
|
|
|
148
137
|
}
|
|
149
138
|
renderMode = renderMode || "replaceChildren";
|
|
150
139
|
if (targetNodeOrNodeArray) {
|
|
151
|
-
|
|
152
|
-
|
|
140
|
+
let firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
|
|
141
|
+
const whenToDispose = function() {
|
|
153
142
|
return !firstTargetNode || !domNodeIsAttachedToDocument(firstTargetNode);
|
|
154
143
|
};
|
|
155
|
-
|
|
156
|
-
return computed(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
144
|
+
const activelyDisposeWhenNodeIsRemoved = firstTargetNode && renderMode === "replaceNode" ? firstTargetNode.parentNode : firstTargetNode;
|
|
145
|
+
return computed(
|
|
146
|
+
// So the DOM is automatically updated when any dependency changes
|
|
147
|
+
function() {
|
|
148
|
+
const bindingContext = dataOrBindingContext && dataOrBindingContext instanceof BindingContextConstructor ? dataOrBindingContext : new BindingContextConstructor(dataOrBindingContext, void 0, void 0, void 0, {
|
|
149
|
+
exportDependencies: true
|
|
150
|
+
});
|
|
151
|
+
const templateName = resolveTemplateName(template, bindingContext.$data, bindingContext);
|
|
152
|
+
const renderedNodesArray = executeTemplate(
|
|
153
|
+
targetNodeOrNodeArray,
|
|
154
|
+
renderMode,
|
|
155
|
+
templateName,
|
|
156
|
+
bindingContext,
|
|
157
|
+
options,
|
|
158
|
+
afterBindingCallback
|
|
159
|
+
);
|
|
160
|
+
if (renderMode === "replaceNode") {
|
|
161
|
+
targetNodeOrNodeArray = renderedNodesArray;
|
|
162
|
+
firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
null,
|
|
166
|
+
{ disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
|
|
167
|
+
);
|
|
165
168
|
} else {
|
|
166
169
|
return memoization.memoize(function(domNode) {
|
|
167
170
|
renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
|
|
@@ -169,7 +172,7 @@ export function renderTemplate(template, dataOrBindingContext, options, targetNo
|
|
|
169
172
|
}
|
|
170
173
|
}
|
|
171
174
|
export default function renderTemplateForEach(template, arrayOrObservableArray, options, targetNode, parentBindingContext, afterBindingCallback) {
|
|
172
|
-
|
|
175
|
+
let arrayItemContext;
|
|
173
176
|
function executeTemplateForArrayItem(arrayValue, index) {
|
|
174
177
|
if (options.as) {
|
|
175
178
|
if (koOptions.createChildContextWithAs) {
|
|
@@ -177,20 +180,24 @@ export default function renderTemplateForEach(template, arrayOrObservableArray,
|
|
|
177
180
|
context.$index = index;
|
|
178
181
|
});
|
|
179
182
|
} else {
|
|
180
|
-
arrayItemContext = parentBindingContext.extend({
|
|
181
|
-
[options.as]: arrayValue,
|
|
182
|
-
$index: index
|
|
183
|
-
});
|
|
183
|
+
arrayItemContext = parentBindingContext.extend({ [options.as]: arrayValue, $index: index });
|
|
184
184
|
}
|
|
185
185
|
} else {
|
|
186
186
|
arrayItemContext = parentBindingContext.createChildContext(arrayValue, options.as, (context) => {
|
|
187
187
|
context.$index = index;
|
|
188
188
|
});
|
|
189
189
|
}
|
|
190
|
-
|
|
191
|
-
return executeTemplate(
|
|
190
|
+
const templateName = resolveTemplateName(template, arrayValue, arrayItemContext);
|
|
191
|
+
return executeTemplate(
|
|
192
|
+
targetNode,
|
|
193
|
+
"ignoreTargetNode",
|
|
194
|
+
templateName,
|
|
195
|
+
arrayItemContext,
|
|
196
|
+
options,
|
|
197
|
+
afterBindingCallback
|
|
198
|
+
);
|
|
192
199
|
}
|
|
193
|
-
|
|
200
|
+
const activateBindingsCallback = function(arrayValue, addedNodesArray) {
|
|
194
201
|
activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext, afterBindingCallback);
|
|
195
202
|
if (options.afterRender) {
|
|
196
203
|
options.afterRender(addedNodesArray, arrayValue);
|
|
@@ -198,42 +205,55 @@ export default function renderTemplateForEach(template, arrayOrObservableArray,
|
|
|
198
205
|
arrayItemContext = null;
|
|
199
206
|
};
|
|
200
207
|
function localSetDomNodeChildrenFromArrayMapping(newArray, changeList) {
|
|
201
|
-
dependencyDetection.ignore(setDomNodeChildrenFromArrayMapping, null, [
|
|
208
|
+
dependencyDetection.ignore(setDomNodeChildrenFromArrayMapping, null, [
|
|
209
|
+
targetNode,
|
|
210
|
+
newArray,
|
|
211
|
+
executeTemplateForArrayItem,
|
|
212
|
+
options,
|
|
213
|
+
activateBindingsCallback,
|
|
214
|
+
changeList
|
|
215
|
+
]);
|
|
202
216
|
bindingEvent.notify(targetNode, bindingEvent.childrenComplete);
|
|
203
217
|
}
|
|
204
218
|
const shouldHideDestroyed = options.includeDestroyed === false || koOptions.foreachHidesDestroyed && !options.includeDestroyed;
|
|
205
219
|
if (!shouldHideDestroyed && !options.beforeRemove && isObservableArray(arrayOrObservableArray)) {
|
|
206
220
|
localSetDomNodeChildrenFromArrayMapping(arrayOrObservableArray.peek());
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
221
|
+
const subscription = arrayOrObservableArray.subscribe(
|
|
222
|
+
function(changeList) {
|
|
223
|
+
localSetDomNodeChildrenFromArrayMapping(arrayOrObservableArray(), changeList);
|
|
224
|
+
},
|
|
225
|
+
null,
|
|
226
|
+
"arrayChange"
|
|
227
|
+
);
|
|
210
228
|
subscription.disposeWhenNodeIsRemoved(targetNode);
|
|
211
229
|
return subscription;
|
|
212
230
|
} else {
|
|
213
|
-
return computed(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
231
|
+
return computed(
|
|
232
|
+
function() {
|
|
233
|
+
let unwrappedArray = unwrap(arrayOrObservableArray) || [];
|
|
234
|
+
const unwrappedIsIterable = Symbol.iterator in unwrappedArray;
|
|
235
|
+
if (!unwrappedIsIterable) {
|
|
236
|
+
unwrappedArray = [unwrappedArray];
|
|
237
|
+
}
|
|
238
|
+
if (shouldHideDestroyed) {
|
|
239
|
+
unwrappedArray = arrayFilter(unwrappedArray, function(item) {
|
|
240
|
+
return item === void 0 || item === null || !unwrap(item._destroy);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
localSetDomNodeChildrenFromArrayMapping(unwrappedArray);
|
|
244
|
+
},
|
|
245
|
+
null,
|
|
246
|
+
{ disposeWhenNodeIsRemoved: targetNode }
|
|
247
|
+
);
|
|
226
248
|
}
|
|
227
249
|
}
|
|
228
|
-
|
|
250
|
+
const templateComputedDomDataKey = domData.nextKey();
|
|
229
251
|
export class TemplateBindingHandler extends AsyncBindingHandler {
|
|
230
252
|
constructor(params) {
|
|
231
253
|
super(params);
|
|
232
254
|
const element = this.$element;
|
|
233
255
|
const bindingValue = unwrap(this.value);
|
|
234
|
-
domData.set(element, "conditional", {
|
|
235
|
-
elseChainSatisfied: observable(true)
|
|
236
|
-
});
|
|
256
|
+
domData.set(element, "conditional", { elseChainSatisfied: observable(true) });
|
|
237
257
|
if (typeof bindingValue === "string" || bindingValue.name) {
|
|
238
258
|
this.bindNamedTemplate();
|
|
239
259
|
} else if ("nodes" in bindingValue) {
|
|
@@ -245,6 +265,10 @@ export class TemplateBindingHandler extends AsyncBindingHandler {
|
|
|
245
265
|
bindNamedTemplate() {
|
|
246
266
|
virtualElements.emptyNode(this.$element);
|
|
247
267
|
}
|
|
268
|
+
// We've been given an array of DOM nodes. Save them as the template source.
|
|
269
|
+
// There is no known use case for the node array being an observable array (if the output
|
|
270
|
+
// varies, put that behavior *into* your template - that's what templates are for), and
|
|
271
|
+
// the implementation would be a mess, so assert that it's not observable.
|
|
248
272
|
bindNodeTemplate(nodes) {
|
|
249
273
|
if (isObservable(nodes)) {
|
|
250
274
|
throw new Error('The "nodes" option must be a plain, non-observable array.');
|
|
@@ -267,12 +291,12 @@ export class TemplateBindingHandler extends AsyncBindingHandler {
|
|
|
267
291
|
onValueChange() {
|
|
268
292
|
const element = this.$element;
|
|
269
293
|
const bindingContext = this.$context;
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
294
|
+
const value = this.value;
|
|
295
|
+
let options = unwrap(value);
|
|
296
|
+
let shouldDisplay = true;
|
|
297
|
+
let templateComputed = null;
|
|
298
|
+
const elseChainSatisfied = domData.get(element, "conditional").elseChainSatisfied;
|
|
299
|
+
let templateName;
|
|
276
300
|
if (typeof options === "string") {
|
|
277
301
|
templateName = value;
|
|
278
302
|
options = {};
|
|
@@ -286,12 +310,26 @@ export class TemplateBindingHandler extends AsyncBindingHandler {
|
|
|
286
310
|
}
|
|
287
311
|
}
|
|
288
312
|
if ("foreach" in options) {
|
|
289
|
-
|
|
290
|
-
templateComputed = renderTemplateForEach(
|
|
313
|
+
const dataArray = shouldDisplay && options.foreach || [];
|
|
314
|
+
templateComputed = renderTemplateForEach(
|
|
315
|
+
templateName || element,
|
|
316
|
+
dataArray,
|
|
317
|
+
options,
|
|
318
|
+
element,
|
|
319
|
+
bindingContext,
|
|
320
|
+
this.completeBinding
|
|
321
|
+
);
|
|
291
322
|
elseChainSatisfied((unwrap(dataArray) || []).length !== 0);
|
|
292
323
|
} else if (shouldDisplay) {
|
|
293
|
-
|
|
294
|
-
templateComputed = renderTemplate(
|
|
324
|
+
const innerBindingContext = "data" in options ? bindingContext.createStaticChildContext(options.data, options.as) : bindingContext;
|
|
325
|
+
templateComputed = renderTemplate(
|
|
326
|
+
templateName || element,
|
|
327
|
+
innerBindingContext,
|
|
328
|
+
options,
|
|
329
|
+
element,
|
|
330
|
+
void 0,
|
|
331
|
+
this.completeBinding
|
|
332
|
+
);
|
|
295
333
|
elseChainSatisfied(true);
|
|
296
334
|
} else {
|
|
297
335
|
virtualElements.emptyNode(element);
|
|
@@ -300,11 +338,15 @@ export class TemplateBindingHandler extends AsyncBindingHandler {
|
|
|
300
338
|
this.disposeOldComputedAndStoreNewOne(element, templateComputed);
|
|
301
339
|
}
|
|
302
340
|
disposeOldComputedAndStoreNewOne(element, newComputed) {
|
|
303
|
-
|
|
341
|
+
const oldComputed = domData.get(element, templateComputedDomDataKey);
|
|
304
342
|
if (oldComputed && typeof oldComputed.dispose === "function") {
|
|
305
343
|
oldComputed.dispose();
|
|
306
344
|
}
|
|
307
|
-
domData.set(
|
|
345
|
+
domData.set(
|
|
346
|
+
element,
|
|
347
|
+
templateComputedDomDataKey,
|
|
348
|
+
newComputed && (!newComputed.isActive || newComputed.isActive()) ? newComputed : void 0
|
|
349
|
+
);
|
|
308
350
|
}
|
|
309
351
|
get controlsDescendants() {
|
|
310
352
|
return true;
|
package/dist/templating.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/templating.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n virtualElements, fixUpContinuousNodeArray, replaceDomNodes, memoization,\n domNodeIsAttachedToDocument, moveCleanedNodesToContainerElement,\n arrayFilter, domData, options as koOptions\n} from '@tko/utils'\n\nimport {\n applyBindings, setDomNodeChildrenFromArrayMapping, AsyncBindingHandler,\n bindingEvent, bindingContext as BindingContextConstructor\n} from '@tko/bind'\n\nimport {\n computed\n} from '@tko/computed'\n\nimport {\n isObservable, dependencyDetection, unwrap, observable, isObservableArray\n} from '@tko/observable'\n\nimport {\n templateEngine\n} from './templateEngine'\n\nimport {\n anonymousTemplate as AnonymousTemplate\n} from './templateSources'\n\nvar _templateEngine\nconst cleanContainerDomDataKey = domData.nextKey()\n\nexport function setTemplateEngine (tEngine) {\n if ((tEngine !== undefined) && !(tEngine instanceof templateEngine)) {\n // TODO: ko.templateEngine to appropriate name\n throw new Error('templateEngine must inherit from ko.templateEngine')\n }\n _templateEngine = tEngine\n}\n\nfunction invokeForEachNodeInContinuousRange (firstNode, lastNode, action) {\n let node\n let nextInQueue = firstNode\n let firstOutOfRangeNode = virtualElements.nextSibling(lastNode)\n while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {\n nextInQueue = virtualElements.nextSibling(node)\n action(node, nextInQueue)\n }\n}\n\nfunction activateBindingsOnContinuousNodeArray (continuousNodeArray, bindingContext, afterBindingCallback) {\n // To be used on any nodes that have been rendered by a template and have been inserted into some parent element\n // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because\n // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,\n // (1) Does a regular \"applyBindings\" to associate bindingContext with this node and to activate any non-memoized bindings\n // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)\n\n if (continuousNodeArray.length) {\n var firstNode = continuousNodeArray[0]\n var lastNode = continuousNodeArray[continuousNodeArray.length - 1]\n var parentNode = firstNode.parentNode\n var provider = koOptions.bindingProviderInstance\n var preprocessNode = provider.preprocessNode\n\n if (preprocessNode) {\n invokeForEachNodeInContinuousRange(firstNode, lastNode, function (node, nextNodeInRange) {\n var nodePreviousSibling = node.previousSibling\n var newNodes = preprocessNode.call(provider, node)\n if (newNodes) {\n if (node === firstNode) { firstNode = newNodes[0] || nextNodeInRange }\n if (node === lastNode) { lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling }\n }\n })\n\n // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.\n // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real\n // first node needs to be in the array).\n continuousNodeArray.length = 0\n if (!firstNode) { // preprocessNode might have removed all the nodes, in which case there's nothing left to do\n return\n }\n if (firstNode === lastNode) {\n continuousNodeArray.push(firstNode)\n } else {\n continuousNodeArray.push(firstNode, lastNode)\n fixUpContinuousNodeArray(continuousNodeArray, parentNode)\n }\n }\n\n // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)\n // whereas a regular applyBindings won't introduce new memoized nodes\n invokeForEachNodeInContinuousRange(firstNode, lastNode, function (node) {\n if (node.nodeType === 1 || node.nodeType === 8) { applyBindings(bindingContext, node).then(afterBindingCallback) }\n })\n invokeForEachNodeInContinuousRange(firstNode, lastNode, function (node) {\n if (node.nodeType === 1 || node.nodeType === 8) { memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]) }\n })\n\n // Make sure any changes done by applyBindings or unmemoize are reflected in the array\n fixUpContinuousNodeArray(continuousNodeArray, parentNode)\n }\n}\n\nfunction getFirstNodeFromPossibleArray (nodeOrNodeArray) {\n return nodeOrNodeArray.nodeType ? nodeOrNodeArray\n : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]\n : null\n}\n\nfunction executeTemplate (targetNodeOrNodeArray, renderMode, template, bindingContext, options, afterBindingCallback) {\n options = options || {}\n var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray)\n var templateDocument = (firstTargetNode || template || {}).ownerDocument\n var templateEngineToUse = (options.templateEngine || _templateEngine)\n var renderedNodesArray = templateEngineToUse.renderTemplate(template, bindingContext, options, templateDocument)\n\n // Loosely check result is an array of DOM nodes\n if ((typeof renderedNodesArray.length !== 'number') || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType !== 'number')) { throw new Error('Template engine must return an array of DOM nodes') }\n\n var haveAddedNodesToParent = false\n switch (renderMode) {\n case 'replaceChildren':\n virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray)\n haveAddedNodesToParent = true\n break\n case 'replaceNode':\n replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray)\n haveAddedNodesToParent = true\n break\n case 'ignoreTargetNode': break\n default:\n throw new Error('Unknown renderMode: ' + renderMode)\n }\n\n if (haveAddedNodesToParent) {\n activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext, afterBindingCallback)\n if (options.afterRender) { dependencyDetection.ignore(options.afterRender, null, [renderedNodesArray, bindingContext['$data']]) }\n if (renderMode === 'replaceChildren') {\n bindingEvent.notify(targetNodeOrNodeArray, bindingEvent.childrenComplete)\n }\n }\n\n return renderedNodesArray\n}\n\nfunction resolveTemplateName (template, data, context) {\n // The template can be specified as:\n if (isObservable(template)) {\n // 1. An observable, with string value\n return template()\n } else if (typeof template === 'function') {\n // 2. A function of (data, context) returning a string\n return template(data, context)\n } else {\n // 3. A string\n return template\n }\n}\n\nexport function renderTemplate (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode, afterBindingCallback) {\n options = options || {}\n if ((options.templateEngine || _templateEngine) === undefined) { throw new Error('Set a template engine before calling renderTemplate') }\n renderMode = renderMode || 'replaceChildren'\n\n if (targetNodeOrNodeArray) {\n var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray)\n\n var whenToDispose = function () { return (!firstTargetNode) || !domNodeIsAttachedToDocument(firstTargetNode) } // Passive disposal (on next evaluation)\n var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode === 'replaceNode') ? firstTargetNode.parentNode : firstTargetNode\n\n return computed( // So the DOM is automatically updated when any dependency changes\n function () {\n // Ensure we've got a proper binding context to work with\n var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof BindingContextConstructor))\n ? dataOrBindingContext\n : new BindingContextConstructor(dataOrBindingContext, null, null, null, { 'exportDependencies': true })\n\n var templateName = resolveTemplateName(template, bindingContext.$data, bindingContext)\n const renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options, afterBindingCallback)\n\n if (renderMode === 'replaceNode') {\n targetNodeOrNodeArray = renderedNodesArray\n firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray)\n }\n },\n null,\n { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }\n )\n } else {\n // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node\n return memoization.memoize(function (domNode) {\n renderTemplate(template, dataOrBindingContext, options, domNode, 'replaceNode')\n })\n }\n}\n\nexport default function renderTemplateForEach (template, arrayOrObservableArray, options, targetNode, parentBindingContext, afterBindingCallback) {\n // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then\n // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.\n var arrayItemContext\n\n // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode\n function executeTemplateForArrayItem (arrayValue, index) {\n // Support selecting template as a function of the data being rendered\n if (options.as) {\n if (koOptions.createChildContextWithAs) {\n arrayItemContext = parentBindingContext.createChildContext(\n arrayValue, options.as, context => { context.$index = index }\n )\n } else {\n arrayItemContext = parentBindingContext.extend({\n [options.as]: arrayValue,\n $index: index\n })\n }\n } else {\n arrayItemContext = parentBindingContext.createChildContext(arrayValue, options.as, context => { context.$index = index })\n }\n\n var templateName = resolveTemplateName(template, arrayValue, arrayItemContext)\n return executeTemplate(targetNode, 'ignoreTargetNode', templateName, arrayItemContext, options, afterBindingCallback)\n }\n\n // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode\n var activateBindingsCallback = function (arrayValue, addedNodesArray /*, index */) {\n activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext, afterBindingCallback)\n if (options.afterRender) { options.afterRender(addedNodesArray, arrayValue) }\n\n // release the \"cache\" variable, so that it can be collected by\n // the GC when its value isn't used from within the bindings anymore.\n arrayItemContext = null\n }\n\n // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).\n // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.\n function localSetDomNodeChildrenFromArrayMapping (newArray, changeList) {\n dependencyDetection.ignore(setDomNodeChildrenFromArrayMapping, null, [targetNode, newArray, executeTemplateForArrayItem, options, activateBindingsCallback, changeList])\n bindingEvent.notify(targetNode, bindingEvent.childrenComplete)\n }\n\n const shouldHideDestroyed = (options.includeDestroyed === false) || (koOptions.foreachHidesDestroyed && !options.includeDestroyed);\n if (!shouldHideDestroyed && !options.beforeRemove && isObservableArray(arrayOrObservableArray)) {\n localSetDomNodeChildrenFromArrayMapping(arrayOrObservableArray.peek())\n var subscription = arrayOrObservableArray.subscribe(function (changeList) {\n localSetDomNodeChildrenFromArrayMapping(arrayOrObservableArray(), changeList)\n }, null, 'arrayChange')\n subscription.disposeWhenNodeIsRemoved(targetNode)\n return subscription\n } else {\n return computed(function () {\n var unwrappedArray = unwrap(arrayOrObservableArray) || []\n const unwrappedIsIterable = Symbol.iterator in unwrappedArray\n if (!unwrappedIsIterable) { unwrappedArray = [unwrappedArray] }\n if (shouldHideDestroyed) {\n // Filter out any entries marked as destroyed\n unwrappedArray = arrayFilter(unwrappedArray, function (item) {\n return item === undefined || item === null || !unwrap(item._destroy);\n })\n }\n localSetDomNodeChildrenFromArrayMapping(unwrappedArray)\n }, null, { disposeWhenNodeIsRemoved: targetNode })\n }\n}\n\nlet templateComputedDomDataKey = domData.nextKey()\n\nexport class TemplateBindingHandler extends AsyncBindingHandler {\n constructor (params) {\n super(params)\n const element = this.$element\n const bindingValue = unwrap(this.value)\n\n // Expose 'conditional' for `else` chaining.\n domData.set(element, 'conditional', {\n elseChainSatisfied: observable(true)\n })\n\n // Support anonymous templates\n if (typeof bindingValue === 'string' || bindingValue.name) {\n this.bindNamedTemplate()\n } else if ('nodes' in bindingValue) {\n this.bindNodeTemplate(bindingValue.nodes || [])\n } else {\n this.bindAnonymousTemplate()\n }\n }\n\n bindNamedTemplate () {\n // It's a named template - clear the element\n virtualElements.emptyNode(this.$element)\n }\n\n // We've been given an array of DOM nodes. Save them as the template source.\n // There is no known use case for the node array being an observable array (if the output\n // varies, put that behavior *into* your template - that's what templates are for), and\n // the implementation would be a mess, so assert that it's not observable.\n bindNodeTemplate (nodes) {\n if (isObservable(nodes)) {\n throw new Error('The \"nodes\" option must be a plain, non-observable array.')\n }\n\n // If the nodes are already attached to a KO-generated container, we reuse that container without moving the\n // elements to a new one (we check only the first node, as the nodes are always moved together)\n let container = nodes[0] && nodes[0].parentNode\n if (!container || !domData.get(container, cleanContainerDomDataKey)) {\n container = moveCleanedNodesToContainerElement(nodes)\n domData.set(container, cleanContainerDomDataKey, true)\n }\n\n new AnonymousTemplate(this.$element).nodes(container)\n }\n\n bindAnonymousTemplate () {\n // It's an anonymous template - store the element contents, then clear the element\n const templateNodes = virtualElements.childNodes(this.$element)\n if (templateNodes.length === 0) {\n throw new Error('Anonymous template defined, but no template content was provided.')\n }\n const container = moveCleanedNodesToContainerElement(templateNodes) // This also removes the nodes from their current parent\n new AnonymousTemplate(this.$element).nodes(container)\n }\n\n onValueChange () {\n const element = this.$element\n const bindingContext = this.$context\n var value = this.value\n var options = unwrap(value)\n var shouldDisplay = true\n var templateComputed = null\n var elseChainSatisfied = domData.get(element, 'conditional').elseChainSatisfied\n var templateName\n\n if (typeof options === 'string') {\n templateName = value\n options = {}\n } else {\n templateName = options.name\n\n // Support \"if\"/\"ifnot\" conditions\n if ('if' in options) {\n shouldDisplay = unwrap(options.if)\n }\n\n if (shouldDisplay && 'ifnot' in options) {\n shouldDisplay = !unwrap(options.ifnot)\n }\n }\n\n if ('foreach' in options) {\n // Render once for each data point (treating data set as empty if shouldDisplay==false)\n var dataArray = (shouldDisplay && options.foreach) || []\n templateComputed = renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext, this.completeBinding)\n\n elseChainSatisfied((unwrap(dataArray) || []).length !== 0)\n } else if (shouldDisplay) {\n // Render once for this single data point (or use the viewModel if no data was provided)\n var innerBindingContext = ('data' in options)\n ? bindingContext.createStaticChildContext(options.data, options.as) // Given an explicit 'data' value, we create a child binding context for it\n : bindingContext // Given no explicit 'data' value, we retain the same binding context\n templateComputed = renderTemplate(templateName || element, innerBindingContext, options, element, undefined, this.completeBinding)\n elseChainSatisfied(true)\n } else {\n virtualElements.emptyNode(element)\n elseChainSatisfied(false)\n }\n\n // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)\n this.disposeOldComputedAndStoreNewOne(element, templateComputed)\n }\n\n disposeOldComputedAndStoreNewOne (element, newComputed) {\n let oldComputed = domData.get(element, templateComputedDomDataKey)\n if (oldComputed && (typeof oldComputed.dispose === 'function')) { oldComputed.dispose() }\n domData.set(element, templateComputedDomDataKey, (newComputed && (!newComputed.isActive || newComputed.isActive())) ? newComputed : undefined)\n }\n\n get controlsDescendants () { return true }\n static get allowVirtualElements () { return true }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import {\n virtualElements,\n fixUpContinuousNodeArray,\n replaceDomNodes,\n memoization,\n domNodeIsAttachedToDocument,\n moveCleanedNodesToContainerElement,\n arrayFilter,\n domData,\n options as koOptions\n} from '@tko/utils'\n\nimport {\n applyBindings,\n setDomNodeChildrenFromArrayMapping,\n AsyncBindingHandler,\n bindingEvent,\n bindingContext as BindingContextConstructor\n} from '@tko/bind'\n\nimport { computed } from '@tko/computed'\n\nimport type { Computed } from '@tko/computed'\n\nimport type { BindingContext } from '@tko/bind'\n\nimport { isObservable, dependencyDetection, unwrap, observable, isObservableArray } from '@tko/observable'\n\nimport { templateEngine } from './templateEngine'\n\nimport type { TemplateEngine, TemplateOptions } from './templateEngine'\n\nimport { anonymousTemplate as AnonymousTemplate } from './templateSources'\n\nlet _templateEngine: TemplateEngine\nconst cleanContainerDomDataKey = domData.nextKey()\n\nexport function setTemplateEngine(tEngine: TemplateEngine | undefined): void {\n if (tEngine !== undefined && !(tEngine instanceof templateEngine)) {\n // TODO: ko.templateEngine to appropriate name\n throw new Error('templateEngine must inherit from ko.templateEngine')\n }\n _templateEngine = tEngine!\n}\n\nfunction invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {\n let node\n let nextInQueue = firstNode\n const firstOutOfRangeNode = virtualElements.nextSibling(lastNode)\n while (nextInQueue && (node = nextInQueue) !== firstOutOfRangeNode) {\n nextInQueue = virtualElements.nextSibling(node)\n action(node, nextInQueue)\n }\n}\n\nfunction activateBindingsOnContinuousNodeArray(\n continuousNodeArray,\n bindingContext: BindingContext,\n afterBindingCallback\n) {\n // To be used on any nodes that have been rendered by a template and have been inserted into some parent element\n // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because\n // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,\n // (1) Does a regular \"applyBindings\" to associate bindingContext with this node and to activate any non-memoized bindings\n // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)\n\n if (continuousNodeArray.length) {\n let firstNode = continuousNodeArray[0]\n let lastNode = continuousNodeArray[continuousNodeArray.length - 1]\n const parentNode = firstNode.parentNode\n const provider = koOptions.bindingProviderInstance\n const preprocessNode = provider.preprocessNode\n\n if (preprocessNode) {\n invokeForEachNodeInContinuousRange(firstNode, lastNode, function (node, nextNodeInRange) {\n const nodePreviousSibling = node.previousSibling\n const newNodes = preprocessNode.call(provider, node)\n if (newNodes) {\n if (node === firstNode) {\n firstNode = newNodes[0] || nextNodeInRange\n }\n if (node === lastNode) {\n lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling\n }\n }\n })\n\n // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.\n // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real\n // first node needs to be in the array).\n continuousNodeArray.length = 0\n if (!firstNode) {\n // preprocessNode might have removed all the nodes, in which case there's nothing left to do\n return\n }\n if (firstNode === lastNode) {\n continuousNodeArray.push(firstNode)\n } else {\n continuousNodeArray.push(firstNode, lastNode)\n fixUpContinuousNodeArray(continuousNodeArray, parentNode)\n }\n }\n\n // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)\n // whereas a regular applyBindings won't introduce new memoized nodes\n invokeForEachNodeInContinuousRange(firstNode, lastNode, function (node) {\n if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.COMMENT_NODE) {\n applyBindings(bindingContext, node).then(afterBindingCallback)\n }\n })\n invokeForEachNodeInContinuousRange(firstNode, lastNode, function (node) {\n if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.COMMENT_NODE) {\n memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext])\n }\n })\n\n // Make sure any changes done by applyBindings or unmemoize are reflected in the array\n fixUpContinuousNodeArray(continuousNodeArray, parentNode)\n }\n}\n\nfunction getFirstNodeFromPossibleArray(nodeOrNodeArray) {\n return nodeOrNodeArray.nodeType ? nodeOrNodeArray : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0] : null\n}\n\nfunction executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options, afterBindingCallback) {\n options = options || {}\n const firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray)\n const templateDocument = (firstTargetNode || template || {}).ownerDocument\n const templateEngineToUse = options.templateEngine || _templateEngine\n const renderedNodesArray = templateEngineToUse.renderTemplate(template, bindingContext, options, templateDocument)\n\n // Loosely check result is an array of DOM nodes\n if (\n typeof renderedNodesArray.length !== 'number'\n || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType !== 'number')\n ) {\n throw new Error('Template engine must return an array of DOM nodes')\n }\n\n let haveAddedNodesToParent = false\n switch (renderMode) {\n case 'replaceChildren':\n virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray)\n haveAddedNodesToParent = true\n break\n case 'replaceNode':\n replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray)\n haveAddedNodesToParent = true\n break\n case 'ignoreTargetNode':\n break\n default:\n throw new Error('Unknown renderMode: ' + renderMode)\n }\n\n if (haveAddedNodesToParent) {\n activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext, afterBindingCallback)\n if (options.afterRender) {\n dependencyDetection.ignore(options.afterRender, null, [renderedNodesArray, bindingContext['$data']])\n }\n if (renderMode === 'replaceChildren') {\n bindingEvent.notify(targetNodeOrNodeArray, bindingEvent.childrenComplete)\n }\n }\n\n return renderedNodesArray\n}\n\nfunction resolveTemplateName(template, data, context) {\n // The template can be specified as:\n if (isObservable(template)) {\n // 1. An observable, with string value\n return template()\n } else if (typeof template === 'function') {\n // 2. A function of (data, context) returning a string\n return template(data, context)\n } else {\n // 3. A string\n return template\n }\n}\n\nexport type RenderModeEnum = 'replaceChildren' | 'replaceNode' | 'ignoreTargetNode'\n\nexport function renderTemplate<T = any>(\n template: string | Node | (() => string | Node),\n dataOrBindingContext: T | BindingContext<T> | null | undefined,\n options: TemplateOptions<T> | null | undefined,\n targetNodeOrNodeArray: Node | Node[],\n renderMode?: RenderModeEnum,\n afterBindingCallback?\n): Computed<void> | string {\n options = options || {}\n if ((options.templateEngine || _templateEngine) === undefined) {\n throw new Error('Set a template engine before calling renderTemplate')\n }\n renderMode = renderMode || 'replaceChildren'\n\n if (targetNodeOrNodeArray) {\n let firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray)\n\n const whenToDispose = function () {\n return !firstTargetNode || !domNodeIsAttachedToDocument(firstTargetNode)\n } // Passive disposal (on next evaluation)\n const activelyDisposeWhenNodeIsRemoved =\n firstTargetNode && renderMode === 'replaceNode' ? firstTargetNode.parentNode : firstTargetNode\n\n return computed(\n // So the DOM is automatically updated when any dependency changes\n function () {\n // Ensure we've got a proper binding context to work with\n const bindingContext =\n dataOrBindingContext && dataOrBindingContext instanceof BindingContextConstructor\n ? dataOrBindingContext\n : new BindingContextConstructor(dataOrBindingContext, undefined, undefined, undefined, {\n exportDependencies: true\n })\n\n const templateName = resolveTemplateName(template, bindingContext.$data, bindingContext)\n const renderedNodesArray = executeTemplate(\n targetNodeOrNodeArray,\n renderMode,\n templateName,\n bindingContext,\n options,\n afterBindingCallback\n )\n\n if (renderMode === 'replaceNode') {\n targetNodeOrNodeArray = renderedNodesArray\n firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray)\n }\n },\n null,\n { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }\n )\n } else {\n // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node\n return memoization.memoize(function (domNode) {\n renderTemplate(template, dataOrBindingContext, options, domNode, 'replaceNode')\n })\n }\n}\n\nexport default function renderTemplateForEach(\n template,\n arrayOrObservableArray,\n options,\n targetNode,\n parentBindingContext,\n afterBindingCallback\n) {\n // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then\n // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.\n let arrayItemContext\n\n // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode\n function executeTemplateForArrayItem(arrayValue, index) {\n // Support selecting template as a function of the data being rendered\n if (options.as) {\n if (koOptions.createChildContextWithAs) {\n arrayItemContext = parentBindingContext.createChildContext(arrayValue, options.as, context => {\n context.$index = index\n })\n } else {\n arrayItemContext = parentBindingContext.extend({ [options.as]: arrayValue, $index: index })\n }\n } else {\n arrayItemContext = parentBindingContext.createChildContext(arrayValue, options.as, context => {\n context.$index = index\n })\n }\n\n const templateName = resolveTemplateName(template, arrayValue, arrayItemContext)\n return executeTemplate(\n targetNode,\n 'ignoreTargetNode',\n templateName,\n arrayItemContext,\n options,\n afterBindingCallback\n )\n }\n\n // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode\n const activateBindingsCallback = function (arrayValue, addedNodesArray /*, index */) {\n activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext, afterBindingCallback)\n if (options.afterRender) {\n options.afterRender(addedNodesArray, arrayValue)\n }\n\n // release the \"cache\" variable, so that it can be collected by\n // the GC when its value isn't used from within the bindings anymore.\n arrayItemContext = null\n }\n\n // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).\n // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.\n function localSetDomNodeChildrenFromArrayMapping(newArray, changeList?) {\n dependencyDetection.ignore(setDomNodeChildrenFromArrayMapping, null, [\n targetNode,\n newArray,\n executeTemplateForArrayItem,\n options,\n activateBindingsCallback,\n changeList\n ])\n bindingEvent.notify(targetNode, bindingEvent.childrenComplete)\n }\n\n const shouldHideDestroyed =\n options.includeDestroyed === false || (koOptions.foreachHidesDestroyed && !options.includeDestroyed)\n if (!shouldHideDestroyed && !options.beforeRemove && isObservableArray(arrayOrObservableArray)) {\n localSetDomNodeChildrenFromArrayMapping(arrayOrObservableArray.peek())\n const subscription = arrayOrObservableArray.subscribe(\n function (changeList) {\n localSetDomNodeChildrenFromArrayMapping(arrayOrObservableArray(), changeList)\n },\n null,\n 'arrayChange'\n )\n subscription.disposeWhenNodeIsRemoved(targetNode)\n return subscription\n } else {\n return computed(\n function () {\n let unwrappedArray = unwrap(arrayOrObservableArray) || []\n const unwrappedIsIterable = Symbol.iterator in unwrappedArray\n if (!unwrappedIsIterable) {\n unwrappedArray = [unwrappedArray]\n }\n if (shouldHideDestroyed) {\n // Filter out any entries marked as destroyed\n unwrappedArray = arrayFilter(unwrappedArray, function (item) {\n return item === undefined || item === null || !unwrap(item._destroy)\n })\n }\n localSetDomNodeChildrenFromArrayMapping(unwrappedArray)\n },\n null,\n { disposeWhenNodeIsRemoved: targetNode }\n )\n }\n}\n\nconst templateComputedDomDataKey = domData.nextKey()\n\nexport class TemplateBindingHandler extends AsyncBindingHandler {\n constructor(params) {\n super(params)\n const element = this.$element\n const bindingValue = unwrap(this.value)\n\n // Expose 'conditional' for `else` chaining.\n domData.set(element, 'conditional', { elseChainSatisfied: observable(true) })\n\n // Support anonymous templates\n if (typeof bindingValue === 'string' || bindingValue.name) {\n this.bindNamedTemplate()\n } else if ('nodes' in bindingValue) {\n this.bindNodeTemplate(bindingValue.nodes || [])\n } else {\n this.bindAnonymousTemplate()\n }\n }\n\n bindNamedTemplate() {\n // It's a named template - clear the element\n virtualElements.emptyNode(this.$element)\n }\n\n // We've been given an array of DOM nodes. Save them as the template source.\n // There is no known use case for the node array being an observable array (if the output\n // varies, put that behavior *into* your template - that's what templates are for), and\n // the implementation would be a mess, so assert that it's not observable.\n bindNodeTemplate(nodes) {\n if (isObservable(nodes)) {\n throw new Error('The \"nodes\" option must be a plain, non-observable array.')\n }\n\n // If the nodes are already attached to a KO-generated container, we reuse that container without moving the\n // elements to a new one (we check only the first node, as the nodes are always moved together)\n let container = nodes[0] && nodes[0].parentNode\n if (!container || !domData.get(container, cleanContainerDomDataKey)) {\n container = moveCleanedNodesToContainerElement(nodes)\n domData.set(container, cleanContainerDomDataKey, true)\n }\n\n new AnonymousTemplate(this.$element).nodes(container)\n }\n\n bindAnonymousTemplate() {\n // It's an anonymous template - store the element contents, then clear the element\n const templateNodes = virtualElements.childNodes(this.$element)\n if (templateNodes.length === 0) {\n throw new Error('Anonymous template defined, but no template content was provided.')\n }\n const container = moveCleanedNodesToContainerElement(templateNodes) // This also removes the nodes from their current parent\n new AnonymousTemplate(this.$element).nodes(container)\n }\n\n onValueChange() {\n const element = this.$element\n const bindingContext = this.$context\n const value = this.value\n let options = unwrap(value)\n let shouldDisplay = true\n let templateComputed: string | Computed<any> | null = null\n const elseChainSatisfied = domData.get(element, 'conditional').elseChainSatisfied\n let templateName\n\n if (typeof options === 'string') {\n templateName = value\n options = {}\n } else {\n templateName = options.name\n\n // Support \"if\"/\"ifnot\" conditions\n if ('if' in options) {\n shouldDisplay = unwrap(options.if)\n }\n\n if (shouldDisplay && 'ifnot' in options) {\n shouldDisplay = !unwrap(options.ifnot)\n }\n }\n\n if ('foreach' in options) {\n // Render once for each data point (treating data set as empty if shouldDisplay==false)\n const dataArray = (shouldDisplay && options.foreach) || []\n templateComputed = renderTemplateForEach(\n templateName || element,\n dataArray,\n options,\n element,\n bindingContext,\n this.completeBinding\n )\n\n elseChainSatisfied((unwrap(dataArray) || []).length !== 0)\n } else if (shouldDisplay) {\n // Render once for this single data point (or use the viewModel if no data was provided)\n const innerBindingContext =\n 'data' in options\n ? bindingContext.createStaticChildContext(options.data, options.as) // Given an explicit 'data' value, we create a child binding context for it\n : bindingContext // Given no explicit 'data' value, we retain the same binding context\n templateComputed = renderTemplate(\n templateName || element,\n innerBindingContext,\n options,\n element,\n undefined,\n this.completeBinding\n )\n elseChainSatisfied(true)\n } else {\n virtualElements.emptyNode(element)\n elseChainSatisfied(false)\n }\n\n // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)\n this.disposeOldComputedAndStoreNewOne(element, templateComputed)\n }\n\n disposeOldComputedAndStoreNewOne(element, newComputed) {\n const oldComputed = domData.get(element, templateComputedDomDataKey)\n if (oldComputed && typeof oldComputed.dispose === 'function') {\n oldComputed.dispose()\n }\n domData.set(\n element,\n templateComputedDomDataKey,\n newComputed && (!newComputed.isActive || newComputed.isActive()) ? newComputed : undefined\n )\n }\n\n override get controlsDescendants() {\n return true\n }\n static override get allowVirtualElements() {\n return true\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|