PageRenderTime 56ms CodeModel.GetById 42ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/ajax/libs/eventproxy/0.1.4/eventproxy.js

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