PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/eddy/0.2.1/eddy.max.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 359 lines | 188 code | 7 blank | 164 comment | 35 complexity | 288b47d9fd9d40f7da3c693c84c66d12 MD5 | raw file
  1. /*!
  2. Copyright (C) 2013 by Andrea Giammarchi
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. (function (Object) {
  20. 'use strict';
  21. // probably the very first script you want to load in any project
  22. // do not redefine same stuff twice anyway
  23. if (Object.eddy) return;
  24. Object.eddy = true;
  25. // all private variables
  26. var /*! (C) Andrea Giammarchi Mit Style License */
  27. ArrayPrototype = Array.prototype,
  28. ObjectPrototype = Object.prototype,
  29. EventPrototype = Event.prototype,
  30. hasOwnProperty = ObjectPrototype.hasOwnProperty,
  31. push = ArrayPrototype.push,
  32. slice = ArrayPrototype.slice,
  33. unshift = ArrayPrototype.unshift,
  34. // IE < 9 has this problem which makes
  35. // eddy.js able to implement its features!
  36. // this would not have been possible in other
  37. // non ES5 compatible browsers so ... thanks IE!
  38. IE_WONT_ENUMERATE_THIS = 'toLocaleString',
  39. SECRET = {toLocaleString:1}.propertyIsEnumerable(
  40. IE_WONT_ENUMERATE_THIS
  41. ) ? '_@eddy' + Math.random() : IE_WONT_ENUMERATE_THIS,
  42. IE = SECRET === IE_WONT_ENUMERATE_THIS,
  43. // used in all ES5 compatible browsers (all but IE < 9)
  44. commonDescriptor = (Object.create || Object)(null),
  45. defineProperty = IE ?
  46. function (self, property, descriptor) {
  47. self[property] = descriptor.value;
  48. } :
  49. Object.defineProperty,
  50. // http://jsperf.com/bind-no-args bind is still freaking slow so...
  51. bind = /* Object.bind || */ function (context) {
  52. // this is not a fully specd replacemenet for Function#bind
  53. // but works specifically for this use case like a charm
  54. var fn = this;
  55. return function () {
  56. return fn.apply(context, arguments);
  57. };
  58. },
  59. indexOf = ArrayPrototype.indexOf || function (value) {
  60. // if you want more standard indexOf use a proper polyfill
  61. // and include it before eddy.js
  62. var i = this.length;
  63. while (i-- && this[i] !== value) {}
  64. return i;
  65. },
  66. // every triggered even has a timeStamp
  67. now = Date.now || function () {
  68. return new Date().getTime();
  69. },
  70. // for ES3+ and JScript native Objects
  71. // no hosted objects are considered here
  72. // see eddy.dom.js for that
  73. eddy = {
  74. /**
  75. * Returns a bound version of the specified method.
  76. * If called again with same method, the initial bound
  77. * object will be returned instead of creating a new one.
  78. * This will make the following assertion always true:
  79. *
  80. * @example
  81. * obj.boundTo('method') === obj.boundTo('method')
  82. * // same as
  83. * obj.boundTo(obj.method) === obj.boundTo(obj.method)
  84. * // same as
  85. * obj.boundTo('method') === obj.boundTo(obj.method)
  86. *
  87. * Bear in mind no arguments can be bound once, only the context.
  88. * Method could be either a function or a string.
  89. * In latter case, be aware Google Closure Compiler
  90. * might change methods name if compiled with
  91. * ADVANCED_OPTION resulting in a broken code.
  92. * Use methods instead of strings if you use such option.
  93. * @param method string|Function the method name to bind
  94. * @return Object the callable bound function/method.
  95. */
  96. boundTo: function boundTo(method) {
  97. var
  98. all = hasOwnProperty.call(this, SECRET) ?
  99. this[SECRET] : setAndGet(this),
  100. m = all.m,
  101. b = all.b,
  102. fn = typeof method === 'string' ? this[method] : method,
  103. i = indexOf.call(m, fn);
  104. return i < 0 ?
  105. (b[push.call(m, fn) - 1] = bind.call(fn, this)) :
  106. b[i];
  107. },
  108. /**
  109. * Borrowed from node.js, it does exactly what node.js does.
  110. *
  111. * @example
  112. * {}.on('evt', function(arg1, arg2, argN){
  113. * console.log(arg1, arg2, argN);
  114. * }).emit('evt', 1, 2, 3);
  115. * // {'0': 1, '1': 2, '2': 3}
  116. *
  117. * @param type string the event name to emit
  118. * @param [any=any] one or more arguments to pass through
  119. * @return boolean true if the event was emitted
  120. */
  121. emit: function emit(type) {
  122. var
  123. has = hasOwnProperty.call(this, SECRET),
  124. listeners = has && this[SECRET].l,
  125. loop = has && hasOwnProperty.call(listeners, type),
  126. array = loop && listeners[type],
  127. args = loop && slice.call(arguments, 1),
  128. i = 0,
  129. length = loop ? array.length : i;
  130. while (i < length) {
  131. triggerEvent(this, array[i++], args);
  132. }
  133. return loop;
  134. },
  135. /**
  136. * Counter part of `.on(type, handler)`
  137. * The equivalent of `removeListener` or `removeEventListener`.
  138. * It removes an event if already added and return same object
  139. *
  140. * @example
  141. * var obj = {}.on('evt', console.boundTo('log'));
  142. * obj.emit('evt', 'OK'); // "OK" true
  143. * obj
  144. * .off('evt', console.boundTo('log'))
  145. * .emit('evt')
  146. * ; // false
  147. *
  148. * @param type string the event name to un-listen to
  149. * @param handler Function|Object the handler used initially
  150. * @return Object the chained object that called `.off()`
  151. */
  152. off: function off(type, handler) {
  153. var
  154. has = hasOwnProperty.call(this, SECRET),
  155. listeners = has && this[SECRET].l,
  156. array = has && hasOwnProperty.call(listeners, type) &&
  157. listeners[type],
  158. i
  159. ;
  160. if (array) {
  161. i = indexOf.call(array, handler);
  162. if (-1 < i) {
  163. array.splice(i, 1);
  164. if (!array.length) {
  165. delete listeners[type];
  166. }
  167. }
  168. }
  169. return this;
  170. },
  171. /**
  172. * The equivalent of `addListener` or `addEventListener`.
  173. * It adds an event if not already added and return same object
  174. *
  175. * @example
  176. * var i = 0;
  177. * function genericEvent() {
  178. * console.log(++i);
  179. * }
  180. * var obj = {};
  181. * obj
  182. * .on('evt', genericEvent)
  183. * .on('evt', genericEvent)
  184. * ;
  185. * obj.emit('evt'); // 1
  186. *
  187. * @param type string the event name to listen to
  188. * @param handler Function|Object the handler used initially
  189. * @param [optional, **reserved**] boolean unshift instead of push
  190. * @return Object the chained object that called `.on()`
  191. */
  192. on: function on(type, handler, capture) {
  193. var
  194. has = hasOwnProperty.call(this, SECRET),
  195. listeners = (has ? this[SECRET] : setAndGet(this)).l,
  196. array = has && hasOwnProperty.call(listeners, type) ?
  197. listeners[type] : listeners[type] = []
  198. ;
  199. if (indexOf.call(array, handler) < 0) {
  200. (capture ? unshift : push).call(array, handler);
  201. }
  202. return this;
  203. },
  204. /**
  205. * Assigns an event that will be dropped the very first time
  206. * it will be triggered/emitted/fired.
  207. *
  208. * @example
  209. * var i = 0;
  210. * var obj = {}.once('increment', function(){
  211. * console.log(++i);
  212. * });
  213. * obj.emit('increment'); // 1 true
  214. * obj.emit('increment'); // false
  215. *
  216. * @param type string the event name to emit
  217. * @param handler Function|Object the handler used initially
  218. * @param [optional, **reserved**] boolean unshift instead of push
  219. * @return Object the chained object that called `.once()`
  220. */
  221. once: function once(type, handler, capture) {
  222. var self = this;
  223. return self.on(type, function once(e) {
  224. self.off(type, once, capture);
  225. triggerEvent(self, handler, arguments);
  226. }, capture);
  227. },
  228. /**
  229. * Triggers an event in a *DOMish* way.
  230. * The handler wil be invoked with a single object
  231. * argument as event with at least a method called
  232. * `stopImmediatePropagation()` able to break the
  233. * method invocation loop.
  234. *
  235. * The event object will have always at least these properties:
  236. * type string the name of the event
  237. * timeStamp number when the event has been triggered
  238. * target object the original object that triggered
  239. * data [any] optional argument passed through
  240. * eventually copied over the event
  241. *
  242. * @example
  243. * var o = {}.on('evt', function(e){
  244. * console.log(e.type);
  245. * console.log(e.data === RegExp);
  246. * });
  247. * o.trigger('evt', RegExp);
  248. * // "evt" true true
  249. *
  250. * @param type string the event name to emit
  251. * @param [any=any] optional data object to pass through
  252. * and/or copy over the event object
  253. * @return boolean true if the event was triggered
  254. */
  255. trigger: function trigger(evt, data) {
  256. var
  257. has = hasOwnProperty.call(this, SECRET),
  258. listeners = has && this[SECRET].l,
  259. isString = typeof evt == 'string',
  260. type = isString ? evt : evt.type,
  261. loop = has && hasOwnProperty.call(listeners, type),
  262. array = loop && listeners[type],
  263. event = isString ?
  264. new Event(this, type, data) : evt,
  265. args = [event],
  266. i = 0,
  267. length = loop ? array.length : i,
  268. isNotAnEventInstance = !(event instanceof Event),
  269. result,
  270. current;
  271. if (isNotAnEventInstance) {
  272. event._active = true;
  273. event.stopImmediatePropagation =
  274. EventPrototype.stopImmediatePropagation;
  275. }
  276. event.currentTarget = this;
  277. while (event._active && i < length) {
  278. triggerEvent(this, array[i++], args);
  279. }
  280. result = !!event._active;
  281. if (isNotAnEventInstance) {
  282. delete event._active;
  283. delete event.stopImmediatePropagation;
  284. }
  285. return result;
  286. }
  287. },
  288. key;
  289. /* eddy.js private helpers/shortcuts */
  290. // the object used to trap listeners and bound functions
  291. function createSecret() {
  292. return {
  293. l: {},
  294. m: [],
  295. b: []
  296. };
  297. }
  298. // assign properties only if not there already
  299. function ifNotPresent(e, key, value) {
  300. if (!hasOwnProperty.call(e, key)) {
  301. e[key] = value;
  302. }
  303. }
  304. function setAndGet(self) {
  305. var value = createSecret();
  306. commonDescriptor.value = value;
  307. defineProperty(self, SECRET, commonDescriptor);
  308. commonDescriptor.value = null;
  309. return value;
  310. }
  311. // check if the handler is a function OR an object
  312. // in latter case invoke `handler.handleEvent(args)`
  313. // compatible with DOM event handlers
  314. function triggerEvent(context, handler, args) {
  315. if (typeof handler == 'function') {
  316. handler.apply(context, args);
  317. } else {
  318. handler.handleEvent.apply(handler, args);
  319. }
  320. }
  321. /* the basic eddy.js Event class */
  322. function Event(target, type, data) {
  323. ifNotPresent(this, 'timeStamp', now());
  324. for (var key in data) {
  325. if (hasOwnProperty.call(data, key)) {
  326. ifNotPresent(this, key, data[key]);
  327. }
  328. }
  329. ifNotPresent(this, 'type', type);
  330. ifNotPresent(this, 'target', target);
  331. if (data) ifNotPresent(this, 'data', data);
  332. }
  333. EventPrototype._active = true;
  334. EventPrototype.stopImmediatePropagation = function () {
  335. this._active = false;
  336. };
  337. // assign in the least obtrusive way eddy properties
  338. for (key in eddy) {
  339. if (hasOwnProperty.call(eddy, key)) {
  340. defineProperty(ObjectPrototype, key, {
  341. enumerable: false,
  342. configurable: true,
  343. writable: true,
  344. value: eddy[key]
  345. });
  346. }
  347. }
  348. }(Object));