Dashboard sipadu mbip
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

event-base-debug.js 41KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 3.4.0
  6. build: nightly
  7. */
  8. (function () {
  9. var GLOBAL_ENV = YUI.Env;
  10. if (!GLOBAL_ENV._ready) {
  11. GLOBAL_ENV._ready = function() {
  12. GLOBAL_ENV.DOMReady = true;
  13. GLOBAL_ENV.remove(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready);
  14. };
  15. GLOBAL_ENV.add(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready);
  16. }
  17. })();
  18. YUI.add('event-base', function(Y) {
  19. /*
  20. * DOM event listener abstraction layer
  21. * @module event
  22. * @submodule event-base
  23. */
  24. /**
  25. * The domready event fires at the moment the browser's DOM is
  26. * usable. In most cases, this is before images are fully
  27. * downloaded, allowing you to provide a more responsive user
  28. * interface.
  29. *
  30. * In YUI 3, domready subscribers will be notified immediately if
  31. * that moment has already passed when the subscription is created.
  32. *
  33. * One exception is if the yui.js file is dynamically injected into
  34. * the page. If this is done, you must tell the YUI instance that
  35. * you did this in order for DOMReady (and window load events) to
  36. * fire normally. That configuration option is 'injected' -- set
  37. * it to true if the yui.js script is not included inline.
  38. *
  39. * This method is part of the 'event-ready' module, which is a
  40. * submodule of 'event'.
  41. *
  42. * @event domready
  43. * @for YUI
  44. */
  45. Y.publish('domready', {
  46. fireOnce: true,
  47. async: true
  48. });
  49. if (YUI.Env.DOMReady) {
  50. Y.fire('domready');
  51. } else {
  52. Y.Do.before(function() { Y.fire('domready'); }, YUI.Env, '_ready');
  53. }
  54. /**
  55. * Custom event engine, DOM event listener abstraction layer, synthetic DOM
  56. * events.
  57. * @module event
  58. * @submodule event-base
  59. */
  60. /**
  61. * Wraps a DOM event, properties requiring browser abstraction are
  62. * fixed here. Provids a security layer when required.
  63. * @class DOMEventFacade
  64. * @param ev {Event} the DOM event
  65. * @param currentTarget {HTMLElement} the element the listener was attached to
  66. * @param wrapper {Event.Custom} the custom event wrapper for this DOM event
  67. */
  68. var ua = Y.UA,
  69. EMPTY = {},
  70. /**
  71. * webkit key remapping required for Safari < 3.1
  72. * @property webkitKeymap
  73. * @private
  74. */
  75. webkitKeymap = {
  76. 63232: 38, // up
  77. 63233: 40, // down
  78. 63234: 37, // left
  79. 63235: 39, // right
  80. 63276: 33, // page up
  81. 63277: 34, // page down
  82. 25: 9, // SHIFT-TAB (Safari provides a different key code in
  83. // this case, even though the shiftKey modifier is set)
  84. 63272: 46, // delete
  85. 63273: 36, // home
  86. 63275: 35 // end
  87. },
  88. /**
  89. * Returns a wrapped node. Intended to be used on event targets,
  90. * so it will return the node's parent if the target is a text
  91. * node.
  92. *
  93. * If accessing a property of the node throws an error, this is
  94. * probably the anonymous div wrapper Gecko adds inside text
  95. * nodes. This likely will only occur when attempting to access
  96. * the relatedTarget. In this case, we now return null because
  97. * the anonymous div is completely useless and we do not know
  98. * what the related target was because we can't even get to
  99. * the element's parent node.
  100. *
  101. * @method resolve
  102. * @private
  103. */
  104. resolve = function(n) {
  105. if (!n) {
  106. return n;
  107. }
  108. try {
  109. if (n && 3 == n.nodeType) {
  110. n = n.parentNode;
  111. }
  112. } catch(e) {
  113. return null;
  114. }
  115. return Y.one(n);
  116. },
  117. DOMEventFacade = function(ev, currentTarget, wrapper) {
  118. this._event = ev;
  119. this._currentTarget = currentTarget;
  120. this._wrapper = wrapper || EMPTY;
  121. // if not lazy init
  122. this.init();
  123. };
  124. Y.extend(DOMEventFacade, Object, {
  125. init: function() {
  126. var e = this._event,
  127. overrides = this._wrapper.overrides,
  128. x = e.pageX,
  129. y = e.pageY,
  130. c,
  131. currentTarget = this._currentTarget;
  132. this.altKey = e.altKey;
  133. this.ctrlKey = e.ctrlKey;
  134. this.metaKey = e.metaKey;
  135. this.shiftKey = e.shiftKey;
  136. this.type = (overrides && overrides.type) || e.type;
  137. this.clientX = e.clientX;
  138. this.clientY = e.clientY;
  139. this.pageX = x;
  140. this.pageY = y;
  141. c = e.keyCode || e.charCode;
  142. if (ua.webkit && (c in webkitKeymap)) {
  143. c = webkitKeymap[c];
  144. }
  145. this.keyCode = c;
  146. this.charCode = c;
  147. this.which = e.which || e.charCode || c;
  148. // this.button = e.button;
  149. this.button = this.which;
  150. this.target = resolve(e.target);
  151. this.currentTarget = resolve(currentTarget);
  152. this.relatedTarget = resolve(e.relatedTarget);
  153. if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
  154. this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
  155. }
  156. if (this._touch) {
  157. this._touch(e, currentTarget, this._wrapper);
  158. }
  159. },
  160. stopPropagation: function() {
  161. this._event.stopPropagation();
  162. this._wrapper.stopped = 1;
  163. this.stopped = 1;
  164. },
  165. stopImmediatePropagation: function() {
  166. var e = this._event;
  167. if (e.stopImmediatePropagation) {
  168. e.stopImmediatePropagation();
  169. } else {
  170. this.stopPropagation();
  171. }
  172. this._wrapper.stopped = 2;
  173. this.stopped = 2;
  174. },
  175. preventDefault: function(returnValue) {
  176. var e = this._event;
  177. e.preventDefault();
  178. e.returnValue = returnValue || false;
  179. this._wrapper.prevented = 1;
  180. this.prevented = 1;
  181. },
  182. halt: function(immediate) {
  183. if (immediate) {
  184. this.stopImmediatePropagation();
  185. } else {
  186. this.stopPropagation();
  187. }
  188. this.preventDefault();
  189. }
  190. });
  191. DOMEventFacade.resolve = resolve;
  192. Y.DOM2EventFacade = DOMEventFacade;
  193. Y.DOMEventFacade = DOMEventFacade;
  194. /**
  195. * The native event
  196. * @property _event
  197. * @type {Native DOM Event}
  198. * @private
  199. */
  200. /**
  201. The name of the event (e.g. "click")
  202. @property type
  203. @type {String}
  204. **/
  205. /**
  206. `true` if the "alt" or "option" key is pressed.
  207. @property altKey
  208. @type {Boolean}
  209. **/
  210. /**
  211. `true` if the shift key is pressed.
  212. @property shiftKey
  213. @type {Boolean}
  214. **/
  215. /**
  216. `true` if the "Windows" key on a Windows keyboard, "command" key on an
  217. Apple keyboard, or "meta" key on other keyboards is pressed.
  218. @property metaKey
  219. @type {Boolean}
  220. **/
  221. /**
  222. `true` if the "Ctrl" or "control" key is pressed.
  223. @property ctrlKey
  224. @type {Boolean}
  225. **/
  226. /**
  227. * The X location of the event on the page (including scroll)
  228. * @property pageX
  229. * @type {Number}
  230. */
  231. /**
  232. * The Y location of the event on the page (including scroll)
  233. * @property pageY
  234. * @type {Number}
  235. */
  236. /**
  237. * The X location of the event in the viewport
  238. * @property clientX
  239. * @type {Number}
  240. */
  241. /**
  242. * The Y location of the event in the viewport
  243. * @property clientY
  244. * @type {Number}
  245. */
  246. /**
  247. * The keyCode for key events. Uses charCode if keyCode is not available
  248. * @property keyCode
  249. * @type {Number}
  250. */
  251. /**
  252. * The charCode for key events. Same as keyCode
  253. * @property charCode
  254. * @type {Number}
  255. */
  256. /**
  257. * The button that was pushed. 1 for left click, 2 for middle click, 3 for
  258. * right click. This is only reliably populated on `mouseup` events.
  259. * @property button
  260. * @type {Number}
  261. */
  262. /**
  263. * The button that was pushed. Same as button.
  264. * @property which
  265. * @type {Number}
  266. */
  267. /**
  268. * Node reference for the targeted element
  269. * @property target
  270. * @type {Node}
  271. */
  272. /**
  273. * Node reference for the element that the listener was attached to.
  274. * @property currentTarget
  275. * @type {Node}
  276. */
  277. /**
  278. * Node reference to the relatedTarget
  279. * @property relatedTarget
  280. * @type {Node}
  281. */
  282. /**
  283. * Number representing the direction and velocity of the movement of the mousewheel.
  284. * Negative is down, the higher the number, the faster. Applies to the mousewheel event.
  285. * @property wheelDelta
  286. * @type {Number}
  287. */
  288. /**
  289. * Stops the propagation to the next bubble target
  290. * @method stopPropagation
  291. */
  292. /**
  293. * Stops the propagation to the next bubble target and
  294. * prevents any additional listeners from being exectued
  295. * on the current target.
  296. * @method stopImmediatePropagation
  297. */
  298. /**
  299. * Prevents the event's default behavior
  300. * @method preventDefault
  301. * @param returnValue {string} sets the returnValue of the event to this value
  302. * (rather than the default false value). This can be used to add a customized
  303. * confirmation query to the beforeunload event).
  304. */
  305. /**
  306. * Stops the event propagation and prevents the default
  307. * event behavior.
  308. * @method halt
  309. * @param immediate {boolean} if true additional listeners
  310. * on the current target will not be executed
  311. */
  312. (function() {
  313. /**
  314. * The event utility provides functions to add and remove event listeners,
  315. * event cleansing. It also tries to automatically remove listeners it
  316. * registers during the unload event.
  317. * @module event
  318. * @main event
  319. * @submodule event-base
  320. */
  321. /**
  322. * The event utility provides functions to add and remove event listeners,
  323. * event cleansing. It also tries to automatically remove listeners it
  324. * registers during the unload event.
  325. *
  326. * @class Event
  327. * @static
  328. */
  329. Y.Env.evt.dom_wrappers = {};
  330. Y.Env.evt.dom_map = {};
  331. var _eventenv = Y.Env.evt,
  332. config = Y.config,
  333. win = config.win,
  334. add = YUI.Env.add,
  335. remove = YUI.Env.remove,
  336. onLoad = function() {
  337. YUI.Env.windowLoaded = true;
  338. Y.Event._load();
  339. remove(win, "load", onLoad);
  340. },
  341. onUnload = function() {
  342. Y.Event._unload();
  343. },
  344. EVENT_READY = 'domready',
  345. COMPAT_ARG = '~yui|2|compat~',
  346. shouldIterate = function(o) {
  347. try {
  348. return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) &&
  349. !o.tagName && !o.alert);
  350. } catch(ex) {
  351. Y.log("collection check failure", "warn", "event");
  352. return false;
  353. }
  354. },
  355. // aliases to support DOM event subscription clean up when the last
  356. // subscriber is detached. deleteAndClean overrides the DOM event's wrapper
  357. // CustomEvent _delete method.
  358. _ceProtoDelete = Y.CustomEvent.prototype._delete,
  359. _deleteAndClean = function(s) {
  360. var ret = _ceProtoDelete.apply(this, arguments);
  361. if (!this.hasSubs()) {
  362. Y.Event._clean(this);
  363. }
  364. return ret;
  365. },
  366. Event = function() {
  367. /**
  368. * True after the onload event has fired
  369. * @property _loadComplete
  370. * @type boolean
  371. * @static
  372. * @private
  373. */
  374. var _loadComplete = false,
  375. /**
  376. * The number of times to poll after window.onload. This number is
  377. * increased if additional late-bound handlers are requested after
  378. * the page load.
  379. * @property _retryCount
  380. * @static
  381. * @private
  382. */
  383. _retryCount = 0,
  384. /**
  385. * onAvailable listeners
  386. * @property _avail
  387. * @static
  388. * @private
  389. */
  390. _avail = [],
  391. /**
  392. * Custom event wrappers for DOM events. Key is
  393. * 'event:' + Element uid stamp + event type
  394. * @property _wrappers
  395. * @type Y.Event.Custom
  396. * @static
  397. * @private
  398. */
  399. _wrappers = _eventenv.dom_wrappers,
  400. _windowLoadKey = null,
  401. /**
  402. * Custom event wrapper map DOM events. Key is
  403. * Element uid stamp. Each item is a hash of custom event
  404. * wrappers as provided in the _wrappers collection. This
  405. * provides the infrastructure for getListeners.
  406. * @property _el_events
  407. * @static
  408. * @private
  409. */
  410. _el_events = _eventenv.dom_map;
  411. return {
  412. /**
  413. * The number of times we should look for elements that are not
  414. * in the DOM at the time the event is requested after the document
  415. * has been loaded. The default is 1000@amp;40 ms, so it will poll
  416. * for 40 seconds or until all outstanding handlers are bound
  417. * (whichever comes first).
  418. * @property POLL_RETRYS
  419. * @type int
  420. * @static
  421. * @final
  422. */
  423. POLL_RETRYS: 1000,
  424. /**
  425. * The poll interval in milliseconds
  426. * @property POLL_INTERVAL
  427. * @type int
  428. * @static
  429. * @final
  430. */
  431. POLL_INTERVAL: 40,
  432. /**
  433. * addListener/removeListener can throw errors in unexpected scenarios.
  434. * These errors are suppressed, the method returns false, and this property
  435. * is set
  436. * @property lastError
  437. * @static
  438. * @type Error
  439. */
  440. lastError: null,
  441. /**
  442. * poll handle
  443. * @property _interval
  444. * @static
  445. * @private
  446. */
  447. _interval: null,
  448. /**
  449. * document readystate poll handle
  450. * @property _dri
  451. * @static
  452. * @private
  453. */
  454. _dri: null,
  455. /**
  456. * True when the document is initially usable
  457. * @property DOMReady
  458. * @type boolean
  459. * @static
  460. */
  461. DOMReady: false,
  462. /**
  463. * @method startInterval
  464. * @static
  465. * @private
  466. */
  467. startInterval: function() {
  468. if (!Event._interval) {
  469. Event._interval = setInterval(Event._poll, Event.POLL_INTERVAL);
  470. }
  471. },
  472. /**
  473. * Executes the supplied callback when the item with the supplied
  474. * id is found. This is meant to be used to execute behavior as
  475. * soon as possible as the page loads. If you use this after the
  476. * initial page load it will poll for a fixed time for the element.
  477. * The number of times it will poll and the frequency are
  478. * configurable. By default it will poll for 10 seconds.
  479. *
  480. * <p>The callback is executed with a single parameter:
  481. * the custom object parameter, if provided.</p>
  482. *
  483. * @method onAvailable
  484. *
  485. * @param {string||string[]} id the id of the element, or an array
  486. * of ids to look for.
  487. * @param {function} fn what to execute when the element is found.
  488. * @param {object} p_obj an optional object to be passed back as
  489. * a parameter to fn.
  490. * @param {boolean|object} p_override If set to true, fn will execute
  491. * in the context of p_obj, if set to an object it
  492. * will execute in the context of that object
  493. * @param checkContent {boolean} check child node readiness (onContentReady)
  494. * @static
  495. * @deprecated Use Y.on("available")
  496. */
  497. // @TODO fix arguments
  498. onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
  499. var a = Y.Array(id), i, availHandle;
  500. // Y.log('onAvailable registered for: ' + id);
  501. for (i=0; i<a.length; i=i+1) {
  502. _avail.push({
  503. id: a[i],
  504. fn: fn,
  505. obj: p_obj,
  506. override: p_override,
  507. checkReady: checkContent,
  508. compat: compat
  509. });
  510. }
  511. _retryCount = this.POLL_RETRYS;
  512. // We want the first test to be immediate, but async
  513. setTimeout(Event._poll, 0);
  514. availHandle = new Y.EventHandle({
  515. _delete: function() {
  516. // set by the event system for lazy DOM listeners
  517. if (availHandle.handle) {
  518. availHandle.handle.detach();
  519. return;
  520. }
  521. var i, j;
  522. // otherwise try to remove the onAvailable listener(s)
  523. for (i = 0; i < a.length; i++) {
  524. for (j = 0; j < _avail.length; j++) {
  525. if (a[i] === _avail[j].id) {
  526. _avail.splice(j, 1);
  527. }
  528. }
  529. }
  530. }
  531. });
  532. return availHandle;
  533. },
  534. /**
  535. * Works the same way as onAvailable, but additionally checks the
  536. * state of sibling elements to determine if the content of the
  537. * available element is safe to modify.
  538. *
  539. * <p>The callback is executed with a single parameter:
  540. * the custom object parameter, if provided.</p>
  541. *
  542. * @method onContentReady
  543. *
  544. * @param {string} id the id of the element to look for.
  545. * @param {function} fn what to execute when the element is ready.
  546. * @param {object} obj an optional object to be passed back as
  547. * a parameter to fn.
  548. * @param {boolean|object} override If set to true, fn will execute
  549. * in the context of p_obj. If an object, fn will
  550. * exectute in the context of that object
  551. *
  552. * @static
  553. * @deprecated Use Y.on("contentready")
  554. */
  555. // @TODO fix arguments
  556. onContentReady: function(id, fn, obj, override, compat) {
  557. return Event.onAvailable(id, fn, obj, override, true, compat);
  558. },
  559. /**
  560. * Adds an event listener
  561. *
  562. * @method attach
  563. *
  564. * @param {String} type The type of event to append
  565. * @param {Function} fn The method the event invokes
  566. * @param {String|HTMLElement|Array|NodeList} el An id, an element
  567. * reference, or a collection of ids and/or elements to assign the
  568. * listener to.
  569. * @param {Object} context optional context object
  570. * @param {Boolean|object} args 0..n arguments to pass to the callback
  571. * @return {EventHandle} an object to that can be used to detach the listener
  572. *
  573. * @static
  574. */
  575. attach: function(type, fn, el, context) {
  576. return Event._attach(Y.Array(arguments, 0, true));
  577. },
  578. _createWrapper: function (el, type, capture, compat, facade) {
  579. var cewrapper,
  580. ek = Y.stamp(el),
  581. key = 'event:' + ek + type;
  582. if (false === facade) {
  583. key += 'native';
  584. }
  585. if (capture) {
  586. key += 'capture';
  587. }
  588. cewrapper = _wrappers[key];
  589. if (!cewrapper) {
  590. // create CE wrapper
  591. cewrapper = Y.publish(key, {
  592. silent: true,
  593. bubbles: false,
  594. contextFn: function() {
  595. if (compat) {
  596. return cewrapper.el;
  597. } else {
  598. cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
  599. return cewrapper.nodeRef;
  600. }
  601. }
  602. });
  603. cewrapper.overrides = {};
  604. // for later removeListener calls
  605. cewrapper.el = el;
  606. cewrapper.key = key;
  607. cewrapper.domkey = ek;
  608. cewrapper.type = type;
  609. cewrapper.fn = function(e) {
  610. cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade))));
  611. };
  612. cewrapper.capture = capture;
  613. if (el == win && type == "load") {
  614. // window load happens once
  615. cewrapper.fireOnce = true;
  616. _windowLoadKey = key;
  617. }
  618. cewrapper._delete = _deleteAndClean;
  619. _wrappers[key] = cewrapper;
  620. _el_events[ek] = _el_events[ek] || {};
  621. _el_events[ek][key] = cewrapper;
  622. add(el, type, cewrapper.fn, capture);
  623. }
  624. return cewrapper;
  625. },
  626. _attach: function(args, conf) {
  627. var compat,
  628. handles, oEl, cewrapper, context,
  629. fireNow = false, ret,
  630. type = args[0],
  631. fn = args[1],
  632. el = args[2] || win,
  633. facade = conf && conf.facade,
  634. capture = conf && conf.capture,
  635. overrides = conf && conf.overrides;
  636. if (args[args.length-1] === COMPAT_ARG) {
  637. compat = true;
  638. }
  639. if (!fn || !fn.call) {
  640. // throw new TypeError(type + " attach call failed, callback undefined");
  641. Y.log(type + " attach call failed, invalid callback", "error", "event");
  642. return false;
  643. }
  644. // The el argument can be an array of elements or element ids.
  645. if (shouldIterate(el)) {
  646. handles=[];
  647. Y.each(el, function(v, k) {
  648. args[2] = v;
  649. handles.push(Event._attach(args.slice(), conf));
  650. });
  651. // return (handles.length === 1) ? handles[0] : handles;
  652. return new Y.EventHandle(handles);
  653. // If the el argument is a string, we assume it is
  654. // actually the id of the element. If the page is loaded
  655. // we convert el to the actual element, otherwise we
  656. // defer attaching the event until the element is
  657. // ready
  658. } else if (Y.Lang.isString(el)) {
  659. // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
  660. if (compat) {
  661. oEl = Y.DOM.byId(el);
  662. } else {
  663. oEl = Y.Selector.query(el);
  664. switch (oEl.length) {
  665. case 0:
  666. oEl = null;
  667. break;
  668. case 1:
  669. oEl = oEl[0];
  670. break;
  671. default:
  672. args[2] = oEl;
  673. return Event._attach(args, conf);
  674. }
  675. }
  676. if (oEl) {
  677. el = oEl;
  678. // Not found = defer adding the event until the element is available
  679. } else {
  680. // Y.log(el + ' not found');
  681. ret = Event.onAvailable(el, function() {
  682. // Y.log('lazy attach: ' + args);
  683. ret.handle = Event._attach(args, conf);
  684. }, Event, true, false, compat);
  685. return ret;
  686. }
  687. }
  688. // Element should be an html element or node
  689. if (!el) {
  690. Y.log("unable to attach event " + type, "warn", "event");
  691. return false;
  692. }
  693. if (Y.Node && Y.instanceOf(el, Y.Node)) {
  694. el = Y.Node.getDOMNode(el);
  695. }
  696. cewrapper = Event._createWrapper(el, type, capture, compat, facade);
  697. if (overrides) {
  698. Y.mix(cewrapper.overrides, overrides);
  699. }
  700. if (el == win && type == "load") {
  701. // if the load is complete, fire immediately.
  702. // all subscribers, including the current one
  703. // will be notified.
  704. if (YUI.Env.windowLoaded) {
  705. fireNow = true;
  706. }
  707. }
  708. if (compat) {
  709. args.pop();
  710. }
  711. context = args[3];
  712. // set context to the Node if not specified
  713. // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
  714. ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
  715. if (fireNow) {
  716. cewrapper.fire();
  717. }
  718. return ret;
  719. },
  720. /**
  721. * Removes an event listener. Supports the signature the event was bound
  722. * with, but the preferred way to remove listeners is using the handle
  723. * that is returned when using Y.on
  724. *
  725. * @method detach
  726. *
  727. * @param {String} type the type of event to remove.
  728. * @param {Function} fn the method the event invokes. If fn is
  729. * undefined, then all event handlers for the type of event are
  730. * removed.
  731. * @param {String|HTMLElement|Array|NodeList|EventHandle} el An
  732. * event handle, an id, an element reference, or a collection
  733. * of ids and/or elements to remove the listener from.
  734. * @return {boolean} true if the unbind was successful, false otherwise.
  735. * @static
  736. */
  737. detach: function(type, fn, el, obj) {
  738. var args=Y.Array(arguments, 0, true), compat, l, ok, i,
  739. id, ce;
  740. if (args[args.length-1] === COMPAT_ARG) {
  741. compat = true;
  742. // args.pop();
  743. }
  744. if (type && type.detach) {
  745. return type.detach();
  746. }
  747. // The el argument can be a string
  748. if (typeof el == "string") {
  749. // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
  750. if (compat) {
  751. el = Y.DOM.byId(el);
  752. } else {
  753. el = Y.Selector.query(el);
  754. l = el.length;
  755. if (l < 1) {
  756. el = null;
  757. } else if (l == 1) {
  758. el = el[0];
  759. }
  760. }
  761. // return Event.detach.apply(Event, args);
  762. }
  763. if (!el) {
  764. return false;
  765. }
  766. if (el.detach) {
  767. args.splice(2, 1);
  768. return el.detach.apply(el, args);
  769. // The el argument can be an array of elements or element ids.
  770. } else if (shouldIterate(el)) {
  771. ok = true;
  772. for (i=0, l=el.length; i<l; ++i) {
  773. args[2] = el[i];
  774. ok = ( Y.Event.detach.apply(Y.Event, args) && ok );
  775. }
  776. return ok;
  777. }
  778. if (!type || !fn || !fn.call) {
  779. return Event.purgeElement(el, false, type);
  780. }
  781. id = 'event:' + Y.stamp(el) + type;
  782. ce = _wrappers[id];
  783. if (ce) {
  784. return ce.detach(fn);
  785. } else {
  786. return false;
  787. }
  788. },
  789. /**
  790. * Finds the event in the window object, the caller's arguments, or
  791. * in the arguments of another method in the callstack. This is
  792. * executed automatically for events registered through the event
  793. * manager, so the implementer should not normally need to execute
  794. * this function at all.
  795. * @method getEvent
  796. * @param {Event} e the event parameter from the handler
  797. * @param {HTMLElement} el the element the listener was attached to
  798. * @return {Event} the event
  799. * @static
  800. */
  801. getEvent: function(e, el, noFacade) {
  802. var ev = e || win.event;
  803. return (noFacade) ? ev :
  804. new Y.DOMEventFacade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]);
  805. },
  806. /**
  807. * Generates an unique ID for the element if it does not already
  808. * have one.
  809. * @method generateId
  810. * @param el the element to create the id for
  811. * @return {string} the resulting id of the element
  812. * @static
  813. */
  814. generateId: function(el) {
  815. return Y.DOM.generateID(el);
  816. },
  817. /**
  818. * We want to be able to use getElementsByTagName as a collection
  819. * to attach a group of events to. Unfortunately, different
  820. * browsers return different types of collections. This function
  821. * tests to determine if the object is array-like. It will also
  822. * fail if the object is an array, but is empty.
  823. * @method _isValidCollection
  824. * @param o the object to test
  825. * @return {boolean} true if the object is array-like and populated
  826. * @deprecated was not meant to be used directly
  827. * @static
  828. * @private
  829. */
  830. _isValidCollection: shouldIterate,
  831. /**
  832. * hook up any deferred listeners
  833. * @method _load
  834. * @static
  835. * @private
  836. */
  837. _load: function(e) {
  838. if (!_loadComplete) {
  839. // Y.log('Load Complete', 'info', 'event');
  840. _loadComplete = true;
  841. // Just in case DOMReady did not go off for some reason
  842. // E._ready();
  843. if (Y.fire) {
  844. Y.fire(EVENT_READY);
  845. }
  846. // Available elements may not have been detected before the
  847. // window load event fires. Try to find them now so that the
  848. // the user is more likely to get the onAvailable notifications
  849. // before the window load notification
  850. Event._poll();
  851. }
  852. },
  853. /**
  854. * Polling function that runs before the onload event fires,
  855. * attempting to attach To DoM Nodes as soon as they are
  856. * available
  857. * @method _poll
  858. * @static
  859. * @private
  860. */
  861. _poll: function() {
  862. if (Event.locked) {
  863. return;
  864. }
  865. if (Y.UA.ie && !YUI.Env.DOMReady) {
  866. // Hold off if DOMReady has not fired and check current
  867. // readyState to protect against the IE operation aborted
  868. // issue.
  869. Event.startInterval();
  870. return;
  871. }
  872. Event.locked = true;
  873. // Y.log.debug("poll");
  874. // keep trying until after the page is loaded. We need to
  875. // check the page load state prior to trying to bind the
  876. // elements so that we can be certain all elements have been
  877. // tested appropriately
  878. var i, len, item, el, notAvail, executeItem,
  879. tryAgain = !_loadComplete;
  880. if (!tryAgain) {
  881. tryAgain = (_retryCount > 0);
  882. }
  883. // onAvailable
  884. notAvail = [];
  885. executeItem = function (el, item) {
  886. var context, ov = item.override;
  887. if (item.compat) {
  888. if (item.override) {
  889. if (ov === true) {
  890. context = item.obj;
  891. } else {
  892. context = ov;
  893. }
  894. } else {
  895. context = el;
  896. }
  897. item.fn.call(context, item.obj);
  898. } else {
  899. context = item.obj || Y.one(el);
  900. item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
  901. }
  902. };
  903. // onAvailable
  904. for (i=0,len=_avail.length; i<len; ++i) {
  905. item = _avail[i];
  906. if (item && !item.checkReady) {
  907. // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
  908. el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
  909. if (el) {
  910. // Y.log('avail: ' + el);
  911. executeItem(el, item);
  912. _avail[i] = null;
  913. } else {
  914. // Y.log('NOT avail: ' + el);
  915. notAvail.push(item);
  916. }
  917. }
  918. }
  919. // onContentReady
  920. for (i=0,len=_avail.length; i<len; ++i) {
  921. item = _avail[i];
  922. if (item && item.checkReady) {
  923. // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
  924. el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
  925. if (el) {
  926. // The element is available, but not necessarily ready
  927. // @todo should we test parentNode.nextSibling?
  928. if (_loadComplete || (el.get && el.get('nextSibling')) || el.nextSibling) {
  929. executeItem(el, item);
  930. _avail[i] = null;
  931. }
  932. } else {
  933. notAvail.push(item);
  934. }
  935. }
  936. }
  937. _retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1;
  938. if (tryAgain) {
  939. // we may need to strip the nulled out items here
  940. Event.startInterval();
  941. } else {
  942. clearInterval(Event._interval);
  943. Event._interval = null;
  944. }
  945. Event.locked = false;
  946. return;
  947. },
  948. /**
  949. * Removes all listeners attached to the given element via addListener.
  950. * Optionally, the node's children can also be purged.
  951. * Optionally, you can specify a specific type of event to remove.
  952. * @method purgeElement
  953. * @param {HTMLElement} el the element to purge
  954. * @param {boolean} recurse recursively purge this element's children
  955. * as well. Use with caution.
  956. * @param {string} type optional type of listener to purge. If
  957. * left out, all listeners will be removed
  958. * @static
  959. */
  960. purgeElement: function(el, recurse, type) {
  961. // var oEl = (Y.Lang.isString(el)) ? Y.one(el) : el,
  962. var oEl = (Y.Lang.isString(el)) ? Y.Selector.query(el, null, true) : el,
  963. lis = Event.getListeners(oEl, type), i, len, children, child;
  964. if (recurse && oEl) {
  965. lis = lis || [];
  966. children = Y.Selector.query('*', oEl);
  967. i = 0;
  968. len = children.length;
  969. for (; i < len; ++i) {
  970. child = Event.getListeners(children[i], type);
  971. if (child) {
  972. lis = lis.concat(child);
  973. }
  974. }
  975. }
  976. if (lis) {
  977. for (i = 0, len = lis.length; i < len; ++i) {
  978. lis[i].detachAll();
  979. }
  980. }
  981. },
  982. /**
  983. * Removes all object references and the DOM proxy subscription for
  984. * a given event for a DOM node.
  985. *
  986. * @method _clean
  987. * @param wrapper {CustomEvent} Custom event proxy for the DOM
  988. * subscription
  989. * @private
  990. * @static
  991. * @since 3.4.0
  992. */
  993. _clean: function (wrapper) {
  994. var key = wrapper.key,
  995. domkey = wrapper.domkey;
  996. remove(wrapper.el, wrapper.type, wrapper.fn, wrapper.capture);
  997. delete _wrappers[key];
  998. delete Y._yuievt.events[key];
  999. if (_el_events[domkey]) {
  1000. delete _el_events[domkey][key];
  1001. if (!Y.Object.size(_el_events[domkey])) {
  1002. delete _el_events[domkey];
  1003. }
  1004. }
  1005. },
  1006. /**
  1007. * Returns all listeners attached to the given element via addListener.
  1008. * Optionally, you can specify a specific type of event to return.
  1009. * @method getListeners
  1010. * @param el {HTMLElement|string} the element or element id to inspect
  1011. * @param type {string} optional type of listener to return. If
  1012. * left out, all listeners will be returned
  1013. * @return {CustomEvent} the custom event wrapper for the DOM event(s)
  1014. * @static
  1015. */
  1016. getListeners: function(el, type) {
  1017. var ek = Y.stamp(el, true), evts = _el_events[ek],
  1018. results=[] , key = (type) ? 'event:' + ek + type : null,
  1019. adapters = _eventenv.plugins;
  1020. if (!evts) {
  1021. return null;
  1022. }
  1023. if (key) {
  1024. // look for synthetic events
  1025. if (adapters[type] && adapters[type].eventDef) {
  1026. key += '_synth';
  1027. }
  1028. if (evts[key]) {
  1029. results.push(evts[key]);
  1030. }
  1031. // get native events as well
  1032. key += 'native';
  1033. if (evts[key]) {
  1034. results.push(evts[key]);
  1035. }
  1036. } else {
  1037. Y.each(evts, function(v, k) {
  1038. results.push(v);
  1039. });
  1040. }
  1041. return (results.length) ? results : null;
  1042. },
  1043. /**
  1044. * Removes all listeners registered by pe.event. Called
  1045. * automatically during the unload event.
  1046. * @method _unload
  1047. * @static
  1048. * @private
  1049. */
  1050. _unload: function(e) {
  1051. Y.each(_wrappers, function(v, k) {
  1052. if (v.type == 'unload') {
  1053. v.fire(e);
  1054. }
  1055. v.detachAll();
  1056. });
  1057. remove(win, "unload", onUnload);
  1058. },
  1059. /**
  1060. * Adds a DOM event directly without the caching, cleanup, context adj, etc
  1061. *
  1062. * @method nativeAdd
  1063. * @param {HTMLElement} el the element to bind the handler to
  1064. * @param {string} type the type of event handler
  1065. * @param {function} fn the callback to invoke
  1066. * @param {boolen} capture capture or bubble phase
  1067. * @static
  1068. * @private
  1069. */
  1070. nativeAdd: add,
  1071. /**
  1072. * Basic remove listener
  1073. *
  1074. * @method nativeRemove
  1075. * @param {HTMLElement} el the element to bind the handler to
  1076. * @param {string} type the type of event handler
  1077. * @param {function} fn the callback to invoke
  1078. * @param {boolen} capture capture or bubble phase
  1079. * @static
  1080. * @private
  1081. */
  1082. nativeRemove: remove
  1083. };
  1084. }();
  1085. Y.Event = Event;
  1086. if (config.injected || YUI.Env.windowLoaded) {
  1087. onLoad();
  1088. } else {
  1089. add(win, "load", onLoad);
  1090. }
  1091. // Process onAvailable/onContentReady items when when the DOM is ready in IE
  1092. if (Y.UA.ie) {
  1093. Y.on(EVENT_READY, Event._poll);
  1094. }
  1095. add(win, "unload", onUnload);
  1096. Event.Custom = Y.CustomEvent;
  1097. Event.Subscriber = Y.Subscriber;
  1098. Event.Target = Y.EventTarget;
  1099. Event.Handle = Y.EventHandle;
  1100. Event.Facade = Y.EventFacade;
  1101. Event._poll();
  1102. })();
  1103. /**
  1104. * DOM event listener abstraction layer
  1105. * @module event
  1106. * @submodule event-base
  1107. */
  1108. /**
  1109. * Executes the callback as soon as the specified element
  1110. * is detected in the DOM. This function expects a selector
  1111. * string for the element(s) to detect. If you already have
  1112. * an element reference, you don't need this event.
  1113. * @event available
  1114. * @param type {string} 'available'
  1115. * @param fn {function} the callback function to execute.
  1116. * @param el {string} an selector for the element(s) to attach
  1117. * @param context optional argument that specifies what 'this' refers to.
  1118. * @param args* 0..n additional arguments to pass on to the callback function.
  1119. * These arguments will be added after the event object.
  1120. * @return {EventHandle} the detach handle
  1121. * @for YUI
  1122. */
  1123. Y.Env.evt.plugins.available = {
  1124. on: function(type, fn, id, o) {
  1125. var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null;
  1126. return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
  1127. }
  1128. };
  1129. /**
  1130. * Executes the callback as soon as the specified element
  1131. * is detected in the DOM with a nextSibling property
  1132. * (indicating that the element's children are available).
  1133. * This function expects a selector
  1134. * string for the element(s) to detect. If you already have
  1135. * an element reference, you don't need this event.
  1136. * @event contentready
  1137. * @param type {string} 'contentready'
  1138. * @param fn {function} the callback function to execute.
  1139. * @param el {string} an selector for the element(s) to attach.
  1140. * @param context optional argument that specifies what 'this' refers to.
  1141. * @param args* 0..n additional arguments to pass on to the callback function.
  1142. * These arguments will be added after the event object.
  1143. * @return {EventHandle} the detach handle
  1144. * @for YUI
  1145. */
  1146. Y.Env.evt.plugins.contentready = {
  1147. on: function(type, fn, id, o) {
  1148. var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null;
  1149. return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
  1150. }
  1151. };
  1152. }, '3.4.0' ,{requires:['event-custom-base']});