4 * Copyright 2009, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://tinymce.moxiecode.com/license
8 * Contributing: http://tinymce.moxiecode.com/contributing
13 var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event;
16 * This class handles DOM events in a cross platform fasion it also keeps track of element
17 * and handler references to be able to clean elements to reduce IE memory leaks.
19 * @class tinymce.dom.EventUtils
21 tinymce.create('tinymce.dom.EventUtils', {
23 * Constructs a new EventUtils instance.
28 EventUtils : function() {
34 * Adds an event handler to the specified object.
37 * @param {Element/Document/Window/Array/String} o Object or element id string to add event handler to or an array of elements/ids/documents.
38 * @param {String/Array} n Name of event handler to add for example: click.
39 * @param {function} f Function to execute when the event occurs.
40 * @param {Object} s Optional scope to execute the function in.
41 * @return {function} Function callback handler the same as the one passed in.
43 * // Adds a click handler to the current document
44 * tinymce.dom.Event.add(document, 'click', function(e) {
45 * console.debug(e.target);
48 add : function(o, n, f, s) {
49 var cb, t = this, el = t.events, r;
51 if (n instanceof Array) {
55 r.push(t.add(o, n, f, s));
62 if (o && o.hasOwnProperty && o instanceof Array) {
67 r.push(t.add(o, n, f, s));
78 // Setup event callback
80 // Is all events disabled
84 e = e || window.event;
86 // Patch in target, preventDefault and stopPropagation in IE it's W3C valid
89 e.target = e.srcElement;
91 // Patch in preventDefault, stopPropagation methods for W3C compatibility
92 tinymce.extend(e, t._stoppers);
102 tinymce.unloads.unshift({func : cb});
115 // Store away listener reference
130 * Removes the specified event handler by name and function from a element or collection of elements.
133 * @param {String/Element/Array} o Element ID string or HTML element or an array of elements or ids to remove handler from.
134 * @param {String} n Event handler name like for example: "click"
135 * @param {function} f Function to remove.
136 * @return {bool/Array} Bool state if true if the handler was removed or an array with states if multiple elements where passed in.
138 * // Adds a click handler to the current document
139 * var func = tinymce.dom.Event.add(document, 'click', function(e) {
140 * console.debug(e.target);
143 * // Removes the click handler from the document
144 * tinymce.dom.Event.remove(document, 'click', func);
146 remove : function(o, n, f) {
147 var t = this, a = t.events, s = false, r;
150 if (o && o.hasOwnProperty && o instanceof Array) {
153 each(o, function(o) {
155 r.push(t.remove(o, n, f));
163 each(a, function(e, i) {
164 if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) {
166 t._remove(o, n, e.cfunc);
176 * Clears all events of a specific object.
179 * @param {Object} o DOM element or object to remove all events from.
181 * // Cancels all mousedown events in the active editor
182 * tinyMCE.activeEditor.onMouseDown.add(function(ed, e) {
183 * return tinymce.dom.Event.cancel(e);
186 clear : function(o) {
187 var t = this, a = t.events, i, e;
192 for (i = a.length - 1; i >= 0; i--) {
196 t._remove(e.obj, e.name, e.cfunc);
197 e.obj = e.cfunc = null;
205 * Cancels an event for both bubbeling and the default browser behavior.
208 * @param {Event} e Event object to cancel.
209 * @return {Boolean} Always false.
211 cancel : function(e) {
217 return this.prevent(e);
221 * Stops propogation/bubbeling of an event.
224 * @param {Event} e Event to cancel bubbeling on.
225 * @return {Boolean} Always false.
228 if (e.stopPropagation)
231 e.cancelBubble = true;
237 * Prevent default browser behvaior of an event.
240 * @param {Event} e Event to prevent default browser behvaior of an event.
241 * @return {Boolean} Always false.
243 prevent : function(e) {
244 if (e.preventDefault)
247 e.returnValue = false;
253 * Destroys the instance.
257 destroy : function() {
260 each(t.events, function(e, i) {
261 t._remove(e.obj, e.name, e.cfunc);
262 e.obj = e.cfunc = null;
269 _add : function(o, n, f) {
271 o.attachEvent('on' + n, f);
272 else if (o.addEventListener)
273 o.addEventListener(n, f, false);
278 _remove : function(o, n, f) {
282 o.detachEvent('on' + n, f);
283 else if (o.removeEventListener)
284 o.removeEventListener(n, f, false);
288 // Might fail with permission denined on IE so we just ignore that
293 _pageInit : function(win) {
296 // Keep it from running more than once
302 each(t.inits, function(c) {
309 _wait : function(win) {
310 var t = this, doc = win.document;
312 // No need since the document is already loaded
313 if (win.tinyMCE_GZ && tinyMCE_GZ.loaded) {
319 if (doc.attachEvent) {
320 doc.attachEvent("onreadystatechange", function() {
321 if (doc.readyState === "complete") {
322 doc.detachEvent("onreadystatechange", arguments.callee);
327 if (doc.documentElement.doScroll && win == win.top) {
333 // If IE is used, use the trick by Diego Perini licensed under MIT by request to the author.
334 // http://javascript.nwbox.com/IEContentLoaded/
335 doc.documentElement.doScroll("left");
337 setTimeout(arguments.callee, 0);
344 } else if (doc.addEventListener) {
345 t._add(win, 'DOMContentLoaded', function() {
350 t._add(win, 'load', function() {
356 preventDefault : function() {
357 this.returnValue = false;
360 stopPropagation : function() {
361 this.cancelBubble = true;
367 * Instance of EventUtils for the current document.
370 * @member tinymce.dom
371 * @type tinymce.dom.EventUtils
373 Event = tinymce.dom.Event = new tinymce.dom.EventUtils();
375 // Dispatch DOM content loaded event for IE and Safari
378 tinymce.addUnload(function() {