]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/event-custom/event-custom-complex.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / event-custom / event-custom-complex.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 YUI.add('event-custom-complex', function(Y) {
9
10
11 /**
12  * Adds event facades, preventable default behavior, and bubbling.
13  * events.
14  * @module event-custom
15  * @submodule event-custom-complex
16  */
17
18 var FACADE,
19     FACADE_KEYS,
20     EMPTY = {},
21     CEProto = Y.CustomEvent.prototype,
22     ETProto = Y.EventTarget.prototype;
23
24 /**
25  * Wraps and protects a custom event for use when emitFacade is set to true.
26  * Requires the event-custom-complex module
27  * @class EventFacade
28  * @param e {Event} the custom event
29  * @param currentTarget {HTMLElement} the element the listener was attached to
30  */
31
32 Y.EventFacade = function(e, currentTarget) {
33
34     e = e || EMPTY;
35
36     this._event = e;
37
38     /**
39      * The arguments passed to fire
40      * @property details
41      * @type Array
42      */
43     this.details = e.details;
44
45     /**
46      * The event type, this can be overridden by the fire() payload
47      * @property type
48      * @type string
49      */
50     this.type = e.type;
51
52     /**
53      * The real event type
54      * @property type
55      * @type string
56      */
57     this._type = e.type;
58
59     //////////////////////////////////////////////////////
60
61     /**
62      * Node reference for the targeted eventtarget
63      * @propery target
64      * @type Node
65      */
66     this.target = e.target;
67
68     /**
69      * Node reference for the element that the listener was attached to.
70      * @propery currentTarget
71      * @type Node
72      */
73     this.currentTarget = currentTarget;
74
75     /**
76      * Node reference to the relatedTarget
77      * @propery relatedTarget
78      * @type Node
79      */
80     this.relatedTarget = e.relatedTarget;
81
82 };
83
84 Y.extend(Y.EventFacade, Object, {
85
86     /**
87      * Stops the propagation to the next bubble target
88      * @method stopPropagation
89      */
90     stopPropagation: function() {
91         this._event.stopPropagation();
92         this.stopped = 1;
93     },
94
95     /**
96      * Stops the propagation to the next bubble target and
97      * prevents any additional listeners from being exectued
98      * on the current target.
99      * @method stopImmediatePropagation
100      */
101     stopImmediatePropagation: function() {
102         this._event.stopImmediatePropagation();
103         this.stopped = 2;
104     },
105
106     /**
107      * Prevents the event's default behavior
108      * @method preventDefault
109      */
110     preventDefault: function() {
111         this._event.preventDefault();
112         this.prevented = 1;
113     },
114
115     /**
116      * Stops the event propagation and prevents the default
117      * event behavior.
118      * @method halt
119      * @param immediate {boolean} if true additional listeners
120      * on the current target will not be executed
121      */
122     halt: function(immediate) {
123         this._event.halt(immediate);
124         this.prevented = 1;
125         this.stopped = (immediate) ? 2 : 1;
126     }
127
128 });
129
130 CEProto.fireComplex = function(args) {
131
132     var es, ef, q, queue, ce, ret, events, subs, postponed,
133         self = this, host = self.host || self, next, oldbubble;
134
135     if (self.stack) {
136         // queue this event if the current item in the queue bubbles
137         if (self.queuable && self.type != self.stack.next.type) {
138             self.log('queue ' + self.type);
139             self.stack.queue.push([self, args]);
140             return true;
141         }
142     }
143
144     es = self.stack || {
145        // id of the first event in the stack
146        id: self.id,
147        next: self,
148        silent: self.silent,
149        stopped: 0,
150        prevented: 0,
151        bubbling: null,
152        type: self.type,
153        // defaultFnQueue: new Y.Queue(),
154        afterQueue: new Y.Queue(),
155        defaultTargetOnly: self.defaultTargetOnly,
156        queue: []
157     };
158
159     subs = self.getSubs();
160
161     self.stopped = (self.type !== es.type) ? 0 : es.stopped;
162     self.prevented = (self.type !== es.type) ? 0 : es.prevented;
163
164     self.target = self.target || host;
165
166     events = new Y.EventTarget({
167         fireOnce: true,
168         context: host
169     });
170
171     self.events = events;
172
173     if (self.preventedFn) {
174         events.on('prevented', self.preventedFn);
175     }
176
177     if (self.stoppedFn) {
178         events.on('stopped', self.stoppedFn);
179     }
180
181     self.currentTarget = host;
182
183     self.details = args.slice(); // original arguments in the details
184
185     // self.log("Firing " + self  + ", " + "args: " + args);
186     self.log("Firing " + self.type);
187
188     self._facade = null; // kill facade to eliminate stale properties
189
190     ef = self._getFacade(args);
191
192     if (Y.Lang.isObject(args[0])) {
193         args[0] = ef;
194     } else {
195         args.unshift(ef);
196     }
197
198     // if (subCount) {
199     if (subs[0]) {
200         // self._procSubs(Y.merge(self.subscribers), args, ef);
201         self._procSubs(subs[0], args, ef);
202     }
203
204     // bubble if this is hosted in an event target and propagation has not been stopped
205     if (self.bubbles && host.bubble && !self.stopped) {
206
207         oldbubble = es.bubbling;
208
209         // self.bubbling = true;
210         es.bubbling = self.type;
211
212         // if (host !== ef.target || es.type != self.type) {
213         if (es.type != self.type) {
214             es.stopped = 0;
215             es.prevented = 0;
216         }
217
218         ret = host.bubble(self, args, null, es);
219
220         self.stopped = Math.max(self.stopped, es.stopped);
221         self.prevented = Math.max(self.prevented, es.prevented);
222
223         // self.bubbling = false;
224         es.bubbling = oldbubble;
225
226     }
227
228     if (self.defaultFn &&
229         !self.prevented &&
230         ((!self.defaultTargetOnly && !es.defaultTargetOnly) || host === ef.target)) {
231
232         self.defaultFn.apply(host, args);
233     }
234
235     // broadcast listeners are fired as discreet events on the
236     // YUI instance and potentially the YUI global.
237     self._broadcast(args);
238
239     // Queue the after
240     if (subs[1] && !self.prevented && self.stopped < 2) {
241         if (es.id === self.id || self.type != host._yuievt.bubbling) {
242             self._procSubs(subs[1], args, ef);
243             while ((next = es.afterQueue.last())) {
244                 next();
245             }
246         } else {
247             postponed = subs[1];
248             if (es.execDefaultCnt) {
249                 postponed = Y.merge(postponed);
250                 Y.each(postponed, function(s) {
251                     s.postponed = true;
252                 });
253             }
254
255             es.afterQueue.add(function() {
256                 self._procSubs(postponed, args, ef);
257             });
258         }
259     }
260
261     self.target = null;
262
263     if (es.id === self.id) {
264         queue = es.queue;
265
266         while (queue.length) {
267             q = queue.pop();
268             ce = q[0];
269             // set up stack to allow the next item to be processed
270             es.next = ce;
271             ce.fire.apply(ce, q[1]);
272         }
273
274         self.stack = null;
275     }
276
277     ret = !(self.stopped);
278
279     if (self.type != host._yuievt.bubbling) {
280         es.stopped = 0;
281         es.prevented = 0;
282         self.stopped = 0;
283         self.prevented = 0;
284     }
285
286     return ret;
287 };
288
289 CEProto._getFacade = function() {
290
291     var ef = this._facade, o, o2,
292     args = this.details;
293
294     if (!ef) {
295         ef = new Y.EventFacade(this, this.currentTarget);
296     }
297
298     // if the first argument is an object literal, apply the
299     // properties to the event facade
300     o = args && args[0];
301
302     if (Y.Lang.isObject(o, true)) {
303
304         o2 = {};
305
306         // protect the event facade properties
307         Y.mix(o2, ef, true, FACADE_KEYS);
308
309         // mix the data
310         Y.mix(ef, o, true);
311
312         // restore ef
313         Y.mix(ef, o2, true, FACADE_KEYS);
314
315         // Allow the event type to be faked
316         // http://yuilibrary.com/projects/yui3/ticket/2528376
317         ef.type = o.type || ef.type;
318     }
319
320     // update the details field with the arguments
321     // ef.type = this.type;
322     ef.details = this.details;
323
324     // use the original target when the event bubbled to this target
325     ef.target = this.originalTarget || this.target;
326
327     ef.currentTarget = this.currentTarget;
328     ef.stopped = 0;
329     ef.prevented = 0;
330
331     this._facade = ef;
332
333     return this._facade;
334 };
335
336 /**
337  * Stop propagation to bubble targets
338  * @for CustomEvent
339  * @method stopPropagation
340  */
341 CEProto.stopPropagation = function() {
342     this.stopped = 1;
343     if (this.stack) {
344         this.stack.stopped = 1;
345     }
346     this.events.fire('stopped', this);
347 };
348
349 /**
350  * Stops propagation to bubble targets, and prevents any remaining
351  * subscribers on the current target from executing.
352  * @method stopImmediatePropagation
353  */
354 CEProto.stopImmediatePropagation = function() {
355     this.stopped = 2;
356     if (this.stack) {
357         this.stack.stopped = 2;
358     }
359     this.events.fire('stopped', this);
360 };
361
362 /**
363  * Prevents the execution of this event's defaultFn
364  * @method preventDefault
365  */
366 CEProto.preventDefault = function() {
367     if (this.preventable) {
368         this.prevented = 1;
369         if (this.stack) {
370             this.stack.prevented = 1;
371         }
372         this.events.fire('prevented', this);
373     }
374 };
375
376 /**
377  * Stops the event propagation and prevents the default
378  * event behavior.
379  * @method halt
380  * @param immediate {boolean} if true additional listeners
381  * on the current target will not be executed
382  */
383 CEProto.halt = function(immediate) {
384     if (immediate) {
385         this.stopImmediatePropagation();
386     } else {
387         this.stopPropagation();
388     }
389     this.preventDefault();
390 };
391
392 /**
393  * Registers another EventTarget as a bubble target.  Bubble order
394  * is determined by the order registered.  Multiple targets can
395  * be specified.
396  *
397  * Events can only bubble if emitFacade is true.
398  *
399  * Included in the event-custom-complex submodule.
400  *
401  * @method addTarget
402  * @param o {EventTarget} the target to add
403  * @for EventTarget
404  */
405 ETProto.addTarget = function(o) {
406     this._yuievt.targets[Y.stamp(o)] = o;
407     this._yuievt.hasTargets = true;
408 };
409
410 /**
411  * Returns an array of bubble targets for this object.
412  * @method getTargets
413  * @return EventTarget[]
414  */
415 ETProto.getTargets = function() {
416     return Y.Object.values(this._yuievt.targets);
417 };
418
419 /**
420  * Removes a bubble target
421  * @method removeTarget
422  * @param o {EventTarget} the target to remove
423  * @for EventTarget
424  */
425 ETProto.removeTarget = function(o) {
426     delete this._yuievt.targets[Y.stamp(o)];
427 };
428
429 /**
430  * Propagate an event.  Requires the event-custom-complex module.
431  * @method bubble
432  * @param evt {CustomEvent} the custom event to propagate
433  * @return {boolean} the aggregated return value from Event.Custom.fire
434  * @for EventTarget
435  */
436 ETProto.bubble = function(evt, args, target, es) {
437
438     var targs = this._yuievt.targets, ret = true,
439         t, type = evt && evt.type, ce, i, bc, ce2,
440         originalTarget = target || (evt && evt.target) || this,
441         oldbubble;
442
443     if (!evt || ((!evt.stopped) && targs)) {
444
445         for (i in targs) {
446             if (targs.hasOwnProperty(i)) {
447                 t = targs[i];
448                 ce = t.getEvent(type, true);
449                 ce2 = t.getSibling(type, ce);
450
451                 if (ce2 && !ce) {
452                     ce = t.publish(type);
453                 }
454
455                 oldbubble = t._yuievt.bubbling;
456                 t._yuievt.bubbling = type;
457
458                 // if this event was not published on the bubble target,
459                 // continue propagating the event.
460                 if (!ce) {
461                     if (t._yuievt.hasTargets) {
462                         t.bubble(evt, args, originalTarget, es);
463                     }
464                 } else {
465
466                     ce.sibling = ce2;
467
468                     // set the original target to that the target payload on the
469                     // facade is correct.
470                     ce.target = originalTarget;
471                     ce.originalTarget = originalTarget;
472                     ce.currentTarget = t;
473                     bc = ce.broadcast;
474                     ce.broadcast = false;
475
476                     // default publish may not have emitFacade true -- that
477                     // shouldn't be what the implementer meant to do
478                     ce.emitFacade = true;
479
480                     ce.stack = es;
481
482                     ret = ret && ce.fire.apply(ce, args || evt.details || []);
483                     ce.broadcast = bc;
484                     ce.originalTarget = null;
485
486
487                     // stopPropagation() was called
488                     if (ce.stopped) {
489                         break;
490                     }
491                 }
492
493                 t._yuievt.bubbling = oldbubble;
494             }
495         }
496     }
497
498     return ret;
499 };
500
501 FACADE = new Y.EventFacade();
502 FACADE_KEYS = Y.Object.keys(FACADE);
503
504
505
506 }, '3.3.0' ,{requires:['event-custom-base']});