snappymail/vendors/knockout/src/components/componentBinding.js
2024-03-04 01:12:40 +01:00

73 lines
3.4 KiB
JavaScript

(() => {
var componentLoadingOperationUniqueId = 0;
ko.bindingHandlers['component'] = {
'init': (element, valueAccessor, ignored1, ignored2, bindingContext) => {
var currentViewModel,
currentLoadingOperationId,
afterRenderSub,
disposeAssociatedComponentViewModel = () => {
var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];
if (typeof currentViewModelDispose === 'function') {
currentViewModelDispose.call(currentViewModel);
}
if (afterRenderSub) {
afterRenderSub['dispose']();
}
afterRenderSub = null;
currentViewModel = null;
// Any in-flight loading operation is no longer relevant, so make sure we ignore its completion
currentLoadingOperationId = null;
};
ko.virtualElements.emptyNode(element);
ko.utils.domNodeDisposal['addDisposeCallback'](element, disposeAssociatedComponentViewModel);
ko.computed(() => {
var componentName = ko.utils.unwrapObservable(valueAccessor()),
componentParams;
if (typeof componentName !== 'string') {
componentParams = ko.utils.unwrapObservable(componentName['params']);
componentName = ko.utils.unwrapObservable(componentName['name']);
}
if (!componentName) {
throw Error('No component name specified');
}
var asyncContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);
var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;
ko['components'].get(componentName, componentDefinition => {
// If this is the current load operation for this element
if (currentLoadingOperationId === loadingOperationId) {
// Clean up previous state
disposeAssociatedComponentViewModel();
// Instantiate and bind new component. Implicitly this cleans any old DOM nodes.
if (!componentDefinition) {
throw Error('Unknown component \'' + componentName + '\'');
}
// cloneTemplateIntoElement
var template = componentDefinition['template'];
if (!template) {
throw Error('Component \'' + componentName + '\' has no template');
}
ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(template));
currentViewModel = componentDefinition['createViewModel'](componentParams, {
'element': element
});
ko.applyBindingsToDescendants(asyncContext['createChildContext'](currentViewModel, {}), element);
}
});
}, { disposeWhenNodeIsRemoved: element });
return { 'controlsDescendantBindings': true };
}
};
ko.virtualElements.allowedBindings['component'] = true;
})();