src/cm/media/js/lib/yui/yui3-3.15.0/build/event-custom-complex/event-custom-complex-debug.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     1 YUI.add('event-custom-complex', function (Y, NAME) {
       
     2 
       
     3 
       
     4 /**
       
     5  * Adds event facades, preventable default behavior, and bubbling.
       
     6  * events.
       
     7  * @module event-custom
       
     8  * @submodule event-custom-complex
       
     9  */
       
    10 
       
    11 var FACADE,
       
    12     FACADE_KEYS,
       
    13     YObject = Y.Object,
       
    14     key,
       
    15     EMPTY = {},
       
    16     CEProto = Y.CustomEvent.prototype,
       
    17     ETProto = Y.EventTarget.prototype,
       
    18 
       
    19     mixFacadeProps = function(facade, payload) {
       
    20         var p;
       
    21 
       
    22         for (p in payload) {
       
    23             if (!(FACADE_KEYS.hasOwnProperty(p))) {
       
    24                 facade[p] = payload[p];
       
    25             }
       
    26         }
       
    27     };
       
    28 
       
    29 /**
       
    30  * Wraps and protects a custom event for use when emitFacade is set to true.
       
    31  * Requires the event-custom-complex module
       
    32  * @class EventFacade
       
    33  * @param e {Event} the custom event
       
    34  * @param currentTarget {HTMLElement} the element the listener was attached to
       
    35  */
       
    36 
       
    37 Y.EventFacade = function(e, currentTarget) {
       
    38 
       
    39     if (!e) {
       
    40         e = EMPTY;
       
    41     }
       
    42 
       
    43     this._event = e;
       
    44 
       
    45     /**
       
    46      * The arguments passed to fire
       
    47      * @property details
       
    48      * @type Array
       
    49      */
       
    50     this.details = e.details;
       
    51 
       
    52     /**
       
    53      * The event type, this can be overridden by the fire() payload
       
    54      * @property type
       
    55      * @type string
       
    56      */
       
    57     this.type = e.type;
       
    58 
       
    59     /**
       
    60      * The real event type
       
    61      * @property _type
       
    62      * @type string
       
    63      * @private
       
    64      */
       
    65     this._type = e.type;
       
    66 
       
    67     //////////////////////////////////////////////////////
       
    68 
       
    69     /**
       
    70      * Node reference for the targeted eventtarget
       
    71      * @property target
       
    72      * @type Node
       
    73      */
       
    74     this.target = e.target;
       
    75 
       
    76     /**
       
    77      * Node reference for the element that the listener was attached to.
       
    78      * @property currentTarget
       
    79      * @type Node
       
    80      */
       
    81     this.currentTarget = currentTarget;
       
    82 
       
    83     /**
       
    84      * Node reference to the relatedTarget
       
    85      * @property relatedTarget
       
    86      * @type Node
       
    87      */
       
    88     this.relatedTarget = e.relatedTarget;
       
    89 
       
    90 };
       
    91 
       
    92 Y.mix(Y.EventFacade.prototype, {
       
    93 
       
    94     /**
       
    95      * Stops the propagation to the next bubble target
       
    96      * @method stopPropagation
       
    97      */
       
    98     stopPropagation: function() {
       
    99         this._event.stopPropagation();
       
   100         this.stopped = 1;
       
   101     },
       
   102 
       
   103     /**
       
   104      * Stops the propagation to the next bubble target and
       
   105      * prevents any additional listeners from being exectued
       
   106      * on the current target.
       
   107      * @method stopImmediatePropagation
       
   108      */
       
   109     stopImmediatePropagation: function() {
       
   110         this._event.stopImmediatePropagation();
       
   111         this.stopped = 2;
       
   112     },
       
   113 
       
   114     /**
       
   115      * Prevents the event's default behavior
       
   116      * @method preventDefault
       
   117      */
       
   118     preventDefault: function() {
       
   119         this._event.preventDefault();
       
   120         this.prevented = 1;
       
   121     },
       
   122 
       
   123     /**
       
   124      * Stops the event propagation and prevents the default
       
   125      * event behavior.
       
   126      * @method halt
       
   127      * @param immediate {boolean} if true additional listeners
       
   128      * on the current target will not be executed
       
   129      */
       
   130     halt: function(immediate) {
       
   131         this._event.halt(immediate);
       
   132         this.prevented = 1;
       
   133         this.stopped = (immediate) ? 2 : 1;
       
   134     }
       
   135 
       
   136 });
       
   137 
       
   138 CEProto.fireComplex = function(args) {
       
   139 
       
   140     var es,
       
   141         ef,
       
   142         q,
       
   143         queue,
       
   144         ce,
       
   145         ret = true,
       
   146         events,
       
   147         subs,
       
   148         ons,
       
   149         afters,
       
   150         afterQueue,
       
   151         postponed,
       
   152         prevented,
       
   153         preventedFn,
       
   154         defaultFn,
       
   155         self = this,
       
   156         host = self.host || self,
       
   157         next,
       
   158         oldbubble,
       
   159         stack = self.stack,
       
   160         yuievt = host._yuievt,
       
   161         hasPotentialSubscribers;
       
   162 
       
   163     if (stack) {
       
   164 
       
   165         // queue this event if the current item in the queue bubbles
       
   166         if (self.queuable && self.type !== stack.next.type) {
       
   167             self.log('queue ' + self.type);
       
   168 
       
   169             if (!stack.queue) {
       
   170                 stack.queue = [];
       
   171             }
       
   172             stack.queue.push([self, args]);
       
   173 
       
   174             return true;
       
   175         }
       
   176     }
       
   177 
       
   178     hasPotentialSubscribers = self.hasSubs() || yuievt.hasTargets || self.broadcast;
       
   179 
       
   180     self.target = self.target || host;
       
   181     self.currentTarget = host;
       
   182 
       
   183     self.details = args.concat();
       
   184 
       
   185     if (hasPotentialSubscribers) {
       
   186 
       
   187         es = stack || {
       
   188 
       
   189            id: self.id, // id of the first event in the stack
       
   190            next: self,
       
   191            silent: self.silent,
       
   192            stopped: 0,
       
   193            prevented: 0,
       
   194            bubbling: null,
       
   195            type: self.type,
       
   196            // defaultFnQueue: new Y.Queue(),
       
   197            defaultTargetOnly: self.defaultTargetOnly
       
   198 
       
   199         };
       
   200 
       
   201         subs = self.getSubs();
       
   202         ons = subs[0];
       
   203         afters = subs[1];
       
   204 
       
   205         self.stopped = (self.type !== es.type) ? 0 : es.stopped;
       
   206         self.prevented = (self.type !== es.type) ? 0 : es.prevented;
       
   207 
       
   208         if (self.stoppedFn) {
       
   209             // PERF TODO: Can we replace with callback, like preventedFn. Look into history
       
   210             events = new Y.EventTarget({
       
   211                 fireOnce: true,
       
   212                 context: host
       
   213             });
       
   214             self.events = events;
       
   215             events.on('stopped', self.stoppedFn);
       
   216         }
       
   217 
       
   218         // self.log("Firing " + self  + ", " + "args: " + args);
       
   219         self.log("Firing " + self.type);
       
   220 
       
   221         self._facade = null; // kill facade to eliminate stale properties
       
   222 
       
   223         ef = self._createFacade(args);
       
   224 
       
   225         if (ons) {
       
   226             self._procSubs(ons, args, ef);
       
   227         }
       
   228 
       
   229         // bubble if this is hosted in an event target and propagation has not been stopped
       
   230         if (self.bubbles && host.bubble && !self.stopped) {
       
   231             oldbubble = es.bubbling;
       
   232 
       
   233             es.bubbling = self.type;
       
   234 
       
   235             if (es.type !== self.type) {
       
   236                 es.stopped = 0;
       
   237                 es.prevented = 0;
       
   238             }
       
   239 
       
   240             ret = host.bubble(self, args, null, es);
       
   241 
       
   242             self.stopped = Math.max(self.stopped, es.stopped);
       
   243             self.prevented = Math.max(self.prevented, es.prevented);
       
   244 
       
   245             es.bubbling = oldbubble;
       
   246         }
       
   247 
       
   248         prevented = self.prevented;
       
   249 
       
   250         if (prevented) {
       
   251             preventedFn = self.preventedFn;
       
   252             if (preventedFn) {
       
   253                 preventedFn.apply(host, args);
       
   254             }
       
   255         } else {
       
   256             defaultFn = self.defaultFn;
       
   257 
       
   258             if (defaultFn && ((!self.defaultTargetOnly && !es.defaultTargetOnly) || host === ef.target)) {
       
   259                 defaultFn.apply(host, args);
       
   260             }
       
   261         }
       
   262 
       
   263         // broadcast listeners are fired as discreet events on the
       
   264         // YUI instance and potentially the YUI global.
       
   265         if (self.broadcast) {
       
   266             self._broadcast(args);
       
   267         }
       
   268 
       
   269         if (afters && !self.prevented && self.stopped < 2) {
       
   270 
       
   271             // Queue the after
       
   272             afterQueue = es.afterQueue;
       
   273 
       
   274             if (es.id === self.id || self.type !== yuievt.bubbling) {
       
   275 
       
   276                 self._procSubs(afters, args, ef);
       
   277 
       
   278                 if (afterQueue) {
       
   279                     while ((next = afterQueue.last())) {
       
   280                         next();
       
   281                     }
       
   282                 }
       
   283             } else {
       
   284                 postponed = afters;
       
   285 
       
   286                 if (es.execDefaultCnt) {
       
   287                     postponed = Y.merge(postponed);
       
   288 
       
   289                     Y.each(postponed, function(s) {
       
   290                         s.postponed = true;
       
   291                     });
       
   292                 }
       
   293 
       
   294                 if (!afterQueue) {
       
   295                     es.afterQueue = new Y.Queue();
       
   296                 }
       
   297 
       
   298                 es.afterQueue.add(function() {
       
   299                     self._procSubs(postponed, args, ef);
       
   300                 });
       
   301             }
       
   302 
       
   303         }
       
   304 
       
   305         self.target = null;
       
   306 
       
   307         if (es.id === self.id) {
       
   308 
       
   309             queue = es.queue;
       
   310 
       
   311             if (queue) {
       
   312                 while (queue.length) {
       
   313                     q = queue.pop();
       
   314                     ce = q[0];
       
   315                     // set up stack to allow the next item to be processed
       
   316                     es.next = ce;
       
   317                     ce._fire(q[1]);
       
   318                 }
       
   319             }
       
   320 
       
   321             self.stack = null;
       
   322         }
       
   323 
       
   324         ret = !(self.stopped);
       
   325 
       
   326         if (self.type !== yuievt.bubbling) {
       
   327             es.stopped = 0;
       
   328             es.prevented = 0;
       
   329             self.stopped = 0;
       
   330             self.prevented = 0;
       
   331         }
       
   332 
       
   333     } else {
       
   334         defaultFn = self.defaultFn;
       
   335 
       
   336         if(defaultFn) {
       
   337             ef = self._createFacade(args);
       
   338 
       
   339             if ((!self.defaultTargetOnly) || (host === ef.target)) {
       
   340                 defaultFn.apply(host, args);
       
   341             }
       
   342         }
       
   343     }
       
   344 
       
   345     // Kill the cached facade to free up memory.
       
   346     // Otherwise we have the facade from the last fire, sitting around forever.
       
   347     self._facade = null;
       
   348 
       
   349     return ret;
       
   350 };
       
   351 
       
   352 /**
       
   353  * @method _hasPotentialSubscribers
       
   354  * @for CustomEvent
       
   355  * @private
       
   356  * @return {boolean} Whether the event has potential subscribers or not
       
   357  */
       
   358 CEProto._hasPotentialSubscribers = function() {
       
   359     return this.hasSubs() || this.host._yuievt.hasTargets || this.broadcast;
       
   360 };
       
   361 
       
   362 /**
       
   363  * Internal utility method to create a new facade instance and
       
   364  * insert it into the fire argument list, accounting for any payload
       
   365  * merging which needs to happen.
       
   366  *
       
   367  * This used to be called `_getFacade`, but the name seemed inappropriate
       
   368  * when it was used without a need for the return value.
       
   369  *
       
   370  * @method _createFacade
       
   371  * @private
       
   372  * @param fireArgs {Array} The arguments passed to "fire", which need to be
       
   373  * shifted (and potentially merged) when the facade is added.
       
   374  * @return {EventFacade} The event facade created.
       
   375  */
       
   376 
       
   377 // TODO: Remove (private) _getFacade alias, once synthetic.js is updated.
       
   378 CEProto._createFacade = CEProto._getFacade = function(fireArgs) {
       
   379 
       
   380     var userArgs = this.details,
       
   381         firstArg = userArgs && userArgs[0],
       
   382         firstArgIsObj = (firstArg && (typeof firstArg === "object")),
       
   383         ef = this._facade;
       
   384 
       
   385     if (!ef) {
       
   386         ef = new Y.EventFacade(this, this.currentTarget);
       
   387     }
       
   388 
       
   389     if (firstArgIsObj) {
       
   390         // protect the event facade properties
       
   391         mixFacadeProps(ef, firstArg);
       
   392 
       
   393         // Allow the event type to be faked http://yuilibrary.com/projects/yui3/ticket/2528376
       
   394         if (firstArg.type) {
       
   395             ef.type = firstArg.type;
       
   396         }
       
   397 
       
   398         if (fireArgs) {
       
   399             fireArgs[0] = ef;
       
   400         }
       
   401     } else {
       
   402         if (fireArgs) {
       
   403             fireArgs.unshift(ef);
       
   404         }
       
   405     }
       
   406 
       
   407     // update the details field with the arguments
       
   408     ef.details = this.details;
       
   409 
       
   410     // use the original target when the event bubbled to this target
       
   411     ef.target = this.originalTarget || this.target;
       
   412 
       
   413     ef.currentTarget = this.currentTarget;
       
   414     ef.stopped = 0;
       
   415     ef.prevented = 0;
       
   416 
       
   417     this._facade = ef;
       
   418 
       
   419     return this._facade;
       
   420 };
       
   421 
       
   422 /**
       
   423  * Utility method to manipulate the args array passed in, to add the event facade,
       
   424  * if it's not already the first arg.
       
   425  *
       
   426  * @method _addFacadeToArgs
       
   427  * @private
       
   428  * @param {Array} The arguments to manipulate
       
   429  */
       
   430 CEProto._addFacadeToArgs = function(args) {
       
   431     var e = args[0];
       
   432 
       
   433     // Trying not to use instanceof, just to avoid potential cross Y edge case issues.
       
   434     if (!(e && e.halt && e.stopImmediatePropagation && e.stopPropagation && e._event)) {
       
   435         this._createFacade(args);
       
   436     }
       
   437 };
       
   438 
       
   439 /**
       
   440  * Stop propagation to bubble targets
       
   441  * @for CustomEvent
       
   442  * @method stopPropagation
       
   443  */
       
   444 CEProto.stopPropagation = function() {
       
   445     this.stopped = 1;
       
   446     if (this.stack) {
       
   447         this.stack.stopped = 1;
       
   448     }
       
   449     if (this.events) {
       
   450         this.events.fire('stopped', this);
       
   451     }
       
   452 };
       
   453 
       
   454 /**
       
   455  * Stops propagation to bubble targets, and prevents any remaining
       
   456  * subscribers on the current target from executing.
       
   457  * @method stopImmediatePropagation
       
   458  */
       
   459 CEProto.stopImmediatePropagation = function() {
       
   460     this.stopped = 2;
       
   461     if (this.stack) {
       
   462         this.stack.stopped = 2;
       
   463     }
       
   464     if (this.events) {
       
   465         this.events.fire('stopped', this);
       
   466     }
       
   467 };
       
   468 
       
   469 /**
       
   470  * Prevents the execution of this event's defaultFn
       
   471  * @method preventDefault
       
   472  */
       
   473 CEProto.preventDefault = function() {
       
   474     if (this.preventable) {
       
   475         this.prevented = 1;
       
   476         if (this.stack) {
       
   477             this.stack.prevented = 1;
       
   478         }
       
   479     }
       
   480 };
       
   481 
       
   482 /**
       
   483  * Stops the event propagation and prevents the default
       
   484  * event behavior.
       
   485  * @method halt
       
   486  * @param immediate {boolean} if true additional listeners
       
   487  * on the current target will not be executed
       
   488  */
       
   489 CEProto.halt = function(immediate) {
       
   490     if (immediate) {
       
   491         this.stopImmediatePropagation();
       
   492     } else {
       
   493         this.stopPropagation();
       
   494     }
       
   495     this.preventDefault();
       
   496 };
       
   497 
       
   498 /**
       
   499  * Registers another EventTarget as a bubble target.  Bubble order
       
   500  * is determined by the order registered.  Multiple targets can
       
   501  * be specified.
       
   502  *
       
   503  * Events can only bubble if emitFacade is true.
       
   504  *
       
   505  * Included in the event-custom-complex submodule.
       
   506  *
       
   507  * @method addTarget
       
   508  * @chainable
       
   509  * @param o {EventTarget} the target to add
       
   510  * @for EventTarget
       
   511  */
       
   512 ETProto.addTarget = function(o) {
       
   513     var etState = this._yuievt;
       
   514 
       
   515     if (!etState.targets) {
       
   516         etState.targets = {};
       
   517     }
       
   518 
       
   519     etState.targets[Y.stamp(o)] = o;
       
   520     etState.hasTargets = true;
       
   521 
       
   522     return this;
       
   523 };
       
   524 
       
   525 /**
       
   526  * Returns an array of bubble targets for this object.
       
   527  * @method getTargets
       
   528  * @return EventTarget[]
       
   529  */
       
   530 ETProto.getTargets = function() {
       
   531     var targets = this._yuievt.targets;
       
   532     return targets ? YObject.values(targets) : [];
       
   533 };
       
   534 
       
   535 /**
       
   536  * Removes a bubble target
       
   537  * @method removeTarget
       
   538  * @chainable
       
   539  * @param o {EventTarget} the target to remove
       
   540  * @for EventTarget
       
   541  */
       
   542 ETProto.removeTarget = function(o) {
       
   543     var targets = this._yuievt.targets;
       
   544 
       
   545     if (targets) {
       
   546         delete targets[Y.stamp(o, true)];
       
   547 
       
   548         if (YObject.size(targets) === 0) {
       
   549             this._yuievt.hasTargets = false;
       
   550         }
       
   551     }
       
   552 
       
   553     return this;
       
   554 };
       
   555 
       
   556 /**
       
   557  * Propagate an event.  Requires the event-custom-complex module.
       
   558  * @method bubble
       
   559  * @param evt {CustomEvent} the custom event to propagate
       
   560  * @return {boolean} the aggregated return value from Event.Custom.fire
       
   561  * @for EventTarget
       
   562  */
       
   563 ETProto.bubble = function(evt, args, target, es) {
       
   564 
       
   565     var targs = this._yuievt.targets,
       
   566         ret = true,
       
   567         t,
       
   568         ce,
       
   569         i,
       
   570         bc,
       
   571         ce2,
       
   572         type = evt && evt.type,
       
   573         originalTarget = target || (evt && evt.target) || this,
       
   574         oldbubble;
       
   575 
       
   576     if (!evt || ((!evt.stopped) && targs)) {
       
   577 
       
   578         for (i in targs) {
       
   579             if (targs.hasOwnProperty(i)) {
       
   580 
       
   581                 t = targs[i];
       
   582 
       
   583                 ce = t._yuievt.events[type];
       
   584 
       
   585                 if (t._hasSiblings) {
       
   586                     ce2 = t.getSibling(type, ce);
       
   587                 }
       
   588 
       
   589                 if (ce2 && !ce) {
       
   590                     ce = t.publish(type);
       
   591                 }
       
   592 
       
   593                 oldbubble = t._yuievt.bubbling;
       
   594                 t._yuievt.bubbling = type;
       
   595 
       
   596                 // if this event was not published on the bubble target,
       
   597                 // continue propagating the event.
       
   598                 if (!ce) {
       
   599                     if (t._yuievt.hasTargets) {
       
   600                         t.bubble(evt, args, originalTarget, es);
       
   601                     }
       
   602                 } else {
       
   603 
       
   604                     if (ce2) {
       
   605                         ce.sibling = ce2;
       
   606                     }
       
   607 
       
   608                     // set the original target to that the target payload on the facade is correct.
       
   609                     ce.target = originalTarget;
       
   610                     ce.originalTarget = originalTarget;
       
   611                     ce.currentTarget = t;
       
   612                     bc = ce.broadcast;
       
   613                     ce.broadcast = false;
       
   614 
       
   615                     // default publish may not have emitFacade true -- that
       
   616                     // shouldn't be what the implementer meant to do
       
   617                     ce.emitFacade = true;
       
   618 
       
   619                     ce.stack = es;
       
   620 
       
   621                     // TODO: See what's getting in the way of changing this to use
       
   622                     // the more performant ce._fire(args || evt.details || []).
       
   623 
       
   624                     // Something in Widget Parent/Child tests is not happy if we
       
   625                     // change it - maybe evt.details related?
       
   626                     ret = ret && ce.fire.apply(ce, args || evt.details || []);
       
   627 
       
   628                     ce.broadcast = bc;
       
   629                     ce.originalTarget = null;
       
   630 
       
   631                     // stopPropagation() was called
       
   632                     if (ce.stopped) {
       
   633                         break;
       
   634                     }
       
   635                 }
       
   636 
       
   637                 t._yuievt.bubbling = oldbubble;
       
   638             }
       
   639         }
       
   640     }
       
   641 
       
   642     return ret;
       
   643 };
       
   644 
       
   645 /**
       
   646  * @method _hasPotentialSubscribers
       
   647  * @for EventTarget
       
   648  * @private
       
   649  * @param {String} fullType The fully prefixed type name
       
   650  * @return {boolean} Whether the event has potential subscribers or not
       
   651  */
       
   652 ETProto._hasPotentialSubscribers = function(fullType) {
       
   653 
       
   654     var etState = this._yuievt,
       
   655         e = etState.events[fullType];
       
   656 
       
   657     if (e) {
       
   658         return e.hasSubs() || etState.hasTargets  || e.broadcast;
       
   659     } else {
       
   660         return false;
       
   661     }
       
   662 };
       
   663 
       
   664 FACADE = new Y.EventFacade();
       
   665 FACADE_KEYS = {};
       
   666 
       
   667 // Flatten whitelist
       
   668 for (key in FACADE) {
       
   669     FACADE_KEYS[key] = true;
       
   670 }
       
   671 
       
   672 
       
   673 }, '@VERSION@', {"requires": ["event-custom-base"]});