dbd918cba2ff9b1b34f30656da2b48afe35e8ed4.svn-base 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210
  1. /*
  2. * Ext JS Library 2.0 Copyright(c) 2006-2007, Ext JS, LLC. licensing@extjs.com
  3. *
  4. * http://extjs.com/license
  5. */
  6. /*
  7. * Copyright (c) 2007, Yahoo! Inc. All rights reserved. Code licensed under the
  8. * BSD License: http://developer.yahoo.net/yui/license.txt version: 2.2.0
  9. */
  10. /**
  11. * The Event Utility provides utilities for managing DOM Events and tools for
  12. * building event systems
  13. *
  14. * @module event
  15. * @title Event Utility
  16. * @namespace YAHOO.util
  17. * @requires yahoo
  18. */
  19. // The first instance of Event will win if it is loaded more than once.
  20. // @TODO this needs to be changed so that only the state data that needs to
  21. // be preserved is kept, while methods are overwritten/added as needed.
  22. // This means that the module pattern can't be used.
  23. if (!YAHOO.util.Event) {
  24. /**
  25. * The event utility provides functions to add and remove event listeners,
  26. * event cleansing. It also tries to automatically remove listeners it
  27. * registers during the unload event.
  28. *
  29. * @class Event
  30. * @static
  31. */
  32. YAHOO.util.Event = function() {
  33. /**
  34. * True after the onload event has fired
  35. *
  36. * @property loadComplete
  37. * @type boolean
  38. * @static
  39. * @private
  40. */
  41. var loadComplete = false;
  42. /**
  43. * Cache of wrapped listeners
  44. *
  45. * @property listeners
  46. * @type array
  47. * @static
  48. * @private
  49. */
  50. var listeners = [];
  51. /**
  52. * User-defined unload function that will be fired before all events are
  53. * detached
  54. *
  55. * @property unloadListeners
  56. * @type array
  57. * @static
  58. * @private
  59. */
  60. var unloadListeners = [];
  61. /**
  62. * Cache of DOM0 event handlers to work around issues with DOM2 events
  63. * in Safari
  64. *
  65. * @property legacyEvents
  66. * @static
  67. * @private
  68. */
  69. var legacyEvents = [];
  70. /**
  71. * Listener stack for DOM0 events
  72. *
  73. * @property legacyHandlers
  74. * @static
  75. * @private
  76. */
  77. var legacyHandlers = [];
  78. /**
  79. * The number of times to poll after window.onload. This number is
  80. * increased if additional late-bound handlers are requested after the
  81. * page load.
  82. *
  83. * @property retryCount
  84. * @static
  85. * @private
  86. */
  87. var retryCount = 0;
  88. /**
  89. * onAvailable listeners
  90. *
  91. * @property onAvailStack
  92. * @static
  93. * @private
  94. */
  95. var onAvailStack = [];
  96. /**
  97. * Lookup table for legacy events
  98. *
  99. * @property legacyMap
  100. * @static
  101. * @private
  102. */
  103. var legacyMap = [];
  104. /**
  105. * Counter for auto id generation
  106. *
  107. * @property counter
  108. * @static
  109. * @private
  110. */
  111. var counter = 0;
  112. /**
  113. * addListener/removeListener can throw errors in unexpected scenarios.
  114. * These errors are suppressed, the method returns false, and this
  115. * property is set
  116. *
  117. * @property lastError
  118. * @type Error
  119. */
  120. var lastError = null;
  121. return {
  122. /**
  123. * The number of times we should look for elements that are not in
  124. * the DOM at the time the event is requested after the document has
  125. * been loaded. The default is 200@amp;50 ms, so it will poll for 10
  126. * seconds or until all outstanding handlers are bound (whichever
  127. * comes first).
  128. *
  129. * @property POLL_RETRYS
  130. * @type int
  131. * @static
  132. * @final
  133. */
  134. POLL_RETRYS : 200,
  135. /**
  136. * The poll interval in milliseconds
  137. *
  138. * @property POLL_INTERVAL
  139. * @type int
  140. * @static
  141. * @final
  142. */
  143. POLL_INTERVAL : 20,
  144. /**
  145. * Element to bind, int constant
  146. *
  147. * @property EL
  148. * @type int
  149. * @static
  150. * @final
  151. */
  152. EL : 0,
  153. /**
  154. * Type of event, int constant
  155. *
  156. * @property TYPE
  157. * @type int
  158. * @static
  159. * @final
  160. */
  161. TYPE : 1,
  162. /**
  163. * Function to execute, int constant
  164. *
  165. * @property FN
  166. * @type int
  167. * @static
  168. * @final
  169. */
  170. FN : 2,
  171. /**
  172. * Function wrapped for scope correction and cleanup, int constant
  173. *
  174. * @property WFN
  175. * @type int
  176. * @static
  177. * @final
  178. */
  179. WFN : 3,
  180. /**
  181. * Object passed in by the user that will be returned as a parameter
  182. * to the callback, int constant
  183. *
  184. * @property OBJ
  185. * @type int
  186. * @static
  187. * @final
  188. */
  189. OBJ : 3,
  190. /**
  191. * Adjusted scope, either the element we are registering the event
  192. * on or the custom object passed in by the listener, int constant
  193. *
  194. * @property ADJ_SCOPE
  195. * @type int
  196. * @static
  197. * @final
  198. */
  199. ADJ_SCOPE : 4,
  200. /**
  201. * Safari detection is necessary to work around the preventDefault
  202. * bug that makes it so you can't cancel a href click from the
  203. * handler. Since this function has been used outside of this
  204. * utility, it was changed to detect all KHTML browser to be more
  205. * friendly towards the non-Safari browsers that share the engine.
  206. * Internally, the preventDefault bug detection now uses the webkit
  207. * property.
  208. *
  209. * @property isSafari
  210. * @private
  211. * @static
  212. * @deprecated
  213. */
  214. isSafari : (/KHTML/gi).test(navigator.userAgent),
  215. /**
  216. * If WebKit is detected, we keep track of the version number of the
  217. * engine. Safari 1.3.2 (312.6): 312.8.1 <-- currently the latest
  218. * available on Mac OSX 10.3. Safari 2.0.2: 416 <-- hasOwnProperty
  219. * introduced Safari 2.0.4: 418 <-- preventDefault fixed (I believe)
  220. * Safari 2.0.4 (419.3): 418.9.1 <-- current release
  221. *
  222. * http://developer.apple.com/internet/safari/uamatrix.html
  223. *
  224. * @property webkit
  225. */
  226. webkit : function() {
  227. var v = navigator.userAgent.match(/AppleWebKit\/([^ ]*)/);
  228. if (v && v[1]) {
  229. return v[1];
  230. }
  231. return null;
  232. }(),
  233. /**
  234. * IE detection needed to properly calculate pageX and pageY.
  235. * capabilities checking didn't seem to work because another browser
  236. * that does not provide the properties have the values calculated
  237. * in a different manner than IE.
  238. *
  239. * @property isIE
  240. * @private
  241. * @static
  242. */
  243. isIE : (!this.webkit && !navigator.userAgent.match(/opera/gi) && navigator.userAgent
  244. .match(/msie/gi)),
  245. /**
  246. * poll handle
  247. *
  248. * @property _interval
  249. * @private
  250. */
  251. _interval : null,
  252. /**
  253. * @method startInterval
  254. * @static
  255. * @private
  256. */
  257. startInterval : function() {
  258. if (!this._interval) {
  259. var self = this;
  260. var callback = function() {
  261. self._tryPreloadAttach();
  262. };
  263. this._interval = setInterval(callback, this.POLL_INTERVAL);
  264. // this.timeout = setTimeout(callback, i);
  265. }
  266. },
  267. /**
  268. * Executes the supplied callback when the item with the supplied id
  269. * is found. This is meant to be used to execute behavior as soon as
  270. * possible as the page loads. If you use this after the initial
  271. * page load it will poll for a fixed time for the element. The
  272. * number of times it will poll and the frequency are configurable.
  273. * By default it will poll for 10 seconds.
  274. *
  275. * @method onAvailable
  276. *
  277. * @param {string}
  278. * p_id the id of the element to look for.
  279. * @param {function}
  280. * p_fn what to execute when the element is found.
  281. * @param {object}
  282. * p_obj an optional object to be passed back as a
  283. * parameter to p_fn.
  284. * @param {boolean}
  285. * p_override If set to true, p_fn will execute in the
  286. * scope of p_obj
  287. *
  288. * @static
  289. */
  290. onAvailable : function(p_id, p_fn, p_obj, p_override) {
  291. onAvailStack.push({
  292. id : p_id,
  293. fn : p_fn,
  294. obj : p_obj,
  295. override : p_override,
  296. checkReady : false
  297. });
  298. retryCount = this.POLL_RETRYS;
  299. this.startInterval();
  300. },
  301. /**
  302. * Works the same way as onAvailable, but additionally checks the
  303. * state of sibling elements to determine if the content of the
  304. * available element is safe to modify.
  305. *
  306. * @method onContentReady
  307. *
  308. * @param {string}
  309. * p_id the id of the element to look for.
  310. * @param {function}
  311. * p_fn what to execute when the element is ready.
  312. * @param {object}
  313. * p_obj an optional object to be passed back as a
  314. * parameter to p_fn.
  315. * @param {boolean}
  316. * p_override If set to true, p_fn will execute in the
  317. * scope of p_obj
  318. *
  319. * @static
  320. */
  321. onContentReady : function(p_id, p_fn, p_obj, p_override) {
  322. onAvailStack.push({
  323. id : p_id,
  324. fn : p_fn,
  325. obj : p_obj,
  326. override : p_override,
  327. checkReady : true
  328. });
  329. retryCount = this.POLL_RETRYS;
  330. this.startInterval();
  331. },
  332. /**
  333. * Appends an event handler
  334. *
  335. * @method addListener
  336. *
  337. * @param {Object}
  338. * el The html element to assign the event to
  339. * @param {String}
  340. * sType The type of event to append
  341. * @param {Function}
  342. * fn The method the event invokes
  343. * @param {Object}
  344. * obj An arbitrary object that will be passed as a
  345. * parameter to the handler
  346. * @param {boolean}
  347. * override If true, the obj passed in becomes the
  348. * execution scope of the listener
  349. * @return {boolean} True if the action was successful or defered,
  350. * false if one or more of the elements could not have the
  351. * listener attached, or if the operation throws an
  352. * exception.
  353. * @static
  354. */
  355. addListener : function(el, sType, fn, obj, override) {
  356. if (!fn || !fn.call) {
  357. return false;
  358. }
  359. // The el argument can be an array of elements or element ids.
  360. if (this._isValidCollection(el)) {
  361. var ok = true;
  362. for (var i = 0, len = el.length; i < len; ++i) {
  363. ok = this.on(el[i], sType, fn, obj, override) && ok;
  364. }
  365. return ok;
  366. } else if (typeof el == "string") {
  367. var oEl = this.getEl(el);
  368. // If the el argument is a string, we assume it is
  369. // actually the id of the element. If the page is loaded
  370. // we convert el to the actual element, otherwise we
  371. // defer attaching the event until onload event fires
  372. // check to see if we need to delay hooking up the event
  373. // until after the page loads.
  374. if (oEl) {
  375. el = oEl;
  376. } else {
  377. // defer adding the event until the element is available
  378. this.onAvailable(el, function() {
  379. YAHOO.util.Event.on(el, sType, fn, obj,
  380. override);
  381. });
  382. return true;
  383. }
  384. }
  385. // Element should be an html element or an array if we get
  386. // here.
  387. if (!el) {
  388. return false;
  389. }
  390. // we need to make sure we fire registered unload events
  391. // prior to automatically unhooking them. So we hang on to
  392. // these instead of attaching them to the window and fire the
  393. // handles explicitly during our one unload event.
  394. if ("unload" == sType && obj !== this) {
  395. unloadListeners[unloadListeners.length] = [el, sType, fn,
  396. obj, override];
  397. return true;
  398. }
  399. // if the user chooses to override the scope, we use the custom
  400. // object passed in, otherwise the executing scope will be the
  401. // HTML element that the event is registered on
  402. var scope = el;
  403. if (override) {
  404. if (override === true) {
  405. scope = obj;
  406. } else {
  407. scope = override;
  408. }
  409. }
  410. // wrap the function so we can return the obj object when
  411. // the event fires;
  412. var wrappedFn = function(e) {
  413. return fn.call(scope, YAHOO.util.Event.getEvent(e), obj);
  414. };
  415. var li = [el, sType, fn, wrappedFn, scope];
  416. var index = listeners.length;
  417. // cache the listener so we can try to automatically unload
  418. listeners[index] = li;
  419. if (this.useLegacyEvent(el, sType)) {
  420. var legacyIndex = this.getLegacyIndex(el, sType);
  421. // Add a new dom0 wrapper if one is not detected for this
  422. // element
  423. if (legacyIndex == -1 || el != legacyEvents[legacyIndex][0]) {
  424. legacyIndex = legacyEvents.length;
  425. legacyMap[el.id + sType] = legacyIndex;
  426. // cache the signature for the DOM0 event, and
  427. // include the existing handler for the event, if any
  428. legacyEvents[legacyIndex] = [el, sType,
  429. el["on" + sType]];
  430. legacyHandlers[legacyIndex] = [];
  431. el["on" + sType] = function(e) {
  432. YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event
  433. .getEvent(e), legacyIndex);
  434. };
  435. }
  436. // add a reference to the wrapped listener to our custom
  437. // stack of events
  438. // legacyHandlers[legacyIndex].push(index);
  439. legacyHandlers[legacyIndex].push(li);
  440. } else {
  441. try {
  442. this._simpleAdd(el, sType, wrappedFn, false);
  443. } catch (ex) {
  444. // handle an error trying to attach an event. If it
  445. // fails
  446. // we need to clean up the cache
  447. this.lastError = ex;
  448. this.removeListener(el, sType, fn);
  449. return false;
  450. }
  451. }
  452. return true;
  453. },
  454. /**
  455. * When using legacy events, the handler is routed to this object so
  456. * we can fire our custom listener stack.
  457. *
  458. * @method fireLegacyEvent
  459. * @static
  460. * @private
  461. */
  462. fireLegacyEvent : function(e, legacyIndex) {
  463. var ok = true, le, lh, li, scope, ret;
  464. lh = legacyHandlers[legacyIndex];
  465. for (var i = 0, len = lh.length; i < len; ++i) {
  466. li = lh[i];
  467. if (li && li[this.WFN]) {
  468. scope = li[this.ADJ_SCOPE];
  469. ret = li[this.WFN].call(scope, e);
  470. ok = (ok && ret);
  471. }
  472. }
  473. // Fire the original handler if we replaced one. We fire this
  474. // after the other events to keep stopPropagation/preventDefault
  475. // that happened in the DOM0 handler from touching our DOM2
  476. // substitute
  477. le = legacyEvents[legacyIndex];
  478. if (le && le[2]) {
  479. le[2](e);
  480. }
  481. return ok;
  482. },
  483. /**
  484. * Returns the legacy event index that matches the supplied
  485. * signature
  486. *
  487. * @method getLegacyIndex
  488. * @static
  489. * @private
  490. */
  491. getLegacyIndex : function(el, sType) {
  492. var key = this.generateId(el) + sType;
  493. if (typeof legacyMap[key] == "undefined") {
  494. return -1;
  495. } else {
  496. return legacyMap[key];
  497. }
  498. },
  499. /**
  500. * Logic that determines when we should automatically use legacy
  501. * events instead of DOM2 events. Currently this is limited to old
  502. * Safari browsers with a broken preventDefault
  503. *
  504. * @method useLegacyEvent
  505. * @static
  506. * @private
  507. */
  508. useLegacyEvent : function(el, sType) {
  509. if (this.webkit && ("click" == sType || "dblclick" == sType)) {
  510. var v = parseInt(this.webkit, 10);
  511. if (!isNaN(v) && v < 418) {
  512. return true;
  513. }
  514. }
  515. return false;
  516. },
  517. /**
  518. * Removes an event handler
  519. *
  520. * @method removeListener
  521. *
  522. * @param {Object}
  523. * el the html element or the id of the element to assign
  524. * the event to.
  525. * @param {String}
  526. * sType the type of event to remove.
  527. * @param {Function}
  528. * fn the method the event invokes. If fn is undefined,
  529. * then all event handlers for the type of event are
  530. * removed.
  531. * @return {boolean} true if the unbind was successful, false
  532. * otherwise.
  533. * @static
  534. */
  535. removeListener : function(el, sType, fn) {
  536. var i, len;
  537. // The el argument can be a string
  538. if (typeof el == "string") {
  539. el = this.getEl(el);
  540. // The el argument can be an array of elements or element
  541. // ids.
  542. } else if (this._isValidCollection(el)) {
  543. var ok = true;
  544. for (i = 0, len = el.length; i < len; ++i) {
  545. ok = (this.removeListener(el[i], sType, fn) && ok);
  546. }
  547. return ok;
  548. }
  549. if (!fn || !fn.call) {
  550. // return false;
  551. return this.purgeElement(el, false, sType);
  552. }
  553. if ("unload" == sType) {
  554. for (i = 0, len = unloadListeners.length; i < len; i++) {
  555. var li = unloadListeners[i];
  556. if (li && li[0] == el && li[1] == sType && li[2] == fn) {
  557. unloadListeners.splice(i, 1);
  558. return true;
  559. }
  560. }
  561. return false;
  562. }
  563. var cacheItem = null;
  564. // The index is a hidden parameter; needed to remove it from
  565. // the method signature because it was tempting users to
  566. // try and take advantage of it, which is not possible.
  567. var index = arguments[3];
  568. if ("undefined" == typeof index) {
  569. index = this._getCacheIndex(el, sType, fn);
  570. }
  571. if (index >= 0) {
  572. cacheItem = listeners[index];
  573. }
  574. if (!el || !cacheItem) {
  575. return false;
  576. }
  577. if (this.useLegacyEvent(el, sType)) {
  578. var legacyIndex = this.getLegacyIndex(el, sType);
  579. var llist = legacyHandlers[legacyIndex];
  580. if (llist) {
  581. for (i = 0, len = llist.length; i < len; ++i) {
  582. li = llist[i];
  583. if (li && li[this.EL] == el
  584. && li[this.TYPE] == sType
  585. && li[this.FN] == fn) {
  586. llist.splice(i, 1);
  587. break;
  588. }
  589. }
  590. }
  591. } else {
  592. try {
  593. this._simpleRemove(el, sType, cacheItem[this.WFN],
  594. false);
  595. } catch (ex) {
  596. this.lastError = ex;
  597. return false;
  598. }
  599. }
  600. // removed the wrapped handler
  601. delete listeners[index][this.WFN];
  602. delete listeners[index][this.FN];
  603. listeners.splice(index, 1);
  604. return true;
  605. },
  606. /**
  607. * Returns the event's target element
  608. *
  609. * @method getTarget
  610. * @param {Event}
  611. * ev the event
  612. * @param {boolean}
  613. * resolveTextNode when set to true the target's parent
  614. * will be returned if the target is a text node.
  615. * @deprecated, the text node is now resolved automatically
  616. * @return {HTMLElement} the event's target
  617. * @static
  618. */
  619. getTarget : function(ev, resolveTextNode) {
  620. var t = ev.target || ev.srcElement;
  621. return this.resolveTextNode(t);
  622. },
  623. /**
  624. * In some cases, some browsers will return a text node inside the
  625. * actual element that was targeted. This normalizes the return
  626. * value for getTarget and getRelatedTarget.
  627. *
  628. * @method resolveTextNode
  629. * @param {HTMLElement}
  630. * node node to resolve
  631. * @return {HTMLElement} the normized node
  632. * @static
  633. */
  634. resolveTextNode : function(node) {
  635. // if (node && node.nodeName &&
  636. // "#TEXT" == node.nodeName.toUpperCase()) {
  637. if (node && 3 == node.nodeType) {
  638. return node.parentNode;
  639. } else {
  640. return node;
  641. }
  642. },
  643. /**
  644. * Returns the event's pageX
  645. *
  646. * @method getPageX
  647. * @param {Event}
  648. * ev the event
  649. * @return {int} the event's pageX
  650. * @static
  651. */
  652. getPageX : function(ev) {
  653. var x = ev.pageX;
  654. if (!x && 0 !== x) {
  655. x = ev.clientX || 0;
  656. if (this.isIE) {
  657. x += this._getScrollLeft();
  658. }
  659. }
  660. return x;
  661. },
  662. /**
  663. * Returns the event's pageY
  664. *
  665. * @method getPageY
  666. * @param {Event}
  667. * ev the event
  668. * @return {int} the event's pageY
  669. * @static
  670. */
  671. getPageY : function(ev) {
  672. var y = ev.pageY;
  673. if (!y && 0 !== y) {
  674. y = ev.clientY || 0;
  675. if (this.isIE) {
  676. y += this._getScrollTop();
  677. }
  678. }
  679. return y;
  680. },
  681. /**
  682. * Returns the pageX and pageY properties as an indexed array.
  683. *
  684. * @method getXY
  685. * @param {Event}
  686. * ev the event
  687. * @return {[x, y]} the pageX and pageY properties of the event
  688. * @static
  689. */
  690. getXY : function(ev) {
  691. return [this.getPageX(ev), this.getPageY(ev)];
  692. },
  693. /**
  694. * Returns the event's related target
  695. *
  696. * @method getRelatedTarget
  697. * @param {Event}
  698. * ev the event
  699. * @return {HTMLElement} the event's relatedTarget
  700. * @static
  701. */
  702. getRelatedTarget : function(ev) {
  703. var t = ev.relatedTarget;
  704. if (!t) {
  705. if (ev.type == "mouseout") {
  706. t = ev.toElement;
  707. } else if (ev.type == "mouseover") {
  708. t = ev.fromElement;
  709. }
  710. }
  711. return this.resolveTextNode(t);
  712. },
  713. /**
  714. * Returns the time of the event. If the time is not included, the
  715. * event is modified using the current time.
  716. *
  717. * @method getTime
  718. * @param {Event}
  719. * ev the event
  720. * @return {Date} the time of the event
  721. * @static
  722. */
  723. getTime : function(ev) {
  724. if (!ev.time) {
  725. var t = allGetServerTime().getTime();
  726. try {
  727. ev.time = t;
  728. } catch (ex) {
  729. this.lastError = ex;
  730. return t;
  731. }
  732. }
  733. return ev.time;
  734. },
  735. /**
  736. * Convenience method for stopPropagation + preventDefault
  737. *
  738. * @method stopEvent
  739. * @param {Event}
  740. * ev the event
  741. * @static
  742. */
  743. stopEvent : function(ev) {
  744. this.stopPropagation(ev);
  745. this.preventDefault(ev);
  746. },
  747. /**
  748. * Stops event propagation
  749. *
  750. * @method stopPropagation
  751. * @param {Event}
  752. * ev the event
  753. * @static
  754. */
  755. stopPropagation : function(ev) {
  756. if (ev.stopPropagation) {
  757. ev.stopPropagation();
  758. } else {
  759. ev.cancelBubble = true;
  760. }
  761. },
  762. /**
  763. * Prevents the default behavior of the event
  764. *
  765. * @method preventDefault
  766. * @param {Event}
  767. * ev the event
  768. * @static
  769. */
  770. preventDefault : function(ev) {
  771. if (ev.preventDefault) {
  772. ev.preventDefault();
  773. } else {
  774. ev.returnValue = false;
  775. }
  776. },
  777. /**
  778. * Finds the event in the window object, the caller's arguments, or
  779. * in the arguments of another method in the callstack. This is
  780. * executed automatically for events registered through the event
  781. * manager, so the implementer should not normally need to execute
  782. * this function at all.
  783. *
  784. * @method getEvent
  785. * @param {Event}
  786. * e the event parameter from the handler
  787. * @return {Event} the event
  788. * @static
  789. */
  790. getEvent : function(e) {
  791. var ev = e || window.event;
  792. if (!ev) {
  793. var c = this.getEvent.caller;
  794. while (c) {
  795. ev = c.arguments[0];
  796. if (ev && Event == ev.constructor) {
  797. break;
  798. }
  799. c = c.caller;
  800. }
  801. }
  802. return ev;
  803. },
  804. /**
  805. * Returns the charcode for an event
  806. *
  807. * @method getCharCode
  808. * @param {Event}
  809. * ev the event
  810. * @return {int} the event's charCode
  811. * @static
  812. */
  813. getCharCode : function(ev) {
  814. return ev.charCode || ev.keyCode || 0;
  815. },
  816. /**
  817. * Locating the saved event handler data by function ref
  818. *
  819. * @method _getCacheIndex
  820. * @static
  821. * @private
  822. */
  823. _getCacheIndex : function(el, sType, fn) {
  824. for (var i = 0, len = listeners.length; i < len; ++i) {
  825. var li = listeners[i];
  826. if (li && li[this.FN] == fn && li[this.EL] == el
  827. && li[this.TYPE] == sType) {
  828. return i;
  829. }
  830. }
  831. return -1;
  832. },
  833. /**
  834. * Generates an unique ID for the element if it does not already
  835. * have one.
  836. *
  837. * @method generateId
  838. * @param el
  839. * the element to create the id for
  840. * @return {string} the resulting id of the element
  841. * @static
  842. */
  843. generateId : function(el) {
  844. var id = el.id;
  845. if (!id) {
  846. id = "yuievtautoid-" + counter;
  847. ++counter;
  848. el.id = id;
  849. }
  850. return id;
  851. },
  852. /**
  853. * We want to be able to use getElementsByTagName as a collection to
  854. * attach a group of events to. Unfortunately, different browsers
  855. * return different types of collections. This function tests to
  856. * determine if the object is array-like. It will also fail if the
  857. * object is an array, but is empty.
  858. *
  859. * @method _isValidCollection
  860. * @param o
  861. * the object to test
  862. * @return {boolean} true if the object is array-like and populated
  863. * @static
  864. * @private
  865. */
  866. _isValidCollection : function(o) {
  867. return (o && // o is something
  868. o.length && // o is indexed
  869. typeof o != "string" && // o is not a string
  870. !o.tagName && // o is not an HTML element
  871. !o.alert && // o is not a window
  872. typeof o[0] != "undefined");
  873. },
  874. /**
  875. * @private
  876. * @property elCache DOM element cache
  877. * @static
  878. */
  879. elCache : {},
  880. /**
  881. * We cache elements bound by id because when the unload event
  882. * fires, we can no longer use document.getElementById
  883. *
  884. * @method getEl
  885. * @static
  886. * @private
  887. */
  888. getEl : function(id) {
  889. return document.getElementById(id);
  890. },
  891. /**
  892. * Clears the element cache
  893. *
  894. * @deprecated Elements are not cached any longer
  895. * @method clearCache
  896. * @static
  897. * @private
  898. */
  899. clearCache : function() {
  900. },
  901. /**
  902. * hook up any deferred listeners
  903. *
  904. * @method _load
  905. * @static
  906. * @private
  907. */
  908. _load : function(e) {
  909. loadComplete = true;
  910. var EU = YAHOO.util.Event;
  911. // Remove the listener to assist with the IE memory issue, but
  912. // not
  913. // for other browsers because FF 1.0x does not like it.
  914. if (this.isIE) {
  915. EU._simpleRemove(window, "load", EU._load);
  916. }
  917. },
  918. /**
  919. * Polling function that runs before the onload event fires,
  920. * attempting to attach to DOM Nodes as soon as they are available
  921. *
  922. * @method _tryPreloadAttach
  923. * @static
  924. * @private
  925. */
  926. _tryPreloadAttach : function() {
  927. if (this.locked) {
  928. return false;
  929. }
  930. this.locked = true;
  931. // keep trying until after the page is loaded. We need to
  932. // check the page load state prior to trying to bind the
  933. // elements so that we can be certain all elements have been
  934. // tested appropriately
  935. var tryAgain = !loadComplete;
  936. if (!tryAgain) {
  937. tryAgain = (retryCount > 0);
  938. }
  939. // onAvailable
  940. var notAvail = [];
  941. for (var i = 0, len = onAvailStack.length; i < len; ++i) {
  942. var item = onAvailStack[i];
  943. if (item) {
  944. var el = this.getEl(item.id);
  945. if (el) {
  946. // The element is available, but not necessarily
  947. // ready
  948. // @todo verify IE7 compatibility
  949. // @todo should we test parentNode.nextSibling?
  950. // @todo re-evaluate global content ready
  951. if (!item.checkReady || loadComplete
  952. || el.nextSibling
  953. || (document && document.body)) {
  954. var scope = el;
  955. if (item.override) {
  956. if (item.override === true) {
  957. scope = item.obj;
  958. } else {
  959. scope = item.override;
  960. }
  961. }
  962. item.fn.call(scope, item.obj);
  963. // delete onAvailStack[i];
  964. // null out instead of delete for Opera
  965. onAvailStack[i] = null;
  966. }
  967. } else {
  968. notAvail.push(item);
  969. }
  970. }
  971. }
  972. retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
  973. if (tryAgain) {
  974. // we may need to strip the nulled out items here
  975. this.startInterval();
  976. } else {
  977. clearInterval(this._interval);
  978. this._interval = null;
  979. }
  980. this.locked = false;
  981. return true;
  982. },
  983. /**
  984. * Removes all listeners attached to the given element via
  985. * addListener. Optionally, the node's children can also be purged.
  986. * Optionally, you can specify a specific type of event to remove.
  987. *
  988. * @method purgeElement
  989. * @param {HTMLElement}
  990. * el the element to purge
  991. * @param {boolean}
  992. * recurse recursively purge this element's children as
  993. * well. Use with caution.
  994. * @param {string}
  995. * sType optional type of listener to purge. If left out,
  996. * all listeners will be removed
  997. * @static
  998. */
  999. purgeElement : function(el, recurse, sType) {
  1000. var elListeners = this.getListeners(el, sType);
  1001. if (elListeners) {
  1002. for (var i = 0, len = elListeners.length; i < len; ++i) {
  1003. var l = elListeners[i];
  1004. // can't use the index on the changing collection
  1005. // this.removeListener(el, l.type, l.fn, l.index);
  1006. this.removeListener(el, l.type, l.fn);
  1007. }
  1008. }
  1009. if (recurse && el && el.childNodes) {
  1010. for (i = 0, len = el.childNodes.length; i < len; ++i) {
  1011. this.purgeElement(el.childNodes[i], recurse, sType);
  1012. }
  1013. }
  1014. },
  1015. /**
  1016. * Returns all listeners attached to the given element via
  1017. * addListener. Optionally, you can specify a specific type of event
  1018. * to return.
  1019. *
  1020. * @method getListeners
  1021. * @param el
  1022. * {HTMLElement} the element to inspect
  1023. * @param sType
  1024. * {string} optional type of listener to return. If left
  1025. * out, all listeners will be returned
  1026. * @return {Object} the listener. Contains the following fields:
  1027. * &nbsp;&nbsp;type: (string) the type of event
  1028. * &nbsp;&nbsp;fn: (function) the callback supplied to
  1029. * addListener &nbsp;&nbsp;obj: (object) the custom object
  1030. * supplied to addListener &nbsp;&nbsp;adjust: (boolean)
  1031. * whether or not to adjust the default scope
  1032. * &nbsp;&nbsp;index: (int) its position in the Event util
  1033. * listener cache
  1034. * @static
  1035. */
  1036. getListeners : function(el, sType) {
  1037. var results = [], searchLists;
  1038. if (!sType) {
  1039. searchLists = [listeners, unloadListeners];
  1040. } else if (sType == "unload") {
  1041. searchLists = [unloadListeners];
  1042. } else {
  1043. searchLists = [listeners];
  1044. }
  1045. for (var j = 0; j < searchLists.length; ++j) {
  1046. var searchList = searchLists[j];
  1047. if (searchList && searchList.length > 0) {
  1048. for (var i = 0, len = searchList.length; i < len; ++i) {
  1049. var l = searchList[i];
  1050. if (l && l[this.EL] === el
  1051. && (!sType || sType === l[this.TYPE])) {
  1052. results.push({
  1053. type : l[this.TYPE],
  1054. fn : l[this.FN],
  1055. obj : l[this.OBJ],
  1056. adjust : l[this.ADJ_SCOPE],
  1057. index : i
  1058. });
  1059. }
  1060. }
  1061. }
  1062. }
  1063. return (results.length) ? results : null;
  1064. },
  1065. /**
  1066. * Removes all listeners registered by pe.event. Called
  1067. * automatically during the unload event.
  1068. *
  1069. * @method _unload
  1070. * @static
  1071. * @private
  1072. */
  1073. _unload : function(e) {
  1074. var EU = YAHOO.util.Event, i, j, l, len, index;
  1075. for (i = 0, len = unloadListeners.length; i < len; ++i) {
  1076. l = unloadListeners[i];
  1077. if (l) {
  1078. var scope = window;
  1079. if (l[EU.ADJ_SCOPE]) {
  1080. if (l[EU.ADJ_SCOPE] === true) {
  1081. scope = l[EU.OBJ];
  1082. } else {
  1083. scope = l[EU.ADJ_SCOPE];
  1084. }
  1085. }
  1086. l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
  1087. unloadListeners[i] = null;
  1088. l = null;
  1089. scope = null;
  1090. }
  1091. }
  1092. unloadListeners = null;
  1093. if (listeners && listeners.length > 0) {
  1094. j = listeners.length;
  1095. while (j) {
  1096. index = j - 1;
  1097. l = listeners[index];
  1098. if (l) {
  1099. EU.removeListener(l[EU.EL], l[EU.TYPE], l[EU.FN],
  1100. index);
  1101. }
  1102. j = j - 1;
  1103. }
  1104. l = null;
  1105. EU.clearCache();
  1106. }
  1107. for (i = 0, len = legacyEvents.length; i < len; ++i) {
  1108. // dereference the element
  1109. // delete legacyEvents[i][0];
  1110. legacyEvents[i][0] = null;
  1111. // delete the array item
  1112. // delete legacyEvents[i];
  1113. legacyEvents[i] = null;
  1114. }
  1115. legacyEvents = null;
  1116. EU._simpleRemove(window, "unload", EU._unload);
  1117. },
  1118. /**
  1119. * Returns scrollLeft
  1120. *
  1121. * @method _getScrollLeft
  1122. * @static
  1123. * @private
  1124. */
  1125. _getScrollLeft : function() {
  1126. return this._getScroll()[1];
  1127. },
  1128. /**
  1129. * Returns scrollTop
  1130. *
  1131. * @method _getScrollTop
  1132. * @static
  1133. * @private
  1134. */
  1135. _getScrollTop : function() {
  1136. return this._getScroll()[0];
  1137. },
  1138. /**
  1139. * Returns the scrollTop and scrollLeft. Used to calculate the pageX
  1140. * and pageY in Internet Explorer
  1141. *
  1142. * @method _getScroll
  1143. * @static
  1144. * @private
  1145. */
  1146. _getScroll : function() {
  1147. var dd = document.documentElement, db = document.body;
  1148. if (dd && (dd.scrollTop || dd.scrollLeft)) {
  1149. return [dd.scrollTop, dd.scrollLeft];
  1150. } else if (db) {
  1151. return [db.scrollTop, db.scrollLeft];
  1152. } else {
  1153. return [0, 0];
  1154. }
  1155. },
  1156. /**
  1157. * Used by old versions of CustomEvent, restored for backwards
  1158. * compatibility
  1159. *
  1160. * @method regCE
  1161. * @private
  1162. */
  1163. regCE : function() {
  1164. // does nothing
  1165. },
  1166. /**
  1167. * Adds a DOM event directly without the caching, cleanup, scope
  1168. * adj, etc
  1169. *
  1170. * @method _simpleAdd
  1171. * @param {HTMLElement}
  1172. * el the element to bind the handler to
  1173. * @param {string}
  1174. * sType the type of event handler
  1175. * @param {function}
  1176. * fn the callback to invoke
  1177. * @param {boolen}
  1178. * capture capture or bubble phase
  1179. * @static
  1180. * @private
  1181. */
  1182. _simpleAdd : function() {
  1183. if (window.addEventListener) {
  1184. return function(el, sType, fn, capture) {
  1185. el.addEventListener(sType, fn, (capture));
  1186. };
  1187. } else if (window.attachEvent) {
  1188. return function(el, sType, fn, capture) {
  1189. el.attachEvent("on" + sType, fn);
  1190. };
  1191. } else {
  1192. return function() {
  1193. };
  1194. }
  1195. }(),
  1196. /**
  1197. * Basic remove listener
  1198. *
  1199. * @method _simpleRemove
  1200. * @param {HTMLElement}
  1201. * el the element to bind the handler to
  1202. * @param {string}
  1203. * sType the type of event handler
  1204. * @param {function}
  1205. * fn the callback to invoke
  1206. * @param {boolen}
  1207. * capture capture or bubble phase
  1208. * @static
  1209. * @private
  1210. */
  1211. _simpleRemove : function() {
  1212. if (window.removeEventListener) {
  1213. return function(el, sType, fn, capture) {
  1214. el.removeEventListener(sType, fn, (capture));
  1215. };
  1216. } else if (window.detachEvent) {
  1217. return function(el, sType, fn) {
  1218. el.detachEvent("on" + sType, fn);
  1219. };
  1220. } else {
  1221. return function() {
  1222. };
  1223. }
  1224. }()
  1225. };
  1226. }();
  1227. (function() {
  1228. var EU = YAHOO.util.Event;
  1229. /**
  1230. * YAHOO.util.Event.on is an alias for addListener
  1231. *
  1232. * @method on
  1233. * @see addListener
  1234. * @static
  1235. */
  1236. EU.on = EU.addListener;
  1237. // YAHOO.mix(EU, YAHOO.util.EventProvider.prototype);
  1238. // EU.createEvent("DOMContentReady");
  1239. // EU.subscribe("DOMContentReady", EU._load);
  1240. if (document && document.body) {
  1241. EU._load();
  1242. } else {
  1243. // EU._simpleAdd(document, "DOMContentLoaded", EU._load);
  1244. EU._simpleAdd(window, "load", EU._load);
  1245. }
  1246. EU._simpleAdd(window, "unload", EU._unload);
  1247. EU._tryPreloadAttach();
  1248. })();
  1249. }
  1250. /**
  1251. * The CustomEvent class lets you define events for your application that can be
  1252. * subscribed to by one or more independent component.
  1253. *
  1254. * @param {String}
  1255. * type The type of event, which is passed to the callback when the
  1256. * event fires
  1257. * @param {Object}
  1258. * oScope The context the event will fire from. "this" will refer to
  1259. * this object in the callback. Default value: the window object. The
  1260. * listener can override this.
  1261. * @param {boolean}
  1262. * silent pass true to prevent the event from writing to the
  1263. * debugsystem
  1264. * @param {int}
  1265. * signature the signature that the custom event subscriber will
  1266. * receive. YAHOO.util.CustomEvent.LIST or
  1267. * YAHOO.util.CustomEvent.FLAT. The default is
  1268. * YAHOO.util.CustomEvent.LIST.
  1269. * @namespace YAHOO.util
  1270. * @class CustomEvent
  1271. * @constructor
  1272. */
  1273. YAHOO.util.CustomEvent = function(type, oScope, silent, signature) {
  1274. /**
  1275. * The type of event, returned to subscribers when the event fires
  1276. *
  1277. * @property type
  1278. * @type string
  1279. */
  1280. this.type = type;
  1281. /**
  1282. * The scope the the event will fire from by default. Defaults to the window
  1283. * obj
  1284. *
  1285. * @property scope
  1286. * @type object
  1287. */
  1288. this.scope = oScope || window;
  1289. /**
  1290. * By default all custom events are logged in the debug build, set silent to
  1291. * true to disable debug outpu for this event.
  1292. *
  1293. * @property silent
  1294. * @type boolean
  1295. */
  1296. this.silent = silent;
  1297. /**
  1298. * Custom events support two styles of arguments provided to the event
  1299. * subscribers.
  1300. * <ul>
  1301. * <li>YAHOO.util.CustomEvent.LIST:
  1302. * <ul>
  1303. * <li>param1: event name</li>
  1304. * <li>param2: array of arguments sent to fire</li>
  1305. * <li>param3: <optional> a custom object supplied by the subscriber</li>
  1306. * </ul>
  1307. * </li>
  1308. * <li>YAHOO.util.CustomEvent.FLAT
  1309. * <ul>
  1310. * <li>param1: the first argument passed to fire. If you need to pass
  1311. * multiple parameters, use and array or object literal</li>
  1312. * <li>param2: <optional> a custom object supplied by the subscriber</li>
  1313. * </ul>
  1314. * </li>
  1315. * </ul>
  1316. *
  1317. * @property signature
  1318. * @type int
  1319. */
  1320. this.signature = signature || YAHOO.util.CustomEvent.LIST;
  1321. /**
  1322. * The subscribers to this event
  1323. *
  1324. * @property subscribers
  1325. * @type Subscriber[]
  1326. */
  1327. this.subscribers = [];
  1328. if (!this.silent) {
  1329. }
  1330. var onsubscribeType = "_YUICEOnSubscribe";
  1331. // Only add subscribe events for events that are not generated by
  1332. // CustomEvent
  1333. if (type !== onsubscribeType) {
  1334. /**
  1335. * Custom events provide a custom event that fires whenever there is a
  1336. * new subscriber to the event. This provides an opportunity to handle
  1337. * the case where there is a non-repeating event that has already fired
  1338. * has a new subscriber.
  1339. *
  1340. * @event subscribeEvent
  1341. * @type YAHOO.util.CustomEvent
  1342. * @param {Function}
  1343. * fn The function to execute
  1344. * @param {Object}
  1345. * obj An object to be passed along when the event fires
  1346. * @param {boolean|Object}
  1347. * override If true, the obj passed in becomes the execution
  1348. * scope of the listener. if an object, that object becomes
  1349. * the the execution scope.
  1350. */
  1351. this.subscribeEvent = new YAHOO.util.CustomEvent(onsubscribeType, this,
  1352. true);
  1353. }
  1354. };
  1355. /**
  1356. * Subscriber listener sigature constant. The LIST type returns three
  1357. * parameters: the event type, the array of args passed to fire, and the
  1358. * optional custom object
  1359. *
  1360. * @property YAHOO.util.CustomEvent.LIST
  1361. * @static
  1362. * @type int
  1363. */
  1364. YAHOO.util.CustomEvent.LIST = 0;
  1365. /**
  1366. * Subscriber listener sigature constant. The FLAT type returns two parameters:
  1367. * the first argument passed to fire and the optional custom object
  1368. *
  1369. * @property YAHOO.util.CustomEvent.FLAT
  1370. * @static
  1371. * @type int
  1372. */
  1373. YAHOO.util.CustomEvent.FLAT = 1;
  1374. YAHOO.util.CustomEvent.prototype = {
  1375. /**
  1376. * Subscribes the caller to this event
  1377. *
  1378. * @method subscribe
  1379. * @param {Function}
  1380. * fn The function to execute
  1381. * @param {Object}
  1382. * obj An object to be passed along when the event fires
  1383. * @param {boolean|Object}
  1384. * override If true, the obj passed in becomes the execution
  1385. * scope of the listener. if an object, that object becomes the
  1386. * the execution scope.
  1387. */
  1388. subscribe : function(fn, obj, override) {
  1389. if (this.subscribeEvent) {
  1390. this.subscribeEvent.fire(fn, obj, override);
  1391. }
  1392. this.subscribers.push(new YAHOO.util.Subscriber(fn, obj, override));
  1393. },
  1394. /**
  1395. * Unsubscribes subscribers.
  1396. *
  1397. * @method unsubscribe
  1398. * @param {Function}
  1399. * fn The subscribed function to remove, if not supplied all will
  1400. * be removed
  1401. * @param {Object}
  1402. * obj The custom object passed to subscribe. This is optional,
  1403. * but if supplied will be used to disambiguate multiple
  1404. * listeners that are the same (e.g., you subscribe many object
  1405. * using a function that lives on the prototype)
  1406. * @return {boolean} True if the subscriber was found and detached.
  1407. */
  1408. unsubscribe : function(fn, obj) {
  1409. if (!fn) {
  1410. return this.unsubscribeAll();
  1411. }
  1412. var found = false;
  1413. for (var i = 0, len = this.subscribers.length; i < len; ++i) {
  1414. var s = this.subscribers[i];
  1415. if (s && s.contains(fn, obj)) {
  1416. this._delete(i);
  1417. found = true;
  1418. }
  1419. }
  1420. return found;
  1421. },
  1422. /**
  1423. * Notifies the subscribers. The callback functions will be executed from
  1424. * the scope specified when the event was created, and with the following
  1425. * parameters:
  1426. * <ul>
  1427. * <li>The type of event</li>
  1428. * <li>All of the arguments fire() was executed with as an array</li>
  1429. * <li>The custom object (if any) that was passed into the subscribe()
  1430. * method</li>
  1431. * </ul>
  1432. *
  1433. * @method fire
  1434. * @param {Object*}
  1435. * arguments an arbitrary set of parameters to pass to the
  1436. * handler.
  1437. * @return {boolean} false if one of the subscribers returned false, true
  1438. * otherwise
  1439. */
  1440. fire : function() {
  1441. var len = this.subscribers.length;
  1442. if (!len && this.silent) {
  1443. return true;
  1444. }
  1445. var args = [], ret = true, i;
  1446. for (i = 0; i < arguments.length; ++i) {
  1447. args.push(arguments[i]);
  1448. }
  1449. var argslength = args.length;
  1450. if (!this.silent) {
  1451. }
  1452. for (i = 0; i < len; ++i) {
  1453. var s = this.subscribers[i];
  1454. if (s) {
  1455. if (!this.silent) {
  1456. }
  1457. var scope = s.getScope(this.scope);
  1458. if (this.signature == YAHOO.util.CustomEvent.FLAT) {
  1459. var param = null;
  1460. if (args.length > 0) {
  1461. param = args[0];
  1462. }
  1463. ret = s.fn.call(scope, param, s.obj);
  1464. } else {
  1465. ret = s.fn.call(scope, this.type, args, s.obj);
  1466. }
  1467. if (false === ret) {
  1468. if (!this.silent) {
  1469. }
  1470. // break;
  1471. return false;
  1472. }
  1473. }
  1474. }
  1475. return true;
  1476. },
  1477. /**
  1478. * Removes all listeners
  1479. *
  1480. * @method unsubscribeAll
  1481. * @return {int} The number of listeners unsubscribed
  1482. */
  1483. unsubscribeAll : function() {
  1484. for (var i = 0, len = this.subscribers.length; i < len; ++i) {
  1485. this._delete(len - 1 - i);
  1486. }
  1487. return i;
  1488. },
  1489. /**
  1490. * @method _delete
  1491. * @private
  1492. */
  1493. _delete : function(index) {
  1494. var s = this.subscribers[index];
  1495. if (s) {
  1496. delete s.fn;
  1497. delete s.obj;
  1498. }
  1499. // delete this.subscribers[index];
  1500. this.subscribers.splice(index, 1);
  1501. },
  1502. /**
  1503. * @method toString
  1504. */
  1505. toString : function() {
  1506. return "CustomEvent: " + "'" + this.type + "', " + "scope: "
  1507. + this.scope;
  1508. }
  1509. };
  1510. // ///////////////////////////////////////////////////////////////////
  1511. /**
  1512. * Stores the subscriber information to be used when the event fires.
  1513. *
  1514. * @param {Function}
  1515. * fn The function to execute
  1516. * @param {Object}
  1517. * obj An object to be passed along when the event fires
  1518. * @param {boolean}
  1519. * override If true, the obj passed in becomes the execution scope of
  1520. * the listener
  1521. * @class Subscriber
  1522. * @constructor
  1523. */
  1524. YAHOO.util.Subscriber = function(fn, obj, override) {
  1525. /**
  1526. * The callback that will be execute when the event fires
  1527. *
  1528. * @property fn
  1529. * @type function
  1530. */
  1531. this.fn = fn;
  1532. /**
  1533. * An optional custom object that will passed to the callback when the event
  1534. * fires
  1535. *
  1536. * @property obj
  1537. * @type object
  1538. */
  1539. this.obj = obj || null;
  1540. /**
  1541. * The default execution scope for the event listener is defined when the
  1542. * event is created (usually the object which contains the event). By
  1543. * setting override to true, the execution scope becomes the custom object
  1544. * passed in by the subscriber. If override is an object, that object
  1545. * becomes the scope.
  1546. *
  1547. * @property override
  1548. * @type boolean|object
  1549. */
  1550. this.override = override;
  1551. };
  1552. /**
  1553. * Returns the execution scope for this listener. If override was set to true
  1554. * the custom obj will be the scope. If override is an object, that is the
  1555. * scope, otherwise the default scope will be used.
  1556. *
  1557. * @method getScope
  1558. * @param {Object}
  1559. * defaultScope the scope to use if this listener does not override
  1560. * it.
  1561. */
  1562. YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
  1563. if (this.override) {
  1564. if (this.override === true) {
  1565. return this.obj;
  1566. } else {
  1567. return this.override;
  1568. }
  1569. }
  1570. return defaultScope;
  1571. };
  1572. /**
  1573. * Returns true if the fn and obj match this objects properties. Used by the
  1574. * unsubscribe method to match the right subscriber.
  1575. *
  1576. * @method contains
  1577. * @param {Function}
  1578. * fn the function to execute
  1579. * @param {Object}
  1580. * obj an object to be passed along when the event fires
  1581. * @return {boolean} true if the supplied arguments match this subscriber's
  1582. * signature.
  1583. */
  1584. YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
  1585. if (obj) {
  1586. return (this.fn == fn && this.obj == obj);
  1587. } else {
  1588. return (this.fn == fn);
  1589. }
  1590. };
  1591. /**
  1592. * @method toString
  1593. */
  1594. YAHOO.util.Subscriber.prototype.toString = function() {
  1595. return "Subscriber { obj: " + (this.obj || "") + ", override: "
  1596. + (this.override || "no") + " }";
  1597. };
  1598. /**
  1599. * EventProvider is designed to be used with YAHOO.augment to wrap CustomEvents
  1600. * in an interface that allows events to be subscribed to and fired by name.
  1601. * This makes it possible for implementing code to subscribe to an event that
  1602. * either has not been created yet, or will not be created at all.
  1603. *
  1604. * @Class EventProvider
  1605. */
  1606. YAHOO.util.EventProvider = function() {
  1607. };
  1608. YAHOO.util.EventProvider.prototype = {
  1609. /**
  1610. * Private storage of custom events
  1611. *
  1612. * @property __yui_events
  1613. * @type Object[]
  1614. * @private
  1615. */
  1616. __yui_events : null,
  1617. /**
  1618. * Private storage of custom event subscribers
  1619. *
  1620. * @property __yui_subscribers
  1621. * @type Object[]
  1622. * @private
  1623. */
  1624. __yui_subscribers : null,
  1625. /**
  1626. * Subscribe to a CustomEvent by event type
  1627. *
  1628. * @method subscribe
  1629. * @param p_type
  1630. * {string} the type, or name of the event
  1631. * @param p_fn
  1632. * {function} the function to exectute when the event fires
  1633. * @param p_obj
  1634. * @param p_obj
  1635. * {Object} An object to be passed along when the event fires
  1636. * @param p_override
  1637. * {boolean} If true, the obj passed in becomes the execution
  1638. * scope of the listener
  1639. */
  1640. subscribe : function(p_type, p_fn, p_obj, p_override) {
  1641. this.__yui_events = this.__yui_events || {};
  1642. var ce = this.__yui_events[p_type];
  1643. if (ce) {
  1644. ce.subscribe(p_fn, p_obj, p_override);
  1645. } else {
  1646. this.__yui_subscribers = this.__yui_subscribers || {};
  1647. var subs = this.__yui_subscribers;
  1648. if (!subs[p_type]) {
  1649. subs[p_type] = [];
  1650. }
  1651. subs[p_type].push({
  1652. fn : p_fn,
  1653. obj : p_obj,
  1654. override : p_override
  1655. });
  1656. }
  1657. },
  1658. /**
  1659. * Unsubscribes one or more listeners the from the specified event
  1660. *
  1661. * @method unsubscribe
  1662. * @param p_type
  1663. * {string} The type, or name of the event
  1664. * @param p_fn
  1665. * {Function} The subscribed function to unsubscribe, if not
  1666. * supplied, all subscribers will be removed.
  1667. * @param p_obj
  1668. * {Object} The custom object passed to subscribe. This is
  1669. * optional, but if supplied will be used to disambiguate
  1670. * multiple listeners that are the same (e.g., you subscribe many
  1671. * object using a function that lives on the prototype)
  1672. * @return {boolean} true if the subscriber was found and detached.
  1673. */
  1674. unsubscribe : function(p_type, p_fn, p_obj) {
  1675. this.__yui_events = this.__yui_events || {};
  1676. var ce = this.__yui_events[p_type];
  1677. if (ce) {
  1678. return ce.unsubscribe(p_fn, p_obj);
  1679. } else {
  1680. return false;
  1681. }
  1682. },
  1683. /**
  1684. * Removes all listeners from the specified event
  1685. *
  1686. * @method unsubscribeAll
  1687. * @param p_type
  1688. * {string} The type, or name of the event
  1689. */
  1690. unsubscribeAll : function(p_type) {
  1691. return this.unsubscribe(p_type);
  1692. },
  1693. /**
  1694. * Creates a new custom event of the specified type. If a custom event by
  1695. * that name already exists, it will not be re-created. In either case the
  1696. * custom event is returned.
  1697. *
  1698. * @method createEvent
  1699. *
  1700. * @param p_type
  1701. * {string} the type, or name of the event
  1702. * @param p_config
  1703. * {object} optional config params. Valid properties are:
  1704. *
  1705. * <ul>
  1706. * <li> scope: defines the default execution scope. If not defined the
  1707. * default scope will be this instance. </li>
  1708. * <li> silent: if true, the custom event will not generate log messages.
  1709. * This is false by default. </li>
  1710. * <li> onSubscribeCallback: specifies a callback to execute when the event
  1711. * has a new subscriber. This will fire immediately for each queued
  1712. * subscriber if any exist prior to the creation of the event. </li>
  1713. * </ul>
  1714. *
  1715. * @return {CustomEvent} the custom event
  1716. *
  1717. */
  1718. createEvent : function(p_type, p_config) {
  1719. this.__yui_events = this.__yui_events || {};
  1720. var opts = p_config || {};
  1721. var events = this.__yui_events;
  1722. if (events[p_type]) {
  1723. } else {
  1724. var scope = opts.scope || this;
  1725. var silent = opts.silent || null;
  1726. var ce = new YAHOO.util.CustomEvent(p_type, scope, silent,
  1727. YAHOO.util.CustomEvent.FLAT);
  1728. events[p_type] = ce;
  1729. if (opts.onSubscribeCallback) {
  1730. ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
  1731. }
  1732. this.__yui_subscribers = this.__yui_subscribers || {};
  1733. var qs = this.__yui_subscribers[p_type];
  1734. if (qs) {
  1735. for (var i = 0; i < qs.length; ++i) {
  1736. ce.subscribe(qs[i].fn, qs[i].obj, qs[i].override);
  1737. }
  1738. }
  1739. }
  1740. return events[p_type];
  1741. },
  1742. /**
  1743. * Fire a custom event by name. The callback functions will be executed from
  1744. * the scope specified when the event was created, and with the following
  1745. * parameters:
  1746. * <ul>
  1747. * <li>The first argument fire() was executed with</li>
  1748. * <li>The custom object (if any) that was passed into the subscribe()
  1749. * method</li>
  1750. * </ul>
  1751. *
  1752. * @method fireEvent
  1753. * @param p_type
  1754. * {string} the type, or name of the event
  1755. * @param arguments
  1756. * {Object*} an arbitrary set of parameters to pass to the
  1757. * handler.
  1758. * @return {boolean} the return value from CustomEvent.fire, or null if the
  1759. * custom event does not exist.
  1760. */
  1761. fireEvent : function(p_type, arg1, arg2, etc) {
  1762. this.__yui_events = this.__yui_events || {};
  1763. var ce = this.__yui_events[p_type];
  1764. if (ce) {
  1765. var args = [];
  1766. for (var i = 1; i < arguments.length; ++i) {
  1767. args.push(arguments[i]);
  1768. }
  1769. return ce.fire.apply(ce, args);
  1770. } else {
  1771. return null;
  1772. }
  1773. },
  1774. /**
  1775. * Returns true if the custom event of the provided type has been created
  1776. * with createEvent.
  1777. *
  1778. * @method hasEvent
  1779. * @param type
  1780. * {string} the type, or name of the event
  1781. */
  1782. hasEvent : function(type) {
  1783. if (this.__yui_events) {
  1784. if (this.__yui_events[type]) {
  1785. return true;
  1786. }
  1787. }
  1788. return false;
  1789. }
  1790. };
  1791. /**
  1792. * KeyListener is a utility that provides an easy interface for listening for
  1793. * keydown/keyup events fired against DOM elements.
  1794. *
  1795. * @namespace YAHOO.util
  1796. * @class KeyListener
  1797. * @constructor
  1798. * @param {HTMLElement}
  1799. * attachTo The element or element ID to which the key event should
  1800. * be attached
  1801. * @param {String}
  1802. * attachTo The element or element ID to which the key event should
  1803. * be attached
  1804. * @param {Object}
  1805. * keyData The object literal representing the key(s) to detect.
  1806. * Possible attributes are shift(boolean), alt(boolean),
  1807. * ctrl(boolean) and keys(either an int or an array of ints
  1808. * representing keycodes).
  1809. * @param {Function}
  1810. * handler The CustomEvent handler to fire when the key event is
  1811. * detected
  1812. * @param {Object}
  1813. * handler An object literal representing the handler.
  1814. * @param {String}
  1815. * event Optional. The event (keydown or keyup) to listen for.
  1816. * Defaults automatically to keydown.
  1817. */
  1818. YAHOO.util.KeyListener = function(attachTo, keyData, handler, event) {
  1819. if (!attachTo) {
  1820. } else if (!keyData) {
  1821. } else if (!handler) {
  1822. }
  1823. if (!event) {
  1824. event = YAHOO.util.KeyListener.KEYDOWN;
  1825. }
  1826. /**
  1827. * The CustomEvent fired internally when a key is pressed
  1828. *
  1829. * @event keyEvent
  1830. * @private
  1831. * @param {Object}
  1832. * keyData The object literal representing the key(s) to detect.
  1833. * Possible attributes are shift(boolean), alt(boolean),
  1834. * ctrl(boolean) and keys(either an int or an array of ints
  1835. * representing keycodes).
  1836. */
  1837. var keyEvent = new YAHOO.util.CustomEvent("keyPressed");
  1838. /**
  1839. * The CustomEvent fired when the KeyListener is enabled via the enable()
  1840. * function
  1841. *
  1842. * @event enabledEvent
  1843. * @param {Object}
  1844. * keyData The object literal representing the key(s) to detect.
  1845. * Possible attributes are shift(boolean), alt(boolean),
  1846. * ctrl(boolean) and keys(either an int or an array of ints
  1847. * representing keycodes).
  1848. */
  1849. this.enabledEvent = new YAHOO.util.CustomEvent("enabled");
  1850. /**
  1851. * The CustomEvent fired when the KeyListener is disabled via the disable()
  1852. * function
  1853. *
  1854. * @event disabledEvent
  1855. * @param {Object}
  1856. * keyData The object literal representing the key(s) to detect.
  1857. * Possible attributes are shift(boolean), alt(boolean),
  1858. * ctrl(boolean) and keys(either an int or an array of ints
  1859. * representing keycodes).
  1860. */
  1861. this.disabledEvent = new YAHOO.util.CustomEvent("disabled");
  1862. if (typeof attachTo == 'string') {
  1863. attachTo = document.getElementById(attachTo);
  1864. }
  1865. if (typeof handler == 'function') {
  1866. keyEvent.subscribe(handler);
  1867. } else {
  1868. keyEvent.subscribe(handler.fn, handler.scope, handler.correctScope);
  1869. }
  1870. /**
  1871. * Handles the key event when a key is pressed.
  1872. *
  1873. * @method handleKeyPress
  1874. * @param {DOMEvent}
  1875. * e The keypress DOM event
  1876. * @param {Object}
  1877. * obj The DOM event scope object
  1878. * @private
  1879. */
  1880. function handleKeyPress(e, obj) {
  1881. if (!keyData.shift) {
  1882. keyData.shift = false;
  1883. }
  1884. if (!keyData.alt) {
  1885. keyData.alt = false;
  1886. }
  1887. if (!keyData.ctrl) {
  1888. keyData.ctrl = false;
  1889. }
  1890. // check held down modifying keys first
  1891. if (e.shiftKey == keyData.shift && e.altKey == keyData.alt
  1892. && e.ctrlKey == keyData.ctrl) { // if we pass this, all
  1893. // modifiers match
  1894. var dataItem;
  1895. var keyPressed;
  1896. if (keyData.keys instanceof Array) {
  1897. for (var i = 0; i < keyData.keys.length; i++) {
  1898. dataItem = keyData.keys[i];
  1899. if (dataItem == e.charCode) {
  1900. keyEvent.fire(e.charCode, e);
  1901. break;
  1902. } else if (dataItem == e.keyCode) {
  1903. keyEvent.fire(e.keyCode, e);
  1904. break;
  1905. }
  1906. }
  1907. } else {
  1908. dataItem = keyData.keys;
  1909. if (dataItem == e.charCode) {
  1910. keyEvent.fire(e.charCode, e);
  1911. } else if (dataItem == e.keyCode) {
  1912. keyEvent.fire(e.keyCode, e);
  1913. }
  1914. }
  1915. }
  1916. }
  1917. /**
  1918. * Enables the KeyListener by attaching the DOM event listeners to the
  1919. * target DOM element
  1920. *
  1921. * @method enable
  1922. */
  1923. this.enable = function() {
  1924. if (!this.enabled) {
  1925. YAHOO.util.Event.addListener(attachTo, event, handleKeyPress);
  1926. this.enabledEvent.fire(keyData);
  1927. }
  1928. /**
  1929. * Boolean indicating the enabled/disabled state of the Tooltip
  1930. *
  1931. * @property enabled
  1932. * @type Boolean
  1933. */
  1934. this.enabled = true;
  1935. };
  1936. /**
  1937. * Disables the KeyListener by removing the DOM event listeners from the
  1938. * target DOM element
  1939. *
  1940. * @method disable
  1941. */
  1942. this.disable = function() {
  1943. if (this.enabled) {
  1944. YAHOO.util.Event.removeListener(attachTo, event, handleKeyPress);
  1945. this.disabledEvent.fire(keyData);
  1946. }
  1947. this.enabled = false;
  1948. };
  1949. /**
  1950. * Returns a String representation of the object.
  1951. *
  1952. * @method toString
  1953. * @return {String} The string representation of the KeyListener
  1954. */
  1955. this.toString = function() {
  1956. return "KeyListener [" + keyData.keys + "] " + attachTo.tagName
  1957. + (attachTo.id ? "[" + attachTo.id + "]" : "");
  1958. };
  1959. };
  1960. /**
  1961. * Constant representing the DOM "keydown" event.
  1962. *
  1963. * @property YAHOO.util.KeyListener.KEYDOWN
  1964. * @static
  1965. * @final
  1966. * @type String
  1967. */
  1968. YAHOO.util.KeyListener.KEYDOWN = "keydown";
  1969. /**
  1970. * Constant representing the DOM "keyup" event.
  1971. *
  1972. * @property YAHOO.util.KeyListener.KEYUP
  1973. * @static
  1974. * @final
  1975. * @type String
  1976. */
  1977. YAHOO.util.KeyListener.KEYUP = "keyup";
  1978. YAHOO.register("event", YAHOO.util.Event, {
  1979. version : "2.2.0",
  1980. build : "127"
  1981. });