1 /** 2 * A base support class for emitting events, based on the 3 * <a href="http://nodejs.org/docs/latest/api/events.html">Event Emitter</a> class from node.js. 4 * It supports registering event listeners for any type of event and later emitting events to 5 * those listeners that registered for a specific type of event. 6 * Typically, users of Content Studio would only use the instances of a class that are 7 * provided by Content Studio, such as an action or the Content Studio instance. And the 8 * most common thing to do would be to register (or deregister) event listeners. 9 * @constructor 10 * @example 11 * CS.on('some-event', function(args) { 12 * // do something. 13 * }); 14 */ 15 function EventEmitter() { 16 var listeners = []; 17 var instance = this; 18 19 /** 20 * @ignore 21 * Creates an <code>Event</code> instance.Functions can be attached to objects, 22 * to be executed when an event is emitted. These functions are called listeners 23 * @constructor 24 * @param {String} type - type of the event 25 * @param {Function} callback - function to be executed with this event occurs. 26 * @param {Boolean} once - true if one time listener is added. 27 */ 28 function Event(type, callback, once) { 29 var eventInstance = this; 30 31 eventInstance.type = type; 32 eventInstance.callback = callback; 33 eventInstance.once = once || false; 34 35 /** 36 * Fires an event with the given arguments. 37 * @param args 38 */ 39 eventInstance.fire = function() { 40 eventInstance.callback.apply(eventInstance, arguments); 41 42 if (eventInstance.once === true) { 43 instance.removeListener(type, eventInstance.callback); 44 } 45 }; 46 }; 47 48 /** @ignore */ 49 var getIndexOf = function(type, callback) { 50 var indexOf = -1; 51 if (listeners.hasOwnProperty(type)) { 52 listeners[type].forEach(function(currentListener, index) { 53 if (currentListener.callback === callback && indexOf == -1) { 54 indexOf = index; 55 } 56 }); 57 } 58 59 return indexOf; 60 }; 61 62 /** 63 * Add a listener which will be called back. An alias for the <code>on()</code> function. 64 */ 65 this.addListener = function(type, listener, once) { 66 if (!listeners.hasOwnProperty(type)) { 67 listeners[type] = []; 68 } 69 70 var indexOfListener = getIndexOf(type, listener); 71 if(indexOfListener == -1) { 72 listeners[type].push(new Event(type, listener, once)); 73 } 74 else { 75 listeners[type][indexOfListener].once = once || false; 76 } 77 }; 78 79 /** 80 * Adds a one time listener for the <code>Event</code>. This listener is 81 * invoked only the next time the event is fired, after which it is removed. 82 * @param {String} type - type of the listener. 83 * @param {Function} listener - the listener 84 * @example 85 * myemitter.once('something', function() { 86 * // will be called only for the first event 87 * }); 88 */ 89 this.once = function(type, listener) { 90 if (!listeners.hasOwnProperty(type)) { 91 listeners[type] = []; 92 } 93 94 instance.addListener(type, listener, true); 95 }; 96 97 /** 98 * Stops a specified listener from receiving further events. 99 * @param {String} type type of the listener 100 * @param {Function} listener the listener 101 */ 102 this.removeListener = function(type, listener) { 103 if (listeners.hasOwnProperty(type)) { 104 listeners[type].forEach(function(currentListener, index) { 105 if (currentListener.callback === listener) { 106 listeners[type].splice(index, 1); 107 } 108 }); 109 } 110 111 if (listeners[type] && listeners[type].length == 0) { 112 delete listeners[type]; 113 } 114 115 return this; 116 }; 117 118 /** 119 * Removes all the listeners that are listening for a specific type 120 * of event. Care should be taken not to disrupt other plug-ins 121 * when calling this on shared event emitters that you do not control 122 * yourself, for example the ones provided by Content Studio. 123 * @param {String} type the type of events that all listeners should be removed. 124 */ 125 this.removeAllListeners = function(type) { 126 if (listeners.hasOwnProperty(type)) { 127 delete listeners[type]; 128 } 129 }; 130 131 /** 132 * Emit an event of a specific type. This will notify (invoke) each of the 133 * listeners in order with any the given arguments. 134 * @param {String} type The type of event to emit 135 * @param args Any additional arguments that should be passed to the listeners 136 */ 137 this.emit = function(type, args) { 138 if (listeners.hasOwnProperty(type)) { 139 listeners[type].forEach(function(currentListener) { 140 return currentListener.fire(args); 141 }); 142 } 143 144 return this; 145 }; 146 147 /** 148 * Add a listener to this event emitter. The listener will be called back 149 * the next time someone emits an event of the type specified by the 150 * <code>type</code> parameter. 151 * @function 152 * @param {String} type the type of events the listener is interested in 153 * @param {Function} listener the callback function that will be invoked when the event is emitted 154 * @param {Boolean} {once=false} true if the listener should only 155 * be notified for the first event, false if the listener should 156 * be notified for all events. 157 */ 158 this.on = this.addListener; 159 160 } 161