event.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /**
  2. * $Id: TinyMCE_DOMUtils.class.js 91 2006-10-02 14:53:22Z spocke $
  3. *
  4. * @author Moxiecode
  5. * @copyright Copyright © 2004-2006, Moxiecode Systems AB, All rights reserved.
  6. */
  7. mox.require([
  8. 'mox.DOM'
  9. ], function() {
  10. /**#@+
  11. * @class This class contains common event handling logic.
  12. * @member mox.Event
  13. * @static
  14. */
  15. mox.create('static mox.Event', {
  16. _domLoaded : [],
  17. _listeners : [],
  18. _cleanups : [],
  19. _domLoadedState : false,
  20. /**#@+
  21. * @method
  22. */
  23. /**
  24. * Adds a event handler to a DOM object.
  25. *
  26. * @param {Object} o DOM object to attach event handler to.
  27. * @param {string} n Name of event to attach like click or load.
  28. * @param {function} f Function callback to execute when the event occurs.
  29. * @param {Object} s Optional scope object to execute callback on.
  30. * @return {function} Function reference to callback, use this with removeHandler.
  31. */
  32. add : function(o, n, f, s) {
  33. var ev = this, cb;
  34. if (!o)
  35. return null;
  36. o = mox.DOM.get(o);
  37. // Shorter version of DOMContentLoaded
  38. if (n == 'init')
  39. n = 'DOMContentLoaded';
  40. // Setup event callback
  41. cb = function(e) {
  42. e = e || window.event;
  43. // Patch in target in IE it's W3C valid
  44. if (e && !e.target)
  45. e.target = e.srcElement;
  46. if (!s)
  47. return f(e);
  48. return f.call(s, e);
  49. };
  50. // Already loaded fire it now!
  51. if (mox.contentLoaded && n == 'DOMContentLoaded') {
  52. cb();
  53. return;
  54. }
  55. // Fake DOMContentLoaded event on IE & Safari
  56. if ((mox.isIE || mox.isSafari) && n == 'DOMContentLoaded') {
  57. this._domLoaded.push(cb);
  58. return cb;
  59. }
  60. // Store away listener reference
  61. this._listeners.push({
  62. obj : o,
  63. name : n,
  64. func : f,
  65. cfunc : cb,
  66. scope : s
  67. });
  68. this._addEvent(o, n, cb);
  69. return cb;
  70. },
  71. /**
  72. * Removes a event handler from the specified object.
  73. *
  74. * @param {Object} o DOM object to remove event handler from.
  75. * @param {string} n Name of event to attach like click or load.
  76. * @param {function} f Function callback to execute when the event occurs.
  77. * @return {function} Function reference to callback.
  78. */
  79. remove : function(o, n, f) {
  80. var i, li = this._listeners, it;
  81. if (!o)
  82. return null;
  83. o = mox.DOM.get(o);
  84. this._removeEvent(o, n, f);
  85. for (i=0; i<li.length; i++) {
  86. it = li[i];
  87. // Is match, then remove it
  88. if (it.obj == o && it.name == n && it.func == f) {
  89. this._removeEvent(it.obj, it.name, it.cfunc);
  90. li.splice(i, 1);
  91. return f;
  92. }
  93. }
  94. return null;
  95. },
  96. /**
  97. * Removes any events hooked onto the specified object.
  98. *
  99. * @param {Object} o DOM object to remove events listeners from.
  100. */
  101. removeAll : function(o) {
  102. var i, li, it;
  103. for (i=0, li = this._listeners; i<li.length; i++) {
  104. it = li[i];
  105. // Is match, then clean it
  106. if (it.obj == o) {
  107. this._removeEvent(it.obj, it.name, it.cfunc);
  108. li.splice(i, 1);
  109. }
  110. }
  111. },
  112. /**
  113. * Cancels the specified event, this will disable the event from be passed to other
  114. * listeners in event chain and also cancel the browsers default behavior.
  115. *
  116. * @param {DOMEvent} e Event to cancel.
  117. * @return {bool} Returns false.
  118. */
  119. cancel : function(e) {
  120. var t = mox.Event;
  121. t.stopPropagation(e);
  122. return t.preventDefault(e);
  123. },
  124. /**
  125. * Stops event propagation. This will cancel the event bubbeling.
  126. *
  127. * @param {DOMEvent} e Event to cancel.
  128. * @return {bool} Returns false.
  129. */
  130. stopPropagation : function(e) {
  131. if (!e)
  132. return false;
  133. if (e.stopPropagation)
  134. e.stopPropagation();
  135. else
  136. e.cancelBubble = true;
  137. return false;
  138. },
  139. /**
  140. * Stops the browsers default behavior.
  141. *
  142. * @param {DOMEvent} e Event to stop.
  143. * @return {bool} Returns false.
  144. */
  145. preventDefault : function(e) {
  146. if (!e)
  147. return false;
  148. if (e.preventDefault)
  149. e.preventDefault();
  150. else
  151. e.returnValue = false;
  152. return false;
  153. },
  154. fire : function(o, n, e) {
  155. var i, li, it;
  156. if (!e)
  157. return false;
  158. for (i=0, li=this._listeners; i<li.length; i++) {
  159. it = li[i];
  160. if (it.obj == o && it.name == n)
  161. it.cfunc(e);
  162. }
  163. return true;
  164. },
  165. /**
  166. * Returns the page X, Y cordinate from a event. This method will returns a lightweight object with just two properties x, y.
  167. *
  168. * @param {DOMEvent} e Event to get page X, Y from.
  169. * @return {Object} Lightweight object with a x, y property.
  170. */
  171. getPageXY : function(e) {
  172. var d = document, de = d.documentElement || d.body, x = e.pageX || e.clientX || 0, y = e.pageY || e.clientY || 0;
  173. if (mox.isIE) {
  174. x += de.scrollLeft;
  175. y += de.scrollTop;
  176. }
  177. return {x : x, y : y};
  178. },
  179. /**
  180. * Adds a memory cleanup function on page unload. This method can be used to add
  181. * custom logic to be executed on page unload since some browsers have
  182. * memory leaks.
  183. *
  184. * @param {function} f Function to execute on page unload.
  185. */
  186. addCleanup : function(f) {
  187. this._cleanups.push(f);
  188. },
  189. // * * Private methods
  190. _unLoad : function() {
  191. var i, ev = mox.Event, li, it, ex;
  192. for (i=0, li=ev._listeners; i<li.length; i++) {
  193. it = li[i];
  194. try {
  195. ev._removeEvent(it.obj, it.name, it.cfunc);
  196. it.obj = it.name = it.cfunc = null;
  197. } catch (ex) {
  198. // Ignore
  199. }
  200. }
  201. for (i=0, li=ev._cleanups; i<li.length; i++) {
  202. try {
  203. li[i]();
  204. } catch (ex) {
  205. // Ignore
  206. }
  207. }
  208. ev._removeEvent(window, 'unload', ev._unLoad);
  209. ev._listeners = [];
  210. ev._cleanups = [];
  211. },
  212. _addEvent : function(o, n, f) {
  213. if (o.attachEvent)
  214. o.attachEvent('on' + n, f);
  215. else if (o.addEventListener)
  216. o.addEventListener(n, f, false);
  217. else
  218. o['on' + n] = f;
  219. },
  220. _removeEvent : function(o, n, f) {
  221. if (o.detachEvent)
  222. o.detachEvent('on' + n, f);
  223. else if (o.removeEventListener)
  224. o.removeEventListener(n, f, false);
  225. else
  226. o['on' + n] = null;
  227. },
  228. _DOMContentLoadedIE : function() {
  229. var e = document.getElementById('_ie_lo');
  230. if (e.readyState == "complete") {
  231. this._dispatchDOMContentLoaded();
  232. e.onreadystatechange = null;
  233. }
  234. },
  235. _dispatchDOMContentLoaded : function() {
  236. var i, ar = mox.Event._domLoaded;
  237. for (i=0; i<ar.length; i++)
  238. ar[i](window.event);
  239. mox.Event._domLoaded = [];
  240. mox.contentLoaded = true;
  241. },
  242. _waitForLoaded : function() {
  243. if (/loaded|complete/.test(document.readyState))
  244. this._dispatchDOMContentLoaded();
  245. else
  246. window.setTimeout('mox.Event._waitForLoaded();', 10);
  247. },
  248. _handleDOMContentLoaded : function(d) {
  249. d = !d ? document : d;
  250. // Force CSS background caching
  251. if (mox.isIE) {
  252. try {
  253. document.execCommand('BackgroundImageCache', false, true);
  254. } catch (e) {
  255. // Ignore
  256. }
  257. }
  258. // Add unload handler
  259. this._addEvent(window, 'unload', this._unLoad);
  260. // Fake DOM content loaded in IE and Safari
  261. if (mox.isIE || mox.isSafari)
  262. this._waitForLoaded();
  263. }
  264. /**#@-*/
  265. });
  266. // Dispatch DOM content loaded event for IE and Safari
  267. mox.Event._handleDOMContentLoaded();
  268. });