PageRenderTime 1146ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/ajax/libs/eventproxy/0.2.0/eventproxy.js

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