UNPKG

durandal-es6

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. This framework replaces the dependency on RequireJS and instead uses ES modules.

227 lines (194 loc) 7.4 kB
import system from "./system"; /** * Durandal events originate from backbone.js but also combine some ideas from signals.js as well as some additional improvements. * Events can be installed into any object and are installed into the `app` module by default for convenient app-wide eventing. * @module events * @requires system */ function EventsModule() { const eventSplitter = /\s+/; const Events = function () {}; /** * Represents an event subscription. * @class Subscription */ const Subscription = function (owner, events) { this.owner = owner; this.events = events; }; /** * Attaches a callback to the event subscription. * @method then * @param {function} callback The callback function to invoke when the event is triggered. * @param {object} [context] An object to use as `this` when invoking the `callback`. * @chainable */ Subscription.prototype.then = function (callback, context) { this.callback = callback || this.callback; this.context = context || this.context; if (!this.callback) { return this; } this.owner.on(this.events, this.callback, this.context); return this; }; /** * Attaches a callback to the event subscription. * @method on * @param {function} [callback] The callback function to invoke when the event is triggered. If `callback` is not provided, the previous callback will be re-activated. * @param {object} [context] An object to use as `this` when invoking the `callback`. * @chainable */ Subscription.prototype.on = Subscription.prototype.then; /** * Cancels the subscription. * @method off * @chainable */ Subscription.prototype.off = function () { this.owner.off(this.events, this.callback, this.context); return this; }; /** * Creates an object with eventing capabilities. * @class Events */ /** * Creates a subscription or registers a callback for the specified event. * @method on * @param {string} events One or more events, separated by white space. * @param {function} [callback] The callback function to invoke when the event is triggered. If `callback` is not provided, a subscription instance is returned. * @param {object} [context] An object to use as `this` when invoking the `callback`. * @return {Subscription|Events} A subscription is returned if no callback is supplied, otherwise the events object is returned for chaining. */ Events.prototype.on = function (events, callback, context) { let calls; let event; let list; if (!callback) { return new Subscription(this, events); } calls = this.callbacks || (this.callbacks = {}); events = events.split(eventSplitter); while ((event = events.shift())) { list = calls[event] || (calls[event] = []); list.push(callback, context); } return this; }; /** * Removes the callbacks for the specified events. * @method off * @param {string} [events] One or more events, separated by white space to turn off. If no events are specified, then the callbacks will be removed. * @param {function} [callback] The callback function to remove. If `callback` is not provided, all callbacks for the specified events will be removed. * @param {object} [context] The object that was used as `this`. Callbacks with this context will be removed. * @chainable */ Events.prototype.off = function (events, callback, context) { let event; let calls; let list; let i; // No events if (!(calls = this.callbacks)) { return this; } // removing all if (!(events || callback || context)) { delete this.callbacks; return this; } events = events ? events.split(eventSplitter) : system.keys(calls); // Loop through the callback list, splicing where appropriate. while ((event = events.shift())) { if (!(list = calls[event]) || !(callback || context)) { delete calls[event]; continue; } for (i = list.length - 2; i >= 0; i -= 2) { if (!((callback && list[i] !== callback) || (context && list[i + 1] !== context))) { list.splice(i, 2); } } } return this; }; /** * Triggers the specified events. * @method trigger * @param {string} [events] One or more events, separated by white space to trigger. * @chainable */ Events.prototype.trigger = function (events) { let event; let calls; let list; let i; let length; let args; let all; const rest = []; if (!(calls = this.callbacks)) { return this; } events = events.split(eventSplitter); for (i = 1, length = arguments.length; i < length; i += 1) { rest[i - 1] = arguments[i]; } // For each event, walk through the list of callbacks twice, first to // trigger the event, then to trigger any `"all"` callbacks. while ((event = events.shift())) { // Copy callback lists to prevent modification. if ((all = calls.all)) { all = all.slice(); } if ((list = calls[event])) { list = list.slice(); } // Execute event callbacks. if (list) { for (i = 0, length = list.length; i < length; i += 2) { list[i].apply(list[i + 1] || this, rest); } } // Execute "all" callbacks. if (all) { args = [event].concat(rest); for (i = 0, length = all.length; i < length; i += 2) { all[i].apply(all[i + 1] || this, args); } } } return this; }; /** * Creates a function that will trigger the specified events when called. Simplifies proxying jQuery (or other) events through to the events object. * @method proxy * @param {string} events One or more events, separated by white space to trigger by invoking the returned function. * @return {function} Calling the function will invoke the previously specified events on the events object. */ Events.prototype.proxy = function (events) { const that = this; return function (arg) { that.trigger(events, arg); }; }; /** * Creates an object with eventing capabilities. * @class EventsModule * @static */ /** * Adds eventing capabilities to the specified object. * @method includeIn * @param {object} targetObject The object to add eventing capabilities to. */ Events.includeIn = function (targetObject) { targetObject.on = Events.prototype.on; targetObject.off = Events.prototype.off; targetObject.trigger = Events.prototype.trigger; targetObject.proxy = Events.prototype.proxy; }; return Events; } export default EventsModule();