[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/event-synthetic/ -> event-synthetic.js (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1