@tko/bind 4.0.0-alpha9.0 → 4.0.0-beta1.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.
@@ -0,0 +1,171 @@
1
+ // @tko/bind 🥊 4.0.0-beta1.0 ESM
2
+ import {
3
+ fixUpContinuousNodeArray,
4
+ replaceDomNodes,
5
+ arrayPushAll,
6
+ anyDomNodeIsAttachedToDocument,
7
+ domData,
8
+ arrayMap,
9
+ arrayForEach,
10
+ virtualElements,
11
+ extend,
12
+ cleanNode,
13
+ removeNode,
14
+ compareArrays
15
+ } from "@tko/utils";
16
+ import {
17
+ dependencyDetection,
18
+ observable
19
+ } from "@tko/observable";
20
+ import { computed } from "@tko/computed";
21
+ function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
22
+ var mappedNodes = [];
23
+ var dependentObservable = computed(function() {
24
+ var newMappedNodes = mapping(valueToMap, index, fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];
25
+ if (mappedNodes.length > 0) {
26
+ replaceDomNodes(mappedNodes, newMappedNodes);
27
+ if (callbackAfterAddingNodes) {
28
+ dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
29
+ }
30
+ }
31
+ mappedNodes.length = 0;
32
+ arrayPushAll(mappedNodes, newMappedNodes);
33
+ }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() {
34
+ return !anyDomNodeIsAttachedToDocument(mappedNodes);
35
+ } });
36
+ return { mappedNodes, dependentObservable: dependentObservable.isActive() ? dependentObservable : void 0 };
37
+ }
38
+ var lastMappingResultDomDataKey = domData.nextKey();
39
+ let deletedItemDummyValue = domData.nextKey();
40
+ export function setDomNodeChildrenFromArrayMapping(domNode, array, mapping, options, callbackAfterAddingNodes, editScript) {
41
+ array = array || [];
42
+ if (typeof array.length === "undefined") {
43
+ array = [array];
44
+ }
45
+ options = options || {};
46
+ let lastMappingResult = domData.get(domNode, lastMappingResultDomDataKey);
47
+ let isFirstExecution = !lastMappingResult;
48
+ var newMappingResult = [];
49
+ var lastMappingResultIndex = 0;
50
+ var newMappingResultIndex = 0;
51
+ var nodesToDelete = [];
52
+ var itemsToProcess = [];
53
+ var itemsForBeforeRemoveCallbacks = [];
54
+ var itemsForMoveCallbacks = [];
55
+ var itemsForAfterAddCallbacks = [];
56
+ var mapData;
57
+ let countWaitingForRemove = 0;
58
+ function itemAdded(value) {
59
+ mapData = { arrayEntry: value, indexObservable: observable(newMappingResultIndex++) };
60
+ newMappingResult.push(mapData);
61
+ itemsToProcess.push(mapData);
62
+ if (!isFirstExecution) {
63
+ itemsForAfterAddCallbacks.push(mapData);
64
+ }
65
+ }
66
+ function itemMovedOrRetained(oldPosition) {
67
+ mapData = lastMappingResult[oldPosition];
68
+ if (newMappingResultIndex !== oldPosition) {
69
+ itemsForMoveCallbacks.push(mapData);
70
+ }
71
+ mapData.indexObservable(newMappingResultIndex++);
72
+ fixUpContinuousNodeArray(mapData.mappedNodes, domNode);
73
+ newMappingResult.push(mapData);
74
+ itemsToProcess.push(mapData);
75
+ }
76
+ function callCallback(callback, items) {
77
+ if (callback) {
78
+ for (var i2 = 0, n = items.length; i2 < n; i2++) {
79
+ arrayForEach(items[i2].mappedNodes, function(node2) {
80
+ callback(node2, i2, items[i2].arrayEntry);
81
+ });
82
+ }
83
+ }
84
+ }
85
+ if (isFirstExecution) {
86
+ arrayForEach(array, itemAdded);
87
+ } else {
88
+ if (!editScript || lastMappingResult && lastMappingResult["_countWaitingForRemove"]) {
89
+ var lastArray = isFirstExecution ? [] : arrayMap(lastMappingResult, function(x) {
90
+ return x.arrayEntry;
91
+ });
92
+ var compareOptions = {
93
+ "dontLimitMoves": options["dontLimitMoves"],
94
+ "sparse": true
95
+ };
96
+ editScript = compareArrays(lastArray, array, compareOptions);
97
+ }
98
+ for (var i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {
99
+ movedIndex = editScriptItem["moved"];
100
+ itemIndex = editScriptItem["index"];
101
+ switch (editScriptItem["status"]) {
102
+ case "deleted":
103
+ while (lastMappingResultIndex < itemIndex) {
104
+ itemMovedOrRetained(lastMappingResultIndex++);
105
+ }
106
+ if (movedIndex === void 0) {
107
+ mapData = lastMappingResult[lastMappingResultIndex];
108
+ if (mapData.dependentObservable) {
109
+ mapData.dependentObservable.dispose();
110
+ mapData.dependentObservable = void 0;
111
+ }
112
+ if (fixUpContinuousNodeArray(mapData.mappedNodes, domNode).length) {
113
+ if (options["beforeRemove"]) {
114
+ newMappingResult.push(mapData);
115
+ itemsToProcess.push(mapData);
116
+ countWaitingForRemove++;
117
+ if (mapData.arrayEntry === deletedItemDummyValue) {
118
+ mapData = null;
119
+ } else {
120
+ itemsForBeforeRemoveCallbacks.push(mapData);
121
+ }
122
+ }
123
+ if (mapData) {
124
+ nodesToDelete.push.apply(nodesToDelete, mapData.mappedNodes);
125
+ }
126
+ }
127
+ }
128
+ lastMappingResultIndex++;
129
+ break;
130
+ case "added":
131
+ while (newMappingResultIndex < itemIndex) {
132
+ itemMovedOrRetained(lastMappingResultIndex++);
133
+ }
134
+ if (movedIndex !== void 0) {
135
+ itemMovedOrRetained(movedIndex);
136
+ } else {
137
+ itemAdded(editScriptItem["value"]);
138
+ }
139
+ break;
140
+ }
141
+ }
142
+ while (newMappingResultIndex < array.length) {
143
+ itemMovedOrRetained(lastMappingResultIndex++);
144
+ }
145
+ newMappingResult["_countWaitingForRemove"] = countWaitingForRemove;
146
+ }
147
+ domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
148
+ callCallback(options["beforeMove"], itemsForMoveCallbacks);
149
+ arrayForEach(nodesToDelete, options["beforeRemove"] ? cleanNode : removeNode);
150
+ i = 0;
151
+ for (var nextNode = virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
152
+ if (!mapData.mappedNodes) {
153
+ extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
154
+ }
155
+ for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
156
+ if (node !== nextNode) {
157
+ virtualElements.insertAfter(domNode, node, lastNode);
158
+ }
159
+ }
160
+ if (!mapData.initialized && callbackAfterAddingNodes) {
161
+ callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
162
+ mapData.initialized = true;
163
+ }
164
+ }
165
+ callCallback(options["beforeRemove"], itemsForBeforeRemoveCallbacks);
166
+ for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) {
167
+ itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue;
168
+ }
169
+ callCallback(options["afterMove"], itemsForMoveCallbacks);
170
+ callCallback(options["afterAdd"], itemsForAfterAddCallbacks);
171
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/arrayToDomNodeChildren.ts"],
4
+ "sourcesContent": ["/* eslint no-cond-assign: 0 */\nimport {\n fixUpContinuousNodeArray, replaceDomNodes, arrayPushAll,\n anyDomNodeIsAttachedToDocument, domData, arrayMap, arrayForEach,\n virtualElements, extend, cleanNode, removeNode, compareArrays\n} from '@tko/utils'\n\nimport {\n dependencyDetection, observable\n} from '@tko/observable'\n\nimport { computed } from '@tko/computed'\n\n// Objective:\n// * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,\n// map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node\n// * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node\n// so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we\n// previously mapped - retain those nodes, and just insert/delete other ones\n\n// \"callbackAfterAddingNodes\" will be invoked after any \"mapping\"-generated nodes are inserted into the container node\n// You can use this, for example, to activate bindings on those nodes.\n\nfunction mapNodeAndRefreshWhenChanged (containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {\n // Map this array value inside a dependentObservable so we re-map when any dependency changes\n var mappedNodes = []\n var dependentObservable = computed(function () {\n var newMappedNodes = mapping(valueToMap, index, fixUpContinuousNodeArray(mappedNodes, containerNode)) || []\n\n // On subsequent evaluations, just replace the previously-inserted DOM nodes\n if (mappedNodes.length > 0) {\n replaceDomNodes(mappedNodes, newMappedNodes)\n if (callbackAfterAddingNodes) { dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]) }\n }\n\n // Replace the contents of the mappedNodes array, thereby updating the record\n // of which nodes would be deleted if valueToMap was itself later removed\n mappedNodes.length = 0\n arrayPushAll(mappedNodes, newMappedNodes)\n }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function () { return !anyDomNodeIsAttachedToDocument(mappedNodes) } })\n return { mappedNodes: mappedNodes, dependentObservable: (dependentObservable.isActive() ? dependentObservable : undefined) }\n}\n\nvar lastMappingResultDomDataKey = domData.nextKey()\nlet deletedItemDummyValue = domData.nextKey()\n\nexport function setDomNodeChildrenFromArrayMapping (domNode, array, mapping, options, callbackAfterAddingNodes, editScript) {\n // Compare the provided array against the previous one\n array = array || []\n if (typeof array.length === 'undefined') {\n array = [array]\n }\n options = options || {}\n let lastMappingResult = domData.get(domNode, lastMappingResultDomDataKey)\n let isFirstExecution = !lastMappingResult\n\n // Build the new mapping result\n var newMappingResult = []\n var lastMappingResultIndex = 0\n var newMappingResultIndex = 0\n\n var nodesToDelete = []\n var itemsToProcess = []\n var itemsForBeforeRemoveCallbacks = []\n var itemsForMoveCallbacks = []\n var itemsForAfterAddCallbacks = []\n var mapData\n let countWaitingForRemove = 0\n\n function itemAdded (value) {\n mapData = { arrayEntry: value, indexObservable: observable(newMappingResultIndex++) }\n newMappingResult.push(mapData)\n itemsToProcess.push(mapData)\n if (!isFirstExecution) {\n itemsForAfterAddCallbacks.push(mapData)\n }\n }\n\n function itemMovedOrRetained (oldPosition) {\n mapData = lastMappingResult[oldPosition]\n if (newMappingResultIndex !== oldPosition) {\n itemsForMoveCallbacks.push(mapData)\n }\n // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray\n mapData.indexObservable(newMappingResultIndex++)\n fixUpContinuousNodeArray(mapData.mappedNodes, domNode)\n newMappingResult.push(mapData)\n itemsToProcess.push(mapData)\n }\n\n function callCallback (callback, items) {\n if (callback) {\n for (var i = 0, n = items.length; i < n; i++) {\n arrayForEach(items[i].mappedNodes, function (node) {\n callback(node, i, items[i].arrayEntry)\n })\n }\n }\n }\n\n if (isFirstExecution) {\n arrayForEach(array, itemAdded)\n } else {\n if (!editScript || (lastMappingResult && lastMappingResult['_countWaitingForRemove'])) {\n // Compare the provided array against the previous one\n var lastArray = isFirstExecution ? [] : arrayMap(lastMappingResult, function (x) { return x.arrayEntry })\n var compareOptions = {\n 'dontLimitMoves': options['dontLimitMoves'],\n 'sparse': true\n }\n editScript = compareArrays(lastArray, array, compareOptions)\n }\n\n for (var i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {\n movedIndex = editScriptItem['moved']\n itemIndex = editScriptItem['index']\n switch (editScriptItem['status']) {\n case 'deleted':\n while (lastMappingResultIndex < itemIndex) {\n itemMovedOrRetained(lastMappingResultIndex++)\n }\n if (movedIndex === undefined) {\n mapData = lastMappingResult[lastMappingResultIndex]\n\n // Stop tracking changes to the mapping for these nodes\n if (mapData.dependentObservable) {\n mapData.dependentObservable.dispose()\n mapData.dependentObservable = undefined\n }\n\n // Queue these nodes for later removal\n if (fixUpContinuousNodeArray(mapData.mappedNodes, domNode).length) {\n if (options['beforeRemove']) {\n newMappingResult.push(mapData)\n itemsToProcess.push(mapData)\n countWaitingForRemove++\n if (mapData.arrayEntry === deletedItemDummyValue) {\n mapData = null\n } else {\n itemsForBeforeRemoveCallbacks.push(mapData)\n }\n }\n if (mapData) {\n nodesToDelete.push.apply(nodesToDelete, mapData.mappedNodes)\n }\n }\n }\n lastMappingResultIndex++\n break\n\n case 'added':\n while (newMappingResultIndex < itemIndex) {\n itemMovedOrRetained(lastMappingResultIndex++)\n }\n if (movedIndex !== undefined) {\n itemMovedOrRetained(movedIndex)\n } else {\n itemAdded(editScriptItem['value'])\n }\n break\n }\n }\n\n while (newMappingResultIndex < array.length) {\n itemMovedOrRetained(lastMappingResultIndex++)\n }\n\n // Record that the current view may still contain deleted items\n // because it means we won't be able to use a provided editScript.\n newMappingResult['_countWaitingForRemove'] = countWaitingForRemove\n }\n\n // Store a copy of the array items we just considered so we can difference it next time\n domData.set(domNode, lastMappingResultDomDataKey, newMappingResult)\n\n // Call beforeMove first before any changes have been made to the DOM\n callCallback(options['beforeMove'], itemsForMoveCallbacks)\n\n // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)\n arrayForEach(nodesToDelete, options['beforeRemove'] ? cleanNode : removeNode)\n\n // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)\n i = 0\n for (var nextNode = virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {\n // Get nodes for newly added items\n if (!mapData.mappedNodes) { extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable)) }\n\n // Put nodes in the right place if they aren't there already\n for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {\n if (node !== nextNode) { virtualElements.insertAfter(domNode, node, lastNode) }\n }\n\n // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)\n if (!mapData.initialized && callbackAfterAddingNodes) {\n callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable)\n mapData.initialized = true\n }\n }\n\n // If there's a beforeRemove callback, call it after reordering.\n // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using\n // some sort of animation, which is why we first reorder the nodes that will be removed. If the\n // callback instead removes the nodes right away, it would be more efficient to skip reordering them.\n // Perhaps we'll make that change in the future if this scenario becomes more common.\n callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks)\n\n // Replace the stored values of deleted items with a dummy value. This provides two benefits: it marks this item\n // as already \"removed\" so we won't call beforeRemove for it again, and it ensures that the item won't match up\n // with an actual item in the array and appear as \"retained\" or \"moved\".\n for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) {\n itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue\n }\n\n // Finally call afterMove and afterAdd callbacks\n callCallback(options['afterMove'], itemsForMoveCallbacks)\n callCallback(options['afterAdd'], itemsForAfterAddCallbacks)\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,122 @@
1
+ // @tko/bind 🥊 4.0.0-beta1.0 ESM
2
+ import { extend, options, domData, isObjectLike } from "@tko/utils";
3
+ import {
4
+ pureComputed
5
+ } from "@tko/computed";
6
+ import {
7
+ unwrap,
8
+ isObservable
9
+ } from "@tko/observable";
10
+ import {
11
+ contextAncestorBindingInfo
12
+ } from "./bindingEvent";
13
+ export const boundElementDomDataKey = domData.nextKey();
14
+ export const contextSubscribeSymbol = Symbol("Knockout Context Subscription");
15
+ const inheritParentIndicator = Symbol("Knockout Parent Indicator");
16
+ export function bindingContext(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, settings) {
17
+ const self = this;
18
+ const shouldInheritData = dataItemOrAccessor === inheritParentIndicator;
19
+ const realDataItemOrAccessor = shouldInheritData ? void 0 : dataItemOrAccessor;
20
+ const isFunc = typeof realDataItemOrAccessor === "function" && !isObservable(realDataItemOrAccessor);
21
+ self.ko = options.knockoutInstance;
22
+ let nodes;
23
+ let subscribable;
24
+ function updateContext() {
25
+ const dataItemOrObservable = isFunc ? realDataItemOrAccessor() : realDataItemOrAccessor;
26
+ let dataItem = unwrap(dataItemOrObservable);
27
+ if (parentContext) {
28
+ if (parentContext[contextSubscribeSymbol]) {
29
+ parentContext[contextSubscribeSymbol]();
30
+ }
31
+ extend(self, parentContext);
32
+ if (contextAncestorBindingInfo in parentContext) {
33
+ self[contextAncestorBindingInfo] = parentContext[contextAncestorBindingInfo];
34
+ }
35
+ } else {
36
+ self.$parents = [];
37
+ self.$root = dataItem;
38
+ }
39
+ self[contextSubscribeSymbol] = subscribable;
40
+ if (shouldInheritData) {
41
+ dataItem = self.$data;
42
+ } else {
43
+ self.$rawData = dataItemOrObservable;
44
+ self.$data = dataItem;
45
+ }
46
+ if (dataItemAlias) {
47
+ self[dataItemAlias] = dataItem;
48
+ }
49
+ if (extendCallback) {
50
+ extendCallback(self, parentContext, dataItem);
51
+ }
52
+ return self.$data;
53
+ }
54
+ if (settings && settings.exportDependencies) {
55
+ updateContext();
56
+ } else {
57
+ subscribable = pureComputed(updateContext);
58
+ subscribable.peek();
59
+ if (subscribable.isActive()) {
60
+ self[contextSubscribeSymbol] = subscribable;
61
+ subscribable["equalityComparer"] = null;
62
+ } else {
63
+ self[contextSubscribeSymbol] = void 0;
64
+ }
65
+ }
66
+ }
67
+ Object.assign(bindingContext.prototype, {
68
+ lookup(token, globals, node) {
69
+ switch (token) {
70
+ case "$element":
71
+ return node;
72
+ case "$context":
73
+ return this;
74
+ case "this":
75
+ case "$data":
76
+ return this.$data;
77
+ }
78
+ const $data = this.$data;
79
+ if (isObjectLike($data) && token in $data) {
80
+ return $data[token];
81
+ }
82
+ if (token in this) {
83
+ return this[token];
84
+ }
85
+ if (token in globals) {
86
+ return globals[token];
87
+ }
88
+ throw new Error(`The variable "${token}" was not found on $data, $context, or globals.`);
89
+ },
90
+ createChildContext(dataItemOrAccessor, dataItemAlias, extendCallback, settings) {
91
+ return new bindingContext(dataItemOrAccessor, this, dataItemAlias, function(self, parentContext) {
92
+ self.$parentContext = parentContext;
93
+ self.$parent = parentContext.$data;
94
+ self.$parents = (parentContext.$parents || []).slice(0);
95
+ self.$parents.unshift(self.$parent);
96
+ if (extendCallback) {
97
+ extendCallback(self);
98
+ }
99
+ }, settings);
100
+ },
101
+ extend(properties) {
102
+ return new bindingContext(inheritParentIndicator, this, null, function(self, parentContext) {
103
+ extend(self, typeof properties === "function" ? properties.call(self) : properties);
104
+ });
105
+ },
106
+ createStaticChildContext(dataItemOrAccessor, dataItemAlias) {
107
+ return this.createChildContext(dataItemOrAccessor, dataItemAlias, null, { "exportDependencies": true });
108
+ }
109
+ });
110
+ export function storedBindingContextForNode(node) {
111
+ const bindingInfo = domData.get(node, boundElementDomDataKey);
112
+ return bindingInfo && bindingInfo.context;
113
+ }
114
+ export function contextFor(node) {
115
+ if (node && (node.nodeType === 1 || node.nodeType === 8)) {
116
+ return storedBindingContextForNode(node);
117
+ }
118
+ }
119
+ export function dataFor(node) {
120
+ var context = contextFor(node);
121
+ return context ? context.$data : void 0;
122
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/bindingContext.ts"],
4
+ "sourcesContent": ["import { extend, options, domData, isObjectLike } from '@tko/utils'\n\nimport {\n pureComputed\n} from '@tko/computed'\n\nimport {\n unwrap, isObservable\n} from '@tko/observable'\n\nimport {\n contextAncestorBindingInfo\n} from './bindingEvent'\n\nexport const boundElementDomDataKey = domData.nextKey()\n\nexport const contextSubscribeSymbol = Symbol('Knockout Context Subscription')\n\n// Unique stub to indicate inheritance.\nconst inheritParentIndicator = Symbol('Knockout Parent Indicator')\n\n// The bindingContext constructor is only called directly to create the root context. For child\n// contexts, use bindingContext.createChildContext or bindingContext.extend.\nexport function bindingContext (dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, settings) {\n const self = this\n const shouldInheritData = dataItemOrAccessor === inheritParentIndicator\n const realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor\n const isFunc = typeof realDataItemOrAccessor === 'function' && !isObservable(realDataItemOrAccessor)\n\n // Export 'ko' in the binding context so it will be available in bindings and templates\n // even if 'ko' isn't exported as a global, such as when using an AMD loader.\n // See https://github.com/SteveSanderson/knockout/issues/490\n self.ko = options.knockoutInstance\n\n let nodes\n let subscribable\n\n // The binding context object includes static properties for the current, parent, and root view models.\n // If a view model is actually stored in an observable, the corresponding binding context object, and\n // any child contexts, must be updated when the view model is changed.\n function updateContext () {\n // Most of the time, the context will directly get a view model object, but if a function is given,\n // we call the function to retrieve the view model. If the function accesses any observables or returns\n // an observable, the dependency is tracked, and those observables can later cause the binding\n // context to be updated.\n const dataItemOrObservable = isFunc ? realDataItemOrAccessor() : realDataItemOrAccessor\n let dataItem = unwrap(dataItemOrObservable)\n\n if (parentContext) {\n // When a \"parent\" context is given, register a dependency on the parent context. Thus whenever the\n // parent context is updated, this context will also be updated.\n if (parentContext[contextSubscribeSymbol]) {\n parentContext[contextSubscribeSymbol]()\n }\n\n // Copy $root and any custom properties from the parent context\n extend(self, parentContext)\n\n // Copy Symbol properties\n if (contextAncestorBindingInfo in parentContext) {\n self[contextAncestorBindingInfo] = parentContext[contextAncestorBindingInfo]\n }\n } else {\n self.$parents = []\n self.$root = dataItem\n }\n\n self[contextSubscribeSymbol] = subscribable\n\n if (shouldInheritData) {\n dataItem = self.$data\n } else {\n self.$rawData = dataItemOrObservable\n self.$data = dataItem\n }\n\n if (dataItemAlias) { self[dataItemAlias] = dataItem }\n\n // The extendCallback function is provided when creating a child context or extending a context.\n // It handles the specific actions needed to finish setting up the binding context. Actions in this\n // function could also add dependencies to this binding context.\n if (extendCallback) { extendCallback(self, parentContext, dataItem) }\n\n return self.$data\n }\n\n if (settings && settings.exportDependencies) {\n // The \"exportDependencies\" option means that the calling code will track any dependencies and re-create\n // the binding context when they change.\n updateContext()\n } else {\n subscribable = pureComputed(updateContext)\n subscribable.peek()\n\n // At this point, the binding context has been initialized, and the \"subscribable\" computed observable is\n // subscribed to any observables that were accessed in the process. If there is nothing to track, the\n // computed will be inactive, and we can safely throw it away. If it's active, the computed is stored in\n // the context object.\n if (subscribable.isActive()) {\n self[contextSubscribeSymbol] = subscribable\n\n // Always notify because even if the model ($data) hasn't changed, other context properties might have changed\n subscribable['equalityComparer'] = null\n } else {\n self[contextSubscribeSymbol] = undefined\n }\n }\n}\n\nObject.assign(bindingContext.prototype, {\n\n lookup (token, globals, node) {\n // short circuits\n switch (token) {\n case '$element': return node\n case '$context': return this\n case 'this': case '$data': return this.$data\n }\n const $data = this.$data\n // instanceof Object covers 1. {}, 2. [], 3. function() {}, 4. new *; it excludes undefined, null, primitives.\n if (isObjectLike($data) && token in $data) { return $data[token] }\n if (token in this) { return this[token] }\n if (token in globals) { return globals[token] }\n\n throw new Error(`The variable \"${token}\" was not found on $data, $context, or globals.`)\n },\n\n // Extend the binding context hierarchy with a new view model object. If the parent context is watching\n // any observables, the new child context will automatically get a dependency on the parent context.\n // But this does not mean that the $data value of the child context will also get updated. If the child\n // view model also depends on the parent view model, you must provide a function that returns the correct\n // view model on each update.\n createChildContext (dataItemOrAccessor, dataItemAlias, extendCallback, settings) {\n return new bindingContext(dataItemOrAccessor, this, dataItemAlias, function (self, parentContext) {\n // Extend the context hierarchy by setting the appropriate pointers\n self.$parentContext = parentContext\n self.$parent = parentContext.$data\n self.$parents = (parentContext.$parents || []).slice(0)\n self.$parents.unshift(self.$parent)\n if (extendCallback) { extendCallback(self) }\n }, settings)\n },\n\n // Extend the binding context with new custom properties. This doesn't change the context hierarchy.\n // Similarly to \"child\" contexts, provide a function here to make sure that the correct values are set\n // when an observable view model is updated.\n extend (properties) {\n // If the parent context references an observable view model, \"_subscribable\" will always be the\n // latest view model object. If not, \"_subscribable\" isn't set, and we can use the static \"$data\" value.\n return new bindingContext(inheritParentIndicator, this, null, function (self, parentContext) {\n extend(self, typeof properties === 'function' ? properties.call(self) : properties)\n })\n },\n\n createStaticChildContext (dataItemOrAccessor, dataItemAlias) {\n return this.createChildContext(dataItemOrAccessor, dataItemAlias, null, { 'exportDependencies': true })\n }\n})\n\nexport function storedBindingContextForNode (node) {\n const bindingInfo = domData.get(node, boundElementDomDataKey)\n return bindingInfo && bindingInfo.context\n}\n\n// Retrieving binding context from arbitrary nodes\nexport function contextFor (node) {\n // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)\n if (node && (node.nodeType === 1 || node.nodeType === 8)) {\n return storedBindingContextForNode(node)\n }\n}\n\nexport function dataFor (node) {\n var context = contextFor(node)\n return context ? context.$data : undefined\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,24 @@
1
+ // @tko/bind 🥊 4.0.0-beta1.0 ESM
2
+ import { domData } from "@tko/utils";
3
+ import { subscribable } from "@tko/observable";
4
+ export const contextAncestorBindingInfo = Symbol("_ancestorBindingInfo");
5
+ const boundElementDomDataKey = domData.nextKey();
6
+ export const bindingEvent = {
7
+ childrenComplete: "childrenComplete",
8
+ descendantsComplete: "descendantsComplete",
9
+ subscribe(node, event, callback, context) {
10
+ const bindingInfo = domData.getOrSet(node, boundElementDomDataKey, {});
11
+ if (!bindingInfo.eventSubscribable) {
12
+ bindingInfo.eventSubscribable = new subscribable();
13
+ }
14
+ return bindingInfo.eventSubscribable.subscribe(callback, context, event);
15
+ },
16
+ notify(node, event) {
17
+ const bindingInfo = domData.get(node, boundElementDomDataKey);
18
+ if (bindingInfo) {
19
+ if (bindingInfo.eventSubscribable) {
20
+ bindingInfo.eventSubscribable.notifySubscribers(node, event);
21
+ }
22
+ }
23
+ }
24
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/bindingEvent.ts"],
4
+ "sourcesContent": ["\nimport { domData } from '@tko/utils'\nimport { subscribable } from '@tko/observable'\n\nexport const contextAncestorBindingInfo = Symbol('_ancestorBindingInfo')\nconst boundElementDomDataKey = domData.nextKey()\n\nexport const bindingEvent = {\n childrenComplete: 'childrenComplete',\n descendantsComplete: 'descendantsComplete',\n\n subscribe (node, event, callback, context) {\n const bindingInfo = domData.getOrSet(node, boundElementDomDataKey, {})\n if (!bindingInfo.eventSubscribable) {\n bindingInfo.eventSubscribable = new subscribable()\n }\n return bindingInfo.eventSubscribable.subscribe(callback, context, event)\n },\n\n notify (node, event) {\n const bindingInfo = domData.get(node, boundElementDomDataKey)\n if (bindingInfo) {\n if (bindingInfo.eventSubscribable) {\n bindingInfo.eventSubscribable.notifySubscribers(node, event)\n }\n }\n }\n}\n\n"],
5
+ "mappings": ";AACA;AACA;AAEO,aAAM,6BAA6B,OAAO,sBAAsB;AACvE,MAAM,yBAAyB,QAAQ,QAAQ;AAExC,aAAM,eAAe;AAAA,EAC1B,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EAErB,UAAW,MAAM,OAAO,UAAU,SAAS;AACzC,UAAM,cAAc,QAAQ,SAAS,MAAM,wBAAwB,CAAC,CAAC;AACrE,QAAI,CAAC,YAAY,mBAAmB;AAClC,kBAAY,oBAAoB,IAAI,aAAa;AAAA,IACnD;AACA,WAAO,YAAY,kBAAkB,UAAU,UAAU,SAAS,KAAK;AAAA,EACzE;AAAA,EAEA,OAAQ,MAAM,OAAO;AACnB,UAAM,cAAc,QAAQ,IAAI,MAAM,sBAAsB;AAC5D,QAAI,aAAa;AACf,UAAI,YAAY,mBAAmB;AACjC,oBAAY,kBAAkB,kBAAkB,MAAM,KAAK;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }