Tab layout, first commit with new third party packages
[openemr.git] / public / assets / knockout-3-4-0 / src / components / componentBinding.js
blob09a0647570c799a442d7dd8948de642259873313
1 (function(undefined) {
3     var componentLoadingOperationUniqueId = 0;
5     ko.bindingHandlers['component'] = {
6         'init': function(element, valueAccessor, ignored1, ignored2, bindingContext) {
7             var currentViewModel,
8                 currentLoadingOperationId,
9                 disposeAssociatedComponentViewModel = function () {
10                     var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];
11                     if (typeof currentViewModelDispose === 'function') {
12                         currentViewModelDispose.call(currentViewModel);
13                     }
14                     currentViewModel = null;
15                     // Any in-flight loading operation is no longer relevant, so make sure we ignore its completion
16                     currentLoadingOperationId = null;
17                 },
18                 originalChildNodes = ko.utils.makeArray(ko.virtualElements.childNodes(element));
20             ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);
22             ko.computed(function () {
23                 var value = ko.utils.unwrapObservable(valueAccessor()),
24                     componentName, componentParams;
26                 if (typeof value === 'string') {
27                     componentName = value;
28                 } else {
29                     componentName = ko.utils.unwrapObservable(value['name']);
30                     componentParams = ko.utils.unwrapObservable(value['params']);
31                 }
33                 if (!componentName) {
34                     throw new Error('No component name specified');
35                 }
37                 var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;
38                 ko.components.get(componentName, function(componentDefinition) {
39                     // If this is not the current load operation for this element, ignore it.
40                     if (currentLoadingOperationId !== loadingOperationId) {
41                         return;
42                     }
44                     // Clean up previous state
45                     disposeAssociatedComponentViewModel();
47                     // Instantiate and bind new component. Implicitly this cleans any old DOM nodes.
48                     if (!componentDefinition) {
49                         throw new Error('Unknown component \'' + componentName + '\'');
50                     }
51                     cloneTemplateIntoElement(componentName, componentDefinition, element);
52                     var componentViewModel = createViewModel(componentDefinition, element, originalChildNodes, componentParams),
53                         childBindingContext = bindingContext['createChildContext'](componentViewModel, /* dataItemAlias */ undefined, function(ctx) {
54                             ctx['$component'] = componentViewModel;
55                             ctx['$componentTemplateNodes'] = originalChildNodes;
56                         });
57                     currentViewModel = componentViewModel;
58                     ko.applyBindingsToDescendants(childBindingContext, element);
59                 });
60             }, null, { disposeWhenNodeIsRemoved: element });
62             return { 'controlsDescendantBindings': true };
63         }
64     };
66     ko.virtualElements.allowedBindings['component'] = true;
68     function cloneTemplateIntoElement(componentName, componentDefinition, element) {
69         var template = componentDefinition['template'];
70         if (!template) {
71             throw new Error('Component \'' + componentName + '\' has no template');
72         }
74         var clonedNodesArray = ko.utils.cloneNodes(template);
75         ko.virtualElements.setDomNodeChildren(element, clonedNodesArray);
76     }
78     function createViewModel(componentDefinition, element, originalChildNodes, componentParams) {
79         var componentViewModelFactory = componentDefinition['createViewModel'];
80         return componentViewModelFactory
81             ? componentViewModelFactory.call(componentDefinition, componentParams, { 'element': element, 'templateNodes': originalChildNodes })
82             : componentParams; // Template-only component
83     }
85 })();