]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/debian/missing-sources/framework/Web/Javascripts/source/tinymce-405/classes/dom/EventUtils.js
baculum: Add missing-sources directory in debian metadata structure
[bacula/bacula] / gui / baculum / debian / missing-sources / framework / Web / Javascripts / source / tinymce-405 / classes / dom / EventUtils.js
1 /**
2  * EventUtils.js
3  *
4  * Copyright, Moxiecode Systems AB
5  * Released under LGPL License.
6  *
7  * License: http://www.tinymce.com/license
8  * Contributing: http://www.tinymce.com/contributing
9  */
10
11 /*jshint loopfunc:true*/
12
13 define("tinymce/dom/EventUtils", [], function() {
14         "use strict";
15
16         var eventExpandoPrefix = "mce-data-";
17         var mouseEventRe = /^(?:mouse|contextmenu)|click/;
18         var deprecated = {keyLocation: 1, layerX: 1, layerY: 1};
19
20         /**
21          * Binds a native event to a callback on the speified target.
22          */
23         function addEvent(target, name, callback, capture) {
24                 if (target.addEventListener) {
25                         target.addEventListener(name, callback, capture || false);
26                 } else if (target.attachEvent) {
27                         target.attachEvent('on' + name, callback);
28                 }
29         }
30
31         /**
32          * Unbinds a native event callback on the specified target.
33          */
34         function removeEvent(target, name, callback, capture) {
35                 if (target.removeEventListener) {
36                         target.removeEventListener(name, callback, capture || false);
37                 } else if (target.detachEvent) {
38                         target.detachEvent('on' + name, callback);
39                 }
40         }
41
42         /**
43          * Normalizes a native event object or just adds the event specific methods on a custom event.
44          */
45         function fix(originalEvent, data) {
46                 var name, event = data || {}, undef;
47
48                 // Dummy function that gets replaced on the delegation state functions
49                 function returnFalse() {
50                         return false;
51                 }
52
53                 // Dummy function that gets replaced on the delegation state functions
54                 function returnTrue() {
55                         return true;
56                 }
57
58                 // Copy all properties from the original event
59                 for (name in originalEvent) {
60                         // layerX/layerY is deprecated in Chrome and produces a warning
61                         if (!deprecated[name]) {
62                                 event[name] = originalEvent[name];
63                         }
64                 }
65
66                 // Normalize target IE uses srcElement
67                 if (!event.target) {
68                         event.target = event.srcElement || document;
69                 }
70
71                 // Calculate pageX/Y if missing and clientX/Y available
72                 if (originalEvent && mouseEventRe.test(originalEvent.type) && originalEvent.pageX === undef && originalEvent.clientX !== undef) {
73                         var eventDoc = event.target.ownerDocument || document;
74                         var doc = eventDoc.documentElement;
75                         var body = eventDoc.body;
76
77                         event.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
78                                 ( doc && doc.clientLeft || body && body.clientLeft || 0);
79
80                         event.pageY = originalEvent.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0 ) -
81                                 ( doc && doc.clientTop  || body && body.clientTop  || 0);
82                 }
83
84                 // Add preventDefault method
85                 event.preventDefault = function() {
86                         event.isDefaultPrevented = returnTrue;
87
88                         // Execute preventDefault on the original event object
89                         if (originalEvent) {
90                                 if (originalEvent.preventDefault) {
91                                         originalEvent.preventDefault();
92                                 } else {
93                                         originalEvent.returnValue = false; // IE
94                                 }
95                         }
96                 };
97
98                 // Add stopPropagation
99                 event.stopPropagation = function() {
100                         event.isPropagationStopped = returnTrue;
101
102                         // Execute stopPropagation on the original event object
103                         if (originalEvent) {
104                                 if (originalEvent.stopPropagation) {
105                                         originalEvent.stopPropagation();
106                                 } else {
107                                         originalEvent.cancelBubble = true; // IE
108                                 }
109                          }
110                 };
111
112                 // Add stopImmediatePropagation
113                 event.stopImmediatePropagation = function() {
114                         event.isImmediatePropagationStopped = returnTrue;
115                         event.stopPropagation();
116                 };
117
118                 // Add event delegation states
119                 if (!event.isDefaultPrevented) {
120                         event.isDefaultPrevented = returnFalse;
121                         event.isPropagationStopped = returnFalse;
122                         event.isImmediatePropagationStopped = returnFalse;
123                 }
124
125                 return event;
126         }
127
128         /**
129          * Bind a DOMContentLoaded event across browsers and executes the callback once the page DOM is initialized.
130          * It will also set/check the domLoaded state of the event_utils instance so ready isn't called multiple times.
131          */
132         function bindOnReady(win, callback, eventUtils) {
133                 var doc = win.document, event = {type: 'ready'};
134
135                 if (eventUtils.domLoaded) {
136                         callback(event);
137                         return;
138                 }
139
140                 // Gets called when the DOM is ready
141                 function readyHandler() {
142                         if (!eventUtils.domLoaded) {
143                                 eventUtils.domLoaded = true;
144                                 callback(event);
145                         }
146                 }
147
148                 function waitForDomLoaded() {
149                         if (doc.readyState === "complete") {
150                                 removeEvent(doc, "readystatechange", waitForDomLoaded);
151                                 readyHandler();
152                         }
153                 }
154
155                 function tryScroll() {
156                         try {
157                                 // If IE is used, use the trick by Diego Perini licensed under MIT by request to the author.
158                                 // http://javascript.nwbox.com/IEContentLoaded/
159                                 doc.documentElement.doScroll("left");
160                         } catch (ex) {
161                                 setTimeout(tryScroll, 0);
162                                 return;
163                         }
164
165                         readyHandler();
166                 }
167
168                 // Use W3C method
169                 if (doc.addEventListener) {
170                         addEvent(win, 'DOMContentLoaded', readyHandler);
171                 } else {
172                         // Use IE method
173                         addEvent(doc, "readystatechange", waitForDomLoaded);
174
175                         // Wait until we can scroll, when we can the DOM is initialized
176                         if (doc.documentElement.doScroll && win === win.top) {
177                                 tryScroll();
178                         }
179                 }
180
181                 // Fallback if any of the above methods should fail for some odd reason
182                 addEvent(win, 'load', readyHandler);
183         }
184
185         /**
186          * This class enables you to bind/unbind native events to elements and normalize it's behavior across browsers.
187          */
188         function EventUtils() {
189                 var self = this, events = {}, count, expando, hasFocusIn, hasMouseEnterLeave, mouseEnterLeave;
190
191                 expando = eventExpandoPrefix + (+new Date()).toString(32);
192                 hasMouseEnterLeave = "onmouseenter" in document.documentElement;
193                 hasFocusIn = "onfocusin" in document.documentElement;
194                 mouseEnterLeave = {mouseenter: 'mouseover', mouseleave: 'mouseout'};
195                 count = 1;
196
197                 // State if the DOMContentLoaded was executed or not
198                 self.domLoaded = false;
199                 self.events = events;
200
201                 /**
202                  * Executes all event handler callbacks for a specific event.
203                  *
204                  * @private
205                  * @param {Event} evt Event object.
206                  * @param {String} id Expando id value to look for.
207                  */
208                 function executeHandlers(evt, id) {
209                         var callbackList, i, l, callback;
210
211                         callbackList = events[id][evt.type];
212                         if (callbackList) {
213                                 for (i = 0, l = callbackList.length; i < l; i++) {
214                                         callback = callbackList[i];
215
216                                         // Check if callback exists might be removed if a unbind is called inside the callback
217                                         if (callback && callback.func.call(callback.scope, evt) === false) {
218                                                 evt.preventDefault();
219                                         }
220
221                                         // Should we stop propagation to immediate listeners
222                                         if (evt.isImmediatePropagationStopped()) {
223                                                 return;
224                                         }
225                                 }
226                         }
227                 }
228
229                 /**
230                  * Binds a callback to an event on the specified target.
231                  *
232                  * @method bind
233                  * @param {Object} target Target node/window or custom object.
234                  * @param {String} names Name of the event to bind.
235                  * @param {function} callback Callback function to execute when the event occurs.
236                  * @param {Object} scope Scope to call the callback function on, defaults to target.
237                  * @return {function} Callback function that got bound.
238                  */
239                 self.bind = function(target, names, callback, scope) {
240                         var id, callbackList, i, name, fakeName, nativeHandler, capture, win = window;
241
242                         // Native event handler function patches the event and executes the callbacks for the expando
243                         function defaultNativeHandler(evt) {
244                                 executeHandlers(fix(evt || win.event), id);
245                         }
246
247                         // Don't bind to text nodes or comments
248                         if (!target || target.nodeType === 3 || target.nodeType === 8) {
249                                 return;
250                         }
251
252                         // Create or get events id for the target
253                         if (!target[expando]) {
254                                 id = count++;
255                                 target[expando] = id;
256                                 events[id] = {};
257                         } else {
258                                 id = target[expando];
259                         }
260
261                         // Setup the specified scope or use the target as a default
262                         scope = scope || target;
263
264                         // Split names and bind each event, enables you to bind multiple events with one call
265                         names = names.split(' ');
266                         i = names.length;
267                         while (i--) {
268                                 name = names[i];
269                                 nativeHandler = defaultNativeHandler;
270                                 fakeName = capture = false;
271
272                                 // Use ready instead of DOMContentLoaded
273                                 if (name === "DOMContentLoaded") {
274                                         name = "ready";
275                                 }
276
277                                 // DOM is already ready
278                                 if (self.domLoaded && name === "ready" && target.readyState == 'complete') {
279                                         callback.call(scope, fix({type: name}));
280                                         continue;
281                                 }
282
283                                 // Handle mouseenter/mouseleaver
284                                 if (!hasMouseEnterLeave) {
285                                         fakeName = mouseEnterLeave[name];
286
287                                         if (fakeName) {
288                                                 nativeHandler = function(evt) {
289                                                         var current, related;
290
291                                                         current = evt.currentTarget;
292                                                         related = evt.relatedTarget;
293
294                                                         // Check if related is inside the current target if it's not then the event should
295                                                         // be ignored since it's a mouseover/mouseout inside the element
296                                                         if (related && current.contains) {
297                                                                 // Use contains for performance
298                                                                 related = current.contains(related);
299                                                         } else {
300                                                                 while (related && related !== current) {
301                                                                         related = related.parentNode;
302                                                                 }
303                                                         }
304
305                                                         // Fire fake event
306                                                         if (!related) {
307                                                                 evt = fix(evt || win.event);
308                                                                 evt.type = evt.type === 'mouseout' ? 'mouseleave' : 'mouseenter';
309                                                                 evt.target = current;
310                                                                 executeHandlers(evt, id);
311                                                         }
312                                                 };
313                                         }
314                                 }
315
316                                 // Fake bubbeling of focusin/focusout
317                                 if (!hasFocusIn && (name === "focusin" || name === "focusout")) {
318                                         capture = true;
319                                         fakeName = name === "focusin" ? "focus" : "blur";
320                                         nativeHandler = function(evt) {
321                                                 evt = fix(evt || win.event);
322                                                 evt.type = evt.type === 'focus' ? 'focusin' : 'focusout';
323                                                 executeHandlers(evt, id);
324                                         };
325                                 }
326
327                                 // Setup callback list and bind native event
328                                 callbackList = events[id][name];
329                                 if (!callbackList) {
330                                         events[id][name] = callbackList = [{func: callback, scope: scope}];
331                                         callbackList.fakeName = fakeName;
332                                         callbackList.capture = capture;
333
334                                         // Add the nativeHandler to the callback list so that we can later unbind it
335                                         callbackList.nativeHandler = nativeHandler;
336
337                                         // Check if the target has native events support
338
339                                         if (name === "ready") {
340                                                 bindOnReady(target, nativeHandler, self);
341                                         } else {
342                                                 addEvent(target, fakeName || name, nativeHandler, capture);
343                                         }
344                                 } else {
345                                         if (name === "ready" && self.domLoaded) {
346                                                 callback({type: name});
347                                         } else {
348                                                 // If it already has an native handler then just push the callback
349                                                 callbackList.push({func: callback, scope: scope});
350                                         }
351                                 }
352                         }
353
354                         target = callbackList = 0; // Clean memory for IE
355
356                         return callback;
357                 };
358
359                 /**
360                  * Unbinds the specified event by name, name and callback or all events on the target.
361                  *
362                  * @method unbind
363                  * @param {Object} target Target node/window or custom object.
364                  * @param {String} names Optional event name to unbind.
365                  * @param {function} callback Optional callback function to unbind.
366                  * @return {EventUtils} Event utils instance.
367                  */
368                 self.unbind = function(target, names, callback) {
369                         var id, callbackList, i, ci, name, eventMap;
370
371                         // Don't bind to text nodes or comments
372                         if (!target || target.nodeType === 3 || target.nodeType === 8) {
373                                 return self;
374                         }
375
376                         // Unbind event or events if the target has the expando
377                         id = target[expando];
378                         if (id) {
379                                 eventMap = events[id];
380
381                                 // Specific callback
382                                 if (names) {
383                                         names = names.split(' ');
384                                         i = names.length;
385                                         while (i--) {
386                                                 name = names[i];
387                                                 callbackList = eventMap[name];
388
389                                                 // Unbind the event if it exists in the map
390                                                 if (callbackList) {
391                                                         // Remove specified callback
392                                                         if (callback) {
393                                                                 ci = callbackList.length;
394                                                                 while (ci--) {
395                                                                         if (callbackList[ci].func === callback) {
396                                                                                 callbackList.splice(ci, 1);
397                                                                         }
398                                                                 }
399                                                         }
400
401                                                         // Remove all callbacks if there isn't a specified callback or there is no callbacks left
402                                                         if (!callback || callbackList.length === 0) {
403                                                                 delete eventMap[name];
404                                                                 removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
405                                                         }
406                                                 }
407                                         }
408                                 } else {
409                                         // All events for a specific element
410                                         for (name in eventMap) {
411                                                 callbackList = eventMap[name];
412                                                 removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
413                                         }
414
415                                         eventMap = {};
416                                 }
417
418                                 // Check if object is empty, if it isn't then we won't remove the expando map
419                                 for (name in eventMap) {
420                                         return self;
421                                 }
422
423                                 // Delete event object
424                                 delete events[id];
425
426                                 // Remove expando from target
427                                 try {
428                                         // IE will fail here since it can't delete properties from window
429                                         delete target[expando];
430                                 } catch (ex) {
431                                         // IE will set it to null
432                                         target[expando] = null;
433                                 }
434                         }
435
436                         return self;
437                 };
438
439                 /**
440                  * Fires the specified event on the specified target.
441                  *
442                  * @method fire
443                  * @param {Object} target Target node/window or custom object.
444                  * @param {String} name Event name to fire.
445                  * @param {Object} args Optional arguments to send to the observers.
446                  * @return {EventUtils} Event utils instance.
447                  */
448                 self.fire = function(target, name, args) {
449                         var id;
450
451                         // Don't bind to text nodes or comments
452                         if (!target || target.nodeType === 3 || target.nodeType === 8) {
453                                 return self;
454                         }
455
456                         // Build event object by patching the args
457                         args = fix(null, args);
458                         args.type = name;
459                         args.target = target;
460
461                         do {
462                                 // Found an expando that means there is listeners to execute
463                                 id = target[expando];
464                                 if (id) {
465                                         executeHandlers(args, id);
466                                 }
467
468                                 // Walk up the DOM
469                                 target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
470                         } while (target && !args.isPropagationStopped());
471
472                         return self;
473                 };
474
475                 /**
476                  * Removes all bound event listeners for the specified target. This will also remove any bound
477                  * listeners to child nodes within that target.
478                  *
479                  * @method clean
480                  * @param {Object} target Target node/window object.
481                  * @return {EventUtils} Event utils instance.
482                  */
483                 self.clean = function(target) {
484                         var i, children, unbind = self.unbind;
485
486                         // Don't bind to text nodes or comments
487                         if (!target || target.nodeType === 3 || target.nodeType === 8) {
488                                 return self;
489                         }
490
491                         // Unbind any element on the specificed target
492                         if (target[expando]) {
493                                 unbind(target);
494                         }
495
496                         // Target doesn't have getElementsByTagName it's probably a window object then use it's document to find the children
497                         if (!target.getElementsByTagName) {
498                                 target = target.document;
499                         }
500
501                         // Remove events from each child element
502                         if (target && target.getElementsByTagName) {
503                                 unbind(target);
504
505                                 children = target.getElementsByTagName('*');
506                                 i = children.length;
507                                 while (i--) {
508                                         target = children[i];
509
510                                         if (target[expando]) {
511                                                 unbind(target);
512                                         }
513                                 }
514                         }
515
516                         return self;
517                 };
518
519                 /**
520                  * Destroys the event object. Call this on IE to remove memory leaks.
521                  */
522                 self.destroy = function() {
523                         events = {};
524                 };
525
526                 // Legacy function for canceling events
527                 self.cancel = function(e) {
528                         if (e) {
529                                 e.preventDefault();
530                                 e.stopImmediatePropagation();
531                         }
532
533                         return false;
534                 };
535         }
536
537         EventUtils.Event = new EventUtils();
538         EventUtils.Event.bind(window, 'ready', function() {});
539
540         return EventUtils;
541 });