| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- /**
- * 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;
- });
|