[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/event-base/ -> event-base.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-base', function (Y, NAME) {
   9  
  10  /*
  11   * DOM event listener abstraction layer
  12   * @module event
  13   * @submodule event-base
  14   */
  15  
  16  /**
  17   * The domready event fires at the moment the browser's DOM is
  18   * usable. In most cases, this is before images are fully
  19   * downloaded, allowing you to provide a more responsive user
  20   * interface.
  21   *
  22   * In YUI 3, domready subscribers will be notified immediately if
  23   * that moment has already passed when the subscription is created.
  24   *
  25   * One exception is if the yui.js file is dynamically injected into
  26   * the page.  If this is done, you must tell the YUI instance that
  27   * you did this in order for DOMReady (and window load events) to
  28   * fire normally.  That configuration option is 'injected' -- set
  29   * it to true if the yui.js script is not included inline.
  30   *
  31   * This method is part of the 'event-ready' module, which is a
  32   * submodule of 'event'.
  33   *
  34   * @event domready
  35   * @for YUI
  36   */
  37  Y.publish('domready', {
  38      fireOnce: true,
  39      async: true
  40  });
  41  
  42  if (YUI.Env.DOMReady) {
  43      Y.fire('domready');
  44  } else {
  45      Y.Do.before(function() { Y.fire('domready'); }, YUI.Env, '_ready');
  46  }
  47  
  48  /**
  49   * Custom event engine, DOM event listener abstraction layer, synthetic DOM
  50   * events.
  51   * @module event
  52   * @submodule event-base
  53   */
  54  
  55  /**
  56   * Wraps a DOM event, properties requiring browser abstraction are
  57   * fixed here.  Provids a security layer when required.
  58   * @class DOMEventFacade
  59   * @param ev {Event} the DOM event
  60   * @param currentTarget {HTMLElement} the element the listener was attached to
  61   * @param wrapper {CustomEvent} the custom event wrapper for this DOM event
  62   */
  63  
  64      var ua = Y.UA,
  65  
  66      EMPTY = {},
  67  
  68      /**
  69       * webkit key remapping required for Safari < 3.1
  70       * @property webkitKeymap
  71       * @private
  72       */
  73      webkitKeymap = {
  74          63232: 38, // up
  75          63233: 40, // down
  76          63234: 37, // left
  77          63235: 39, // right
  78          63276: 33, // page up
  79          63277: 34, // page down
  80          25:     9, // SHIFT-TAB (Safari provides a different key code in
  81                     // this case, even though the shiftKey modifier is set)
  82          63272: 46, // delete
  83          63273: 36, // home
  84          63275: 35  // end
  85      },
  86  
  87      /**
  88       * Returns a wrapped node.  Intended to be used on event targets,
  89       * so it will return the node's parent if the target is a text
  90       * node.
  91       *
  92       * If accessing a property of the node throws an error, this is
  93       * probably the anonymous div wrapper Gecko adds inside text
  94       * nodes.  This likely will only occur when attempting to access
  95       * the relatedTarget.  In this case, we now return null because
  96       * the anonymous div is completely useless and we do not know
  97       * what the related target was because we can't even get to
  98       * the element's parent node.
  99       *
 100       * @method resolve
 101       * @private
 102       */
 103      resolve = function(n) {
 104          if (!n) {
 105              return n;
 106          }
 107          try {
 108              if (n && 3 == n.nodeType) {
 109                  n = n.parentNode;
 110              }
 111          } catch(e) {
 112              return null;
 113          }
 114  
 115          return Y.one(n);
 116      },
 117  
 118      DOMEventFacade = function(ev, currentTarget, wrapper) {
 119          this._event = ev;
 120          this._currentTarget = currentTarget;
 121          this._wrapper = wrapper || EMPTY;
 122  
 123          // if not lazy init
 124          this.init();
 125      };
 126  
 127  Y.extend(DOMEventFacade, Object, {
 128  
 129      init: function() {
 130  
 131          var e = this._event,
 132              overrides = this._wrapper.overrides,
 133              x = e.pageX,
 134              y = e.pageY,
 135              c,
 136              currentTarget = this._currentTarget;
 137  
 138          this.altKey   = e.altKey;
 139          this.ctrlKey  = e.ctrlKey;
 140          this.metaKey  = e.metaKey;
 141          this.shiftKey = e.shiftKey;
 142          this.type     = (overrides && overrides.type) || e.type;
 143          this.clientX  = e.clientX;
 144          this.clientY  = e.clientY;
 145  
 146          this.pageX = x;
 147          this.pageY = y;
 148  
 149          // charCode is unknown in keyup, keydown. keyCode is unknown in keypress.
 150          // FF 3.6 - 8+? pass 0 for keyCode in keypress events.
 151          // Webkit, FF 3.6-8+?, and IE9+? pass 0 for charCode in keydown, keyup.
 152          // Webkit and IE9+? duplicate charCode in keyCode.
 153          // Opera never sets charCode, always keyCode (though with the charCode).
 154          // IE6-8 don't set charCode or which.
 155          // All browsers other than IE6-8 set which=keyCode in keydown, keyup, and
 156          // which=charCode in keypress.
 157          //
 158          // Moral of the story: (e.which || e.keyCode) will always return the
 159          // known code for that key event phase. e.keyCode is often different in
 160          // keypress from keydown and keyup.
 161          c = e.keyCode || e.charCode;
 162  
 163          if (ua.webkit && (c in webkitKeymap)) {
 164              c = webkitKeymap[c];
 165          }
 166  
 167          this.keyCode = c;
 168          this.charCode = c;
 169          // Fill in e.which for IE - implementers should always use this over
 170          // e.keyCode or e.charCode.
 171          this.which = e.which || e.charCode || c;
 172          // this.button = e.button;
 173          this.button = this.which;
 174  
 175          this.target = resolve(e.target);
 176          this.currentTarget = resolve(currentTarget);
 177          this.relatedTarget = resolve(e.relatedTarget);
 178  
 179          if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
 180              this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
 181          }
 182  
 183          if (this._touch) {
 184              this._touch(e, currentTarget, this._wrapper);
 185          }
 186      },
 187  
 188      stopPropagation: function() {
 189          this._event.stopPropagation();
 190          this._wrapper.stopped = 1;
 191          this.stopped = 1;
 192      },
 193  
 194      stopImmediatePropagation: function() {
 195          var e = this._event;
 196          if (e.stopImmediatePropagation) {
 197              e.stopImmediatePropagation();
 198          } else {
 199              this.stopPropagation();
 200          }
 201          this._wrapper.stopped = 2;
 202          this.stopped = 2;
 203      },
 204  
 205      preventDefault: function(returnValue) {
 206          var e = this._event;
 207          e.preventDefault();
 208          if (returnValue) {
 209              e.returnValue = returnValue;
 210          }
 211          this._wrapper.prevented = 1;
 212          this.prevented = 1;
 213      },
 214  
 215      halt: function(immediate) {
 216          if (immediate) {
 217              this.stopImmediatePropagation();
 218          } else {
 219              this.stopPropagation();
 220          }
 221  
 222          this.preventDefault();
 223      }
 224  
 225  });
 226  
 227  DOMEventFacade.resolve = resolve;
 228  Y.DOM2EventFacade = DOMEventFacade;
 229  Y.DOMEventFacade = DOMEventFacade;
 230  
 231      /**
 232       * The native event
 233       * @property _event
 234       * @type {DOMEvent}
 235       * @private
 236       */
 237  
 238      /**
 239      The name of the event (e.g. "click")
 240  
 241      @property type
 242      @type {String}
 243      **/
 244  
 245      /**
 246      `true` if the "alt" or "option" key is pressed.
 247  
 248      @property altKey
 249      @type {Boolean}
 250      **/
 251  
 252      /**
 253      `true` if the shift key is pressed.
 254  
 255      @property shiftKey
 256      @type {Boolean}
 257      **/
 258  
 259      /**
 260      `true` if the "Windows" key on a Windows keyboard, "command" key on an
 261      Apple keyboard, or "meta" key on other keyboards is pressed.
 262  
 263      @property metaKey
 264      @type {Boolean}
 265      **/
 266  
 267      /**
 268      `true` if the "Ctrl" or "control" key is pressed.
 269  
 270      @property ctrlKey
 271      @type {Boolean}
 272      **/
 273  
 274      /**
 275       * The X location of the event on the page (including scroll)
 276       * @property pageX
 277       * @type {Number}
 278       */
 279  
 280      /**
 281       * The Y location of the event on the page (including scroll)
 282       * @property pageY
 283       * @type {Number}
 284       */
 285  
 286      /**
 287       * The X location of the event in the viewport
 288       * @property clientX
 289       * @type {Number}
 290       */
 291  
 292      /**
 293       * The Y location of the event in the viewport
 294       * @property clientY
 295       * @type {Number}
 296       */
 297  
 298      /**
 299       * The keyCode for key events.  Uses charCode if keyCode is not available
 300       * @property keyCode
 301       * @type {Number}
 302       */
 303  
 304      /**
 305       * The charCode for key events.  Same as keyCode
 306       * @property charCode
 307       * @type {Number}
 308       */
 309  
 310      /**
 311       * The button that was pushed. 1 for left click, 2 for middle click, 3 for
 312       * right click.  This is only reliably populated on `mouseup` events.
 313       * @property button
 314       * @type {Number}
 315       */
 316  
 317      /**
 318       * The button that was pushed.  Same as button.
 319       * @property which
 320       * @type {Number}
 321       */
 322  
 323      /**
 324       * Node reference for the targeted element
 325       * @property target
 326       * @type {Node}
 327       */
 328  
 329      /**
 330       * Node reference for the element that the listener was attached to.
 331       * @property currentTarget
 332       * @type {Node}
 333       */
 334  
 335      /**
 336       * Node reference to the relatedTarget
 337       * @property relatedTarget
 338       * @type {Node}
 339       */
 340  
 341      /**
 342       * Number representing the direction and velocity of the movement of the mousewheel.
 343       * Negative is down, the higher the number, the faster.  Applies to the mousewheel event.
 344       * @property wheelDelta
 345       * @type {Number}
 346       */
 347  
 348      /**
 349       * Stops the propagation to the next bubble target
 350       * @method stopPropagation
 351       */
 352  
 353      /**
 354       * Stops the propagation to the next bubble target and
 355       * prevents any additional listeners from being exectued
 356       * on the current target.
 357       * @method stopImmediatePropagation
 358       */
 359  
 360      /**
 361       * Prevents the event's default behavior
 362       * @method preventDefault
 363       * @param returnValue {string} sets the returnValue of the event to this value
 364       * (rather than the default false value).  This can be used to add a customized
 365       * confirmation query to the beforeunload event).
 366       */
 367  
 368      /**
 369       * Stops the event propagation and prevents the default
 370       * event behavior.
 371       * @method halt
 372       * @param immediate {boolean} if true additional listeners
 373       * on the current target will not be executed
 374       */
 375  (function() {
 376  
 377  /**
 378   * The event utility provides functions to add and remove event listeners,
 379   * event cleansing.  It also tries to automatically remove listeners it
 380   * registers during the unload event.
 381   * @module event
 382   * @main event
 383   * @submodule event-base
 384   */
 385  
 386  /**
 387   * The event utility provides functions to add and remove event listeners,
 388   * event cleansing.  It also tries to automatically remove listeners it
 389   * registers during the unload event.
 390   *
 391   * @class Event
 392   * @static
 393   */
 394  
 395  Y.Env.evt.dom_wrappers = {};
 396  Y.Env.evt.dom_map = {};
 397  
 398  var _eventenv = Y.Env.evt,
 399      config = Y.config,
 400      win = config.win,
 401      add = YUI.Env.add,
 402      remove = YUI.Env.remove,
 403  
 404      onLoad = function() {
 405          YUI.Env.windowLoaded = true;
 406          Y.Event._load();
 407          remove(win, "load", onLoad);
 408      },
 409  
 410      onUnload = function() {
 411          Y.Event._unload();
 412      },
 413  
 414      EVENT_READY = 'domready',
 415  
 416      COMPAT_ARG = '~yui|2|compat~',
 417  
 418      shouldIterate = function(o) {
 419          try {
 420              // TODO: See if there's a more performant way to return true early on this, for the common case
 421              return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) && !o.tagName && !Y.DOM.isWindow(o));
 422          } catch(ex) {
 423              return false;
 424          }
 425      },
 426  
 427      // aliases to support DOM event subscription clean up when the last
 428      // subscriber is detached. deleteAndClean overrides the DOM event's wrapper
 429      // CustomEvent _delete method.
 430      _ceProtoDelete = Y.CustomEvent.prototype._delete,
 431      _deleteAndClean = function(s) {
 432          var ret = _ceProtoDelete.apply(this, arguments);
 433  
 434          if (!this.hasSubs()) {
 435              Y.Event._clean(this);
 436          }
 437  
 438          return ret;
 439      },
 440  
 441  Event = function() {
 442  
 443      /**
 444       * True after the onload event has fired
 445       * @property _loadComplete
 446       * @type boolean
 447       * @static
 448       * @private
 449       */
 450      var _loadComplete =  false,
 451  
 452      /**
 453       * The number of times to poll after window.onload.  This number is
 454       * increased if additional late-bound handlers are requested after
 455       * the page load.
 456       * @property _retryCount
 457       * @static
 458       * @private
 459       */
 460      _retryCount = 0,
 461  
 462      /**
 463       * onAvailable listeners
 464       * @property _avail
 465       * @static
 466       * @private
 467       */
 468      _avail = [],
 469  
 470      /**
 471       * Custom event wrappers for DOM events.  Key is
 472       * 'event:' + Element uid stamp + event type
 473       * @property _wrappers
 474       * @type CustomEvent
 475       * @static
 476       * @private
 477       */
 478      _wrappers = _eventenv.dom_wrappers,
 479  
 480      _windowLoadKey = null,
 481  
 482      /**
 483       * Custom event wrapper map DOM events.  Key is
 484       * Element uid stamp.  Each item is a hash of custom event
 485       * wrappers as provided in the _wrappers collection.  This
 486       * provides the infrastructure for getListeners.
 487       * @property _el_events
 488       * @static
 489       * @private
 490       */
 491      _el_events = _eventenv.dom_map;
 492  
 493      return {
 494  
 495          /**
 496           * The number of times we should look for elements that are not
 497           * in the DOM at the time the event is requested after the document
 498           * has been loaded.  The default is 1000@amp;40 ms, so it will poll
 499           * for 40 seconds or until all outstanding handlers are bound
 500           * (whichever comes first).
 501           * @property POLL_RETRYS
 502           * @type int
 503           * @static
 504           * @final
 505           */
 506          POLL_RETRYS: 1000,
 507  
 508          /**
 509           * The poll interval in milliseconds
 510           * @property POLL_INTERVAL
 511           * @type int
 512           * @static
 513           * @final
 514           */
 515          POLL_INTERVAL: 40,
 516  
 517          /**
 518           * addListener/removeListener can throw errors in unexpected scenarios.
 519           * These errors are suppressed, the method returns false, and this property
 520           * is set
 521           * @property lastError
 522           * @static
 523           * @type Error
 524           */
 525          lastError: null,
 526  
 527  
 528          /**
 529           * poll handle
 530           * @property _interval
 531           * @static
 532           * @private
 533           */
 534          _interval: null,
 535  
 536          /**
 537           * document readystate poll handle
 538           * @property _dri
 539           * @static
 540           * @private
 541           */
 542           _dri: null,
 543  
 544          /**
 545           * True when the document is initially usable
 546           * @property DOMReady
 547           * @type boolean
 548           * @static
 549           */
 550          DOMReady: false,
 551  
 552          /**
 553           * @method startInterval
 554           * @static
 555           * @private
 556           */
 557          startInterval: function() {
 558              if (!Event._interval) {
 559  Event._interval = setInterval(Event._poll, Event.POLL_INTERVAL);
 560              }
 561          },
 562  
 563          /**
 564           * Executes the supplied callback when the item with the supplied
 565           * id is found.  This is meant to be used to execute behavior as
 566           * soon as possible as the page loads.  If you use this after the
 567           * initial page load it will poll for a fixed time for the element.
 568           * The number of times it will poll and the frequency are
 569           * configurable.  By default it will poll for 10 seconds.
 570           *
 571           * <p>The callback is executed with a single parameter:
 572           * the custom object parameter, if provided.</p>
 573           *
 574           * @method onAvailable
 575           *
 576           * @param {string||string[]}   id the id of the element, or an array
 577           * of ids to look for.
 578           * @param {function} fn what to execute when the element is found.
 579           * @param {object}   p_obj an optional object to be passed back as
 580           *                   a parameter to fn.
 581           * @param {boolean|object}  p_override If set to true, fn will execute
 582           *                   in the context of p_obj, if set to an object it
 583           *                   will execute in the context of that object
 584           * @param checkContent {boolean} check child node readiness (onContentReady)
 585           * @static
 586           * @deprecated Use Y.on("available")
 587           */
 588          // @TODO fix arguments
 589          onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
 590  
 591              var a = Y.Array(id), i, availHandle;
 592  
 593              for (i=0; i<a.length; i=i+1) {
 594                  _avail.push({
 595                      id:         a[i],
 596                      fn:         fn,
 597                      obj:        p_obj,
 598                      override:   p_override,
 599                      checkReady: checkContent,
 600                      compat:     compat
 601                  });
 602              }
 603              _retryCount = this.POLL_RETRYS;
 604  
 605              // We want the first test to be immediate, but async
 606              setTimeout(Event._poll, 0);
 607  
 608              availHandle = new Y.EventHandle({
 609  
 610                  _delete: function() {
 611                      // set by the event system for lazy DOM listeners
 612                      if (availHandle.handle) {
 613                          availHandle.handle.detach();
 614                          return;
 615                      }
 616  
 617                      var i, j;
 618  
 619                      // otherwise try to remove the onAvailable listener(s)
 620                      for (i = 0; i < a.length; i++) {
 621                          for (j = 0; j < _avail.length; j++) {
 622                              if (a[i] === _avail[j].id) {
 623                                  _avail.splice(j, 1);
 624                              }
 625                          }
 626                      }
 627                  }
 628  
 629              });
 630  
 631              return availHandle;
 632          },
 633  
 634          /**
 635           * Works the same way as onAvailable, but additionally checks the
 636           * state of sibling elements to determine if the content of the
 637           * available element is safe to modify.
 638           *
 639           * <p>The callback is executed with a single parameter:
 640           * the custom object parameter, if provided.</p>
 641           *
 642           * @method onContentReady
 643           *
 644           * @param {string}   id the id of the element to look for.
 645           * @param {function} fn what to execute when the element is ready.
 646           * @param {object}   obj an optional object to be passed back as
 647           *                   a parameter to fn.
 648           * @param {boolean|object}  override If set to true, fn will execute
 649           *                   in the context of p_obj.  If an object, fn will
 650           *                   exectute in the context of that object
 651           *
 652           * @static
 653           * @deprecated Use Y.on("contentready")
 654           */
 655          // @TODO fix arguments
 656          onContentReady: function(id, fn, obj, override, compat) {
 657              return Event.onAvailable(id, fn, obj, override, true, compat);
 658          },
 659  
 660          /**
 661           * Adds an event listener
 662           *
 663           * @method attach
 664           *
 665           * @param {String}   type     The type of event to append
 666           * @param {Function} fn        The method the event invokes
 667           * @param {String|HTMLElement|Array|NodeList} el An id, an element
 668           *  reference, or a collection of ids and/or elements to assign the
 669           *  listener to.
 670           * @param {Object}   context optional context object
 671           * @param {Boolean|object}  args 0..n arguments to pass to the callback
 672           * @return {EventHandle} an object to that can be used to detach the listener
 673           *
 674           * @static
 675           */
 676  
 677          attach: function(type, fn, el, context) {
 678              return Event._attach(Y.Array(arguments, 0, true));
 679          },
 680  
 681          _createWrapper: function (el, type, capture, compat, facade) {
 682  
 683              var cewrapper,
 684                  ek  = Y.stamp(el),
 685                  key = 'event:' + ek + type;
 686  
 687              if (false === facade) {
 688                  key += 'native';
 689              }
 690              if (capture) {
 691                  key += 'capture';
 692              }
 693  
 694  
 695              cewrapper = _wrappers[key];
 696  
 697  
 698              if (!cewrapper) {
 699                  // create CE wrapper
 700                  cewrapper = Y.publish(key, {
 701                      silent: true,
 702                      bubbles: false,
 703                      emitFacade:false,
 704                      contextFn: function() {
 705                          if (compat) {
 706                              return cewrapper.el;
 707                          } else {
 708                              cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
 709                              return cewrapper.nodeRef;
 710                          }
 711                      }
 712                  });
 713  
 714                  cewrapper.overrides = {};
 715  
 716                  // for later removeListener calls
 717                  cewrapper.el = el;
 718                  cewrapper.key = key;
 719                  cewrapper.domkey = ek;
 720                  cewrapper.type = type;
 721                  cewrapper.fn = function(e) {
 722                      cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade))));
 723                  };
 724                  cewrapper.capture = capture;
 725  
 726                  if (el == win && type == "load") {
 727                      // window load happens once
 728                      cewrapper.fireOnce = true;
 729                      _windowLoadKey = key;
 730                  }
 731                  cewrapper._delete = _deleteAndClean;
 732  
 733                  _wrappers[key] = cewrapper;
 734                  _el_events[ek] = _el_events[ek] || {};
 735                  _el_events[ek][key] = cewrapper;
 736  
 737                  add(el, type, cewrapper.fn, capture);
 738              }
 739  
 740              return cewrapper;
 741  
 742          },
 743  
 744          _attach: function(args, conf) {
 745  
 746              var compat,
 747                  handles, oEl, cewrapper, context,
 748                  fireNow = false, ret,
 749                  type = args[0],
 750                  fn = args[1],
 751                  el = args[2] || win,
 752                  facade = conf && conf.facade,
 753                  capture = conf && conf.capture,
 754                  overrides = conf && conf.overrides;
 755  
 756              if (args[args.length-1] === COMPAT_ARG) {
 757                  compat = true;
 758              }
 759  
 760              if (!fn || !fn.call) {
 761                  return false;
 762              }
 763  
 764              // The el argument can be an array of elements or element ids.
 765              if (shouldIterate(el)) {
 766  
 767                  handles=[];
 768  
 769                  Y.each(el, function(v, k) {
 770                      args[2] = v;
 771                      handles.push(Event._attach(args.slice(), conf));
 772                  });
 773  
 774                  // return (handles.length === 1) ? handles[0] : handles;
 775                  return new Y.EventHandle(handles);
 776  
 777              // If the el argument is a string, we assume it is
 778              // actually the id of the element.  If the page is loaded
 779              // we convert el to the actual element, otherwise we
 780              // defer attaching the event until the element is
 781              // ready
 782              } else if (Y.Lang.isString(el)) {
 783  
 784                  // oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
 785  
 786                  if (compat) {
 787                      oEl = Y.DOM.byId(el);
 788                  } else {
 789  
 790                      oEl = Y.Selector.query(el);
 791  
 792                      switch (oEl.length) {
 793                          case 0:
 794                              oEl = null;
 795                              break;
 796                          case 1:
 797                              oEl = oEl[0];
 798                              break;
 799                          default:
 800                              args[2] = oEl;
 801                              return Event._attach(args, conf);
 802                      }
 803                  }
 804  
 805                  if (oEl) {
 806  
 807                      el = oEl;
 808  
 809                  // Not found = defer adding the event until the element is available
 810                  } else {
 811  
 812                      ret = Event.onAvailable(el, function() {
 813  
 814                          ret.handle = Event._attach(args, conf);
 815  
 816                      }, Event, true, false, compat);
 817  
 818                      return ret;
 819  
 820                  }
 821              }
 822  
 823              // Element should be an html element or node
 824              if (!el) {
 825                  return false;
 826              }
 827  
 828              if (Y.Node && Y.instanceOf(el, Y.Node)) {
 829                  el = Y.Node.getDOMNode(el);
 830              }
 831  
 832              cewrapper = Event._createWrapper(el, type, capture, compat, facade);
 833              if (overrides) {
 834                  Y.mix(cewrapper.overrides, overrides);
 835              }
 836  
 837              if (el == win && type == "load") {
 838  
 839                  // if the load is complete, fire immediately.
 840                  // all subscribers, including the current one
 841                  // will be notified.
 842                  if (YUI.Env.windowLoaded) {
 843                      fireNow = true;
 844                  }
 845              }
 846  
 847              if (compat) {
 848                  args.pop();
 849              }
 850  
 851              context = args[3];
 852  
 853              // set context to the Node if not specified
 854              // ret = cewrapper.on.apply(cewrapper, trimmedArgs);
 855              ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
 856  
 857              if (fireNow) {
 858                  cewrapper.fire();
 859              }
 860  
 861              return ret;
 862  
 863          },
 864  
 865          /**
 866           * Removes an event listener.  Supports the signature the event was bound
 867           * with, but the preferred way to remove listeners is using the handle
 868           * that is returned when using Y.on
 869           *
 870           * @method detach
 871           *
 872           * @param {String} type the type of event to remove.
 873           * @param {Function} fn the method the event invokes.  If fn is
 874           * undefined, then all event handlers for the type of event are
 875           * removed.
 876           * @param {String|HTMLElement|Array|NodeList|EventHandle} el An
 877           * event handle, an id, an element reference, or a collection
 878           * of ids and/or elements to remove the listener from.
 879           * @return {boolean} true if the unbind was successful, false otherwise.
 880           * @static
 881           */
 882          detach: function(type, fn, el, obj) {
 883  
 884              var args=Y.Array(arguments, 0, true), compat, l, ok, i,
 885                  id, ce;
 886  
 887              if (args[args.length-1] === COMPAT_ARG) {
 888                  compat = true;
 889                  // args.pop();
 890              }
 891  
 892              if (type && type.detach) {
 893                  return type.detach();
 894              }
 895  
 896              // The el argument can be a string
 897              if (typeof el == "string") {
 898  
 899                  // el = (compat) ? Y.DOM.byId(el) : Y.all(el);
 900                  if (compat) {
 901                      el = Y.DOM.byId(el);
 902                  } else {
 903                      el = Y.Selector.query(el);
 904                      l = el.length;
 905                      if (l < 1) {
 906                          el = null;
 907                      } else if (l == 1) {
 908                          el = el[0];
 909                      }
 910                  }
 911                  // return Event.detach.apply(Event, args);
 912              }
 913  
 914              if (!el) {
 915                  return false;
 916              }
 917  
 918              if (el.detach) {
 919                  args.splice(2, 1);
 920                  return el.detach.apply(el, args);
 921              // The el argument can be an array of elements or element ids.
 922              } else if (shouldIterate(el)) {
 923                  ok = true;
 924                  for (i=0, l=el.length; i<l; ++i) {
 925                      args[2] = el[i];
 926                      ok = ( Y.Event.detach.apply(Y.Event, args) && ok );
 927                  }
 928  
 929                  return ok;
 930              }
 931  
 932              if (!type || !fn || !fn.call) {
 933                  return Event.purgeElement(el, false, type);
 934              }
 935  
 936              id = 'event:' + Y.stamp(el) + type;
 937              ce = _wrappers[id];
 938  
 939              if (ce) {
 940                  return ce.detach(fn);
 941              } else {
 942                  return false;
 943              }
 944  
 945          },
 946  
 947          /**
 948           * Finds the event in the window object, the caller's arguments, or
 949           * in the arguments of another method in the callstack.  This is
 950           * executed automatically for events registered through the event
 951           * manager, so the implementer should not normally need to execute
 952           * this function at all.
 953           * @method getEvent
 954           * @param {Event} e the event parameter from the handler
 955           * @param {HTMLElement} el the element the listener was attached to
 956           * @return {Event} the event
 957           * @static
 958           */
 959          getEvent: function(e, el, noFacade) {
 960              var ev = e || win.event;
 961  
 962              return (noFacade) ? ev :
 963                  new Y.DOMEventFacade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]);
 964          },
 965  
 966          /**
 967           * Generates an unique ID for the element if it does not already
 968           * have one.
 969           * @method generateId
 970           * @param el the element to create the id for
 971           * @return {string} the resulting id of the element
 972           * @static
 973           */
 974          generateId: function(el) {
 975              return Y.DOM.generateID(el);
 976          },
 977  
 978          /**
 979           * We want to be able to use getElementsByTagName as a collection
 980           * to attach a group of events to.  Unfortunately, different
 981           * browsers return different types of collections.  This function
 982           * tests to determine if the object is array-like.  It will also
 983           * fail if the object is an array, but is empty.
 984           * @method _isValidCollection
 985           * @param o the object to test
 986           * @return {boolean} true if the object is array-like and populated
 987           * @deprecated was not meant to be used directly
 988           * @static
 989           * @private
 990           */
 991          _isValidCollection: shouldIterate,
 992  
 993          /**
 994           * hook up any deferred listeners
 995           * @method _load
 996           * @static
 997           * @private
 998           */
 999          _load: function(e) {
1000              if (!_loadComplete) {
1001                  _loadComplete = true;
1002  
1003                  // Just in case DOMReady did not go off for some reason
1004                  // E._ready();
1005                  if (Y.fire) {
1006                      Y.fire(EVENT_READY);
1007                  }
1008  
1009                  // Available elements may not have been detected before the
1010                  // window load event fires. Try to find them now so that the
1011                  // the user is more likely to get the onAvailable notifications
1012                  // before the window load notification
1013                  Event._poll();
1014              }
1015          },
1016  
1017          /**
1018           * Polling function that runs before the onload event fires,
1019           * attempting to attach to DOM Nodes as soon as they are
1020           * available
1021           * @method _poll
1022           * @static
1023           * @private
1024           */
1025          _poll: function() {
1026              if (Event.locked) {
1027                  return;
1028              }
1029  
1030              if (Y.UA.ie && !YUI.Env.DOMReady) {
1031                  // Hold off if DOMReady has not fired and check current
1032                  // readyState to protect against the IE operation aborted
1033                  // issue.
1034                  Event.startInterval();
1035                  return;
1036              }
1037  
1038              Event.locked = true;
1039  
1040              // keep trying until after the page is loaded.  We need to
1041              // check the page load state prior to trying to bind the
1042              // elements so that we can be certain all elements have been
1043              // tested appropriately
1044              var i, len, item, el, notAvail, executeItem,
1045                  tryAgain = !_loadComplete;
1046  
1047              if (!tryAgain) {
1048                  tryAgain = (_retryCount > 0);
1049              }
1050  
1051              // onAvailable
1052              notAvail = [];
1053  
1054              executeItem = function (el, item) {
1055                  var context, ov = item.override;
1056                  try {
1057                      if (item.compat) {
1058                          if (item.override) {
1059                              if (ov === true) {
1060                                  context = item.obj;
1061                              } else {
1062                                  context = ov;
1063                              }
1064                          } else {
1065                              context = el;
1066                          }
1067                          item.fn.call(context, item.obj);
1068                      } else {
1069                          context = item.obj || Y.one(el);
1070                          item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
1071                      }
1072                  } catch (e) {
1073                  }
1074              };
1075  
1076              // onAvailable
1077              for (i=0,len=_avail.length; i<len; ++i) {
1078                  item = _avail[i];
1079                  if (item && !item.checkReady) {
1080  
1081                      // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
1082                      el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
1083  
1084                      if (el) {
1085                          executeItem(el, item);
1086                          _avail[i] = null;
1087                      } else {
1088                          notAvail.push(item);
1089                      }
1090                  }
1091              }
1092  
1093              // onContentReady
1094              for (i=0,len=_avail.length; i<len; ++i) {
1095                  item = _avail[i];
1096                  if (item && item.checkReady) {
1097  
1098                      // el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
1099                      el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
1100  
1101                      if (el) {
1102                          // The element is available, but not necessarily ready
1103                          // @todo should we test parentNode.nextSibling?
1104                          if (_loadComplete || (el.get && el.get('nextSibling')) || el.nextSibling) {
1105                              executeItem(el, item);
1106                              _avail[i] = null;
1107                          }
1108                      } else {
1109                          notAvail.push(item);
1110                      }
1111                  }
1112              }
1113  
1114              _retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1;
1115  
1116              if (tryAgain) {
1117                  // we may need to strip the nulled out items here
1118                  Event.startInterval();
1119              } else {
1120                  clearInterval(Event._interval);
1121                  Event._interval = null;
1122              }
1123  
1124              Event.locked = false;
1125  
1126              return;
1127  
1128          },
1129  
1130          /**
1131           * Removes all listeners attached to the given element via addListener.
1132           * Optionally, the node's children can also be purged.
1133           * Optionally, you can specify a specific type of event to remove.
1134           * @method purgeElement
1135           * @param {HTMLElement} el the element to purge
1136           * @param {boolean} recurse recursively purge this element's children
1137           * as well.  Use with caution.
1138           * @param {string} type optional type of listener to purge. If
1139           * left out, all listeners will be removed
1140           * @static
1141           */
1142          purgeElement: function(el, recurse, type) {
1143              // var oEl = (Y.Lang.isString(el)) ? Y.one(el) : el,
1144              var oEl = (Y.Lang.isString(el)) ?  Y.Selector.query(el, null, true) : el,
1145                  lis = Event.getListeners(oEl, type), i, len, children, child;
1146  
1147              if (recurse && oEl) {
1148                  lis = lis || [];
1149                  children = Y.Selector.query('*', oEl);
1150                  len = children.length;
1151                  for (i = 0; i < len; ++i) {
1152                      child = Event.getListeners(children[i], type);
1153                      if (child) {
1154                          lis = lis.concat(child);
1155                      }
1156                  }
1157              }
1158  
1159              if (lis) {
1160                  for (i = 0, len = lis.length; i < len; ++i) {
1161                      lis[i].detachAll();
1162                  }
1163              }
1164  
1165          },
1166  
1167          /**
1168           * Removes all object references and the DOM proxy subscription for
1169           * a given event for a DOM node.
1170           *
1171           * @method _clean
1172           * @param wrapper {CustomEvent} Custom event proxy for the DOM
1173           *                  subscription
1174           * @private
1175           * @static
1176           * @since 3.4.0
1177           */
1178          _clean: function (wrapper) {
1179              var key    = wrapper.key,
1180                  domkey = wrapper.domkey;
1181  
1182              remove(wrapper.el, wrapper.type, wrapper.fn, wrapper.capture);
1183              delete _wrappers[key];
1184              delete Y._yuievt.events[key];
1185              if (_el_events[domkey]) {
1186                  delete _el_events[domkey][key];
1187                  if (!Y.Object.size(_el_events[domkey])) {
1188                      delete _el_events[domkey];
1189                  }
1190              }
1191          },
1192  
1193          /**
1194           * Returns all listeners attached to the given element via addListener.
1195           * Optionally, you can specify a specific type of event to return.
1196           * @method getListeners
1197           * @param el {HTMLElement|string} the element or element id to inspect
1198           * @param type {string} optional type of listener to return. If
1199           * left out, all listeners will be returned
1200           * @return {CustomEvent} the custom event wrapper for the DOM event(s)
1201           * @static
1202           */
1203          getListeners: function(el, type) {
1204              var ek = Y.stamp(el, true), evts = _el_events[ek],
1205                  results=[] , key = (type) ? 'event:' + ek + type : null,
1206                  adapters = _eventenv.plugins;
1207  
1208              if (!evts) {
1209                  return null;
1210              }
1211  
1212              if (key) {
1213                  // look for synthetic events
1214                  if (adapters[type] && adapters[type].eventDef) {
1215                      key += '_synth';
1216                  }
1217  
1218                  if (evts[key]) {
1219                      results.push(evts[key]);
1220                  }
1221  
1222                  // get native events as well
1223                  key += 'native';
1224                  if (evts[key]) {
1225                      results.push(evts[key]);
1226                  }
1227  
1228              } else {
1229                  Y.each(evts, function(v, k) {
1230                      results.push(v);
1231                  });
1232              }
1233  
1234              return (results.length) ? results : null;
1235          },
1236  
1237          /**
1238           * Removes all listeners registered by pe.event.  Called
1239           * automatically during the unload event.
1240           * @method _unload
1241           * @static
1242           * @private
1243           */
1244          _unload: function(e) {
1245              Y.each(_wrappers, function(v, k) {
1246                  if (v.type == 'unload') {
1247                      v.fire(e);
1248                  }
1249                  v.detachAll();
1250              });
1251              remove(win, "unload", onUnload);
1252          },
1253  
1254          /**
1255           * Adds a DOM event directly without the caching, cleanup, context adj, etc
1256           *
1257           * @method nativeAdd
1258           * @param {HTMLElement} el      the element to bind the handler to
1259           * @param {string}      type   the type of event handler
1260           * @param {function}    fn      the callback to invoke
1261           * @param {Boolean}      capture capture or bubble phase
1262           * @static
1263           * @private
1264           */
1265          nativeAdd: add,
1266  
1267          /**
1268           * Basic remove listener
1269           *
1270           * @method nativeRemove
1271           * @param {HTMLElement} el      the element to bind the handler to
1272           * @param {string}      type   the type of event handler
1273           * @param {function}    fn      the callback to invoke
1274           * @param {Boolean}      capture capture or bubble phase
1275           * @static
1276           * @private
1277           */
1278          nativeRemove: remove
1279      };
1280  
1281  }();
1282  
1283  Y.Event = Event;
1284  
1285  if (config.injected || YUI.Env.windowLoaded) {
1286      onLoad();
1287  } else {
1288      add(win, "load", onLoad);
1289  }
1290  
1291  // Process onAvailable/onContentReady items when when the DOM is ready in IE
1292  if (Y.UA.ie) {
1293      Y.on(EVENT_READY, Event._poll);
1294  
1295      // In IE6 and below, detach event handlers when the page is unloaded in
1296      // order to try and prevent cross-page memory leaks. This isn't done in
1297      // other browsers because a) it's not necessary, and b) it breaks the
1298      // back/forward cache.
1299      if (Y.UA.ie < 7) {
1300          try {
1301              add(win, "unload", onUnload);
1302          } catch(e) {
1303          }
1304      }
1305  }
1306  
1307  Event.Custom = Y.CustomEvent;
1308  Event.Subscriber = Y.Subscriber;
1309  Event.Target = Y.EventTarget;
1310  Event.Handle = Y.EventHandle;
1311  Event.Facade = Y.EventFacade;
1312  
1313  Event._poll();
1314  
1315  }());
1316  
1317  /**
1318   * DOM event listener abstraction layer
1319   * @module event
1320   * @submodule event-base
1321   */
1322  
1323  /**
1324   * Executes the callback as soon as the specified element
1325   * is detected in the DOM.  This function expects a selector
1326   * string for the element(s) to detect.  If you already have
1327   * an element reference, you don't need this event.
1328   * @event available
1329   * @param type {string} 'available'
1330   * @param fn {function} the callback function to execute.
1331   * @param el {string} an selector for the element(s) to attach
1332   * @param context optional argument that specifies what 'this' refers to.
1333   * @param args* 0..n additional arguments to pass on to the callback function.
1334   * These arguments will be added after the event object.
1335   * @return {EventHandle} the detach handle
1336   * @for YUI
1337   */
1338  Y.Env.evt.plugins.available = {
1339      on: function(type, fn, id, o) {
1340          var a = arguments.length > 4 ?  Y.Array(arguments, 4, true) : null;
1341          return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
1342      }
1343  };
1344  
1345  /**
1346   * Executes the callback as soon as the specified element
1347   * is detected in the DOM with a nextSibling property
1348   * (indicating that the element's children are available).
1349   * This function expects a selector
1350   * string for the element(s) to detect.  If you already have
1351   * an element reference, you don't need this event.
1352   * @event contentready
1353   * @param type {string} 'contentready'
1354   * @param fn {function} the callback function to execute.
1355   * @param el {string} an selector for the element(s) to attach.
1356   * @param context optional argument that specifies what 'this' refers to.
1357   * @param args* 0..n additional arguments to pass on to the callback function.
1358   * These arguments will be added after the event object.
1359   * @return {EventHandle} the detach handle
1360   * @for YUI
1361   */
1362  Y.Env.evt.plugins.contentready = {
1363      on: function(type, fn, id, o) {
1364          var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null;
1365          return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
1366      }
1367  };
1368  
1369  
1370  }, '3.17.2', {"requires": ["event-custom-base"]});


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