UNPKG

durandal

Version:

Durandal is a cross-device, cross-platform client framework written in JavaScript and designed to make Single Page Applications (SPAs) easy to create and maintain. We've used it to build apps for PC, Mac, Linux, iOS and Android...and now it's your turn...

153 lines (136 loc) 5.91 kB
/** * Durandal 2.2.0 Copyright (c) 2010-2016 Blue Spire Consulting, Inc. All Rights Reserved. * Available via the MIT license. * see: http://durandaljs.com or https://github.com/BlueSpire/Durandal for details. */ /** * The binder joins an object instance and a DOM element tree by applying databinding and/or invoking binding lifecycle callbacks (binding and bindingComplete). * @module binder * @requires system * @requires knockout */ define(['durandal/system', 'knockout'], function (system, ko) { var binder, insufficientInfoMessage = 'Insufficient Information to Bind', unexpectedViewMessage = 'Unexpected View Type', bindingInstructionKey = 'durandal-binding-instruction', koBindingContextKey = '__ko_bindingContext__'; function normalizeBindingInstruction(result){ if(result === undefined){ return { applyBindings: true }; } if(system.isBoolean(result)){ return { applyBindings:result }; } if(result.applyBindings === undefined){ result.applyBindings = true; } return result; } function doBind(obj, view, bindingTarget, data){ if (!view || !bindingTarget) { if (binder.throwOnErrors) { system.error(insufficientInfoMessage); } else { system.log(insufficientInfoMessage, view, data); } return; } if (!view.getAttribute) { if (binder.throwOnErrors) { system.error(unexpectedViewMessage); } else { system.log(unexpectedViewMessage, view, data); } return; } var viewName = view.getAttribute('data-view'); try { var instruction; if (obj && obj.binding) { instruction = obj.binding(view); } instruction = normalizeBindingInstruction(instruction); binder.binding(data, view, instruction); if(instruction.applyBindings){ system.log('Binding', viewName, data); ko.applyBindings(bindingTarget, view); }else if(obj){ ko.utils.domData.set(view, koBindingContextKey, { $data:obj }); } binder.bindingComplete(data, view, instruction); if (obj && obj.bindingComplete) { obj.bindingComplete(view); } ko.utils.domData.set(view, bindingInstructionKey, instruction); return instruction; } catch (e) { e.message = e.message + ';\nView: ' + viewName + ";\nModuleId: " + system.getModuleId(data); if (binder.throwOnErrors) { system.error(e); } else { system.log(e.message); } } } /** * @class BinderModule * @static */ return binder = { /** * Called before every binding operation. Does nothing by default. * @method binding * @param {object} data The data that is about to be bound. * @param {DOMElement} view The view that is about to be bound. * @param {object} instruction The object that carries the binding instructions. */ binding: system.noop, /** * Called after every binding operation. Does nothing by default. * @method bindingComplete * @param {object} data The data that has just been bound. * @param {DOMElement} view The view that has just been bound. * @param {object} instruction The object that carries the binding instructions. */ bindingComplete: system.noop, /** * Indicates whether or not the binding system should throw errors or not. * @property {boolean} throwOnErrors * @default false The binding system will not throw errors by default. Instead it will log them. */ throwOnErrors: false, /** * Gets the binding instruction that was associated with a view when it was bound. * @method getBindingInstruction * @param {DOMElement} view The view that was previously bound. * @return {object} The object that carries the binding instructions. */ getBindingInstruction:function(view){ return ko.utils.domData.get(view, bindingInstructionKey); }, /** * Binds the view, preserving the existing binding context. Optionally, a new context can be created, parented to the previous context. * @method bindContext * @param {KnockoutBindingContext} bindingContext The current binding context. * @param {DOMElement} view The view to bind. * @param {object} [obj] The data to bind to, causing the creation of a child binding context if present. * @param {string} [dataAlias] An alias for $data if present. */ bindContext: function(bindingContext, view, obj, dataAlias) { if (obj && bindingContext) { bindingContext = bindingContext.createChildContext(obj, typeof(dataAlias) === 'string' ? dataAlias : null); } return doBind(obj, view, bindingContext, obj || (bindingContext ? bindingContext.$data : null)); }, /** * Binds the view, preserving the existing binding context. Optionally, a new context can be created, parented to the previous context. * @method bind * @param {object} obj The data to bind to. * @param {DOMElement} view The view to bind. */ bind: function(obj, view) { return doBind(obj, view, obj, obj); } }; });