mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-26 18:49:20 +03:00
80 lines
3.8 KiB
JavaScript
80 lines
3.8 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;
|
|
},
|
|
originalChildNodes = [...ko.virtualElements.childNodes(element)];
|
|
|
|
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 new 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 new Error('Unknown component \'' + componentName + '\'');
|
|
}
|
|
// cloneTemplateIntoElement
|
|
var template = componentDefinition['template'];
|
|
if (!template) {
|
|
throw new Error('Component \'' + componentName + '\' has no template');
|
|
}
|
|
ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(template));
|
|
|
|
currentViewModel = componentDefinition['createViewModel'](componentParams, {
|
|
'element': element,
|
|
'templateNodes': originalChildNodes
|
|
});
|
|
ko.applyBindingsToDescendants(asyncContext['createChildContext'](currentViewModel, {
|
|
'extend': ctx => {
|
|
ctx['$component'] = currentViewModel;
|
|
ctx['$componentTemplateNodes'] = originalChildNodes;
|
|
}
|
|
}), element);
|
|
}
|
|
});
|
|
}, { disposeWhenNodeIsRemoved: element });
|
|
|
|
return { 'controlsDescendantBindings': true };
|
|
}
|
|
};
|
|
|
|
ko.virtualElements.allowedBindings['component'] = true;
|
|
|
|
})();
|