PageRenderTime 2ms CodeModel.GetById 31ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/ajax/libs/eventproxy/0.1.3/eventproxy.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 360 lines | 212 code | 26 blank | 122 comment | 38 complexity | 5629aef52f2dff1d6ede3e5251bb6cca MD5 | raw file
  1/*global exports */
  2/**
  3 * @fileoverview This file is used for define the EventProxy library.
  4 * @author <a href="mailto:shyvo1987@gmail.com">Jackson Tian</a>
  5 * @version 0.1.0
  6 */
  7
  8;(function (name, definition) {
  9  var theModule = definition(),
 10    // this is considered "safe":
 11    hasDefine = typeof define === 'function' && define.amd,
 12    // hasDefine = typeof define === 'function',
 13    hasExports = typeof module !== 'undefined' && module.exports;
 14 
 15  if (hasDefine) { // AMD Module
 16    define(theModule);
 17  } else if (hasExports) { // Node.js Module
 18    module.exports = theModule;
 19  } else { // Assign to common namespaces or simply the global object (window)
 20    this[name] = theModule;
 21  }
 22})('EventProxy', function () {
 23  /**
 24   * @description EventProxy. A module that can be mixed in to *any object* in order to provide it with
 25   * custom events. You may `bind` or `unbind` a callback function to an event;
 26   * `trigger`-ing an event fires all callbacks in succession.
 27   * @constructor
 28   * @name EventProxy
 29   * @class EventProxy. An implementation of task/event based asynchronous pattern.
 30   * @example
 31   * var render = function (template, resources) {};
 32   * var proxy = new EventProxy();
 33   * proxy.assign("template", "l10n", render);
 34   * proxy.trigger("template", template);
 35   * proxy.trigger("l10n", resources);
 36   */
 37  var EventProxy = function () {
 38    if (!(this instanceof EventProxy)) {
 39      return new EventProxy();
 40    }
 41    this._callbacks = {};
 42    this._fired = {};
 43  };
 44
 45  /**
 46   * @description Bind an event, specified by a string name, `ev`, to a `callback` function.
 47   * Passing `"all"` will bind the callback to all events fired.
 48   * @memberOf EventProxy#
 49   * @param {string} eventName Event name.
 50   * @param {function} callback Callback.
 51   */
 52  EventProxy.prototype.addListener = function (ev, callback) {
 53    this._callbacks = this._callbacks || {};
 54    this._callbacks[ev] = this._callbacks[ev] || [];
 55    this._callbacks[ev].push(callback);
 56    return this;
 57  };
 58  EventProxy.prototype.bind = EventProxy.prototype.addListener;
 59  EventProxy.prototype.on = EventProxy.prototype.addListener;
 60  EventProxy.prototype.await = EventProxy.prototype.addListener;
 61
 62  /**
 63   * @description Remove one or many callbacks. If `callback` is null, removes all
 64   * callbacks for the event. If `ev` is null, removes all bound callbacks
 65   * for all events.
 66   * @memberOf EventProxy#
 67   * @param {string} eventName Event name.
 68   * @param {function} callback Callback.
 69   */
 70  EventProxy.prototype.removeListener = function (ev, callback) {
 71    var calls = this._callbacks, i, l;
 72    if (!ev) {
 73      this._callbacks = {};
 74    } else if (calls) {
 75      if (!callback) {
 76        calls[ev] = [];
 77      } else {
 78        var list = calls[ev];
 79        if (!list) {
 80          return this;
 81        }
 82        l = list.length;
 83        for (i = 0; i < l; i++) {
 84          if (callback === list[i]) {
 85            list[i] = null;
 86            break;
 87          }
 88        }
 89      }
 90    }
 91    return this;
 92  };
 93  EventProxy.prototype.unbind = EventProxy.prototype.removeListener;
 94
 95  /**
 96   * @description Remove all listeners.
 97   * It equals unbind(); Just add this API for as same as Event.Emitter.
 98   * @memberOf EventProxy#
 99   * @param {string} event Event name.
100   */
101  EventProxy.prototype.removeAllListeners = function (event) {
102    return this.unbind(event);
103  };
104
105  /**
106   * @description Trigger an event, firing all bound callbacks. Callbacks are passed the
107   * same arguments as `trigger` is, apart from the event name.
108   * Listening for `"all"` passes the true event name as the first argument.
109   * @param {string} eventName Event name
110   * @param {mix} data Pass in data
111   */
112  EventProxy.prototype.trigger = function (eventName, data) {
113    var list, calls, ev, callback, args, i, l;
114    var both = 2;
115    if (!(calls = this._callbacks)) {
116      return this;
117    }
118    while (both--) {
119      ev = both ? eventName : 'all';
120      list = calls[ev];
121      if (list) {
122        for (i = 0, l = list.length; i < l; i++) {
123          if (!(callback = list[i])) {
124            list.splice(i, 1); i--; l--;
125          } else {
126            args = both ? Array.prototype.slice.call(arguments, 1) : arguments;
127            callback.apply(this, args);
128          }
129        }
130      }
131    }
132    return this;
133  };
134  EventProxy.prototype.emit = EventProxy.prototype.trigger;
135  EventProxy.prototype.fire = EventProxy.prototype.trigger;
136
137  /**
138   * @description Bind an event like the bind method, but will remove the listener after it was fired.
139   * @param {string} ev Event name
140   * @param {function} callback Callback
141   */
142  EventProxy.prototype.once = function (ev, callback) {
143    var self = this,
144      wrapper = function () {
145        callback.apply(self, arguments);
146        self.unbind(ev, wrapper);
147      };
148    this.bind(ev, wrapper);
149    return this;
150  };
151  
152  /**
153   * @description Bind an event, and trigger it immediately.
154   * @param {string} ev Event name.
155   * @param {function} callback Callback.
156   * @param {mix} data The data that will be passed to calback as arguments.
157   */
158  EventProxy.prototype.immediate = function (ev, callback, data) {
159    this.bind(ev, callback);
160    this.trigger(ev, data);
161    return this;
162  };
163
164  var _assign = function (eventname1, eventname2, cb, once) {
165    var proxy = this, length, index = 0, argsLength = arguments.length,
166      bind, _all,
167      callback, events, isOnce, times = 0, flag = {};
168
169    // Check the arguments length.
170    if (argsLength < 3) {
171      return this;
172    }
173
174    events = Array.prototype.slice.apply(arguments, [0, argsLength - 2]);
175    callback = arguments[argsLength - 2];
176    isOnce = arguments[argsLength - 1];
177
178    // Check the callback type.
179    if (typeof callback !== "function") {
180      return this;
181    }
182
183    length = events.length;
184    bind = function (key) {
185      var method = isOnce ? "once" : "bind";
186      proxy[method](key, function (data) {
187        proxy._fired[key] = proxy._fired[key] || {};
188        proxy._fired[key].data = data;
189        if (!flag[key]) {
190          flag[key] = true;
191          times++;
192        }
193      });
194    };
195
196    for (index = 0; index < length; index++) {
197      bind(events[index]);
198    }
199
200    _all = function (event) {
201      if (times < length) {
202        return;
203      }
204      if (!flag[event]) {
205        return;
206      }
207      var data = [];
208      for (index = 0; index < length; index++) {
209        data.push(proxy._fired[events[index]].data);
210      }
211      if (isOnce) {
212        proxy.unbind("all", _all);
213      }
214      callback.apply(null, data);
215    };
216    proxy.bind("all", _all);
217  };
218
219  /**
220   * @description Assign some events, after all events were fired, the callback will be executed once.
221   * @example
222   * proxy.all(ev1, ev2, callback);
223   * proxy.all([ev1, ev2], callback);
224   * proxy.all(ev1, [ev2, ev3], callback);
225   * @param {string} eventName1 First event name.
226   * @param {string} eventName2 Second event name.
227   * @param {function} callback Callback, that will be called after predefined events were fired.
228   */
229  EventProxy.prototype.all = function (eventname1, eventname2, cb) {
230    var args = Array.prototype.concat.apply([], arguments);
231    args.push(true);
232    _assign.apply(this, args);
233    return this;
234  };
235  EventProxy.prototype.assign = EventProxy.prototype.all;
236
237  /**
238   * @description Assign some events, after all events were fired, the callback will be executed first time.
239   * then any event that predefined be fired again, the callback will executed with the newest data.
240   * @example
241   * proxy.tail(ev1, ev2, callback);
242   * proxy.tail([ev1, ev2], callback);
243   * proxy.tail(ev1, [ev2, ev3], callback);
244   * @memberOf EventProxy#
245   * @param {string} eventName1 First event name.
246   * @param {string} eventName2 Second event name.
247   * @param {function} callback Callback, that will be called after predefined events were fired.
248   */
249  EventProxy.prototype.tail = function () {
250    var args = Array.prototype.concat.apply([], arguments);
251    args.push(false);
252    _assign.apply(this, args);
253    return this;
254  };
255  EventProxy.prototype.assignAll = EventProxy.prototype.tail;
256  EventProxy.prototype.assignAlways = EventProxy.prototype.tail;
257
258  /**
259   * @description The callback will be executed after the event be fired N times.
260   * @memberOf EventProxy#
261   * @param {string} eventName Event name.
262   * @param {number} times N times.
263   * @param {function} callback Callback, that will be called after event was fired N times.
264   */
265  EventProxy.prototype.after = function (eventName, times, callback) {
266    if (times === 0) {
267      callback.call(null, []);
268      return this;
269    }
270    var proxy = this,
271      firedData = [],
272      all;
273    all = function (name, data) {
274      if (name === eventName) {
275        times--;
276        firedData.push(data);
277        if (times < 1) {
278          proxy.unbind("all", all);
279          callback.apply(null, [firedData]);
280        }
281      }
282    };
283    proxy.bind("all", all);
284    return this;
285  };
286
287  /**
288   * @description The callback will be executed after any registered event was fired. It only executed once.
289   * @memberOf EventProxy#
290   * @param {string} eventName1 Event name.
291   * @param {string} eventName2 Event name.
292   * @param {function} callback The callback will get a map that has data and eventName attributes.
293   */
294  EventProxy.prototype.any = function () {
295    var proxy = this,
296      index,
297      _bind,
298      len = arguments.length,
299      callback = arguments[len - 1],
300      events = Array.prototype.slice.apply(arguments, [0, len - 1]),
301      count = events.length,
302      _eventName = events.join("_");
303
304    proxy.once(_eventName, callback);
305
306    _bind = function (key) {
307      proxy.bind(key, function (data) {
308        proxy.trigger(_eventName, {"data": data, eventName: key});
309      });
310    };
311
312    for (index = 0; index < count; index++) {
313      _bind(events[index]);
314    }
315  };
316
317  /**
318   * @description The callback will be executed when the evnet name not equals with assigned evnet.
319   * @memberOf EventProxy#
320   * @param {string} eventName Event name.
321   * @param {function} callback Callback.
322   */
323  EventProxy.prototype.not = function (eventName, callback) {
324    var proxy = this;
325    proxy.bind("all", function (name, data) {
326      if (name !== eventName) {
327        callback(data);
328      }
329    });
330  };
331  
332  /**
333   * Create a new EventProxy
334   * @example
335   *     var ep = EventProxy.create();
336   *     ep.assign('user', 'articles', function(user, articles) {
337   *       // do something...
338   *     });
339   *
340   *     // or one line ways: Create EventProxy and Assign
341   *
342   *     var ep = EventProxy.create('user', 'articles', function(user, articles) {
343   *       // do something...
344   *     });
345   *
346   * @returns {EventProxy}
347   */
348  EventProxy.create = function () {
349    var ep = new EventProxy();
350    if (arguments.length) {
351      ep.assign.apply(ep, Array.prototype.slice.call(arguments));
352    }
353    return ep;
354  };
355
356  // Backwards compatibility
357  EventProxy.EventProxy = EventProxy;
358
359  return EventProxy;
360});