1 (function($) { 2 /** @exports $ as puredom */ 3 4 /** Creates a new EventEmitter instance. 5 * @class Fire events and listen for fired events. 6 */ 7 $.EventEmitter = function EventEmitter() { 8 this._eventRegistry = []; 9 }; 10 11 var proto = $.EventEmitter.prototype; 12 13 function multi(inst, func, type, handler, collector) { 14 var o = typeof type, 15 t, i, ret; 16 if (o==='object' && type) { 17 for (i in type) { 18 if (type.hasOwnProperty(i)) { 19 ret = inst[func](i, type[i]); 20 if (collector) { 21 collector.push(ret); 22 } 23 } 24 } 25 return true; 26 } 27 if (o==='string' && type.indexOf(',')>-1) { 28 t = type.split(','); 29 for (i=0; i<t.length; i++) { 30 ret = inst[func](t[i], handler); 31 if (collector) { 32 collector.push(ret); 33 } 34 } 35 return true; 36 } 37 return false; 38 } 39 40 function normalizeType(type) { 41 return String(type).toLowerCase().replace(/(^on|\s+)/gim,''); 42 } 43 44 $.extend(proto, /** @lends puredom.EventEmitter# */ { 45 46 /** Register an event listener on the instance. 47 * @param {String} type An event type, or a comma-seprated list of event types. 48 * @param {Function} handler A function to call in response to events of the given type. 49 * @returns {this} 50 */ 51 on : function(type, handler) { 52 type = normalizeType(type); 53 if (!multi(this, 'on', type, handler)) { 54 this._eventRegistry.push({ 55 type : type, 56 handler : handler 57 }); 58 } 59 return this; 60 }, 61 62 63 /** A version of {@link puredom.EventEmitter#on .on()} that removes handlers once they are called. 64 * @see puredom.EventEmitter#on 65 * @param {String} type An event type, or a comma-seprated list of event types. 66 * @param {Function} handler A function to call in response to events of the given type. Will only be called once. 67 * @returns {this} 68 */ 69 once : function(type, handler) { 70 type = normalizeType(type); 71 if (!multi(this, 'once', type, handler)) { 72 this.on(type, function onceProxy() { 73 this.removeListener(type, onceProxy); 74 return handler.apply(this, arguments); 75 }); 76 } 77 return this; 78 }, 79 80 81 /** Remove an event listener from the instance. 82 * @param {String} type An event type, or a comma-seprated list of event types. 83 * @param {Function} handler A reference to the handler, as was originally passed to {puredom.EventEmitter#addEventListener}. 84 * @returns {this} 85 */ 86 removeListener : function(type, handler) { 87 var x, r; 88 type = normalizeType(type); 89 if (!multi(this, 'removeListener', type, handler)) { 90 for (x=this._eventRegistry.length; x--; ) { 91 r = this._eventRegistry[x]; 92 if (r.type===type && r.handler===handler) { 93 this._eventRegistry.splice(x, 1); 94 break; 95 } 96 } 97 } 98 return this; 99 }, 100 101 102 /** Fire an event of a given type. <br /> 103 * Pass a comma-separated list for <code>type</code> to fire multiple events at once. 104 * @param {String} type Event type, or a comma-seprated list of event types. 105 * @param {Array} [args] Arguments to pass to each handler. Non-Array values get auto-boxed into an Array. 106 * @returns {Array} an Array of handler return values. The Array also has "truthy" and "falsey" properties indicating if any handlers returned <code>true</code> or <code>false</code>, respectively. 107 */ 108 emit : function(type, args) { 109 var returns = [], 110 x, r, rval; 111 type = normalizeType(type); 112 args = Array.prototype.slice.call(arguments, 1); 113 if (multi(this, 'emit', type, args, returns)) { 114 return Array.prototype.concat.apply([], returns); 115 } 116 for (x=this._eventRegistry.length; x--; ) { 117 r = this._eventRegistry[x]; 118 if (r.type===type) { 119 if (returns.length===0) { 120 returns.falsy = returns.falsey = returns.truthy = true; 121 } 122 rval = r.handler.apply(this, args); 123 returns.push(rval); 124 if (rval===true) { 125 returns.falsy = returns.falsey = false; 126 } 127 else if (rval===false) { 128 returns.truthy = false; 129 } 130 if (rval===false) { 131 break; 132 } 133 } 134 } 135 return returns; 136 }, 137 138 /** Deprecated alternative version of {@link puredom.EventEmitter#emit emit()} that 139 * accepts an Array of event parameters as the second argument. 140 * @function 141 * @private 142 * @deprecated 143 */ 144 fireEvent : function(type, args) { 145 return this.emit.apply(this, ([type]).concat(args)); 146 } 147 148 }); 149 150 151 $.forEach(/** @lends puredom.EventEmitter# */{ 152 153 /** Alias of {@link puredom.EventEmitter#on on()} 154 * @function 155 * @private 156 */ 157 addListener : 'on', 158 159 /** Alias of {@link puredom.EventEmitter#on on()} 160 * @function 161 * @private 162 */ 163 addEventListener : 'on', 164 165 /** Alias of {@link puredom.EventEmitter#removeListener removeListener()} 166 * @function 167 * @private 168 */ 169 removeEventListener : 'removeListener', 170 171 /** Alias of {@link puredom.EventEmitter#emit emit()} 172 * @function 173 * @private 174 */ 175 trigger : 'emit' 176 177 }, function(alias, key) { 178 proto[key] = proto[alias]; 179 }); 180 181 }(puredom)); 182