eve.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // ┌────────────────────────────────────────────────────────────┐ \\
  15. // │ Eve 0.4.2 - JavaScript Events Library │ \\
  16. // ├────────────────────────────────────────────────────────────┤ \\
  17. // │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
  18. // └────────────────────────────────────────────────────────────┘ \\
  19. (function (glob) {
  20. var version = "0.4.2",
  21. has = "hasOwnProperty",
  22. separator = /[\.\/]/,
  23. wildcard = "*",
  24. fun = function () {},
  25. numsort = function (a, b) {
  26. return a - b;
  27. },
  28. current_event,
  29. stop,
  30. events = {n: {}},
  31. /*\
  32. * eve
  33. [ method ]
  34. * Fires event with given `name`, given scope and other parameters.
  35. > Arguments
  36. - name (string) name of the *event*, dot (`.`) or slash (`/`) separated
  37. - scope (object) context for the event handlers
  38. - varargs (...) the rest of arguments will be sent to event handlers
  39. = (object) array of returned values from the listeners
  40. \*/
  41. eve = function (name, scope) {
  42. name = String(name);
  43. var e = events,
  44. oldstop = stop,
  45. args = Array.prototype.slice.call(arguments, 2),
  46. listeners = eve.listeners(name),
  47. z = 0,
  48. f = false,
  49. l,
  50. indexed = [],
  51. queue = {},
  52. out = [],
  53. ce = current_event,
  54. errors = [];
  55. current_event = name;
  56. stop = 0;
  57. for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
  58. indexed.push(listeners[i].zIndex);
  59. if (listeners[i].zIndex < 0) {
  60. queue[listeners[i].zIndex] = listeners[i];
  61. }
  62. }
  63. indexed.sort(numsort);
  64. while (indexed[z] < 0) {
  65. l = queue[indexed[z++]];
  66. out.push(l.apply(scope, args));
  67. if (stop) {
  68. stop = oldstop;
  69. return out;
  70. }
  71. }
  72. for (i = 0; i < ii; i++) {
  73. l = listeners[i];
  74. if ("zIndex" in l) {
  75. if (l.zIndex == indexed[z]) {
  76. out.push(l.apply(scope, args));
  77. if (stop) {
  78. break;
  79. }
  80. do {
  81. z++;
  82. l = queue[indexed[z]];
  83. l && out.push(l.apply(scope, args));
  84. if (stop) {
  85. break;
  86. }
  87. } while (l)
  88. } else {
  89. queue[l.zIndex] = l;
  90. }
  91. } else {
  92. out.push(l.apply(scope, args));
  93. if (stop) {
  94. break;
  95. }
  96. }
  97. }
  98. stop = oldstop;
  99. current_event = ce;
  100. return out.length ? out : null;
  101. };
  102. // Undocumented. Debug only.
  103. eve._events = events;
  104. /*\
  105. * eve.listeners
  106. [ method ]
  107. * Internal method which gives you array of all event handlers that will be triggered by the given `name`.
  108. > Arguments
  109. - name (string) name of the event, dot (`.`) or slash (`/`) separated
  110. = (array) array of event handlers
  111. \*/
  112. eve.listeners = function (name) {
  113. var names = name.split(separator),
  114. e = events,
  115. item,
  116. items,
  117. k,
  118. i,
  119. ii,
  120. j,
  121. jj,
  122. nes,
  123. es = [e],
  124. out = [];
  125. for (i = 0, ii = names.length; i < ii; i++) {
  126. nes = [];
  127. for (j = 0, jj = es.length; j < jj; j++) {
  128. e = es[j].n;
  129. items = [e[names[i]], e[wildcard]];
  130. k = 2;
  131. while (k--) {
  132. item = items[k];
  133. if (item) {
  134. nes.push(item);
  135. out = out.concat(item.f || []);
  136. }
  137. }
  138. }
  139. es = nes;
  140. }
  141. return out;
  142. };
  143. /*\
  144. * eve.on
  145. [ method ]
  146. **
  147. * Binds given event handler with a given name. You can use wildcards “`*`” for the names:
  148. | eve.on("*.under.*", f);
  149. | eve("mouse.under.floor"); // triggers f
  150. * Use @eve to trigger the listener.
  151. **
  152. > Arguments
  153. **
  154. - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
  155. - f (function) event handler function
  156. **
  157. = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
  158. > Example:
  159. | eve.on("mouse", eatIt)(2);
  160. | eve.on("mouse", scream);
  161. | eve.on("mouse", catchIt)(1);
  162. * This will ensure that `catchIt()` function will be called before `eatIt()`.
  163. *
  164. * If you want to put your handler before non-indexed handlers, specify a negative value.
  165. * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
  166. \*/
  167. eve.on = function (name, f) {
  168. name = String(name);
  169. if (typeof f != "function") {
  170. return function () {};
  171. }
  172. var names = name.split(separator),
  173. e = events;
  174. for (var i = 0, ii = names.length; i < ii; i++) {
  175. e = e.n;
  176. e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}});
  177. }
  178. e.f = e.f || [];
  179. for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
  180. return fun;
  181. }
  182. e.f.push(f);
  183. return function (zIndex) {
  184. if (+zIndex == +zIndex) {
  185. f.zIndex = +zIndex;
  186. }
  187. };
  188. };
  189. /*\
  190. * eve.f
  191. [ method ]
  192. **
  193. * Returns function that will fire given event with optional arguments.
  194. * Arguments that will be passed to the result function will be also
  195. * concated to the list of final arguments.
  196. | el.onclick = eve.f("click", 1, 2);
  197. | eve.on("click", function (a, b, c) {
  198. | console.log(a, b, c); // 1, 2, [event object]
  199. | });
  200. > Arguments
  201. - event (string) event name
  202. - varargs (…) and any other arguments
  203. = (function) possible event handler function
  204. \*/
  205. eve.f = function (event) {
  206. var attrs = [].slice.call(arguments, 1);
  207. return function () {
  208. eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0)));
  209. };
  210. };
  211. /*\
  212. * eve.stop
  213. [ method ]
  214. **
  215. * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
  216. \*/
  217. eve.stop = function () {
  218. stop = 1;
  219. };
  220. /*\
  221. * eve.nt
  222. [ method ]
  223. **
  224. * Could be used inside event handler to figure out actual name of the event.
  225. **
  226. > Arguments
  227. **
  228. - subname (string) #optional subname of the event
  229. **
  230. = (string) name of the event, if `subname` is not specified
  231. * or
  232. = (boolean) `true`, if current event’s name contains `subname`
  233. \*/
  234. eve.nt = function (subname) {
  235. if (subname) {
  236. return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
  237. }
  238. return current_event;
  239. };
  240. /*\
  241. * eve.nts
  242. [ method ]
  243. **
  244. * Could be used inside event handler to figure out actual name of the event.
  245. **
  246. **
  247. = (array) names of the event
  248. \*/
  249. eve.nts = function () {
  250. return current_event.split(separator);
  251. };
  252. /*\
  253. * eve.off
  254. [ method ]
  255. **
  256. * Removes given function from the list of event listeners assigned to given name.
  257. * If no arguments specified all the events will be cleared.
  258. **
  259. > Arguments
  260. **
  261. - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
  262. - f (function) event handler function
  263. \*/
  264. /*\
  265. * eve.unbind
  266. [ method ]
  267. **
  268. * See @eve.off
  269. \*/
  270. eve.off = eve.unbind = function (name, f) {
  271. if (!name) {
  272. eve._events = events = {n: {}};
  273. return;
  274. }
  275. var names = name.split(separator),
  276. e,
  277. key,
  278. splice,
  279. i, ii, j, jj,
  280. cur = [events];
  281. for (i = 0, ii = names.length; i < ii; i++) {
  282. for (j = 0; j < cur.length; j += splice.length - 2) {
  283. splice = [j, 1];
  284. e = cur[j].n;
  285. if (names[i] != wildcard) {
  286. if (e[names[i]]) {
  287. splice.push(e[names[i]]);
  288. }
  289. } else {
  290. for (key in e) if (e[has](key)) {
  291. splice.push(e[key]);
  292. }
  293. }
  294. cur.splice.apply(cur, splice);
  295. }
  296. }
  297. for (i = 0, ii = cur.length; i < ii; i++) {
  298. e = cur[i];
  299. while (e.n) {
  300. if (f) {
  301. if (e.f) {
  302. for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) {
  303. e.f.splice(j, 1);
  304. break;
  305. }
  306. !e.f.length && delete e.f;
  307. }
  308. for (key in e.n) if (e.n[has](key) && e.n[key].f) {
  309. var funcs = e.n[key].f;
  310. for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) {
  311. funcs.splice(j, 1);
  312. break;
  313. }
  314. !funcs.length && delete e.n[key].f;
  315. }
  316. } else {
  317. delete e.f;
  318. for (key in e.n) if (e.n[has](key) && e.n[key].f) {
  319. delete e.n[key].f;
  320. }
  321. }
  322. e = e.n;
  323. }
  324. }
  325. };
  326. /*\
  327. * eve.once
  328. [ method ]
  329. **
  330. * Binds given event handler with a given name to only run once then unbind itself.
  331. | eve.once("login", f);
  332. | eve("login"); // triggers f
  333. | eve("login"); // no listeners
  334. * Use @eve to trigger the listener.
  335. **
  336. > Arguments
  337. **
  338. - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
  339. - f (function) event handler function
  340. **
  341. = (function) same return function as @eve.on
  342. \*/
  343. eve.once = function (name, f) {
  344. var f2 = function () {
  345. eve.unbind(name, f2);
  346. return f.apply(this, arguments);
  347. };
  348. return eve.on(name, f2);
  349. };
  350. /*\
  351. * eve.version
  352. [ property (string) ]
  353. **
  354. * Current version of the library.
  355. \*/
  356. eve.version = version;
  357. eve.toString = function () {
  358. return "You are running Eve " + version;
  359. };
  360. (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define != "undefined" ? (define("eve", [], function() { return eve; })) : (glob.eve = eve));
  361. })(this);