75674460cfa8424e73de5951a82daa5cc60462d5.svn-base 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
  2. YAHOO.util.CustomEvent = function(type, oScope) {
  3. this.type = type;
  4. this.scope = oScope || window;
  5. this.subscribers = [];
  6. if (YAHOO.util["Event"]) {
  7. YAHOO.util.Event.regCE(this);
  8. }
  9. };
  10. YAHOO.util.CustomEvent.prototype = {
  11. subscribe : function(fn, obj, bOverride) {
  12. this.subscribers.push(new YAHOO.util.Subscriber(fn, obj, bOverride));
  13. },
  14. unsubscribe : function(fn, obj) {
  15. var found = false;
  16. for (var i = 0; i < this.subscribers.length; ++i) {
  17. var s = this.subscribers[i];
  18. if (s && s.contains(fn, obj)) {
  19. this._delete(i);
  20. found = true;
  21. }
  22. }
  23. return found;
  24. },
  25. fire : function() {
  26. for (var i = 0; i < this.subscribers.length; ++i) {
  27. var s = this.subscribers[i];
  28. if (s) {
  29. var scope = (s.override) ? s.obj : this.scope;
  30. s.fn.call(scope, this.type, arguments, s.obj);
  31. }
  32. }
  33. },
  34. unsubscribeAll : function() {
  35. for (var i = 0; i < this.subscribers.length; ++i) {
  36. this._delete(i);
  37. }
  38. },
  39. _delete : function(index) {
  40. var s = this.subscribers[index];
  41. if (s) {
  42. delete s.fn;
  43. delete s.obj;
  44. }
  45. delete this.subscribers[index];
  46. }
  47. };
  48. YAHOO.util.Subscriber = function(fn, obj, bOverride) {
  49. this.fn = fn;
  50. this.obj = obj || null;
  51. this.override = (bOverride);
  52. };
  53. YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
  54. return (this.fn == fn && this.obj == obj);
  55. };
  56. if (!YAHOO.util.Event) {
  57. YAHOO.util.Event = function() {
  58. var loadComplete = false;
  59. var listeners = [];
  60. var delayedListeners = [];
  61. var unloadListeners = [];
  62. var customEvents = [];
  63. var legacyEvents = [];
  64. var legacyHandlers = [];
  65. return {
  66. EL : 0,
  67. TYPE : 1,
  68. FN : 2,
  69. WFN : 3,
  70. SCOPE : 3,
  71. ADJ_SCOPE : 4,
  72. isSafari : (navigator.userAgent.match(/safari/gi)),
  73. isIE : (!this.isSafari && navigator.userAgent.match(/msie/gi)),
  74. addListener : function(el, sType, fn, oScope, bOverride) {
  75. if (this._isValidCollection(el)) {
  76. var ok = true;
  77. for (var i = 0; i < el.length; ++i) {
  78. ok = (this.on(el[i], sType, fn, oScope, bOverride) && ok);
  79. }
  80. return ok;
  81. } else if (typeof el == "string") {
  82. if (loadComplete) {
  83. el = this.getEl(el);
  84. } else {
  85. delayedListeners[delayedListeners.length] = [el, sType,
  86. fn, oScope, bOverride];
  87. return true;
  88. }
  89. }
  90. if (!el) {
  91. return false;
  92. }
  93. if ("unload" == sType && oScope !== this) {
  94. unloadListeners[unloadListeners.length] = [el, sType, fn,
  95. oScope, bOverride];
  96. return true;
  97. }
  98. var scope = (bOverride) ? oScope : el;
  99. var wrappedFn = function(e) {
  100. return fn.call(scope, YAHOO.util.Event.getEvent(e), oScope);
  101. };
  102. var li = [el, sType, fn, wrappedFn, scope];
  103. var index = listeners.length;
  104. listeners[index] = li;
  105. if (this.useLegacyEvent(el, sType)) {
  106. var legacyIndex = this.getLegacyIndex(el, sType);
  107. if (legacyIndex == -1) {
  108. legacyIndex = legacyEvents.length;
  109. legacyEvents[legacyIndex] = [el, sType,
  110. el["on" + sType]];
  111. legacyHandlers[legacyIndex] = [];
  112. el["on" + sType] = function(e) {
  113. YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event
  114. .getEvent(e), legacyIndex);
  115. };
  116. }
  117. legacyHandlers[legacyIndex].push(index);
  118. } else if (el.addEventListener) {
  119. el.addEventListener(sType, wrappedFn, false);
  120. } else if (el.attachEvent) {
  121. el.attachEvent("on" + sType, wrappedFn);
  122. }
  123. return true;
  124. },
  125. fireLegacyEvent : function(e, legacyIndex) {
  126. var ok = true;
  127. var le = legacyHandlers[legacyIndex];
  128. for (i = 0; i < le.length; ++i) {
  129. var index = le[i];
  130. if (index) {
  131. var li = listeners[index];
  132. var scope = li[this.ADJ_SCOPE];
  133. var ret = li[this.WFN].call(scope, e);
  134. ok = (ok && ret);
  135. }
  136. }
  137. return ok;
  138. },
  139. getLegacyIndex : function(el, sType) {
  140. for (var i = 0; i < legacyEvents.length; ++i) {
  141. var le = legacyEvents[i];
  142. if (le && le[0] == el && le[1] == sType) {
  143. return i;
  144. }
  145. }
  146. return -1;
  147. },
  148. useLegacyEvent : function(el, sType) {
  149. return ((!el.addEventListener && !el.attachEvent) || (sType == "click" && this.isSafari));
  150. },
  151. removeListener : function(el, sType, fn) {
  152. if (typeof el == "string") {
  153. el = this.getEl(el);
  154. } else if (this._isValidCollection(el)) {
  155. var ok = true;
  156. for (var i = 0; i < el.length; ++i) {
  157. ok = (this.removeListener(el[i], sType, fn) && ok);
  158. }
  159. return ok;
  160. }
  161. var cacheItem = null;
  162. var index = this._getCacheIndex(el, sType, fn);
  163. if (index >= 0) {
  164. cacheItem = listeners[index];
  165. }
  166. if (!el || !cacheItem) {
  167. return false;
  168. }
  169. if (el.removeEventListener) {
  170. el.removeEventListener(sType, cacheItem[this.WFN], false);
  171. } else if (el.detachEvent) {
  172. el.detachEvent("on" + sType, cacheItem[this.WFN]);
  173. }
  174. delete listeners[index][this.WFN];
  175. delete listeners[index][this.FN];
  176. delete listeners[index];
  177. return true;
  178. },
  179. getTarget : function(ev, resolveTextNode) {
  180. var t = ev.target || ev.srcElement;
  181. if (resolveTextNode && t && "#text" == t.nodeName) {
  182. return t.parentNode;
  183. } else {
  184. return t;
  185. }
  186. },
  187. getPageX : function(ev) {
  188. var x = ev.pageX;
  189. if (!x && 0 !== x) {
  190. x = ev.clientX || 0;
  191. if (this.isIE) {
  192. x += this._getScrollLeft();
  193. }
  194. }
  195. return x;
  196. },
  197. getPageY : function(ev) {
  198. var y = ev.pageY;
  199. if (!y && 0 !== y) {
  200. y = ev.clientY || 0;
  201. if (this.isIE) {
  202. y += this._getScrollTop();
  203. }
  204. }
  205. return y;
  206. },
  207. getRelatedTarget : function(ev) {
  208. var t = ev.relatedTarget;
  209. if (!t) {
  210. if (ev.type == "mouseout") {
  211. t = ev.toElement;
  212. } else if (ev.type == "mouseover") {
  213. t = ev.fromElement;
  214. }
  215. }
  216. return t;
  217. },
  218. getTime : function(ev) {
  219. if (!ev.time) {
  220. var t = allGetServerTime().getTime();
  221. try {
  222. ev.time = t;
  223. } catch (e) {
  224. return t;
  225. }
  226. }
  227. return ev.time;
  228. },
  229. stopEvent : function(ev) {
  230. this.stopPropagation(ev);
  231. this.preventDefault(ev);
  232. },
  233. stopPropagation : function(ev) {
  234. if (ev.stopPropagation) {
  235. ev.stopPropagation();
  236. } else {
  237. ev.cancelBubble = true;
  238. }
  239. },
  240. preventDefault : function(ev) {
  241. if (ev.preventDefault) {
  242. ev.preventDefault();
  243. } else {
  244. ev.returnValue = false;
  245. }
  246. },
  247. getEvent : function(e) {
  248. var ev = e || window.event;
  249. if (!ev) {
  250. var c = this.getEvent.caller;
  251. while (c) {
  252. ev = c.arguments[0];
  253. if (ev && Event == ev.constructor) {
  254. break;
  255. }
  256. c = c.caller;
  257. }
  258. }
  259. return ev;
  260. },
  261. getCharCode : function(ev) {
  262. return ev.charCode || (ev.type == "keypress") ? ev.keyCode : 0;
  263. },
  264. _getCacheIndex : function(el, sType, fn) {
  265. for (var i = 0; i < listeners.length; ++i) {
  266. var li = listeners[i];
  267. if (li && li[this.FN] == fn && li[this.EL] == el
  268. && li[this.TYPE] == sType) {
  269. return i;
  270. }
  271. }
  272. return -1;
  273. },
  274. _isValidCollection : function(o) {
  275. return (o && o.length && typeof o != "string" && !o.tagName
  276. && !o.alert && typeof o[0] != "undefined");
  277. },
  278. elCache : {},
  279. getEl : function(id) {
  280. return document.getElementById(id);
  281. },
  282. clearCache : function() {
  283. for (i in this.elCache) {
  284. delete this.elCache[i];
  285. }
  286. },
  287. regCE : function(ce) {
  288. customEvents.push(ce);
  289. },
  290. _load : function(e) {
  291. loadComplete = true;
  292. },
  293. _tryPreloadAttach : function() {
  294. var tryAgain = !loadComplete;
  295. for (var i = 0; i < delayedListeners.length; ++i) {
  296. var d = delayedListeners[i];
  297. if (d) {
  298. var el = this.getEl(d[this.EL]);
  299. if (el) {
  300. this.on(el, d[this.TYPE], d[this.FN],
  301. d[this.SCOPE], d[this.ADJ_SCOPE]);
  302. delete delayedListeners[i];
  303. }
  304. }
  305. }
  306. if (tryAgain) {
  307. setTimeout("YAHOO.util.Event._tryPreloadAttach()", 50);
  308. }
  309. },
  310. _unload : function(e, me) {
  311. for (var i = 0; i < unloadListeners.length; ++i) {
  312. var l = unloadListeners[i];
  313. if (l) {
  314. var scope = (l[this.ADJ_SCOPE])
  315. ? l[this.SCOPE]
  316. : window;
  317. l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE]);
  318. }
  319. }
  320. if (listeners && listeners.length > 0) {
  321. for (i = 0; i < listeners.length; ++i) {
  322. l = listeners[i];
  323. if (l) {
  324. this.removeListener(l[this.EL], l[this.TYPE],
  325. l[this.FN]);
  326. }
  327. }
  328. this.clearCache();
  329. }
  330. for (i = 0; i < customEvents.length; ++i) {
  331. customEvents[i].unsubscribeAll();
  332. delete customEvents[i];
  333. }
  334. for (i = 0; i < legacyEvents.length; ++i) {
  335. delete legacyEvents[i][0];
  336. delete legacyEvents[i];
  337. }
  338. },
  339. _getScrollLeft : function() {
  340. return this._getScroll()[1];
  341. },
  342. _getScrollTop : function() {
  343. return this._getScroll()[0];
  344. },
  345. _getScroll : function() {
  346. var dd = document.documentElement;
  347. db = document.body;
  348. if (dd && dd.scrollTop) {
  349. return [dd.scrollTop, dd.scrollLeft];
  350. } else if (db) {
  351. return [db.scrollTop, db.scrollLeft];
  352. } else {
  353. return [0, 0];
  354. }
  355. }
  356. };
  357. }();
  358. YAHOO.util.Event.on = YAHOO.util.Event.addListener;
  359. if (document && document.body) {
  360. YAHOO.util.Event._load();
  361. } else {
  362. YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load,
  363. YAHOO.util.Event, true);
  364. }
  365. YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload,
  366. YAHOO.util.Event, true);
  367. YAHOO.util.Event._tryPreloadAttach();
  368. }