@tko/bind 4.0.0-beta1.3 → 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/BindingHandler.js +17 -9
- package/dist/BindingHandler.js.map +2 -2
- package/dist/BindingResult.js +10 -33
- package/dist/BindingResult.js.map +2 -2
- package/dist/DescendantBindingHandler.js +13 -34
- package/dist/DescendantBindingHandler.js.map +2 -2
- package/dist/LegacyBindingHandler.js +15 -8
- package/dist/LegacyBindingHandler.js.map +2 -2
- package/dist/applyBindings.js +91 -76
- package/dist/applyBindings.js.map +3 -3
- package/dist/arrayToDomNodeChildren.js +66 -53
- package/dist/arrayToDomNodeChildren.js.map +2 -2
- package/dist/bindingContext.js +37 -30
- package/dist/bindingContext.js.map +2 -2
- package/dist/bindingEvent.js +7 -4
- package/dist/bindingEvent.js.map +2 -2
- package/dist/index.cjs +728 -513
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +4 -8
- package/dist/index.js.map +2 -2
- package/dist/index.mjs +4 -8
- package/dist/index.mjs.map +2 -2
- package/package.json +8 -9
- package/LICENSE +0 -22
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/applyBindings.ts"],
|
|
4
|
-
"sourcesContent": ["\n/* eslint no-cond-assign: 0 */\n\nimport {\n extend, objectMap, virtualElements, tagNameLower, domData, objectForEach,\n arrayIndexOf, arrayForEach, options\n} from '@tko/utils'\n\nimport {\n dependencyDetection\n} from '@tko/observable'\n\nimport {\n computed\n} from '@tko/computed'\n\nimport {\n dataFor, bindingContext, boundElementDomDataKey, contextSubscribeSymbol\n} from './bindingContext'\n\nimport {\n bindingEvent\n} from './bindingEvent'\n\nimport {\n BindingResult\n} from './BindingResult'\n\nimport {\n LegacyBindingHandler\n} from './LegacyBindingHandler'\n\n// The following element types will not be recursed into during binding.\nconst bindingDoesNotRecurseIntoElementTypes = {\n // Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,\n // because it's unexpected and a potential XSS issue.\n // Also bindings should not operate on <template> elements since this breaks in Internet Explorer\n // and because such elements' contents are always intended to be bound in a different context\n // from where they appear in the document.\n 'script': true,\n 'textarea': true,\n 'template': true\n}\n\nfunction getBindingProvider () {\n return options.bindingProviderInstance.instance || options.bindingProviderInstance\n}\n\nfunction isProviderForNode (provider, node) {\n const nodeTypes = provider.FOR_NODE_TYPES || [1, 3, 8]\n return nodeTypes.includes(node.nodeType)\n}\n\nfunction asProperHandlerClass (handler, bindingKey) {\n if (!handler) { return }\n return handler.isBindingHandlerClass ? handler\n : LegacyBindingHandler.getOrCreateFor(bindingKey, handler)\n}\n\nfunction getBindingHandlerFromComponent (bindingKey, $component) {\n if (!$component || typeof $component.getBindingHandler !== 'function') { return }\n return asProperHandlerClass($component.getBindingHandler(bindingKey))\n}\n\nexport function getBindingHandler (bindingKey) {\n const bindingDefinition = options.getBindingHandler(bindingKey) || getBindingProvider().bindingHandlers.get(bindingKey)\n return asProperHandlerClass(bindingDefinition, bindingKey)\n}\n\n// Returns the value of a valueAccessor function\nfunction evaluateValueAccessor (valueAccessor) {\n return valueAccessor()\n}\n\nfunction applyBindingsToDescendantsInternal (bindingContext, elementOrVirtualElement, asyncBindingsApplied) {\n let nextInQueue = virtualElements.firstChild(elementOrVirtualElement)\n\n if (!nextInQueue) { return }\n\n let currentChild\n const provider = getBindingProvider()\n const preprocessNode = provider.preprocessNode\n\n // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's\n // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to\n // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that\n // trigger insertion of <template> contents at that point in the document.\n if (preprocessNode) {\n while (currentChild = nextInQueue) {\n nextInQueue = virtualElements.nextSibling(currentChild)\n preprocessNode.call(provider, currentChild)\n }\n\n // Reset nextInQueue for the next loop\n nextInQueue = virtualElements.firstChild(elementOrVirtualElement)\n }\n\n while (currentChild = nextInQueue) {\n // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position\n nextInQueue = virtualElements.nextSibling(currentChild)\n applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild, asyncBindingsApplied)\n }\n\n bindingEvent.notify(elementOrVirtualElement, bindingEvent.childrenComplete)\n}\n\nfunction hasBindings (node) {\n const provider = getBindingProvider()\n return isProviderForNode(provider, node) && provider.nodeHasBindings(node)\n}\n\nfunction nodeOrChildHasBindings (node) {\n return hasBindings(node) || [...node.childNodes].some(c => nodeOrChildHasBindings(c))\n}\n\nfunction applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified, asyncBindingsApplied) {\n var isElement = nodeVerified.nodeType === 1\n if (isElement) { // Workaround IE <= 8 HTML parsing weirdness\n virtualElements.normaliseVirtualElementDomStructure(nodeVerified)\n }\n\n // Perf optimisation: Apply bindings only if...\n // (1) We need to store the binding info for the node (all element nodes)\n // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)\n\n let shouldApplyBindings = isElement || // Case (1)\n hasBindings(nodeVerified) // Case (2)\n\n const { shouldBindDescendants } = shouldApplyBindings\n ? applyBindingsToNodeInternal(nodeVerified, null, bindingContext, asyncBindingsApplied)\n : { shouldBindDescendants: true }\n\n if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[tagNameLower(nodeVerified)]) {\n // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,\n // * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,\n // hence bindingContextsMayDifferFromDomParentElement is false\n // * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may\n // skip over any number of intermediate virtual elements, any of which might define a custom binding context,\n // hence bindingContextsMayDifferFromDomParentElement is true\n applyBindingsToDescendantsInternal(bindingContext, nodeVerified, asyncBindingsApplied)\n }\n}\n\n\nfunction * topologicalSortBindings (bindings, $component) {\n const results = []\n // Depth-first sort\n const bindingsConsidered = {} // A temporary record of which bindings are already in 'result'\n const cyclicDependencyStack = [] // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it\n\n objectForEach(bindings, function pushBinding (bindingKey) {\n if (!bindingsConsidered[bindingKey]) {\n const binding = getBindingHandlerFromComponent(bindingKey, $component) || getBindingHandler(bindingKey)\n if (!binding) { return }\n // First add dependencies (if any) of the current binding\n if (binding.after) {\n cyclicDependencyStack.push(bindingKey)\n arrayForEach(binding.after, function (bindingDependencyKey) {\n if (!bindings[bindingDependencyKey]) { return }\n if (arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {\n throw Error('Cannot combine the following bindings, because they have a cyclic dependency: ' + cyclicDependencyStack.join(', '))\n } else {\n pushBinding(bindingDependencyKey)\n }\n })\n cyclicDependencyStack.length--\n }\n // Next add the current binding\n results.push([ bindingKey, binding ])\n }\n bindingsConsidered[bindingKey] = true\n })\n\n for (const result of results) { yield result }\n}\n\nfunction applyBindingsToNodeInternal (node, sourceBindings, bindingContext, asyncBindingsApplied) {\n const bindingInfo = domData.getOrSet(node, boundElementDomDataKey, {})\n // Prevent multiple applyBindings calls for the same node, except when a binding value is specified\n const alreadyBound = bindingInfo.alreadyBound\n if (!sourceBindings) {\n if (alreadyBound) {\n if (!nodeOrChildHasBindings(node)) { return false }\n onBindingError({\n during: 'apply',\n errorCaptured: new Error('You cannot apply bindings multiple times to the same element.'),\n element: node,\n bindingContext\n })\n return false\n }\n bindingInfo.alreadyBound = true\n }\n\n if (!alreadyBound) {\n bindingInfo.context = bindingContext\n }\n\n // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings\n var bindings\n if (sourceBindings && typeof sourceBindings !== 'function') {\n bindings = sourceBindings\n } else {\n const provider = getBindingProvider()\n const getBindings = provider.getBindingAccessors\n\n if (isProviderForNode(provider, node)) {\n // Get the binding from the provider within a computed observable so that we can update the bindings whenever\n // the binding context is updated or if the binding provider accesses observables.\n var bindingsUpdater = computed(\n function () {\n bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext)\n // Register a dependency on the binding context to support observable view models.\n if (bindings && bindingContext[contextSubscribeSymbol]) { bindingContext[contextSubscribeSymbol]() }\n return bindings\n },\n null, { disposeWhenNodeIsRemoved: node }\n )\n\n if (!bindings || !bindingsUpdater.isActive()) { bindingsUpdater = null }\n }\n }\n\n var bindingHandlerThatControlsDescendantBindings\n if (bindings) {\n const $component = bindingContext.$component || {}\n\n const allBindingHandlers = {}\n domData.set(node, 'bindingHandlers', allBindingHandlers)\n\n // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding\n // context update), just return the value accessor from the binding. Otherwise, return a function that always gets\n // the latest binding value and registers a dependency on the binding updater.\n const getValueAccessor = bindingsUpdater\n ? (bindingKey) => function (optionalValue) {\n const valueAccessor = bindingsUpdater()[bindingKey]\n if (arguments.length === 0) {\n return evaluateValueAccessor(valueAccessor)\n } else {\n return valueAccessor(optionalValue)\n }\n } : (bindingKey) => bindings[bindingKey]\n\n // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated\n function allBindings () {\n return objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor)\n }\n\n // The following is the 3.x allBindings API\n allBindings.has = (key) => key in bindings\n allBindings.get = (key) => bindings[key] && evaluateValueAccessor(getValueAccessor(key))\n\n if (bindingEvent.childrenComplete in bindings) {\n bindingEvent.subscribe(node, bindingEvent.childrenComplete, () => {\n const callback = evaluateValueAccessor(bindings[bindingEvent.childrenComplete])\n if (!callback) { return }\n const nodes = virtualElements.childNodes(node)\n if (nodes.length) { callback(nodes, dataFor(nodes[0])) }\n })\n }\n\n const bindingsGenerated = topologicalSortBindings(bindings, $component)\n const nodeAsyncBindingPromises = new Set()\n for (const [key, BindingHandlerClass] of bindingsGenerated) {\n // Go through the sorted bindings, calling init and update for each\n function reportBindingError (during, errorCaptured) {\n onBindingError({\n during,\n errorCaptured,\n bindings,\n allBindings,\n bindingKey: key,\n bindingContext,\n element: node,\n valueAccessor: getValueAccessor(key)\n })\n }\n\n if (node.nodeType === 8 && !BindingHandlerClass.allowVirtualElements) {\n throw new Error(`The binding '${key}' cannot be used with virtual elements`)\n }\n\n try {\n const bindingHandler = dependencyDetection.ignore(() =>\n new BindingHandlerClass({\n allBindings,\n $element: node,\n $context: bindingContext,\n onError: reportBindingError,\n valueAccessor (...v) { return getValueAccessor(key)(...v) }\n })\n )\n\n if (bindingHandler.onValueChange) {\n dependencyDetection.ignore(() =>\n bindingHandler.computed('onValueChange')\n )\n }\n\n // Expose the bindings via domData.\n allBindingHandlers[key] = bindingHandler\n\n if (bindingHandler.controlsDescendants) {\n if (bindingHandlerThatControlsDescendantBindings !== undefined) { throw new Error('Multiple bindings (' + bindingHandlerThatControlsDescendantBindings + ' and ' + key + ') are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.') }\n bindingHandlerThatControlsDescendantBindings = key\n }\n\n if (bindingHandler.bindingCompleted instanceof Promise) {\n asyncBindingsApplied.add(bindingHandler.bindingCompleted)\n nodeAsyncBindingPromises.add(bindingHandler.bindingCompleted)\n }\n } catch (err) {\n reportBindingError('creation', err)\n }\n }\n\n triggerDescendantsComplete(node, bindings, nodeAsyncBindingPromises)\n }\n\n const shouldBindDescendants = bindingHandlerThatControlsDescendantBindings === undefined\n return { shouldBindDescendants }\n}\n\n/**\n *\n * @param {HTMLElement} node\n * @param {Object} bindings\n * @param {[Promise]} nodeAsyncBindingPromises\n */\nfunction triggerDescendantsComplete (node, bindings, nodeAsyncBindingPromises) {\n /** descendantsComplete ought to be an instance of the descendantsComplete\n * binding handler. */\n const hasBindingHandler = bindingEvent.descendantsComplete in bindings\n const hasFirstChild = virtualElements.firstChild(node)\n const accessor = hasBindingHandler && evaluateValueAccessor(bindings[bindingEvent.descendantsComplete])\n const callback = () => {\n bindingEvent.notify(node, bindingEvent.descendantsComplete)\n if (accessor && hasFirstChild) { accessor(node) }\n }\n if (nodeAsyncBindingPromises.size) {\n Promise.all(nodeAsyncBindingPromises).then(callback)\n } else {\n callback()\n }\n}\n\n\nfunction getBindingContext (viewModelOrBindingContext, extendContextCallback) {\n return viewModelOrBindingContext && (viewModelOrBindingContext instanceof bindingContext)\n ? viewModelOrBindingContext\n : new bindingContext(viewModelOrBindingContext, undefined, undefined, extendContextCallback)\n}\n\nexport function applyBindingAccessorsToNode (node, bindings, viewModelOrBindingContext, asyncBindingsApplied) {\n if (node.nodeType === 1) { // If it's an element, workaround IE <= 8 HTML parsing weirdness\n virtualElements.normaliseVirtualElementDomStructure(node)\n }\n return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext), asyncBindingsApplied)\n}\n\nexport function applyBindingsToNode (node, bindings, viewModelOrBindingContext) {\n const asyncBindingsApplied = new Set()\n const bindingContext = getBindingContext(viewModelOrBindingContext)\n const bindingAccessors = getBindingProvider().makeBindingAccessors(bindings, bindingContext, node)\n applyBindingAccessorsToNode(node, bindingAccessors, bindingContext, asyncBindingsApplied)\n return new BindingResult({asyncBindingsApplied, rootNode: node, bindingContext})\n}\n\nexport function applyBindingsToDescendants (viewModelOrBindingContext, rootNode) {\n const asyncBindingsApplied = new Set()\n if (rootNode.nodeType === 1 || rootNode.nodeType === 8) {\n const bindingContext = getBindingContext(viewModelOrBindingContext)\n applyBindingsToDescendantsInternal(bindingContext, rootNode, asyncBindingsApplied)\n return new BindingResult({asyncBindingsApplied, rootNode, bindingContext})\n }\n return new BindingResult({asyncBindingsApplied, rootNode})\n}\n\nexport function applyBindings (viewModelOrBindingContext, rootNode, extendContextCallback) {\n const asyncBindingsApplied = new Set()\n // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here.\n if (!options.jQuery === undefined && options.jQuery) {\n options.jQuery = options.jQuery\n }\n\n // rootNode is optional\n if (!rootNode) {\n rootNode = window.document.body\n if (!rootNode) {\n throw Error('ko.applyBindings: could not find window.document.body; has the document been loaded?')\n }\n } else if (rootNode.nodeType !== 1 && rootNode.nodeType !== 8) {\n throw Error('ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node')\n }\n const rootContext = getBindingContext(viewModelOrBindingContext, extendContextCallback)\n applyBindingsToNodeAndDescendantsInternal(rootContext, rootNode, asyncBindingsApplied)\n return Promise.all(asyncBindingsApplied)\n}\n\nfunction onBindingError (spec) {\n var error, bindingText\n if (spec.bindingKey) {\n // During: 'init' or initial 'update'\n error = spec.errorCaptured\n spec.message = 'Unable to process binding \"' + spec.bindingKey +\n '\" in binding \"' + spec.bindingKey +\n '\"\\nMessage: ' + (error.message ? error.message : error)\n } else {\n // During: 'apply'\n error = spec.errorCaptured\n }\n try {\n extend(error, spec)\n } catch (e) {\n // Read-only error e.g. a DOMEXception.\n spec.stack = error.stack\n error = new Error(error.message ? error.message : error)\n extend(error, spec)\n }\n options.onError(error)\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["/* eslint no-cond-assign: 0 */\n\nimport {\n extend,\n objectMap,\n virtualElements,\n tagNameLower,\n domData,\n objectForEach,\n arrayIndexOf,\n arrayForEach,\n options\n} from '@tko/utils'\n\nimport { dependencyDetection } from '@tko/observable'\n\nimport type { Observable } from '@tko/observable'\n\nimport { Computed, computed } from '@tko/computed'\n\nimport { dataFor, bindingContext, boundElementDomDataKey, contextSubscribeSymbol } from './bindingContext'\n\nimport { bindingEvent } from './bindingEvent'\n\nimport { BindingResult } from './BindingResult'\n\nimport { LegacyBindingHandler } from './LegacyBindingHandler'\n\nimport type { Provider } from '@tko/provider'\nimport type { BindingHandler, AllBindings } from './BindingHandler'\nimport type { BindingContext } from './bindingContext'\n\ninterface BindingError {\n during: string\n errorCaptured: Error\n bindings?: any\n allBindings?: AllBindings\n bindingKey?: string\n bindingContext: BindingContext\n element: Node\n valueAccessor?: Function\n message?: string\n stack?: any\n}\n\ntype BindingHandlerOrUndefined = (typeof BindingHandler & BindingHandler) | undefined\n\n// The following element types will not be recursed into during binding.\nconst bindingDoesNotRecurseIntoElementTypes = {\n // Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,\n // because it's unexpected and a potential XSS issue.\n // Also bindings should not operate on <template> elements since this breaks in Internet Explorer\n // and because such elements' contents are always intended to be bound in a different context\n // from where they appear in the document.\n script: true,\n textarea: true,\n template: true\n}\n\nfunction getBindingProvider(): Provider {\n return options.bindingProviderInstance.instance || options.bindingProviderInstance\n}\n\nfunction isProviderForNode(provider: Provider, node: Node): boolean {\n const nodeTypes = provider.FOR_NODE_TYPES || [Node.ELEMENT_NODE, Node.TEXT_NODE, Node.COMMENT_NODE]\n return nodeTypes.includes(node.nodeType)\n}\n\nfunction asProperHandlerClass(handler?: any, bindingKey?: string): BindingHandlerOrUndefined {\n if (!handler) {\n return\n }\n return handler.isBindingHandlerClass ? handler : LegacyBindingHandler.getOrCreateFor(bindingKey, handler)\n}\n\nfunction getBindingHandlerFromComponent(bindingKey: string, $component: any): BindingHandlerOrUndefined {\n if (!$component || typeof $component.getBindingHandler !== 'function') {\n return\n }\n return asProperHandlerClass($component.getBindingHandler(bindingKey))\n}\n\nexport function getBindingHandler(bindingKey: string): BindingHandlerOrUndefined {\n const bindingDefinition =\n options.getBindingHandler(bindingKey) || getBindingProvider().bindingHandlers.get(bindingKey)\n return asProperHandlerClass(bindingDefinition, bindingKey)\n}\n\n// Returns the value of a valueAccessor function\nfunction evaluateValueAccessor(valueAccessor: Function): any {\n return valueAccessor()\n}\n\nfunction applyBindingsToDescendantsInternal(\n bindingContext: BindingContext,\n elementOrVirtualElement: Node,\n asyncBindingsApplied: Set<any>\n) {\n let nextInQueue: ChildNode | null = virtualElements.firstChild(elementOrVirtualElement)\n\n if (!nextInQueue) {\n return\n }\n\n let currentChild: Node | null\n const provider = getBindingProvider()\n const preprocessNode = provider.preprocessNode\n\n // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's\n // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to\n // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that\n // trigger insertion of <template> contents at that point in the document.\n if (preprocessNode) {\n while ((currentChild = nextInQueue)) {\n nextInQueue = virtualElements.nextSibling(currentChild)\n preprocessNode.call(provider, currentChild)\n }\n\n // Reset nextInQueue for the next loop\n nextInQueue = virtualElements.firstChild(elementOrVirtualElement)\n }\n\n while ((currentChild = nextInQueue)) {\n // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position\n nextInQueue = virtualElements.nextSibling(currentChild)\n applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild, asyncBindingsApplied)\n }\n\n bindingEvent.notify(elementOrVirtualElement, bindingEvent.childrenComplete)\n}\n\nfunction hasBindings(node: Node): boolean | undefined {\n const provider = getBindingProvider()\n return isProviderForNode(provider, node) && provider.nodeHasBindings(node as Element)\n}\n\nfunction nodeOrChildHasBindings(node: Node): boolean {\n return hasBindings(node) || [...node.childNodes].some(c => nodeOrChildHasBindings(c))\n}\n\nfunction applyBindingsToNodeAndDescendantsInternal(\n bindingContext: BindingContext,\n nodeVerified: Node,\n asyncBindingsApplied\n) {\n const isElement = nodeVerified.nodeType === Node.ELEMENT_NODE\n if (isElement) {\n // Workaround IE <= 8 HTML parsing weirdness\n virtualElements.normaliseVirtualElementDomStructure(nodeVerified)\n }\n\n // Perf optimisation: Apply bindings only if...\n // (1) We need to store the binding info for the node (all element nodes)\n // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)\n\n const shouldApplyBindings =\n isElement // Case (1)\n || hasBindings(nodeVerified) // Case (2)\n\n const { shouldBindDescendants }: any = shouldApplyBindings\n ? applyBindingsToNodeInternal(nodeVerified, null, bindingContext, asyncBindingsApplied)\n : { shouldBindDescendants: true }\n\n if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[tagNameLower(nodeVerified as Element)]) {\n // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,\n // * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,\n // hence bindingContextsMayDifferFromDomParentElement is false\n // * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may\n // skip over any number of intermediate virtual elements, any of which might define a custom binding context,\n // hence bindingContextsMayDifferFromDomParentElement is true\n applyBindingsToDescendantsInternal(bindingContext, nodeVerified, asyncBindingsApplied)\n }\n}\n\nfunction* topologicalSortBindings(bindings: Record<string, any>, $component: any) {\n const results: [string, typeof BindingHandler][] = []\n // Depth-first sort\n const bindingsConsidered = {} // A temporary record of which bindings are already in 'result'\n const cyclicDependencyStack = new Array() // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it\n\n objectForEach(bindings, function pushBinding(bindingKey) {\n if (!bindingsConsidered[bindingKey]) {\n const binding = getBindingHandlerFromComponent(bindingKey, $component) || getBindingHandler(bindingKey)\n if (!binding) {\n return\n }\n // First add dependencies (if any) of the current binding\n if (binding.after) {\n cyclicDependencyStack.push(bindingKey)\n arrayForEach(binding.after, function (bindingDependencyKey) {\n if (!bindings[bindingDependencyKey]) {\n return\n }\n if (arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {\n throw Error(\n 'Cannot combine the following bindings, because they have a cyclic dependency: '\n + cyclicDependencyStack.join(', ')\n )\n } else {\n pushBinding(bindingDependencyKey)\n }\n })\n cyclicDependencyStack.length--\n }\n // Next add the current binding\n results.push([bindingKey, binding])\n }\n bindingsConsidered[bindingKey] = true\n })\n\n for (const result of results) {\n yield result\n }\n}\n\nfunction applyBindingsToNodeInternal<T>(\n node: Node,\n sourceBindings: Record<string, any> | null,\n bindingContext: BindingContext<T>,\n asyncBindingsApplied?: Set<any>\n) {\n const bindingInfo = domData.getOrSet(node, boundElementDomDataKey, {})\n // Prevent multiple applyBindings calls for the same node, except when a binding value is specified\n const alreadyBound = bindingInfo.alreadyBound\n if (!sourceBindings) {\n if (alreadyBound) {\n if (!nodeOrChildHasBindings(node)) {\n return false\n }\n onBindingError({\n during: 'apply',\n errorCaptured: new Error('You cannot apply bindings multiple times to the same element.'),\n element: node,\n bindingContext\n })\n return false\n }\n bindingInfo.alreadyBound = true\n }\n\n if (!alreadyBound) {\n bindingInfo.context = bindingContext\n }\n\n // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings\n let bindings: Record<string, any> | null = null\n let bindingsUpdater: Computed | null = null\n if (sourceBindings && typeof sourceBindings !== 'function') {\n bindings = sourceBindings\n } else {\n const provider = getBindingProvider()\n const getBindings = provider.getBindingAccessors\n\n if (isProviderForNode(provider, node)) {\n // Get the binding from the provider within a computed observable so that we can update the bindings whenever\n // the binding context is updated or if the binding provider accesses observables.\n bindingsUpdater = computed(\n function () {\n bindings = sourceBindings\n ? sourceBindings(bindingContext, node)\n : getBindings.call(provider, node, bindingContext)\n // Register a dependency on the binding context to support observable view models.\n if (bindings && bindingContext[contextSubscribeSymbol]) {\n bindingContext[contextSubscribeSymbol]()\n }\n return bindings\n },\n null,\n { disposeWhenNodeIsRemoved: node }\n )\n\n if (!bindings || !bindingsUpdater.isActive()) {\n bindingsUpdater = null\n }\n }\n }\n\n let bindingHandlerThatControlsDescendantBindings: string | undefined\n if (bindings) {\n const $component = bindingContext.$component || {}\n\n const allBindingHandlers = {}\n domData.set(node, 'bindingHandlers', allBindingHandlers)\n\n // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding\n // context update), just return the value accessor from the binding. Otherwise, return a function that always gets\n // the latest binding value and registers a dependency on the binding updater.\n const getValueAccessor = bindingsUpdater\n ? bindingKey =>\n function (optionalValue) {\n const valueAccessor = bindingsUpdater()[bindingKey]\n if (arguments.length === 0) {\n return evaluateValueAccessor(valueAccessor)\n } else {\n return valueAccessor(optionalValue)\n }\n }\n : bindingKey => bindings![bindingKey]\n\n // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated\n const allBindings: AllBindings = function (): any {\n return objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor)\n }\n\n // The following is the 3.x allBindings API\n allBindings.has = (key: string) => key in bindings!\n allBindings.get = (key: string) => bindings![key] && evaluateValueAccessor(getValueAccessor(key))\n\n if (bindingEvent.childrenComplete in bindings) {\n bindingEvent.subscribe(\n node,\n bindingEvent.childrenComplete,\n () => {\n const callback = evaluateValueAccessor(bindings![bindingEvent.childrenComplete])\n if (!callback) {\n return\n }\n const nodes = virtualElements.childNodes(node)\n if (nodes.length) {\n callback(nodes, dataFor(nodes[0]))\n }\n },\n null\n )\n }\n\n const bindingsGenerated = topologicalSortBindings(bindings, $component)\n const nodeAsyncBindingPromises = new Set<Promise<any>>()\n for (const [key, BindingHandlerClass] of bindingsGenerated) {\n // Go through the sorted bindings, calling init and update for each\n const reportBindingError = function (during: string, errorCaptured: Error) {\n onBindingError({\n during,\n errorCaptured,\n bindings,\n allBindings,\n bindingKey: key,\n bindingContext,\n element: node,\n valueAccessor: getValueAccessor(key)\n })\n }\n\n if (node.nodeType === Node.COMMENT_NODE && !BindingHandlerClass.allowVirtualElements) {\n throw new Error(`The binding '${key}' cannot be used with virtual elements`)\n }\n\n try {\n const bindingHandler = dependencyDetection.ignore(\n () =>\n new BindingHandlerClass({\n allBindings,\n $element: node,\n $context: bindingContext,\n onError: reportBindingError,\n valueAccessor(...v) {\n return getValueAccessor(key)(...v)\n }\n })\n )\n\n if (bindingHandler.onValueChange) {\n dependencyDetection.ignore(() => bindingHandler.computed('onValueChange'))\n }\n\n // Expose the bindings via domData.\n allBindingHandlers[key] = bindingHandler\n\n if (bindingHandler.controlsDescendants) {\n if (bindingHandlerThatControlsDescendantBindings !== undefined) {\n throw new Error(\n 'Multiple bindings ('\n + bindingHandlerThatControlsDescendantBindings\n + ' and '\n + key\n + ') are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.'\n )\n }\n bindingHandlerThatControlsDescendantBindings = key\n }\n\n if (bindingHandler.bindingCompleted instanceof Promise) {\n asyncBindingsApplied!.add(bindingHandler.bindingCompleted)\n nodeAsyncBindingPromises.add(bindingHandler.bindingCompleted)\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n reportBindingError('creation', error)\n }\n }\n\n triggerDescendantsComplete(node, bindings, nodeAsyncBindingPromises)\n }\n\n const shouldBindDescendants = bindingHandlerThatControlsDescendantBindings === undefined\n return { shouldBindDescendants }\n}\n\n/**\n *\n * @param {HTMLElement} node\n * @param {Object} bindings\n * @param {[Promise]} nodeAsyncBindingPromises\n */\nfunction triggerDescendantsComplete(node: Node, bindings: object, nodeAsyncBindingPromises: Set<Promise<any>>) {\n /** descendantsComplete ought to be an instance of the descendantsComplete\n * binding handler. */\n const hasBindingHandler = bindingEvent.descendantsComplete in bindings\n const hasFirstChild = virtualElements.firstChild(node)\n const accessor = hasBindingHandler && evaluateValueAccessor(bindings[bindingEvent.descendantsComplete])\n const callback = () => {\n bindingEvent.notify(node, bindingEvent.descendantsComplete)\n if (accessor && hasFirstChild) {\n accessor(node)\n }\n }\n if (nodeAsyncBindingPromises.size) {\n Promise.all(nodeAsyncBindingPromises).then(callback)\n } else {\n callback()\n }\n}\n\n// used in applyBinding, bindingContext.ts\nexport type BindingContextExtendCallback<T = any> = (\n self: BindingContext<T>,\n parentContext?: BindingContext<T>,\n dataItem?: T\n) => void\n\nfunction getBindingContext<T = any>(\n viewModelOrBindingContext: any,\n extendContextCallback?: BindingContextExtendCallback<T>\n): BindingContext<T> {\n return viewModelOrBindingContext && viewModelOrBindingContext instanceof bindingContext\n ? viewModelOrBindingContext\n : new bindingContext<T>(viewModelOrBindingContext, undefined, undefined, extendContextCallback)\n}\n\nexport function applyBindingAccessorsToNode<T = any>(\n node: HTMLElement,\n bindings: Record<string, any>,\n viewModelOrBindingContext?: BindingContext<T> | Observable<T> | T,\n asyncBindingsApplied?: Set<any>\n) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n // If it's an element, workaround IE <= 8 HTML parsing weirdness\n virtualElements.normaliseVirtualElementDomStructure(node)\n }\n return applyBindingsToNodeInternal<T>(\n node,\n bindings,\n getBindingContext(viewModelOrBindingContext),\n asyncBindingsApplied\n )\n}\n\nexport function applyBindingsToNode<T = any>(\n node: HTMLElement,\n bindings: Record<string, any>,\n viewModelOrBindingContext: BindingContext<T> | Observable<T> | T\n): BindingResult {\n const asyncBindingsApplied = new Set()\n const bindingContext = getBindingContext<T>(viewModelOrBindingContext)\n const bindingAccessors = getBindingProvider().makeBindingAccessors(bindings, bindingContext, node)\n applyBindingAccessorsToNode(node, bindingAccessors, bindingContext, asyncBindingsApplied)\n return new BindingResult({ asyncBindingsApplied, rootNode: node, bindingContext })\n}\n\nexport function applyBindingsToDescendants<T = any>(\n viewModelOrBindingContext: T | BindingContext<T>,\n rootNode: Node\n): BindingResult {\n const asyncBindingsApplied = new Set()\n const bindingContext = getBindingContext(viewModelOrBindingContext)\n if (rootNode.nodeType === Node.ELEMENT_NODE || rootNode.nodeType === Node.COMMENT_NODE) {\n applyBindingsToDescendantsInternal(bindingContext, rootNode, asyncBindingsApplied)\n return new BindingResult({ asyncBindingsApplied, rootNode, bindingContext })\n }\n return new BindingResult({ asyncBindingsApplied, rootNode, bindingContext })\n}\n\nexport function applyBindings<T = any>(\n viewModelOrBindingContext: BindingContext<T> | Observable<T> | T,\n rootNode: HTMLElement,\n extendContextCallback?: BindingContextExtendCallback<T>\n): Promise<unknown> {\n const asyncBindingsApplied = new Set()\n\n // rootNode is optional\n if (!rootNode) {\n rootNode = window.document.body\n if (!rootNode) {\n throw Error('ko.applyBindings: could not find window.document.body; has the document been loaded?')\n }\n } else if (rootNode.nodeType !== Node.ELEMENT_NODE && rootNode.nodeType !== Node.COMMENT_NODE) {\n throw Error('ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node')\n }\n const rootContext = getBindingContext<T>(viewModelOrBindingContext, extendContextCallback)\n applyBindingsToNodeAndDescendantsInternal(rootContext, rootNode, asyncBindingsApplied)\n return Promise.all(asyncBindingsApplied)\n}\n\nfunction onBindingError(spec: BindingError) {\n let error: Error\n if (spec.bindingKey) {\n // During: 'init' or initial 'update'\n error = spec.errorCaptured\n spec.message =\n 'Unable to process binding \"'\n + spec.bindingKey\n + '\" in binding \"'\n + spec.bindingKey\n + '\"\\nMessage: '\n + (error.message ? error.message : error)\n } else {\n // During: 'apply'\n error = spec.errorCaptured\n }\n try {\n extend(error, spec)\n } catch (e: any) {\n // Read-only error e.g. a DOMEXception.\n spec.stack = error.stack\n\n const message = error.message || String(error)\n const originalName = error.name\n error = new Error(message)\n if (originalName && originalName !== 'Error') {\n error.name = originalName\n }\n extend(error, spec)\n }\n options.onError(error)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["bindingContext"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// @tko/bind 🥊 4.0.0
|
|
1
|
+
// @tko/bind 🥊 4.0.0 ESM
|
|
2
|
+
"use strict";
|
|
2
3
|
import {
|
|
3
4
|
fixUpContinuousNodeArray,
|
|
4
5
|
replaceDomNodes,
|
|
@@ -13,47 +14,54 @@ import {
|
|
|
13
14
|
removeNode,
|
|
14
15
|
compareArrays
|
|
15
16
|
} from "@tko/utils";
|
|
16
|
-
import {
|
|
17
|
-
dependencyDetection,
|
|
18
|
-
observable
|
|
19
|
-
} from "@tko/observable";
|
|
17
|
+
import { dependencyDetection, observable } from "@tko/observable";
|
|
20
18
|
import { computed } from "@tko/computed";
|
|
21
19
|
function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
const mappedNodes = [];
|
|
21
|
+
const dependentObservable = computed(
|
|
22
|
+
function() {
|
|
23
|
+
const newMappedNodes = mapping(valueToMap, index, fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];
|
|
24
|
+
if (mappedNodes.length > 0) {
|
|
25
|
+
replaceDomNodes(mappedNodes, newMappedNodes);
|
|
26
|
+
if (callbackAfterAddingNodes) {
|
|
27
|
+
dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
mappedNodes.length = 0;
|
|
31
|
+
arrayPushAll(mappedNodes, newMappedNodes);
|
|
32
|
+
},
|
|
33
|
+
null,
|
|
34
|
+
{
|
|
35
|
+
disposeWhenNodeIsRemoved: containerNode,
|
|
36
|
+
disposeWhen: function() {
|
|
37
|
+
return !anyDomNodeIsAttachedToDocument(mappedNodes);
|
|
29
38
|
}
|
|
30
39
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
return { mappedNodes, dependentObservable: dependentObservable.isActive() ? dependentObservable : void 0 };
|
|
40
|
+
);
|
|
41
|
+
return {
|
|
42
|
+
mappedNodes,
|
|
43
|
+
dependentObservable: dependentObservable.isActive() ? dependentObservable : void 0
|
|
44
|
+
};
|
|
37
45
|
}
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
const lastMappingResultDomDataKey = domData.nextKey();
|
|
47
|
+
const deletedItemDummyValue = domData.nextKey();
|
|
40
48
|
export function setDomNodeChildrenFromArrayMapping(domNode, array, mapping, options, callbackAfterAddingNodes, editScript) {
|
|
41
49
|
array = array || [];
|
|
42
50
|
if (typeof array.length === "undefined") {
|
|
43
51
|
array = [array];
|
|
44
52
|
}
|
|
45
53
|
options = options || {};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const lastMappingResult = domData.get(domNode, lastMappingResultDomDataKey);
|
|
55
|
+
const isFirstExecution = !lastMappingResult;
|
|
56
|
+
const newMappingResult = new Array();
|
|
57
|
+
let lastMappingResultIndex = 0;
|
|
58
|
+
let newMappingResultIndex = 0;
|
|
59
|
+
const nodesToDelete = [];
|
|
60
|
+
const itemsToProcess = [];
|
|
61
|
+
const itemsForBeforeRemoveCallbacks = [];
|
|
62
|
+
const itemsForMoveCallbacks = [];
|
|
63
|
+
const itemsForAfterAddCallbacks = [];
|
|
64
|
+
let mapData;
|
|
57
65
|
let countWaitingForRemove = 0;
|
|
58
66
|
function itemAdded(value) {
|
|
59
67
|
mapData = { arrayEntry: value, indexObservable: observable(newMappingResultIndex++) };
|
|
@@ -75,9 +83,9 @@ export function setDomNodeChildrenFromArrayMapping(domNode, array, mapping, opti
|
|
|
75
83
|
}
|
|
76
84
|
function callCallback(callback, items) {
|
|
77
85
|
if (callback) {
|
|
78
|
-
for (
|
|
79
|
-
arrayForEach(items[
|
|
80
|
-
callback(
|
|
86
|
+
for (let i = 0, n = items.length; i < n; i++) {
|
|
87
|
+
arrayForEach(items[i].mappedNodes, function(node) {
|
|
88
|
+
callback(node, i, items[i].arrayEntry);
|
|
81
89
|
});
|
|
82
90
|
}
|
|
83
91
|
}
|
|
@@ -86,16 +94,13 @@ export function setDomNodeChildrenFromArrayMapping(domNode, array, mapping, opti
|
|
|
86
94
|
arrayForEach(array, itemAdded);
|
|
87
95
|
} else {
|
|
88
96
|
if (!editScript || lastMappingResult && lastMappingResult["_countWaitingForRemove"]) {
|
|
89
|
-
|
|
97
|
+
const lastArray = arrayMap(lastMappingResult, function(x) {
|
|
90
98
|
return x.arrayEntry;
|
|
91
99
|
});
|
|
92
|
-
|
|
93
|
-
"dontLimitMoves": options["dontLimitMoves"],
|
|
94
|
-
"sparse": true
|
|
95
|
-
};
|
|
100
|
+
const compareOptions = { dontLimitMoves: options.dontLimitMoves, sparse: true };
|
|
96
101
|
editScript = compareArrays(lastArray, array, compareOptions);
|
|
97
102
|
}
|
|
98
|
-
for (
|
|
103
|
+
for (let i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {
|
|
99
104
|
movedIndex = editScriptItem["moved"];
|
|
100
105
|
itemIndex = editScriptItem["index"];
|
|
101
106
|
switch (editScriptItem["status"]) {
|
|
@@ -110,7 +115,7 @@ export function setDomNodeChildrenFromArrayMapping(domNode, array, mapping, opti
|
|
|
110
115
|
mapData.dependentObservable = void 0;
|
|
111
116
|
}
|
|
112
117
|
if (fixUpContinuousNodeArray(mapData.mappedNodes, domNode).length) {
|
|
113
|
-
if (options
|
|
118
|
+
if (options.beforeRemove) {
|
|
114
119
|
newMappingResult.push(mapData);
|
|
115
120
|
itemsToProcess.push(mapData);
|
|
116
121
|
countWaitingForRemove++;
|
|
@@ -120,7 +125,7 @@ export function setDomNodeChildrenFromArrayMapping(domNode, array, mapping, opti
|
|
|
120
125
|
itemsForBeforeRemoveCallbacks.push(mapData);
|
|
121
126
|
}
|
|
122
127
|
}
|
|
123
|
-
if (mapData) {
|
|
128
|
+
if (mapData?.mappedNodes) {
|
|
124
129
|
nodesToDelete.push.apply(nodesToDelete, mapData.mappedNodes);
|
|
125
130
|
}
|
|
126
131
|
}
|
|
@@ -145,14 +150,22 @@ export function setDomNodeChildrenFromArrayMapping(domNode, array, mapping, opti
|
|
|
145
150
|
newMappingResult["_countWaitingForRemove"] = countWaitingForRemove;
|
|
146
151
|
}
|
|
147
152
|
domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
|
|
148
|
-
callCallback(options
|
|
149
|
-
arrayForEach(nodesToDelete, options
|
|
150
|
-
|
|
151
|
-
for (var nextNode = virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
|
|
153
|
+
callCallback(options.beforeMove, itemsForMoveCallbacks);
|
|
154
|
+
arrayForEach(nodesToDelete, options.beforeRemove ? cleanNode : removeNode);
|
|
155
|
+
for (let k = 0, nextNode = virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[k]; k++) {
|
|
152
156
|
if (!mapData.mappedNodes) {
|
|
153
|
-
extend(
|
|
157
|
+
extend(
|
|
158
|
+
mapData,
|
|
159
|
+
mapNodeAndRefreshWhenChanged(
|
|
160
|
+
domNode,
|
|
161
|
+
mapping,
|
|
162
|
+
mapData.arrayEntry,
|
|
163
|
+
callbackAfterAddingNodes,
|
|
164
|
+
mapData.indexObservable
|
|
165
|
+
)
|
|
166
|
+
);
|
|
154
167
|
}
|
|
155
|
-
for (
|
|
168
|
+
for (let j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
|
|
156
169
|
if (node !== nextNode) {
|
|
157
170
|
virtualElements.insertAfter(domNode, node, lastNode);
|
|
158
171
|
}
|
|
@@ -162,10 +175,10 @@ export function setDomNodeChildrenFromArrayMapping(domNode, array, mapping, opti
|
|
|
162
175
|
mapData.initialized = true;
|
|
163
176
|
}
|
|
164
177
|
}
|
|
165
|
-
callCallback(options
|
|
166
|
-
for (
|
|
167
|
-
itemsForBeforeRemoveCallbacks[
|
|
178
|
+
callCallback(options.beforeRemove, itemsForBeforeRemoveCallbacks);
|
|
179
|
+
for (let x = 0; x < itemsForBeforeRemoveCallbacks.length; ++x) {
|
|
180
|
+
itemsForBeforeRemoveCallbacks[x].arrayEntry = deletedItemDummyValue;
|
|
168
181
|
}
|
|
169
|
-
callCallback(options
|
|
170
|
-
callCallback(options
|
|
182
|
+
callCallback(options.afterMove, itemsForMoveCallbacks);
|
|
183
|
+
callCallback(options.afterAdd, itemsForAfterAddCallbacks);
|
|
171
184
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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": "
|
|
4
|
+
"sourcesContent": ["/* eslint no-cond-assign: 0 */\nimport {\n fixUpContinuousNodeArray,\n replaceDomNodes,\n arrayPushAll,\n anyDomNodeIsAttachedToDocument,\n domData,\n arrayMap,\n arrayForEach,\n virtualElements,\n extend,\n cleanNode,\n removeNode,\n compareArrays\n} from '@tko/utils'\n\nimport { dependencyDetection, observable } from '@tko/observable'\n\nimport type { Observable } from '@tko/observable'\n\nimport { computed } from '@tko/computed'\n\nimport type { Computed } from '@tko/computed'\n\ntype MappingFunction<T = any> = (valueToMap: T, index: number | Observable<number>, nodes: Node[]) => Node[]\ntype MappingAfterAddFunction<T = any> = (arrayEntry: T, nodes: Node[], index: Observable<number>) => Node[]\ntype MappingHookFunction<T = any> = (nodes: Node[], index: number, arrayEntry: T) => void\n\ninterface MappingOptions<T = any> {\n dontLimitMoves?: boolean\n beforeMove?: MappingHookFunction<T>\n beforeRemove?: MappingHookFunction<T>\n afterAdd?: MappingHookFunction<T>\n afterMove?: MappingHookFunction<T>\n afterRemove?: MappingHookFunction<T>\n sparse?: boolean\n}\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(\n containerNode: Node,\n mapping: MappingFunction,\n valueToMap: any,\n callbackAfterAddingNodes: MappingAfterAddFunction | undefined,\n index: number | Observable<number>\n) {\n // Map this array value inside a dependentObservable so we re-map when any dependency changes\n const mappedNodes: Node[] = []\n const dependentObservable: Computed<void> = computed(\n function () {\n const newMappedNodes: Node[] =\n 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) {\n dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index])\n }\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 },\n null,\n {\n disposeWhenNodeIsRemoved: containerNode,\n disposeWhen: function () {\n return !anyDomNodeIsAttachedToDocument(mappedNodes)\n }\n }\n )\n return {\n mappedNodes: mappedNodes,\n dependentObservable: dependentObservable.isActive() ? dependentObservable : undefined\n }\n}\n\nconst lastMappingResultDomDataKey = domData.nextKey()\nconst deletedItemDummyValue = domData.nextKey()\n\nexport function setDomNodeChildrenFromArrayMapping<T = any>(\n domNode: Node,\n array: any,\n mapping: MappingFunction<T>,\n options?: MappingOptions<T>,\n callbackAfterAddingNodes?: MappingAfterAddFunction<T> | ((...params: any) => any),\n editScript?: any[]\n) {\n // Compare the provided array against the previous one\n array = array || []\n if (typeof array.length === 'undefined') {\n array = [array]\n }\n\n options = options || {}\n const lastMappingResult = domData.get(domNode, lastMappingResultDomDataKey)\n const isFirstExecution = !lastMappingResult\n\n // Build the new mapping result\n const newMappingResult = new Array()\n let lastMappingResultIndex = 0\n let newMappingResultIndex = 0\n\n const nodesToDelete: Node[] = []\n const itemsToProcess: MapDataType[] = []\n const itemsForBeforeRemoveCallbacks: MapDataType[] = []\n const itemsForMoveCallbacks: MapDataType[] = []\n const itemsForAfterAddCallbacks: MapDataType[] = []\n let mapData: MapDataType | null\n let countWaitingForRemove = 0\n\n type MapDataType = {\n arrayEntry: any\n indexObservable: Observable<number>\n mappedNodes?: Node[]\n dependentObservable?: Computed<void>\n initialized?: boolean\n }\n\n function itemAdded(value: any) {\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: number) {\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: MappingHookFunction<T> | undefined, items: any[]) {\n if (callback) {\n for (let 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 const lastArray = arrayMap(lastMappingResult, function (x) {\n return x.arrayEntry\n })\n const compareOptions = { dontLimitMoves: options.dontLimitMoves, sparse: true }\n editScript = compareArrays(lastArray, array, compareOptions)\n }\n\n for (\n let i = 0, editScriptItem: number[], movedIndex: number, itemIndex: number;\n (editScriptItem = editScript[i]);\n i++\n ) {\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?.mappedNodes) {\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 for (let k = 0, nextNode = virtualElements.firstChild(domNode), lastNode, node; (mapData = itemsToProcess[k]); k++) {\n // Get nodes for newly added items\n if (!mapData.mappedNodes) {\n extend(\n mapData,\n mapNodeAndRefreshWhenChanged(\n domNode,\n mapping,\n mapData.arrayEntry,\n callbackAfterAddingNodes,\n mapData.indexObservable\n )\n )\n }\n\n // Put nodes in the right place if they aren't there already\n for (let j = 0; (node = mapData.mappedNodes![j]); nextNode = node.nextSibling, lastNode = node, j++) {\n if (node !== nextNode) {\n virtualElements.insertAfter(domNode, node, lastNode)\n }\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 (let x = 0; x < itemsForBeforeRemoveCallbacks.length; ++x) {\n itemsForBeforeRemoveCallbacks[x].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
6
|
"names": []
|
|
7
7
|
}
|
package/dist/bindingContext.js
CHANGED
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
// @tko/bind 🥊 4.0.0
|
|
1
|
+
// @tko/bind 🥊 4.0.0 ESM
|
|
2
|
+
"use strict";
|
|
2
3
|
import { extend, options, domData, isObjectLike } from "@tko/utils";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
} from "
|
|
6
|
-
import {
|
|
7
|
-
unwrap,
|
|
8
|
-
isObservable
|
|
9
|
-
} from "@tko/observable";
|
|
10
|
-
import {
|
|
11
|
-
contextAncestorBindingInfo
|
|
12
|
-
} from "./bindingEvent";
|
|
4
|
+
import { pureComputed } from "@tko/computed";
|
|
5
|
+
import { unwrap, isObservable } from "@tko/observable";
|
|
6
|
+
import { contextAncestorBindingInfo } from "./bindingEvent";
|
|
13
7
|
export const boundElementDomDataKey = domData.nextKey();
|
|
14
|
-
export const contextSubscribeSymbol = Symbol("Knockout Context Subscription");
|
|
15
|
-
const inheritParentIndicator = Symbol("Knockout Parent Indicator");
|
|
16
|
-
export function
|
|
8
|
+
export const contextSubscribeSymbol = /* @__PURE__ */ Symbol("Knockout Context Subscription");
|
|
9
|
+
const inheritParentIndicator = /* @__PURE__ */ Symbol("Knockout Parent Indicator");
|
|
10
|
+
export const bindingContext = function bindingContextFactory(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, settings) {
|
|
17
11
|
const self = this;
|
|
18
12
|
const shouldInheritData = dataItemOrAccessor === inheritParentIndicator;
|
|
19
13
|
const realDataItemOrAccessor = shouldInheritData ? void 0 : dataItemOrAccessor;
|
|
20
14
|
const isFunc = typeof realDataItemOrAccessor === "function" && !isObservable(realDataItemOrAccessor);
|
|
21
15
|
self.ko = options.knockoutInstance;
|
|
22
|
-
let nodes;
|
|
23
16
|
let subscribable;
|
|
24
17
|
function updateContext() {
|
|
25
18
|
const dataItemOrObservable = isFunc ? realDataItemOrAccessor() : realDataItemOrAccessor;
|
|
@@ -33,7 +26,7 @@ export function bindingContext(dataItemOrAccessor, parentContext, dataItemAlias,
|
|
|
33
26
|
self[contextAncestorBindingInfo] = parentContext[contextAncestorBindingInfo];
|
|
34
27
|
}
|
|
35
28
|
} else {
|
|
36
|
-
self.$parents =
|
|
29
|
+
self.$parents = new Array();
|
|
37
30
|
self.$root = dataItem;
|
|
38
31
|
}
|
|
39
32
|
self[contextSubscribeSymbol] = subscribable;
|
|
@@ -63,7 +56,7 @@ export function bindingContext(dataItemOrAccessor, parentContext, dataItemAlias,
|
|
|
63
56
|
self[contextSubscribeSymbol] = void 0;
|
|
64
57
|
}
|
|
65
58
|
}
|
|
66
|
-
}
|
|
59
|
+
};
|
|
67
60
|
Object.assign(bindingContext.prototype, {
|
|
68
61
|
lookup(token, globals, node) {
|
|
69
62
|
switch (token) {
|
|
@@ -87,24 +80,38 @@ Object.assign(bindingContext.prototype, {
|
|
|
87
80
|
}
|
|
88
81
|
throw new Error(`The variable "${token}" was not found on $data, $context, or globals.`);
|
|
89
82
|
},
|
|
83
|
+
// Extend the binding context hierarchy with a new view model object. If the parent context is watching
|
|
84
|
+
// any observables, the new child context will automatically get a dependency on the parent context.
|
|
85
|
+
// But this does not mean that the $data value of the child context will also get updated. If the child
|
|
86
|
+
// view model also depends on the parent view model, you must provide a function that returns the correct
|
|
87
|
+
// view model on each update.
|
|
90
88
|
createChildContext(dataItemOrAccessor, dataItemAlias, extendCallback, settings) {
|
|
91
|
-
return new bindingContext(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
89
|
+
return new bindingContext(
|
|
90
|
+
dataItemOrAccessor,
|
|
91
|
+
this,
|
|
92
|
+
dataItemAlias,
|
|
93
|
+
function(self, parentContext) {
|
|
94
|
+
self.$parentContext = parentContext;
|
|
95
|
+
self.$parent = parentContext?.$data;
|
|
96
|
+
self.$parents = (parentContext?.$parents ?? []).slice(0);
|
|
97
|
+
self.$parents.unshift(self.$parent);
|
|
98
|
+
if (extendCallback) {
|
|
99
|
+
extendCallback(self);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
settings
|
|
103
|
+
);
|
|
100
104
|
},
|
|
105
|
+
// Extend the binding context with new custom properties. This doesn't change the context hierarchy.
|
|
106
|
+
// Similarly to "child" contexts, provide a function here to make sure that the correct values are set
|
|
107
|
+
// when an observable view model is updated.
|
|
101
108
|
extend(properties) {
|
|
102
|
-
return new bindingContext(inheritParentIndicator, this,
|
|
109
|
+
return new bindingContext(inheritParentIndicator, this, void 0, function(self, parentContext) {
|
|
103
110
|
extend(self, typeof properties === "function" ? properties.call(self) : properties);
|
|
104
111
|
});
|
|
105
112
|
},
|
|
106
113
|
createStaticChildContext(dataItemOrAccessor, dataItemAlias) {
|
|
107
|
-
return this.createChildContext(dataItemOrAccessor, dataItemAlias, null, {
|
|
114
|
+
return this.createChildContext(dataItemOrAccessor, dataItemAlias, null, { exportDependencies: true });
|
|
108
115
|
}
|
|
109
116
|
});
|
|
110
117
|
export function storedBindingContextForNode(node) {
|
|
@@ -112,11 +119,11 @@ export function storedBindingContextForNode(node) {
|
|
|
112
119
|
return bindingInfo && bindingInfo.context;
|
|
113
120
|
}
|
|
114
121
|
export function contextFor(node) {
|
|
115
|
-
if (node && (node.nodeType ===
|
|
122
|
+
if (node && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.COMMENT_NODE)) {
|
|
116
123
|
return storedBindingContextForNode(node);
|
|
117
124
|
}
|
|
118
125
|
}
|
|
119
126
|
export function dataFor(node) {
|
|
120
|
-
|
|
127
|
+
const context = contextFor(node);
|
|
121
128
|
return context ? context.$data : void 0;
|
|
122
129
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/bindingContext.ts"],
|
|
4
|
-
"sourcesContent": ["import { extend, options, domData, isObjectLike } from '@tko/utils'\n\nimport {
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { extend, options, domData, isObjectLike } from '@tko/utils'\nimport type { KnockoutInstance } from '@tko/builder'\n\nimport { pureComputed } from '@tko/computed'\n\nimport { unwrap, isObservable } from '@tko/observable'\n\nimport type { Observable } from '@tko/observable'\n\nimport { contextAncestorBindingInfo } from './bindingEvent'\n\nimport { BindingContextExtendCallback } from './applyBindings'\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\nexport interface BindingContextSetting {\n exportDependencies?: boolean\n}\n\nexport interface BindingContext<T = any> {\n ko: KnockoutInstance\n\n [symbol: symbol]: any\n $parent?: any\n $parents: any[]\n $root: any\n $data: T\n $rawData: T | Observable<T>\n $index?: Observable<number>\n $parentContext?: BindingContext<any>\n // $componentTemplateNodes: any; added in makeChildBindingContext to context\n // $componentTemplateSlotNodes; added in makeChildBindingContext to context\n\n $component?: any\n\n extend(properties: object): BindingContext<T>\n extend(properties: (self: BindingContext<T>) => object): BindingContext<T>\n\n lookup(token: string, globals: any, node: any)\n\n createChildContext(\n dataItemOrAccessor: any,\n dataItemAlias?: string,\n extendCallback?: Function,\n settings?: BindingContextSetting\n ): BindingContext\n createStaticChildContext(dataItemOrAccessor: any, dataItemAlias: any): BindingContext\n}\n\n// Interface for the factory method 'bindingContext', which creates and returns a typed instance of BindingContext<T>\nexport interface bindingContext {\n new <T = any>(\n dataItemOrAccessor: any,\n parentContext?: BindingContext,\n dataItemAlias?: string,\n extendCallback?: BindingContextExtendCallback,\n settings?: BindingContextSetting\n ): BindingContext<T>\n}\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 const bindingContext = function bindingContextFactory<T>(\n dataItemOrAccessor: any,\n parentContext?: BindingContext,\n dataItemAlias?: string,\n extendCallback?: BindingContextExtendCallback<T>,\n settings?: BindingContextSetting\n) {\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 subscribable: any\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 = new Array()\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) {\n self[dataItemAlias] = dataItem\n }\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) {\n extendCallback(self, parentContext, dataItem)\n }\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} as unknown as bindingContext\n\nObject.assign(bindingContext.prototype, {\n lookup(token: string, globals: any, node: any) {\n // short circuits\n switch (token) {\n case '$element':\n return node\n case '$context':\n return this\n case 'this':\n case '$data':\n 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) {\n return $data[token]\n }\n if (token in this) {\n return this[token]\n }\n if (token in globals) {\n return globals[token]\n }\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(\n dataItemOrAccessor: any,\n dataItemAlias?: string,\n extendCallback?: BindingContextExtendCallback,\n settings?: BindingContextSetting\n ): BindingContext {\n return new bindingContext(\n dataItemOrAccessor,\n this,\n dataItemAlias,\n 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) {\n extendCallback(self)\n }\n },\n settings\n )\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, undefined, function (self, parentContext) {\n extend(self, typeof properties === 'function' ? properties.call(self) : properties)\n })\n },\n\n createStaticChildContext(dataItemOrAccessor: any, dataItemAlias: any): BindingContext {\n return this.createChildContext(dataItemOrAccessor, dataItemAlias, null, { exportDependencies: true })\n }\n})\n\nexport function storedBindingContextForNode(node: 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: 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 === Node.ELEMENT_NODE || node.nodeType === Node.COMMENT_NODE)) {\n return storedBindingContextForNode(node)\n }\n}\n\nexport function dataFor<T = any>(node: Node): T | undefined {\n const context = contextFor(node)\n return context ? context.$data : undefined\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|