Files
ECAILLE Fabrice (externe) e2277667c5 Fix: add dependencies
2017-05-04 10:26:11 +02:00

196 lines
7.4 KiB
JavaScript

/**
* Durandal 2.1.0 Copyright (c) 2012 Blue Spire Consulting, Inc. All Rights Reserved.
* Available via the MIT license.
* see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details.
*/
/**
* Layers the widget sugar on top of the composition system.
* @module widget
* @requires system
* @requires composition
* @requires jquery
* @requires knockout
*/
define(['durandal/system', 'durandal/composition', 'jquery', 'knockout'], function(system, composition, $, ko) {
var kindModuleMaps = {},
kindViewMaps = {},
bindableSettings = ['model', 'view', 'kind'],
widgetDataKey = 'durandal-widget-data';
function extractParts(element, settings){
var data = ko.utils.domData.get(element, widgetDataKey);
if(!data){
data = {
parts:composition.cloneNodes(ko.virtualElements.childNodes(element))
};
ko.virtualElements.emptyNode(element);
ko.utils.domData.set(element, widgetDataKey, data);
}
settings.parts = data.parts;
}
/**
* @class WidgetModule
* @static
*/
var widget = {
getSettings: function(valueAccessor) {
var settings = ko.utils.unwrapObservable(valueAccessor()) || {};
if (system.isString(settings)) {
return { kind: settings };
}
for (var attrName in settings) {
if (ko.utils.arrayIndexOf(bindableSettings, attrName) != -1) {
settings[attrName] = ko.utils.unwrapObservable(settings[attrName]);
} else {
settings[attrName] = settings[attrName];
}
}
return settings;
},
/**
* Creates a ko binding handler for the specified kind.
* @method registerKind
* @param {string} kind The kind to create a custom binding handler for.
*/
registerKind: function(kind) {
ko.bindingHandlers[kind] = {
init: function() {
return { controlsDescendantBindings: true };
},
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var settings = widget.getSettings(valueAccessor);
settings.kind = kind;
extractParts(element, settings);
widget.create(element, settings, bindingContext, true);
}
};
ko.virtualElements.allowedBindings[kind] = true;
composition.composeBindings.push(kind + ':');
},
/**
* Maps views and module to the kind identifier if a non-standard pattern is desired.
* @method mapKind
* @param {string} kind The kind name.
* @param {string} [viewId] The unconventional view id to map the kind to.
* @param {string} [moduleId] The unconventional module id to map the kind to.
*/
mapKind: function(kind, viewId, moduleId) {
if (viewId) {
kindViewMaps[kind] = viewId;
}
if (moduleId) {
kindModuleMaps[kind] = moduleId;
}
},
/**
* Maps a kind name to it's module id. First it looks up a custom mapped kind, then falls back to `convertKindToModulePath`.
* @method mapKindToModuleId
* @param {string} kind The kind name.
* @return {string} The module id.
*/
mapKindToModuleId: function(kind) {
return kindModuleMaps[kind] || widget.convertKindToModulePath(kind);
},
/**
* Converts a kind name to it's module path. Used to conventionally map kinds who aren't explicitly mapped through `mapKind`.
* @method convertKindToModulePath
* @param {string} kind The kind name.
* @return {string} The module path.
*/
convertKindToModulePath: function(kind) {
return 'widgets/' + kind + '/viewmodel';
},
/**
* Maps a kind name to it's view id. First it looks up a custom mapped kind, then falls back to `convertKindToViewPath`.
* @method mapKindToViewId
* @param {string} kind The kind name.
* @return {string} The view id.
*/
mapKindToViewId: function(kind) {
return kindViewMaps[kind] || widget.convertKindToViewPath(kind);
},
/**
* Converts a kind name to it's view id. Used to conventionally map kinds who aren't explicitly mapped through `mapKind`.
* @method convertKindToViewPath
* @param {string} kind The kind name.
* @return {string} The view id.
*/
convertKindToViewPath: function(kind) {
return 'widgets/' + kind + '/view';
},
createCompositionSettings: function(element, settings) {
if (!settings.model) {
settings.model = this.mapKindToModuleId(settings.kind);
}
if (!settings.view) {
settings.view = this.mapKindToViewId(settings.kind);
}
settings.preserveContext = true;
settings.activate = true;
settings.activationData = settings;
settings.mode = 'templated';
return settings;
},
/**
* Creates a widget.
* @method create
* @param {DOMElement} element The DOMElement or knockout virtual element that serves as the target element for the widget.
* @param {object} settings The widget settings.
* @param {object} [bindingContext] The current binding context.
*/
create: function(element, settings, bindingContext, fromBinding) {
if(!fromBinding){
settings = widget.getSettings(function() { return settings; }, element);
}
var compositionSettings = widget.createCompositionSettings(element, settings);
composition.compose(element, compositionSettings, bindingContext);
},
/**
* Installs the widget module by adding the widget binding handler and optionally registering kinds.
* @method install
* @param {object} config The module config. Add a `kinds` array with the names of widgets to automatically register. You can also specify a `bindingName` if you wish to use another name for the widget binding, such as "control" for example.
*/
install:function(config){
config.bindingName = config.bindingName || 'widget';
if(config.kinds){
var toRegister = config.kinds;
for(var i = 0; i < toRegister.length; i++){
widget.registerKind(toRegister[i]);
}
}
ko.bindingHandlers[config.bindingName] = {
init: function() {
return { controlsDescendantBindings: true };
},
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var settings = widget.getSettings(valueAccessor);
extractParts(element, settings);
widget.create(element, settings, bindingContext, true);
}
};
composition.composeBindings.push(config.bindingName + ':');
ko.virtualElements.allowedBindings[config.bindingName] = true;
}
};
return widget;
});