src/cm/media/js/lib/yui/yui3-3.15.0/build/event-synthetic/event-synthetic-debug.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     1 YUI.add('event-synthetic', function (Y, NAME) {
       
     2 
       
     3 /**
       
     4  * Define new DOM events that can be subscribed to from Nodes.
       
     5  *
       
     6  * @module event
       
     7  * @submodule event-synthetic
       
     8  */
       
     9 var CustomEvent = Y.CustomEvent,
       
    10     DOMMap   = Y.Env.evt.dom_map,
       
    11     toArray  = Y.Array,
       
    12     YLang    = Y.Lang,
       
    13     isObject = YLang.isObject,
       
    14     isString = YLang.isString,
       
    15     isArray  = YLang.isArray,
       
    16     query    = Y.Selector.query,
       
    17     noop     = function () {};
       
    18 
       
    19 /**
       
    20  * <p>The triggering mechanism used by SyntheticEvents.</p>
       
    21  *
       
    22  * <p>Implementers should not instantiate these directly.  Use the Notifier
       
    23  * provided to the event's implemented <code>on(node, sub, notifier)</code> or
       
    24  * <code>delegate(node, sub, notifier, filter)</code> methods.</p>
       
    25  *
       
    26  * @class SyntheticEvent.Notifier
       
    27  * @constructor
       
    28  * @param handle {EventHandle} the detach handle for the subscription to an
       
    29  *              internal custom event used to execute the callback passed to
       
    30  *              on(..) or delegate(..)
       
    31  * @param emitFacade {Boolean} take steps to ensure the first arg received by
       
    32  *              the subscription callback is an event facade
       
    33  * @private
       
    34  * @since 3.2.0
       
    35  */
       
    36 function Notifier(handle, emitFacade) {
       
    37     this.handle     = handle;
       
    38     this.emitFacade = emitFacade;
       
    39 }
       
    40 
       
    41 /**
       
    42  * <p>Executes the subscription callback, passing the firing arguments as the
       
    43  * first parameters to that callback. For events that are configured with
       
    44  * emitFacade=true, it is common practice to pass the triggering DOMEventFacade
       
    45  * as the first parameter.  Barring a proper DOMEventFacade or EventFacade
       
    46  * (from a CustomEvent), a new EventFacade will be generated.  In that case, if
       
    47  * fire() is called with a simple object, it will be mixed into the facade.
       
    48  * Otherwise, the facade will be prepended to the callback parameters.</p>
       
    49  *
       
    50  * <p>For notifiers provided to delegate logic, the first argument should be an
       
    51  * object with a &quot;currentTarget&quot; property to identify what object to
       
    52  * default as 'this' in the callback.  Typically this is gleaned from the
       
    53  * DOMEventFacade or EventFacade, but if configured with emitFacade=false, an
       
    54  * object must be provided.  In that case, the object will be removed from the
       
    55  * callback parameters.</p>
       
    56  *
       
    57  * <p>Additional arguments passed during event subscription will be
       
    58  * automatically added after those passed to fire().</p>
       
    59  *
       
    60  * @method fire
       
    61  * @param {EventFacade|DOMEventFacade|any} e (see description)
       
    62  * @param {any[]} [arg*] additional arguments received by all subscriptions
       
    63  * @private
       
    64  */
       
    65 Notifier.prototype.fire = function (e) {
       
    66     // first arg to delegate notifier should be an object with currentTarget
       
    67     var args     = toArray(arguments, 0, true),
       
    68         handle   = this.handle,
       
    69         ce       = handle.evt,
       
    70         sub      = handle.sub,
       
    71         thisObj  = sub.context,
       
    72         delegate = sub.filter,
       
    73         event    = e || {},
       
    74         ret;
       
    75 
       
    76     if (this.emitFacade) {
       
    77         if (!e || !e.preventDefault) {
       
    78             event = ce._getFacade();
       
    79 
       
    80             if (isObject(e) && !e.preventDefault) {
       
    81                 Y.mix(event, e, true);
       
    82                 args[0] = event;
       
    83             } else {
       
    84                 args.unshift(event);
       
    85             }
       
    86         }
       
    87 
       
    88         event.type    = ce.type;
       
    89         event.details = args.slice();
       
    90 
       
    91         if (delegate) {
       
    92             event.container = ce.host;
       
    93         }
       
    94     } else if (delegate && isObject(e) && e.currentTarget) {
       
    95         args.shift();
       
    96     }
       
    97 
       
    98     sub.context = thisObj || event.currentTarget || ce.host;
       
    99     ret = ce.fire.apply(ce, args);
       
   100 
       
   101     // have to handle preventedFn and stoppedFn manually because
       
   102     // Notifier CustomEvents are forced to emitFacade=false
       
   103     if (e.prevented && ce.preventedFn) {
       
   104         ce.preventedFn.apply(ce, args);
       
   105     }
       
   106 
       
   107     if (e.stopped && ce.stoppedFn) {
       
   108         ce.stoppedFn.apply(ce, args);
       
   109     }
       
   110 
       
   111     sub.context = thisObj; // reset for future firing
       
   112 
       
   113     // to capture callbacks that return false to stopPropagation.
       
   114     // Useful for delegate implementations
       
   115     return ret;
       
   116 };
       
   117 
       
   118 /**
       
   119  * Manager object for synthetic event subscriptions to aggregate multiple synths on the
       
   120  * same node without colliding with actual DOM subscription entries in the global map of
       
   121  * DOM subscriptions.  Also facilitates proper cleanup on page unload.
       
   122  *
       
   123  * @class SynthRegistry
       
   124  * @constructor
       
   125  * @param el {HTMLElement} the DOM element
       
   126  * @param yuid {String} the yuid stamp for the element
       
   127  * @param key {String} the generated id token used to identify an event type +
       
   128  *                     element in the global DOM subscription map.
       
   129  * @private
       
   130  */
       
   131 function SynthRegistry(el, yuid, key) {
       
   132     this.handles = [];
       
   133     this.el      = el;
       
   134     this.key     = key;
       
   135     this.domkey  = yuid;
       
   136 }
       
   137 
       
   138 SynthRegistry.prototype = {
       
   139     constructor: SynthRegistry,
       
   140 
       
   141     // A few object properties to fake the CustomEvent interface for page
       
   142     // unload cleanup.  DON'T TOUCH!
       
   143     type      : '_synth',
       
   144     fn        : noop,
       
   145     capture   : false,
       
   146 
       
   147     /**
       
   148      * Adds a subscription from the Notifier registry.
       
   149      *
       
   150      * @method register
       
   151      * @param handle {EventHandle} the subscription
       
   152      * @since 3.4.0
       
   153      */
       
   154     register: function (handle) {
       
   155         handle.evt.registry = this;
       
   156         this.handles.push(handle);
       
   157     },
       
   158 
       
   159     /**
       
   160      * Removes the subscription from the Notifier registry.
       
   161      *
       
   162      * @method _unregisterSub
       
   163      * @param sub {Subscription} the subscription
       
   164      * @since 3.4.0
       
   165      */
       
   166     unregister: function (sub) {
       
   167         var handles = this.handles,
       
   168             events = DOMMap[this.domkey],
       
   169             i;
       
   170 
       
   171         for (i = handles.length - 1; i >= 0; --i) {
       
   172             if (handles[i].sub === sub) {
       
   173                 handles.splice(i, 1);
       
   174                 break;
       
   175             }
       
   176         }
       
   177 
       
   178         // Clean up left over objects when there are no more subscribers.
       
   179         if (!handles.length) {
       
   180             delete events[this.key];
       
   181             if (!Y.Object.size(events)) {
       
   182                 delete DOMMap[this.domkey];
       
   183             }
       
   184         }
       
   185     },
       
   186 
       
   187     /**
       
   188      * Used by the event system's unload cleanup process.  When navigating
       
   189      * away from the page, the event system iterates the global map of element
       
   190      * subscriptions and detaches everything using detachAll().  Normally,
       
   191      * the map is populated with custom events, so this object needs to
       
   192      * at least support the detachAll method to duck type its way to
       
   193      * cleanliness.
       
   194      *
       
   195      * @method detachAll
       
   196      * @private
       
   197      * @since 3.4.0
       
   198      */
       
   199     detachAll : function () {
       
   200         var handles = this.handles,
       
   201             i = handles.length;
       
   202 
       
   203         while (--i >= 0) {
       
   204             handles[i].detach();
       
   205         }
       
   206     }
       
   207 };
       
   208 
       
   209 /**
       
   210  * <p>Wrapper class for the integration of new events into the YUI event
       
   211  * infrastructure.  Don't instantiate this object directly, use
       
   212  * <code>Y.Event.define(type, config)</code>.  See that method for details.</p>
       
   213  *
       
   214  * <p>Properties that MAY or SHOULD be specified in the configuration are noted
       
   215  * below and in the description of <code>Y.Event.define</code>.</p>
       
   216  *
       
   217  * @class SyntheticEvent
       
   218  * @constructor
       
   219  * @param cfg {Object} Implementation pieces and configuration
       
   220  * @since 3.1.0
       
   221  * @in event-synthetic
       
   222  */
       
   223 function SyntheticEvent() {
       
   224     this._init.apply(this, arguments);
       
   225 }
       
   226 
       
   227 Y.mix(SyntheticEvent, {
       
   228     Notifier: Notifier,
       
   229     SynthRegistry: SynthRegistry,
       
   230 
       
   231     /**
       
   232      * Returns the array of subscription handles for a node for the given event
       
   233      * type.  Passing true as the third argument will create a registry entry
       
   234      * in the event system's DOM map to host the array if one doesn't yet exist.
       
   235      *
       
   236      * @method getRegistry
       
   237      * @param node {Node} the node
       
   238      * @param type {String} the event
       
   239      * @param create {Boolean} create a registration entry to host a new array
       
   240      *                  if one doesn't exist.
       
   241      * @return {Array}
       
   242      * @static
       
   243      * @protected
       
   244      * @since 3.2.0
       
   245      */
       
   246     getRegistry: function (node, type, create) {
       
   247         var el     = node._node,
       
   248             yuid   = Y.stamp(el),
       
   249             key    = 'event:' + yuid + type + '_synth',
       
   250             events = DOMMap[yuid];
       
   251 
       
   252         if (create) {
       
   253             if (!events) {
       
   254                 events = DOMMap[yuid] = {};
       
   255             }
       
   256             if (!events[key]) {
       
   257                 events[key] = new SynthRegistry(el, yuid, key);
       
   258             }
       
   259         }
       
   260 
       
   261         return (events && events[key]) || null;
       
   262     },
       
   263 
       
   264     /**
       
   265      * Alternate <code>_delete()</code> method for the CustomEvent object
       
   266      * created to manage SyntheticEvent subscriptions.
       
   267      *
       
   268      * @method _deleteSub
       
   269      * @param sub {Subscription} the subscription to clean up
       
   270      * @private
       
   271      * @since 3.2.0
       
   272      */
       
   273     _deleteSub: function (sub) {
       
   274         if (sub && sub.fn) {
       
   275             var synth = this.eventDef,
       
   276                 method = (sub.filter) ? 'detachDelegate' : 'detach';
       
   277 
       
   278             this._subscribers = [];
       
   279 
       
   280             if (CustomEvent.keepDeprecatedSubs) {
       
   281                 this.subscribers = {};
       
   282             }
       
   283 
       
   284             synth[method](sub.node, sub, this.notifier, sub.filter);
       
   285             this.registry.unregister(sub);
       
   286 
       
   287             delete sub.fn;
       
   288             delete sub.node;
       
   289             delete sub.context;
       
   290         }
       
   291     },
       
   292 
       
   293     prototype: {
       
   294         constructor: SyntheticEvent,
       
   295 
       
   296         /**
       
   297          * Construction logic for the event.
       
   298          *
       
   299          * @method _init
       
   300          * @protected
       
   301          */
       
   302         _init: function () {
       
   303             var config = this.publishConfig || (this.publishConfig = {});
       
   304 
       
   305             // The notification mechanism handles facade creation
       
   306             this.emitFacade = ('emitFacade' in config) ?
       
   307                                 config.emitFacade :
       
   308                                 true;
       
   309             config.emitFacade  = false;
       
   310         },
       
   311 
       
   312         /**
       
   313          * <p>Implementers MAY provide this method definition.</p>
       
   314          *
       
   315          * <p>Implement this function if the event supports a different
       
   316          * subscription signature.  This function is used by both
       
   317          * <code>on()</code> and <code>delegate()</code>.  The second parameter
       
   318          * indicates that the event is being subscribed via
       
   319          * <code>delegate()</code>.</p>
       
   320          *
       
   321          * <p>Implementations must remove extra arguments from the args list
       
   322          * before returning.  The required args for <code>on()</code>
       
   323          * subscriptions are</p>
       
   324          * <pre><code>[type, callback, target, context, argN...]</code></pre>
       
   325          *
       
   326          * <p>The required args for <code>delegate()</code>
       
   327          * subscriptions are</p>
       
   328          *
       
   329          * <pre><code>[type, callback, target, filter, context, argN...]</code></pre>
       
   330          *
       
   331          * <p>The return value from this function will be stored on the
       
   332          * subscription in the '_extra' property for reference elsewhere.</p>
       
   333          *
       
   334          * @method processArgs
       
   335          * @param args {Array} parmeters passed to Y.on(..) or Y.delegate(..)
       
   336          * @param delegate {Boolean} true if the subscription is from Y.delegate
       
   337          * @return {any}
       
   338          */
       
   339         processArgs: noop,
       
   340 
       
   341         /**
       
   342          * <p>Implementers MAY override this property.</p>
       
   343          *
       
   344          * <p>Whether to prevent multiple subscriptions to this event that are
       
   345          * classified as being the same.  By default, this means the subscribed
       
   346          * callback is the same function.  See the <code>subMatch</code>
       
   347          * method.  Setting this to true will impact performance for high volume
       
   348          * events.</p>
       
   349          *
       
   350          * @property preventDups
       
   351          * @type {Boolean}
       
   352          * @default false
       
   353          */
       
   354         //preventDups  : false,
       
   355 
       
   356         /**
       
   357          * <p>Implementers SHOULD provide this method definition.</p>
       
   358          *
       
   359          * Implementation logic for subscriptions done via <code>node.on(type,
       
   360          * fn)</code> or <code>Y.on(type, fn, target)</code>.  This
       
   361          * function should set up the monitor(s) that will eventually fire the
       
   362          * event.  Typically this involves subscribing to at least one DOM
       
   363          * event.  It is recommended to store detach handles from any DOM
       
   364          * subscriptions to make for easy cleanup in the <code>detach</code>
       
   365          * method.  Typically these handles are added to the <code>sub</code>
       
   366          * object.  Also for SyntheticEvents that leverage a single DOM
       
   367          * subscription under the hood, it is recommended to pass the DOM event
       
   368          * object to <code>notifier.fire(e)</code>.  (The event name on the
       
   369          * object will be updated).
       
   370          *
       
   371          * @method on
       
   372          * @param node {Node} the node the subscription is being applied to
       
   373          * @param sub {Subscription} the object to track this subscription
       
   374          * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to
       
   375          *              trigger the execution of the subscribers
       
   376          */
       
   377         on: noop,
       
   378 
       
   379         /**
       
   380          * <p>Implementers SHOULD provide this method definition.</p>
       
   381          *
       
   382          * <p>Implementation logic for detaching subscriptions done via
       
   383          * <code>node.on(type, fn)</code>.  This function should clean up any
       
   384          * subscriptions made in the <code>on()</code> phase.</p>
       
   385          *
       
   386          * @method detach
       
   387          * @param node {Node} the node the subscription was applied to
       
   388          * @param sub {Subscription} the object tracking this subscription
       
   389          * @param notifier {SyntheticEvent.Notifier} the Notifier used to
       
   390          *              trigger the execution of the subscribers
       
   391          */
       
   392         detach: noop,
       
   393 
       
   394         /**
       
   395          * <p>Implementers SHOULD provide this method definition.</p>
       
   396          *
       
   397          * <p>Implementation logic for subscriptions done via
       
   398          * <code>node.delegate(type, fn, filter)</code> or
       
   399          * <code>Y.delegate(type, fn, container, filter)</code>.  Like with
       
   400          * <code>on()</code> above, this function should monitor the environment
       
   401          * for the event being fired, and trigger subscription execution by
       
   402          * calling <code>notifier.fire(e)</code>.</p>
       
   403          *
       
   404          * <p>This function receives a fourth argument, which is the filter
       
   405          * used to identify which Node's are of interest to the subscription.
       
   406          * The filter will be either a boolean function that accepts a target
       
   407          * Node for each hierarchy level as the event bubbles, or a selector
       
   408          * string.  To translate selector strings into filter functions, use
       
   409          * <code>Y.delegate.compileFilter(filter)</code>.</p>
       
   410          *
       
   411          * @method delegate
       
   412          * @param node {Node} the node the subscription is being applied to
       
   413          * @param sub {Subscription} the object to track this subscription
       
   414          * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to
       
   415          *              trigger the execution of the subscribers
       
   416          * @param filter {String|Function} Selector string or function that
       
   417          *              accepts an event object and returns null, a Node, or an
       
   418          *              array of Nodes matching the criteria for processing.
       
   419          * @since 3.2.0
       
   420          */
       
   421         delegate       : noop,
       
   422 
       
   423         /**
       
   424          * <p>Implementers SHOULD provide this method definition.</p>
       
   425          *
       
   426          * <p>Implementation logic for detaching subscriptions done via
       
   427          * <code>node.delegate(type, fn, filter)</code> or
       
   428          * <code>Y.delegate(type, fn, container, filter)</code>.  This function
       
   429          * should clean up any subscriptions made in the
       
   430          * <code>delegate()</code> phase.</p>
       
   431          *
       
   432          * @method detachDelegate
       
   433          * @param node {Node} the node the subscription was applied to
       
   434          * @param sub {Subscription} the object tracking this subscription
       
   435          * @param notifier {SyntheticEvent.Notifier} the Notifier used to
       
   436          *              trigger the execution of the subscribers
       
   437          * @param filter {String|Function} Selector string or function that
       
   438          *              accepts an event object and returns null, a Node, or an
       
   439          *              array of Nodes matching the criteria for processing.
       
   440          * @since 3.2.0
       
   441          */
       
   442         detachDelegate : noop,
       
   443 
       
   444         /**
       
   445          * Sets up the boilerplate for detaching the event and facilitating the
       
   446          * execution of subscriber callbacks.
       
   447          *
       
   448          * @method _on
       
   449          * @param args {Array} array of arguments passed to
       
   450          *              <code>Y.on(...)</code> or <code>Y.delegate(...)</code>
       
   451          * @param delegate {Boolean} true if called from
       
   452          * <code>Y.delegate(...)</code>
       
   453          * @return {EventHandle} the detach handle for this subscription
       
   454          * @private
       
   455          * since 3.2.0
       
   456          */
       
   457         _on: function (args, delegate) {
       
   458             var handles  = [],
       
   459                 originalArgs = args.slice(),
       
   460                 extra    = this.processArgs(args, delegate),
       
   461                 selector = args[2],
       
   462                 method   = delegate ? 'delegate' : 'on',
       
   463                 nodes, handle;
       
   464 
       
   465             // Can't just use Y.all because it doesn't support window (yet?)
       
   466             nodes = (isString(selector)) ?
       
   467                 query(selector) :
       
   468                 toArray(selector || Y.one(Y.config.win));
       
   469 
       
   470             if (!nodes.length && isString(selector)) {
       
   471                 handle = Y.on('available', function () {
       
   472                     Y.mix(handle, Y[method].apply(Y, originalArgs), true);
       
   473                 }, selector);
       
   474 
       
   475                 return handle;
       
   476             }
       
   477 
       
   478             Y.Array.each(nodes, function (node) {
       
   479                 var subArgs = args.slice(),
       
   480                     filter;
       
   481 
       
   482                 node = Y.one(node);
       
   483 
       
   484                 if (node) {
       
   485                     if (delegate) {
       
   486                         filter = subArgs.splice(3, 1)[0];
       
   487                     }
       
   488 
       
   489                     // (type, fn, el, thisObj, ...) => (fn, thisObj, ...)
       
   490                     subArgs.splice(0, 4, subArgs[1], subArgs[3]);
       
   491 
       
   492                     if (!this.preventDups ||
       
   493                         !this.getSubs(node, args, null, true))
       
   494                     {
       
   495                         handles.push(this._subscribe(node, method, subArgs, extra, filter));
       
   496                     }
       
   497                 }
       
   498             }, this);
       
   499 
       
   500             return (handles.length === 1) ?
       
   501                 handles[0] :
       
   502                 new Y.EventHandle(handles);
       
   503         },
       
   504 
       
   505         /**
       
   506          * Creates a new Notifier object for use by this event's
       
   507          * <code>on(...)</code> or <code>delegate(...)</code> implementation
       
   508          * and register the custom event proxy in the DOM system for cleanup.
       
   509          *
       
   510          * @method _subscribe
       
   511          * @param node {Node} the Node hosting the event
       
   512          * @param method {String} "on" or "delegate"
       
   513          * @param args {Array} the subscription arguments passed to either
       
   514          *              <code>Y.on(...)</code> or <code>Y.delegate(...)</code>
       
   515          *              after running through <code>processArgs(args)</code> to
       
   516          *              normalize the argument signature
       
   517          * @param extra {any} Extra data parsed from
       
   518          *              <code>processArgs(args)</code>
       
   519          * @param filter {String|Function} the selector string or function
       
   520          *              filter passed to <code>Y.delegate(...)</code> (not
       
   521          *              present when called from <code>Y.on(...)</code>)
       
   522          * @return {EventHandle}
       
   523          * @private
       
   524          * @since 3.2.0
       
   525          */
       
   526         _subscribe: function (node, method, args, extra, filter) {
       
   527             var dispatcher = new Y.CustomEvent(this.type, this.publishConfig),
       
   528                 handle     = dispatcher.on.apply(dispatcher, args),
       
   529                 notifier   = new Notifier(handle, this.emitFacade),
       
   530                 registry   = SyntheticEvent.getRegistry(node, this.type, true),
       
   531                 sub        = handle.sub;
       
   532 
       
   533             sub.node   = node;
       
   534             sub.filter = filter;
       
   535             if (extra) {
       
   536                 this.applyArgExtras(extra, sub);
       
   537             }
       
   538 
       
   539             Y.mix(dispatcher, {
       
   540                 eventDef     : this,
       
   541                 notifier     : notifier,
       
   542                 host         : node,       // I forget what this is for
       
   543                 currentTarget: node,       // for generating facades
       
   544                 target       : node,       // for generating facades
       
   545                 el           : node._node, // For category detach
       
   546 
       
   547                 _delete      : SyntheticEvent._deleteSub
       
   548             }, true);
       
   549 
       
   550             handle.notifier = notifier;
       
   551 
       
   552             registry.register(handle);
       
   553 
       
   554             // Call the implementation's "on" or "delegate" method
       
   555             this[method](node, sub, notifier, filter);
       
   556 
       
   557             return handle;
       
   558         },
       
   559 
       
   560         /**
       
   561          * <p>Implementers MAY provide this method definition.</p>
       
   562          *
       
   563          * <p>Implement this function if you want extra data extracted during
       
   564          * processArgs to be propagated to subscriptions on a per-node basis.
       
   565          * That is to say, if you call <code>Y.on('xyz', fn, xtra, 'div')</code>
       
   566          * the data returned from processArgs will be shared
       
   567          * across the subscription objects for all the divs.  If you want each
       
   568          * subscription to receive unique information, do that processing
       
   569          * here.</p>
       
   570          *
       
   571          * <p>The default implementation adds the data extracted by processArgs
       
   572          * to the subscription object as <code>sub._extra</code>.</p>
       
   573          *
       
   574          * @method applyArgExtras
       
   575          * @param extra {any} Any extra data extracted from processArgs
       
   576          * @param sub {Subscription} the individual subscription
       
   577          */
       
   578         applyArgExtras: function (extra, sub) {
       
   579             sub._extra = extra;
       
   580         },
       
   581 
       
   582         /**
       
   583          * Removes the subscription(s) from the internal subscription dispatch
       
   584          * mechanism.  See <code>SyntheticEvent._deleteSub</code>.
       
   585          *
       
   586          * @method _detach
       
   587          * @param args {Array} The arguments passed to
       
   588          *                  <code>node.detach(...)</code>
       
   589          * @private
       
   590          * @since 3.2.0
       
   591          */
       
   592         _detach: function (args) {
       
   593             // Can't use Y.all because it doesn't support window (yet?)
       
   594             // TODO: Does Y.all support window now?
       
   595             var target = args[2],
       
   596                 els    = (isString(target)) ?
       
   597                             query(target) : toArray(target),
       
   598                 node, i, len, handles, j;
       
   599 
       
   600             // (type, fn, el, context, filter?) => (type, fn, context, filter?)
       
   601             args.splice(2, 1);
       
   602 
       
   603             for (i = 0, len = els.length; i < len; ++i) {
       
   604                 node = Y.one(els[i]);
       
   605 
       
   606                 if (node) {
       
   607                     handles = this.getSubs(node, args);
       
   608 
       
   609                     if (handles) {
       
   610                         for (j = handles.length - 1; j >= 0; --j) {
       
   611                             handles[j].detach();
       
   612                         }
       
   613                     }
       
   614                 }
       
   615             }
       
   616         },
       
   617 
       
   618         /**
       
   619          * Returns the detach handles of subscriptions on a node that satisfy a
       
   620          * search/filter function.  By default, the filter used is the
       
   621          * <code>subMatch</code> method.
       
   622          *
       
   623          * @method getSubs
       
   624          * @param node {Node} the node hosting the event
       
   625          * @param args {Array} the array of original subscription args passed
       
   626          *              to <code>Y.on(...)</code> (before
       
   627          *              <code>processArgs</code>
       
   628          * @param filter {Function} function used to identify a subscription
       
   629          *              for inclusion in the returned array
       
   630          * @param first {Boolean} stop after the first match (used to check for
       
   631          *              duplicate subscriptions)
       
   632          * @return {EventHandle[]} detach handles for the matching subscriptions
       
   633          */
       
   634         getSubs: function (node, args, filter, first) {
       
   635             var registry = SyntheticEvent.getRegistry(node, this.type),
       
   636                 handles  = [],
       
   637                 allHandles, i, len, handle;
       
   638 
       
   639             if (registry) {
       
   640                 allHandles = registry.handles;
       
   641 
       
   642                 if (!filter) {
       
   643                     filter = this.subMatch;
       
   644                 }
       
   645 
       
   646                 for (i = 0, len = allHandles.length; i < len; ++i) {
       
   647                     handle = allHandles[i];
       
   648                     if (filter.call(this, handle.sub, args)) {
       
   649                         if (first) {
       
   650                             return handle;
       
   651                         } else {
       
   652                             handles.push(allHandles[i]);
       
   653                         }
       
   654                     }
       
   655                 }
       
   656             }
       
   657 
       
   658             return handles.length && handles;
       
   659         },
       
   660 
       
   661         /**
       
   662          * <p>Implementers MAY override this to define what constitutes a
       
   663          * &quot;same&quot; subscription.  Override implementations should
       
   664          * consider the lack of a comparator as a match, so calling
       
   665          * <code>getSubs()</code> with no arguments will return all subs.</p>
       
   666          *
       
   667          * <p>Compares a set of subscription arguments against a Subscription
       
   668          * object to determine if they match.  The default implementation
       
   669          * compares the callback function against the second argument passed to
       
   670          * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p>
       
   671          *
       
   672          * @method subMatch
       
   673          * @param sub {Subscription} the existing subscription
       
   674          * @param args {Array} the calling arguments passed to
       
   675          *                  <code>Y.on(...)</code> etc.
       
   676          * @return {Boolean} true if the sub can be described by the args
       
   677          *                  present
       
   678          * @since 3.2.0
       
   679          */
       
   680         subMatch: function (sub, args) {
       
   681             // Default detach cares only about the callback matching
       
   682             return !args[1] || sub.fn === args[1];
       
   683         }
       
   684     }
       
   685 }, true);
       
   686 
       
   687 Y.SyntheticEvent = SyntheticEvent;
       
   688 
       
   689 /**
       
   690  * <p>Defines a new event in the DOM event system.  Implementers are
       
   691  * responsible for monitoring for a scenario whereby the event is fired.  A
       
   692  * notifier object is provided to the functions identified below.  When the
       
   693  * criteria defining the event are met, call notifier.fire( [args] ); to
       
   694  * execute event subscribers.</p>
       
   695  *
       
   696  * <p>The first parameter is the name of the event.  The second parameter is a
       
   697  * configuration object which define the behavior of the event system when the
       
   698  * new event is subscribed to or detached from.  The methods that should be
       
   699  * defined in this configuration object are <code>on</code>,
       
   700  * <code>detach</code>, <code>delegate</code>, and <code>detachDelegate</code>.
       
   701  * You are free to define any other methods or properties needed to define your
       
   702  * event.  Be aware, however, that since the object is used to subclass
       
   703  * SyntheticEvent, you should avoid method names used by SyntheticEvent unless
       
   704  * your intention is to override the default behavior.</p>
       
   705  *
       
   706  * <p>This is a list of properties and methods that you can or should specify
       
   707  * in the configuration object:</p>
       
   708  *
       
   709  * <dl>
       
   710  *   <dt><code>on</code></dt>
       
   711  *       <dd><code>function (node, subscription, notifier)</code> The
       
   712  *       implementation logic for subscription.  Any special setup you need to
       
   713  *       do to create the environment for the event being fired--E.g. native
       
   714  *       DOM event subscriptions.  Store subscription related objects and
       
   715  *       state on the <code>subscription</code> object.  When the
       
   716  *       criteria have been met to fire the synthetic event, call
       
   717  *       <code>notifier.fire(e)</code>.  See Notifier's <code>fire()</code>
       
   718  *       method for details about what to pass as parameters.</dd>
       
   719  *
       
   720  *   <dt><code>detach</code></dt>
       
   721  *       <dd><code>function (node, subscription, notifier)</code> The
       
   722  *       implementation logic for cleaning up a detached subscription. E.g.
       
   723  *       detach any DOM subscriptions added in <code>on</code>.</dd>
       
   724  *
       
   725  *   <dt><code>delegate</code></dt>
       
   726  *       <dd><code>function (node, subscription, notifier, filter)</code> The
       
   727  *       implementation logic for subscription via <code>Y.delegate</code> or
       
   728  *       <code>node.delegate</code>.  The filter is typically either a selector
       
   729  *       string or a function.  You can use
       
   730  *       <code>Y.delegate.compileFilter(selectorString)</code> to create a
       
   731  *       filter function from a selector string if needed.  The filter function
       
   732  *       expects an event object as input and should output either null, a
       
   733  *       matching Node, or an array of matching Nodes.  Otherwise, this acts
       
   734  *       like <code>on</code> DOM event subscriptions.  Store subscription
       
   735  *       related objects and information on the <code>subscription</code>
       
   736  *       object.  When the criteria have been met to fire the synthetic event,
       
   737  *       call <code>notifier.fire(e)</code> as noted above.</dd>
       
   738  *
       
   739  *   <dt><code>detachDelegate</code></dt>
       
   740  *       <dd><code>function (node, subscription, notifier)</code> The
       
   741  *       implementation logic for cleaning up a detached delegate subscription.
       
   742  *       E.g. detach any DOM delegate subscriptions added in
       
   743  *       <code>delegate</code>.</dd>
       
   744  *
       
   745  *   <dt><code>publishConfig</code></dt>
       
   746  *       <dd>(Object) The configuration object that will be used to instantiate
       
   747  *       the underlying CustomEvent. See Notifier's <code>fire</code> method
       
   748  *       for details.</dd>
       
   749  *
       
   750  *   <dt><code>processArgs</code></dt
       
   751  *       <dd>
       
   752  *          <p><code>function (argArray, fromDelegate)</code> Optional method
       
   753  *          to extract any additional arguments from the subscription
       
   754  *          signature.  Using this allows <code>on</code> or
       
   755  *          <code>delegate</code> signatures like
       
   756  *          <code>node.on(&quot;hover&quot;, overCallback,
       
   757  *          outCallback)</code>.</p>
       
   758  *          <p>When processing an atypical argument signature, make sure the
       
   759  *          args array is returned to the normal signature before returning
       
   760  *          from the function.  For example, in the &quot;hover&quot; example
       
   761  *          above, the <code>outCallback</code> needs to be <code>splice</code>d
       
   762  *          out of the array.  The expected signature of the args array for
       
   763  *          <code>on()</code> subscriptions is:</p>
       
   764  *          <pre>
       
   765  *              <code>[type, callback, target, contextOverride, argN...]</code>
       
   766  *          </pre>
       
   767  *          <p>And for <code>delegate()</code>:</p>
       
   768  *          <pre>
       
   769  *              <code>[type, callback, target, filter, contextOverride, argN...]</code>
       
   770  *          </pre>
       
   771  *          <p>where <code>target</code> is the node the event is being
       
   772  *          subscribed for.  You can see these signatures documented for
       
   773  *          <code>Y.on()</code> and <code>Y.delegate()</code> respectively.</p>
       
   774  *          <p>Whatever gets returned from the function will be stored on the
       
   775  *          <code>subscription</code> object under
       
   776  *          <code>subscription._extra</code>.</p></dd>
       
   777  *   <dt><code>subMatch</code></dt>
       
   778  *       <dd>
       
   779  *           <p><code>function (sub, args)</code>  Compares a set of
       
   780  *           subscription arguments against a Subscription object to determine
       
   781  *           if they match.  The default implementation compares the callback
       
   782  *           function against the second argument passed to
       
   783  *           <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p>
       
   784  *       </dd>
       
   785  * </dl>
       
   786  *
       
   787  * @method define
       
   788  * @param type {String} the name of the event
       
   789  * @param config {Object} the prototype definition for the new event (see above)
       
   790  * @param force {Boolean} override an existing event (use with caution)
       
   791  * @return {SyntheticEvent} the subclass implementation instance created to
       
   792  *              handle event subscriptions of this type
       
   793  * @static
       
   794  * @for Event
       
   795  * @since 3.1.0
       
   796  * @in event-synthetic
       
   797  */
       
   798 Y.Event.define = function (type, config, force) {
       
   799     var eventDef, Impl, synth;
       
   800 
       
   801     if (type && type.type) {
       
   802         eventDef = type;
       
   803         force = config;
       
   804     } else if (config) {
       
   805         eventDef = Y.merge({ type: type }, config);
       
   806     }
       
   807 
       
   808     if (eventDef) {
       
   809         if (force || !Y.Node.DOM_EVENTS[eventDef.type]) {
       
   810             Impl = function () {
       
   811                 SyntheticEvent.apply(this, arguments);
       
   812             };
       
   813             Y.extend(Impl, SyntheticEvent, eventDef);
       
   814             synth = new Impl();
       
   815 
       
   816             type = synth.type;
       
   817 
       
   818             Y.Node.DOM_EVENTS[type] = Y.Env.evt.plugins[type] = {
       
   819                 eventDef: synth,
       
   820 
       
   821                 on: function () {
       
   822                     return synth._on(toArray(arguments));
       
   823                 },
       
   824 
       
   825                 delegate: function () {
       
   826                     return synth._on(toArray(arguments), true);
       
   827                 },
       
   828 
       
   829                 detach: function () {
       
   830                     return synth._detach(toArray(arguments));
       
   831                 }
       
   832             };
       
   833 
       
   834         }
       
   835     } else if (isString(type) || isArray(type)) {
       
   836         Y.Array.each(toArray(type), function (t) {
       
   837             Y.Node.DOM_EVENTS[t] = 1;
       
   838         });
       
   839     }
       
   840 
       
   841     return synth;
       
   842 };
       
   843 
       
   844 
       
   845 }, '@VERSION@', {"requires": ["node-base", "event-custom-complex"]});