3
Copyright 2011 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('event-custom-complex', function(Y) {
11
* Adds event facades, preventable default behavior, and bubbling.
13
* @module event-custom
14
* @submodule event-custom-complex
20
CEProto = Y.CustomEvent.prototype,
21
ETProto = Y.EventTarget.prototype;
24
* Wraps and protects a custom event for use when emitFacade is set to true.
25
* Requires the event-custom-complex module
27
* @param e {Event} the custom event
28
* @param currentTarget {HTMLElement} the element the listener was attached to
31
Y.EventFacade = function(e, currentTarget) {
38
* The arguments passed to fire
42
this.details = e.details;
45
* The event type, this can be overridden by the fire() payload
59
//////////////////////////////////////////////////////
62
* Node reference for the targeted eventtarget
66
this.target = e.target;
69
* Node reference for the element that the listener was attached to.
70
* @property currentTarget
73
this.currentTarget = currentTarget;
76
* Node reference to the relatedTarget
77
* @property relatedTarget
80
this.relatedTarget = e.relatedTarget;
84
Y.extend(Y.EventFacade, Object, {
87
* Stops the propagation to the next bubble target
88
* @method stopPropagation
90
stopPropagation: function() {
91
this._event.stopPropagation();
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
101
stopImmediatePropagation: function() {
102
this._event.stopImmediatePropagation();
107
* Prevents the event's default behavior
108
* @method preventDefault
110
preventDefault: function() {
111
this._event.preventDefault();
116
* Stops the event propagation and prevents the default
119
* @param immediate {boolean} if true additional listeners
120
* on the current target will not be executed
122
halt: function(immediate) {
123
this._event.halt(immediate);
125
this.stopped = (immediate) ? 2 : 1;
130
CEProto.fireComplex = function(args) {
132
var es, ef, q, queue, ce, ret, events, subs, postponed,
133
self = this, host = self.host || self, next, oldbubble;
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]);
145
// id of the first event in the stack
153
// defaultFnQueue: new Y.Queue(),
154
afterQueue: new Y.Queue(),
155
defaultTargetOnly: self.defaultTargetOnly,
159
subs = self.getSubs();
161
self.stopped = (self.type !== es.type) ? 0 : es.stopped;
162
self.prevented = (self.type !== es.type) ? 0 : es.prevented;
164
self.target = self.target || host;
166
events = new Y.EventTarget({
171
self.events = events;
173
if (self.stoppedFn) {
174
events.on('stopped', self.stoppedFn);
177
self.currentTarget = host;
179
self.details = args.slice(); // original arguments in the details
181
// self.log("Firing " + self + ", " + "args: " + args);
182
self.log("Firing " + self.type);
184
self._facade = null; // kill facade to eliminate stale properties
186
ef = self._getFacade(args);
188
if (Y.Lang.isObject(args[0])) {
196
// self._procSubs(Y.merge(self.subscribers), args, ef);
197
self._procSubs(subs[0], args, ef);
200
// bubble if this is hosted in an event target and propagation has not been stopped
201
if (self.bubbles && host.bubble && !self.stopped) {
203
oldbubble = es.bubbling;
205
// self.bubbling = true;
206
es.bubbling = self.type;
208
// if (host !== ef.target || es.type != self.type) {
209
if (es.type != self.type) {
214
ret = host.bubble(self, args, null, es);
216
self.stopped = Math.max(self.stopped, es.stopped);
217
self.prevented = Math.max(self.prevented, es.prevented);
219
// self.bubbling = false;
220
es.bubbling = oldbubble;
224
if (self.prevented) {
225
if (self.preventedFn) {
226
self.preventedFn.apply(host, args);
228
} else if (self.defaultFn &&
229
((!self.defaultTargetOnly && !es.defaultTargetOnly) ||
230
host === ef.target)) {
231
self.defaultFn.apply(host, args);
234
// broadcast listeners are fired as discreet events on the
235
// YUI instance and potentially the YUI global.
236
self._broadcast(args);
239
if (subs[1] && !self.prevented && self.stopped < 2) {
240
if (es.id === self.id || self.type != host._yuievt.bubbling) {
241
self._procSubs(subs[1], args, ef);
242
while ((next = es.afterQueue.last())) {
247
if (es.execDefaultCnt) {
248
postponed = Y.merge(postponed);
249
Y.each(postponed, function(s) {
254
es.afterQueue.add(function() {
255
self._procSubs(postponed, args, ef);
262
if (es.id === self.id) {
265
while (queue.length) {
268
// set up stack to allow the next item to be processed
270
ce.fire.apply(ce, q[1]);
276
ret = !(self.stopped);
278
if (self.type != host._yuievt.bubbling) {
288
CEProto._getFacade = function() {
290
var ef = this._facade, o, o2,
294
ef = new Y.EventFacade(this, this.currentTarget);
297
// if the first argument is an object literal, apply the
298
// properties to the event facade
301
if (Y.Lang.isObject(o, true)) {
305
// protect the event facade properties
306
Y.mix(o2, ef, true, FACADE_KEYS);
312
Y.mix(ef, o2, true, FACADE_KEYS);
314
// Allow the event type to be faked
315
// http://yuilibrary.com/projects/yui3/ticket/2528376
316
ef.type = o.type || ef.type;
319
// update the details field with the arguments
320
// ef.type = this.type;
321
ef.details = this.details;
323
// use the original target when the event bubbled to this target
324
ef.target = this.originalTarget || this.target;
326
ef.currentTarget = this.currentTarget;
336
* Stop propagation to bubble targets
338
* @method stopPropagation
340
CEProto.stopPropagation = function() {
343
this.stack.stopped = 1;
345
this.events.fire('stopped', this);
349
* Stops propagation to bubble targets, and prevents any remaining
350
* subscribers on the current target from executing.
351
* @method stopImmediatePropagation
353
CEProto.stopImmediatePropagation = function() {
356
this.stack.stopped = 2;
358
this.events.fire('stopped', this);
362
* Prevents the execution of this event's defaultFn
363
* @method preventDefault
365
CEProto.preventDefault = function() {
366
if (this.preventable) {
369
this.stack.prevented = 1;
375
* Stops the event propagation and prevents the default
378
* @param immediate {boolean} if true additional listeners
379
* on the current target will not be executed
381
CEProto.halt = function(immediate) {
383
this.stopImmediatePropagation();
385
this.stopPropagation();
387
this.preventDefault();
391
* Registers another EventTarget as a bubble target. Bubble order
392
* is determined by the order registered. Multiple targets can
395
* Events can only bubble if emitFacade is true.
397
* Included in the event-custom-complex submodule.
400
* @param o {EventTarget} the target to add
403
ETProto.addTarget = function(o) {
404
this._yuievt.targets[Y.stamp(o)] = o;
405
this._yuievt.hasTargets = true;
409
* Returns an array of bubble targets for this object.
411
* @return EventTarget[]
413
ETProto.getTargets = function() {
414
return Y.Object.values(this._yuievt.targets);
418
* Removes a bubble target
419
* @method removeTarget
420
* @param o {EventTarget} the target to remove
423
ETProto.removeTarget = function(o) {
424
delete this._yuievt.targets[Y.stamp(o)];
428
* Propagate an event. Requires the event-custom-complex module.
430
* @param evt {CustomEvent} the custom event to propagate
431
* @return {boolean} the aggregated return value from Event.Custom.fire
434
ETProto.bubble = function(evt, args, target, es) {
436
var targs = this._yuievt.targets, ret = true,
437
t, type = evt && evt.type, ce, i, bc, ce2,
438
originalTarget = target || (evt && evt.target) || this,
441
if (!evt || ((!evt.stopped) && targs)) {
443
// Y.log('Bubbling ' + evt.type);
445
if (targs.hasOwnProperty(i)) {
447
ce = t.getEvent(type, true);
448
ce2 = t.getSibling(type, ce);
451
ce = t.publish(type);
454
oldbubble = t._yuievt.bubbling;
455
t._yuievt.bubbling = type;
457
// if this event was not published on the bubble target,
458
// continue propagating the event.
460
if (t._yuievt.hasTargets) {
461
t.bubble(evt, args, originalTarget, es);
467
// set the original target to that the target payload on the
468
// facade is correct.
469
ce.target = originalTarget;
470
ce.originalTarget = originalTarget;
471
ce.currentTarget = t;
473
ce.broadcast = false;
475
// default publish may not have emitFacade true -- that
476
// shouldn't be what the implementer meant to do
477
ce.emitFacade = true;
481
ret = ret && ce.fire.apply(ce, args || evt.details || []);
483
ce.originalTarget = null;
486
// stopPropagation() was called
492
t._yuievt.bubbling = oldbubble;
500
FACADE = new Y.EventFacade();
501
FACADE_KEYS = Y.Object.keys(FACADE);
505
}, '3.4.1' ,{requires:['event-custom-base']});