%PDF- %PDF-
Direktori : /proc/985914/root/data/old/home/stash/atlassian/stash/3.7.1/atlassian-stash/static/util/ |
Current File : //proc/985914/root/data/old/home/stash/atlassian/stash/3.7.1/atlassian-stash/static/util/widget.js |
define('util/widget', [ 'lodash', 'util/mixin' ], function( _, mix ) { 'use strict'; function getListeners(obj, eventName) { if (!obj._listeners) { obj._listeners = {}; } if (!obj._listeners[eventName]) { obj._listeners[eventName] = []; } return obj._listeners[eventName]; } // Not exposed separately to encourage people to use the full widget mixin. Can be reconsidered var events = { /** * listen to an event * @param {string} eventName * @param {function} handler * @returns {this} */ on : function(eventName, handler) { var listeners = getListeners(this, eventName); if (!_.contains(listeners, handler)) { listeners.push(handler); } return this; }, /** * Stop listening to an event * @param {string} eventName * @param {function} handler * @returns {this} */ off : function(eventName, handler) { var listeners = getListeners(this, eventName); var i = listeners.length; while(i--) { // if it's the callback, or the boundOff for the callback if (listeners[i] === handler || listeners[i]._handler === handler) { listeners.splice(i, 1); } } return this; }, /** * Listen to an event once, then unbind it from future occurrences of the event * @param {string} eventName * @param {function} handler * @returns {this} */ once : function(eventName, handler) { var boundOff = this.off.bind(this, eventName, handler); boundOff._handler = handler; this.on(eventName, handler); this.on(eventName, boundOff); return this; }, /** * Call all listeners for an event. * @param {string} eventName * @param {...*} argument * @returns {this} */ trigger : function(eventName/*, ...args */) { var listeners = getListeners(this, eventName).slice(); var args = [].slice.call(arguments, 1); var self = this; listeners.forEach(function(fn) { try { fn.apply(self, args); } catch (e) { _.defer(function() { throw e; }); } }); return this; } }; // Not exposed separately to encourage people to use the full widget mixin. Can be reconsidered var lifecycle = { /** * Call _init from your widget to bind all methods to this instance and populate this._options * with incoming options and defaults. * * Use MyCtor.defaults = {} to specify default options. * * @param {Object} options - options for this widget. * @param {Object} defaults - defaults for this widget. * @private */ _init : function(options, defaults) { _.bindAll.apply(_, [this].concat(_.functions(this))); this._options = _.extend({}, defaults || this.constructor && this.constructor.defaults, options); return this; }, /** * Add a thing to be destroyed when I am destroyed. * @param {{ destroy : function }} destroyable - thing to destroy with me * @private */ _addDestroyable : function(destroyable) { if (!this._destroyables) { this._destroyables = []; } if (_.isFunction(destroyable)) { destroyable = { destroy : destroyable }; } if (!destroyable.destroy) { throw new Error("Argument is not destroyable"); } this._destroyables.push(destroyable); return this; }, /** * When called, the widget is no longer usable. All nested destroyables will have destroy called on them. * If the event mixin is included, the destroy event will be fired. */ destroy : function() { if (this._destroyables) { _.invoke(this._destroyables, 'destroy'); this._destroyables = null; } if (this.trigger) { this.trigger('destroy'); } if (this._listeners) { this._listeners = null; } } }; var widget = mix(events, lifecycle).into({}); return { mixInto : mix(widget).into }; });