]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/tiny_mce/classes/dom/EventUtils.js
Release 6.5.0
[Github/sugarcrm.git] / include / javascript / tiny_mce / classes / dom / EventUtils.js
1 /**
2  * EventUtils.js
3  *
4  * Copyright 2009, Moxiecode Systems AB
5  * Released under LGPL License.
6  *
7  * License: http://tinymce.moxiecode.com/license
8  * Contributing: http://tinymce.moxiecode.com/contributing
9  */
10
11 (function(tinymce) {
12         // Shorten names
13         var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event;
14
15         /**
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.
18          *
19          * @class tinymce.dom.EventUtils
20          */
21         tinymce.create('tinymce.dom.EventUtils', {
22                 /**
23                  * Constructs a new EventUtils instance.
24                  *
25                  * @constructor
26                  * @method EventUtils
27                  */
28                 EventUtils : function() {
29                         this.inits = [];
30                         this.events = [];
31                 },
32
33                 /**
34                  * Adds an event handler to the specified object.
35                  *
36                  * @method add
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.
42                  * @example
43                  * // Adds a click handler to the current document
44                  * tinymce.dom.Event.add(document, 'click', function(e) {
45                  *    console.debug(e.target);
46                  * });
47                  */
48                 add : function(o, n, f, s) {
49                         var cb, t = this, el = t.events, r;
50
51                         if (n instanceof Array) {
52                                 r = [];
53
54                                 each(n, function(n) {
55                                         r.push(t.add(o, n, f, s));
56                                 });
57
58                                 return r;
59                         }
60
61                         // Handle array
62                         if (o && o.hasOwnProperty && o instanceof Array) {
63                                 r = [];
64
65                                 each(o, function(o) {
66                                         o = DOM.get(o);
67                                         r.push(t.add(o, n, f, s));
68                                 });
69
70                                 return r;
71                         }
72
73                         o = DOM.get(o);
74
75                         if (!o)
76                                 return;
77
78                         // Setup event callback
79                         cb = function(e) {
80                                 // Is all events disabled
81                                 if (t.disabled)
82                                         return;
83
84                                 e = e || window.event;
85
86                                 // Patch in target, preventDefault and stopPropagation in IE it's W3C valid
87                                 if (e && isIE) {
88                                         if (!e.target)
89                                                 e.target = e.srcElement;
90
91                                         // Patch in preventDefault, stopPropagation methods for W3C compatibility
92                                         tinymce.extend(e, t._stoppers);
93                                 }
94
95                                 if (!s)
96                                         return f(e);
97
98                                 return f.call(s, e);
99                         };
100
101                         if (n == 'unload') {
102                                 tinymce.unloads.unshift({func : cb});
103                                 return cb;
104                         }
105
106                         if (n == 'init') {
107                                 if (t.domLoaded)
108                                         cb();
109                                 else
110                                         t.inits.push(cb);
111
112                                 return cb;
113                         }
114
115                         // Store away listener reference
116                         el.push({
117                                 obj : o,
118                                 name : n,
119                                 func : f,
120                                 cfunc : cb,
121                                 scope : s
122                         });
123
124                         t._add(o, n, cb);
125
126                         return f;
127                 },
128
129                 /**
130                  * Removes the specified event handler by name and function from a element or collection of elements.
131                  *
132                  * @method remove
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.
137                  * @example
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);
141                  * });
142                  * 
143                  * // Removes the click handler from the document
144                  * tinymce.dom.Event.remove(document, 'click', func);
145                  */
146                 remove : function(o, n, f) {
147                         var t = this, a = t.events, s = false, r;
148
149                         // Handle array
150                         if (o && o.hasOwnProperty && o instanceof Array) {
151                                 r = [];
152
153                                 each(o, function(o) {
154                                         o = DOM.get(o);
155                                         r.push(t.remove(o, n, f));
156                                 });
157
158                                 return r;
159                         }
160
161                         o = DOM.get(o);
162
163                         each(a, function(e, i) {
164                                 if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) {
165                                         a.splice(i, 1);
166                                         t._remove(o, n, e.cfunc);
167                                         s = true;
168                                         return false;
169                                 }
170                         });
171
172                         return s;
173                 },
174
175                 /**
176                  * Clears all events of a specific object.
177                  *
178                  * @method clear
179                  * @param {Object} o DOM element or object to remove all events from.
180                  * @example
181                  * // Cancels all mousedown events in the active editor
182                  * tinyMCE.activeEditor.onMouseDown.add(function(ed, e) {
183                  *    return tinymce.dom.Event.cancel(e);
184                  * });
185                  */
186                 clear : function(o) {
187                         var t = this, a = t.events, i, e;
188
189                         if (o) {
190                                 o = DOM.get(o);
191
192                                 for (i = a.length - 1; i >= 0; i--) {
193                                         e = a[i];
194
195                                         if (e.obj === o) {
196                                                 t._remove(e.obj, e.name, e.cfunc);
197                                                 e.obj = e.cfunc = null;
198                                                 a.splice(i, 1);
199                                         }
200                                 }
201                         }
202                 },
203
204                 /**
205                  * Cancels an event for both bubbeling and the default browser behavior.
206                  *
207                  * @method cancel
208                  * @param {Event} e Event object to cancel.
209                  * @return {Boolean} Always false.
210                  */
211                 cancel : function(e) {
212                         if (!e)
213                                 return false;
214
215                         this.stop(e);
216
217                         return this.prevent(e);
218                 },
219
220                 /**
221                  * Stops propogation/bubbeling of an event.
222                  *
223                  * @method stop
224                  * @param {Event} e Event to cancel bubbeling on.
225                  * @return {Boolean} Always false.
226                  */
227                 stop : function(e) {
228                         if (e.stopPropagation)
229                                 e.stopPropagation();
230                         else
231                                 e.cancelBubble = true;
232
233                         return false;
234                 },
235
236                 /**
237                  * Prevent default browser behvaior of an event.
238                  *
239                  * @method prevent
240                  * @param {Event} e Event to prevent default browser behvaior of an event.
241                  * @return {Boolean} Always false.
242                  */
243                 prevent : function(e) {
244                         if (e.preventDefault)
245                                 e.preventDefault();
246                         else
247                                 e.returnValue = false;
248
249                         return false;
250                 },
251
252                 /**
253                  * Destroys the instance.
254                  *
255                  * @method destroy
256                  */
257                 destroy : function() {
258                         var t = this;
259
260                         each(t.events, function(e, i) {
261                                 t._remove(e.obj, e.name, e.cfunc);
262                                 e.obj = e.cfunc = null;
263                         });
264
265                         t.events = [];
266                         t = null;
267                 },
268
269                 _add : function(o, n, f) {
270                         if (o.attachEvent)
271                                 o.attachEvent('on' + n, f);
272                         else if (o.addEventListener)
273                                 o.addEventListener(n, f, false);
274                         else
275                                 o['on' + n] = f;
276                 },
277
278                 _remove : function(o, n, f) {
279                         if (o) {
280                                 try {
281                                         if (o.detachEvent)
282                                                 o.detachEvent('on' + n, f);
283                                         else if (o.removeEventListener)
284                                                 o.removeEventListener(n, f, false);
285                                         else
286                                                 o['on' + n] = null;
287                                 } catch (ex) {
288                                         // Might fail with permission denined on IE so we just ignore that
289                                 }
290                         }
291                 },
292
293                 _pageInit : function(win) {
294                         var t = this;
295
296                         // Keep it from running more than once
297                         if (t.domLoaded)
298                                 return;
299
300                         t.domLoaded = true;
301
302                         each(t.inits, function(c) {
303                                 c();
304                         });
305
306                         t.inits = [];
307                 },
308
309                 _wait : function(win) {
310                         var t = this, doc = win.document;
311
312                         // No need since the document is already loaded
313                         if (win.tinyMCE_GZ && tinyMCE_GZ.loaded) {
314                                 t.domLoaded = 1;
315                                 return;
316                         }
317
318                         // Use IE method
319                         if (doc.attachEvent) {
320                                 doc.attachEvent("onreadystatechange", function() {
321                                         if (doc.readyState === "complete") {
322                                                 doc.detachEvent("onreadystatechange", arguments.callee);
323                                                 t._pageInit(win);
324                                         }
325                                 });
326
327                                 if (doc.documentElement.doScroll && win == win.top) {
328                                         (function() {
329                                                 if (t.domLoaded)
330                                                         return;
331
332                                                 try {
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");
336                                                 } catch (ex) {
337                                                         setTimeout(arguments.callee, 0);
338                                                         return;
339                                                 }
340
341                                                 t._pageInit(win);
342                                         })();
343                                 }
344                         } else if (doc.addEventListener) {
345                                 t._add(win, 'DOMContentLoaded', function() {
346                                         t._pageInit(win);
347                                 });
348                         }
349
350                         t._add(win, 'load', function() {
351                                 t._pageInit(win);
352                         });
353                 },
354
355                 _stoppers : {
356                         preventDefault : function() {
357                                 this.returnValue = false;
358                         },
359
360                         stopPropagation : function() {
361                                 this.cancelBubble = true;
362                         }
363                 }
364         });
365
366         /**
367          * Instance of EventUtils for the current document.
368          *
369          * @property Event
370          * @member tinymce.dom
371          * @type tinymce.dom.EventUtils
372          */
373         Event = tinymce.dom.Event = new tinymce.dom.EventUtils();
374
375         // Dispatch DOM content loaded event for IE and Safari
376         Event._wait(window);
377
378         tinymce.addUnload(function() {
379                 Event.destroy();
380         });
381 })(tinymce);