KnockoutJS don't scramble exportDependencies. controlsDescendantBindings, createChildContext

This commit is contained in:
the-djmaze 2024-03-03 19:10:00 +01:00
parent a8e38a998f
commit 766d3eaa98
8 changed files with 16 additions and 16 deletions

View file

@ -78,7 +78,7 @@ ko.bindingContext = class {
return self['$data']; return self['$data'];
}; };
if (options?.exportDependencies) { if (options?.['exportDependencies']) {
// The "exportDependencies" option means that the calling code will track any dependencies and re-create // The "exportDependencies" option means that the calling code will track any dependencies and re-create
// the binding context when they change. // the binding context when they change.
updateContext(); updateContext();
@ -104,7 +104,7 @@ ko.bindingContext = class {
// But this does not mean that the $data value of the child context will also get updated. If the child // But this does not mean that the $data value of the child context will also get updated. If the child
// view model also depends on the parent view model, you must provide a function that returns the correct // view model also depends on the parent view model, you must provide a function that returns the correct
// view model on each update. // view model on each update.
createChildContext(dataItemOrAccessor, options) { 'createChildContext'(dataItemOrAccessor, options) {
return new ko.bindingContext(dataItemOrAccessor, this, (self, parentContext) => { return new ko.bindingContext(dataItemOrAccessor, this, (self, parentContext) => {
// Extend the context hierarchy by setting the appropriate pointers // Extend the context hierarchy by setting the appropriate pointers
self['$parentContext'] = parentContext; self['$parentContext'] = parentContext;
@ -380,7 +380,7 @@ function applyBindingsToNodeInternal(node, sourceBindings, bindingContext) {
var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend); var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);
// If this binding handler claims to control descendant bindings, make a note of this // If this binding handler claims to control descendant bindings, make a note of this
if (initResult && initResult.controlsDescendantBindings) { if (initResult && initResult['controlsDescendantBindings']) {
if (bindingHandlerThatControlsDescendantBindings !== undefined) if (bindingHandlerThatControlsDescendantBindings !== undefined)
throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element."); throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
bindingHandlerThatControlsDescendantBindings = bindingKey; bindingHandlerThatControlsDescendantBindings = bindingKey;

View file

@ -1,7 +1,7 @@
ko.bindingHandlers['html'] = { ko.bindingHandlers['html'] = {
'init': () => ( 'init': () => (
// Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications) // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
{ controlsDescendantBindings: true } { 'controlsDescendantBindings': true }
), ),
'update': (element, valueAccessor) => { 'update': (element, valueAccessor) => {
// setHtml will unwrap the value if needed // setHtml will unwrap the value if needed

View file

@ -7,7 +7,7 @@ function makeWithIfBinding(bindingKey, isWith, isNot) {
var savedNodes, contextOptions = {}, needAsyncContext; var savedNodes, contextOptions = {}, needAsyncContext;
if (isWith) { if (isWith) {
contextOptions = { exportDependencies: true }; contextOptions = { 'exportDependencies': true };
} }
needAsyncContext = allBindings['has'](ko.bindingEvent.descendantsComplete); needAsyncContext = allBindings['has'](ko.bindingEvent.descendantsComplete);
@ -26,7 +26,7 @@ function makeWithIfBinding(bindingKey, isWith, isNot) {
contextOptions['dataDependency'] = ko.dependencyDetection.computed(); contextOptions['dataDependency'] = ko.dependencyDetection.computed();
childContext = isWith childContext = isWith
? bindingContext.createChildContext(typeof value == "function" ? value : valueAccessor, contextOptions) ? bindingContext['createChildContext'](typeof value == "function" ? value : valueAccessor, contextOptions)
: (ko.dependencyDetection.getDependenciesCount() : (ko.dependencyDetection.getDependenciesCount()
? bindingContext['extend'](null, contextOptions) ? bindingContext['extend'](null, contextOptions)
: bindingContext : bindingContext
@ -50,7 +50,7 @@ function makeWithIfBinding(bindingKey, isWith, isNot) {
}, { disposeWhenNodeIsRemoved: element }); }, { disposeWhenNodeIsRemoved: element });
return { controlsDescendantBindings: true }; return { 'controlsDescendantBindings': true };
} }
}; };
ko.virtualElements.allowedBindings[bindingKey] = true; ko.virtualElements.allowedBindings[bindingKey] = true;

View file

@ -11,7 +11,7 @@ ko.bindingHandlers['options'] = {
} }
// Ensures that the binding processor doesn't try to bind the options // Ensures that the binding processor doesn't try to bind the options
return { controlsDescendantBindings: true }; return { 'controlsDescendantBindings': true };
}, },
'update': (element, valueAccessor, allBindings) => { 'update': (element, valueAccessor, allBindings) => {

View file

@ -2,7 +2,7 @@ ko.bindingHandlers['text'] = {
'init': () => ( 'init': () => (
// Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications). // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).
// It should also make things faster, as we no longer have to consider whether the text node might be bindable. // It should also make things faster, as we no longer have to consider whether the text node might be bindable.
{ controlsDescendantBindings: true } { 'controlsDescendantBindings': true }
), ),
'update': (element, valueAccessor) => { 'update': (element, valueAccessor) => {
if (8 === element.nodeType) { if (8 === element.nodeType) {

View file

@ -59,12 +59,12 @@
currentViewModel = componentDefinition['createViewModel'](componentParams, { currentViewModel = componentDefinition['createViewModel'](componentParams, {
'element': element 'element': element
}); });
ko.applyBindingsToDescendants(asyncContext.createChildContext(currentViewModel, {}), element); ko.applyBindingsToDescendants(asyncContext['createChildContext'](currentViewModel, {}), element);
} }
}); });
}, { disposeWhenNodeIsRemoved: element }); }, { disposeWhenNodeIsRemoved: element });
return { controlsDescendantBindings: true }; return { 'controlsDescendantBindings': true };
} }
}; };

View file

@ -25,7 +25,7 @@ ko.computed = (evaluatorFunctionOrOptions, options) => {
pure: false, pure: false,
isSleeping: false, isSleeping: false,
readFunction: options["read"], readFunction: options["read"],
disposeWhenNodeIsRemoved: options.disposeWhenNodeIsRemoved, disposeWhenNodeIsRemoved: options.disposeWhenNodeIsRemoved || null,
disposeWhen: options.disposeWhen, disposeWhen: options.disposeWhen,
domNodeDisposalCallback: null, domNodeDisposalCallback: null,
dependencyTracking: {}, dependencyTracking: {},

View file

@ -102,7 +102,7 @@
// Ensure we've got a proper binding context to work with // Ensure we've got a proper binding context to work with
var bindingContext = (dataOrBindingContext instanceof ko.bindingContext) var bindingContext = (dataOrBindingContext instanceof ko.bindingContext)
? dataOrBindingContext ? dataOrBindingContext
: new ko.bindingContext(dataOrBindingContext, null, null, { exportDependencies: true }); : new ko.bindingContext(dataOrBindingContext, null, null, { "exportDependencies": true });
var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext); var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext);
executeTemplate(targetNodeOrNodeArray, true, templateName, bindingContext, options); executeTemplate(targetNodeOrNodeArray, true, templateName, bindingContext, options);
@ -122,7 +122,7 @@
// This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
var executeTemplateForArrayItem = (arrayValue, index) => { var executeTemplateForArrayItem = (arrayValue, index) => {
// Support selecting template as a function of the data being rendered // Support selecting template as a function of the data being rendered
arrayItemContext = parentBindingContext.createChildContext(arrayValue, { arrayItemContext = parentBindingContext['createChildContext'](arrayValue, {
'extend': context => context['$index'] = index 'extend': context => context['$index'] = index
}); });
@ -247,8 +247,8 @@
// Render once for this single data point (or use the viewModel if no data was provided) // Render once for this single data point (or use the viewModel if no data was provided)
var innerBindingContext = bindingContext; var innerBindingContext = bindingContext;
if ('data' in options) { if ('data' in options) {
innerBindingContext = bindingContext.createChildContext(options['data'], { innerBindingContext = bindingContext['createChildContext'](options['data'], {
exportDependencies: true 'exportDependencies': true
}); });
} }
templateComputed = renderTemplate(template, innerBindingContext, options, element); templateComputed = renderTemplate(template, innerBindingContext, options, element);