UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

245 lines (204 loc) 7.57 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Martin Wittemann (wittemann) ************************************************************************ */ /** * Basic implementation for an event emitter. This supplies a basic and * minimalistic event mechanism. */ qx.Bootstrap.define("qx.event.Emitter", { extend : Object, statics : { /** Static storage for all event listener */ __storage : [] }, members : { __listener : null, __any : null, /** * Attach a listener to the event emitter. The given <code>name</code> * will define the type of event. Handing in a <code>'*'</code> will * listen to all events emitted by the event emitter. * * @param name {String} The name of the event to listen to. * @param listener {Function} The function execute on {@link #emit}. * @param ctx {var?Window} The context of the listener. * @return {Integer} An unique <code>id</code> for the attached listener. */ on : function(name, listener, ctx) { var id = qx.event.Emitter.__storage.length; this.__getStorage(name).push({listener: listener, ctx: ctx, id: id, name: name}); qx.event.Emitter.__storage.push({name: name, listener: listener, ctx: ctx}); return id; }, /** * Attach a listener to the event emitter which will be executed only once. * The given <code>name</code> will define the type of event. Handing in a * <code>'*'</code> will listen to all events emitted by the event emitter. * * @param name {String} The name of the event to listen to. * @param listener {Function} The function execute on {@link #emit}. * @param ctx {var?Window} The context of the listener. * @return {Integer} An unique <code>id</code> for the attached listener. */ once : function(name, listener, ctx) { var id = qx.event.Emitter.__storage.length; this.__getStorage(name).push({listener: listener, ctx: ctx, once: true, id: id}); qx.event.Emitter.__storage.push({name: name, listener: listener, ctx: ctx}); return id; }, /** * Remove a listener from the event emitter. The given <code>name</code> * will define the type of event. * * @param name {String} The name of the event to listen to. * @param listener {Function} The function execute on {@link #emit}. * @param ctx {var?Window} The context of the listener. * @return {Integer|null} The listener's id if it was removed or * <code>null</code> if it wasn't found */ off : function(name, listener, ctx) { var storage = this.__getStorage(name); for (var i = storage.length - 1; i >= 0; i--) { var entry = storage[i]; if (entry.listener == listener && entry.ctx == ctx) { storage.splice(i, 1); qx.event.Emitter.__storage[entry.id] = null; return entry.id; } } return null; }, /** * Removes the listener identified by the given <code>id</code>. The id * will be return on attaching the listener and can be stored for removing. * * @param id {Integer} The id of the listener. * @return {Integer|null} The listener's id if it was removed or * <code>null</code> if it wasn't found */ offById : function(id) { var entry = qx.event.Emitter.__storage[id]; if (entry) { this.off(entry.name, entry.listener, entry.ctx); } return null; }, /** * Alternative for {@link #on}. * @param name {String} The name of the event to listen to. * @param listener {Function} The function execute on {@link #emit}. * @param ctx {var?Window} The context of the listener. * @return {Integer} An unique <code>id</code> for the attached listener. */ addListener : function(name, listener, ctx) { return this.on(name, listener, ctx); }, /** * Alternative for {@link #once}. * @param name {String} The name of the event to listen to. * @param listener {Function} The function execute on {@link #emit}. * @param ctx {var?Window} The context of the listener. * @return {Integer} An unique <code>id</code> for the attached listener. */ addListenerOnce : function(name, listener, ctx) { return this.once(name, listener, ctx); }, /** * Alternative for {@link #off}. * @param name {String} The name of the event to listen to. * @param listener {Function} The function execute on {@link #emit}. * @param ctx {var?Window} The context of the listener. */ removeListener : function(name, listener, ctx) { this.off(name, listener, ctx); }, /** * Alternative for {@link #offById}. * @param id {Integer} The id of the listener. */ removeListenerById : function(id) { this.offById(id); }, /** * Emits an event with the given name. The data will be passed * to the listener. * @param name {String} The name of the event to emit. * @param data {var?undefined} The data which should be passed to the listener. */ emit : function(name, data) { var storage = this.__getStorage(name).concat(); var toDelete = []; for (var i = 0; i < storage.length; i++) { var entry = storage[i]; entry.listener.call(entry.ctx, data); if (entry.once) { toDelete.push(entry); } } // listener callbacks could manipulate the storage // (e.g. module.Event.once) toDelete.forEach(function(entry) { var origStorage = this.__getStorage(name); var idx = origStorage.indexOf(entry); origStorage.splice(idx, 1); }.bind(this)); // call on any storage = this.__getStorage("*"); for (var i = storage.length - 1; i >= 0; i--) { var entry = storage[i]; entry.listener.call(entry.ctx, data); } }, /** * Returns the internal attached listener. * @internal * @return {Map} A map which has the event name as key. The values are * arrays containing a map with 'listener' and 'ctx'. */ getListeners : function() { return this.__listener; }, /** * Returns the data entry for a given event id. If the entry could * not be found, undefined will be returned. * @internal * @param id {Number} The listeners id * @return {Map|undefined} The data entry if found */ getEntryById : function(id) { for (var name in this.__listener) { var store = this.__listener[name]; for (var i=0, j=store.length; i<j; i++) { if (store[i].id === id) { return store[i]; } } } }, /** * Internal helper which will return the storage for the given name. * @param name {String} The name of the event. * @return {Array} An array which is the storage for the listener and * the given event name. */ __getStorage : function(name) { if (this.__listener == null) { this.__listener = {}; } if (this.__listener[name] == null) { this.__listener[name] = []; } return this.__listener[name]; } } });