[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-event/ -> yui2-event-debug.js (source)

   1  YUI.add('yui2-event', function(Y) {
   2      var YAHOO    = Y.YUI2;
   3      /*
   4  Copyright (c) 2011, Yahoo! Inc. All rights reserved.
   5  Code licensed under the BSD License:
   6  http://developer.yahoo.com/yui/license.html
   7  version: 2.9.0
   8  */
   9  
  10  /**
  11   * The CustomEvent class lets you define events for your application
  12   * that can be subscribed to by one or more independent component.
  13   *
  14   * @param {String}  type The type of event, which is passed to the callback
  15   *                  when the event fires
  16   * @param {Object}  context The context the event will fire from.  "this" will
  17   *                  refer to this object in the callback.  Default value:
  18   *                  the window object.  The listener can override this.
  19   * @param {boolean} silent pass true to prevent the event from writing to
  20   *                  the debugsystem
  21   * @param {int}     signature the signature that the custom event subscriber
  22   *                  will receive. YAHOO.util.CustomEvent.LIST or
  23   *                  YAHOO.util.CustomEvent.FLAT.  The default is
  24   *                  YAHOO.util.CustomEvent.LIST.
  25   * @param fireOnce {boolean} If configured to fire once, the custom event
  26   * will only notify subscribers a single time regardless of how many times
  27   * the event is fired.  In addition, new subscribers will be notified
  28   * immediately if the event has already been fired.
  29   * @namespace YAHOO.util
  30   * @class CustomEvent
  31   * @constructor
  32   */
  33  YAHOO.util.CustomEvent = function(type, context, silent, signature, fireOnce) {
  34  
  35      /**
  36       * The type of event, returned to subscribers when the event fires
  37       * @property type
  38       * @type string
  39       */
  40      this.type = type;
  41  
  42      /**
  43       * The context the event will fire from by default. Defaults to the window obj.
  44       * @property scope
  45       * @type object
  46       */
  47      this.scope = context || window;
  48  
  49      /**
  50       * By default all custom events are logged in the debug build. Set silent to true
  51       * to disable debug output for this event.
  52       * @property silent
  53       * @type boolean
  54       */
  55      this.silent = silent;
  56  
  57      /**
  58       * If configured to fire once, the custom event will only notify subscribers
  59       * a single time regardless of how many times the event is fired.  In addition,
  60       * new subscribers will be notified immediately if the event has already been
  61       * fired.
  62       * @property fireOnce
  63       * @type boolean
  64       * @default false
  65       */
  66      this.fireOnce = fireOnce;
  67  
  68      /**
  69       * Indicates whether or not this event has ever been fired.
  70       * @property fired
  71       * @type boolean
  72       * @default false
  73       */
  74      this.fired = false;
  75  
  76      /**
  77       * For fireOnce events the arguments the event was fired with are stored
  78       * so that new subscribers get the proper payload.
  79       * @property firedWith
  80       * @type Array
  81       */
  82      this.firedWith = null;
  83  
  84      /**
  85       * Custom events support two styles of arguments provided to the event
  86       * subscribers.
  87       * <ul>
  88       * <li>YAHOO.util.CustomEvent.LIST:
  89       *   <ul>
  90       *   <li>param1: event name</li>
  91       *   <li>param2: array of arguments sent to fire</li>
  92       *   <li>param3: <optional> a custom object supplied by the subscriber</li>
  93       *   </ul>
  94       * </li>
  95       * <li>YAHOO.util.CustomEvent.FLAT
  96       *   <ul>
  97       *   <li>param1: the first argument passed to fire.  If you need to
  98       *           pass multiple parameters, use and array or object literal</li>
  99       *   <li>param2: <optional> a custom object supplied by the subscriber</li>
 100       *   </ul>
 101       * </li>
 102       * </ul>
 103       *   @property signature
 104       *   @type int
 105       */
 106      this.signature = signature || YAHOO.util.CustomEvent.LIST;
 107  
 108      /**
 109       * The subscribers to this event
 110       * @property subscribers
 111       * @type Subscriber[]
 112       */
 113      this.subscribers = [];
 114  
 115      if (!this.silent) {
 116          YAHOO.log( "Creating " + this, "info", "Event" );
 117      }
 118  
 119      var onsubscribeType = "_YUICEOnSubscribe";
 120  
 121      // Only add subscribe events for events that are not generated by
 122      // CustomEvent
 123      if (type !== onsubscribeType) {
 124  
 125          /**
 126           * Custom events provide a custom event that fires whenever there is
 127           * a new subscriber to the event.  This provides an opportunity to
 128           * handle the case where there is a non-repeating event that has
 129           * already fired has a new subscriber.
 130           *
 131           * @event subscribeEvent
 132           * @type YAHOO.util.CustomEvent
 133           * @param fn {Function} The function to execute
 134           * @param obj <Object> An object to be passed along when the event fires.
 135           * Defaults to the custom event.
 136           * @param override <boolean|Object> If true, the obj passed in becomes the
 137           * execution context of the listener. If an object, that object becomes
 138           * the execution context. Defaults to the custom event.
 139           */
 140          this.subscribeEvent =
 141                  new YAHOO.util.CustomEvent(onsubscribeType, this, true);
 142  
 143      }
 144  
 145  
 146      /**
 147       * In order to make it possible to execute the rest of the subscriber
 148       * stack when one thows an exception, the subscribers exceptions are
 149       * caught.  The most recent exception is stored in this property
 150       * @property lastError
 151       * @type Error
 152       */
 153      this.lastError = null;
 154  };
 155  
 156  /**
 157   * Subscriber listener sigature constant.  The LIST type returns three
 158   * parameters: the event type, the array of args passed to fire, and
 159   * the optional custom object
 160   * @property YAHOO.util.CustomEvent.LIST
 161   * @static
 162   * @type int
 163   */
 164  YAHOO.util.CustomEvent.LIST = 0;
 165  
 166  /**
 167   * Subscriber listener sigature constant.  The FLAT type returns two
 168   * parameters: the first argument passed to fire and the optional
 169   * custom object
 170   * @property YAHOO.util.CustomEvent.FLAT
 171   * @static
 172   * @type int
 173   */
 174  YAHOO.util.CustomEvent.FLAT = 1;
 175  
 176  YAHOO.util.CustomEvent.prototype = {
 177  
 178      /**
 179       * Subscribes the caller to this event
 180       * @method subscribe
 181       * @param {Function} fn        The function to execute
 182       * @param {Object}   obj       An object to be passed along when the event
 183       * fires.
 184       * @param {boolean|Object} overrideContext If true, the obj passed in
 185       * becomes the execution.
 186       * context of the listener. If an object, that object becomes the execution
 187       * context.
 188       */
 189      subscribe: function(fn, obj, overrideContext) {
 190  
 191          if (!fn) {
 192  throw new Error("Invalid callback for subscriber to '" + this.type + "'");
 193          }
 194  
 195          if (this.subscribeEvent) {
 196              this.subscribeEvent.fire(fn, obj, overrideContext);
 197          }
 198  
 199          var s = new YAHOO.util.Subscriber(fn, obj, overrideContext);
 200  
 201          if (this.fireOnce && this.fired) {
 202              this.notify(s, this.firedWith);
 203          } else {
 204              this.subscribers.push(s);
 205          }
 206      },
 207  
 208      /**
 209       * Unsubscribes subscribers.
 210       * @method unsubscribe
 211       * @param {Function} fn  The subscribed function to remove, if not supplied
 212       *                       all will be removed
 213       * @param {Object}   obj  The custom object passed to subscribe.  This is
 214       *                        optional, but if supplied will be used to
 215       *                        disambiguate multiple listeners that are the same
 216       *                        (e.g., you subscribe many object using a function
 217       *                        that lives on the prototype)
 218       * @return {boolean} True if the subscriber was found and detached.
 219       */
 220      unsubscribe: function(fn, obj) {
 221  
 222          if (!fn) {
 223              return this.unsubscribeAll();
 224          }
 225  
 226          var found = false;
 227          for (var i=0, len=this.subscribers.length; i<len; ++i) {
 228              var s = this.subscribers[i];
 229              if (s && s.contains(fn, obj)) {
 230                  this._delete(i);
 231                  found = true;
 232              }
 233          }
 234  
 235          return found;
 236      },
 237  
 238      /**
 239       * Notifies the subscribers.  The callback functions will be executed
 240       * from the context specified when the event was created, and with the
 241       * following parameters:
 242       *   <ul>
 243       *   <li>The type of event</li>
 244       *   <li>All of the arguments fire() was executed with as an array</li>
 245       *   <li>The custom object (if any) that was passed into the subscribe()
 246       *       method</li>
 247       *   </ul>
 248       * @method fire
 249       * @param {Object*} arguments an arbitrary set of parameters to pass to
 250       *                            the handler.
 251       * @return {boolean} false if one of the subscribers returned false,
 252       *                   true otherwise
 253       */
 254      fire: function() {
 255  
 256          this.lastError = null;
 257  
 258          var errors = [],
 259              len=this.subscribers.length;
 260  
 261  
 262          var args=[].slice.call(arguments, 0), ret=true, i, rebuild=false;
 263  
 264          if (this.fireOnce) {
 265              if (this.fired) {
 266                  YAHOO.log('fireOnce event has already fired: ' + this.type);
 267                  return true;
 268              } else {
 269                  this.firedWith = args;
 270              }
 271          }
 272  
 273          this.fired = true;
 274  
 275          if (!len && this.silent) {
 276              //YAHOO.log('DEBUG no subscribers');
 277              return true;
 278          }
 279  
 280          if (!this.silent) {
 281              YAHOO.log( "Firing "       + this  + ", " +
 282                         "args: "        + args  + ", " +
 283                         "subscribers: " + len,
 284                         "info", "Event"                  );
 285          }
 286  
 287          // make a copy of the subscribers so that there are
 288          // no index problems if one subscriber removes another.
 289          var subs = this.subscribers.slice();
 290  
 291          for (i=0; i<len; ++i) {
 292              var s = subs[i];
 293              if (!s || !s.fn) {
 294                  rebuild=true;
 295              } else {
 296  
 297                  ret = this.notify(s, args);
 298  
 299                  if (false === ret) {
 300                      if (!this.silent) {
 301                          YAHOO.log("Event stopped, sub " + i + " of " + len, "info", "Event");
 302                      }
 303  
 304                      break;
 305                  }
 306              }
 307          }
 308  
 309          return (ret !== false);
 310      },
 311  
 312      notify: function(s, args) {
 313  
 314          var ret, param=null, scope = s.getScope(this.scope),
 315                   throwErrors = YAHOO.util.Event.throwErrors;
 316  
 317          if (!this.silent) {
 318              YAHOO.log( this.type + "-> " + s, "info", "Event" );
 319          }
 320  
 321          if (this.signature == YAHOO.util.CustomEvent.FLAT) {
 322  
 323              if (args.length > 0) {
 324                  param = args[0];
 325              }
 326  
 327              try {
 328                  ret = s.fn.call(scope, param, s.obj);
 329              } catch(e) {
 330                  this.lastError = e;
 331                  // errors.push(e);
 332                  YAHOO.log(this + " subscriber exception: " + e, "error", "Event");
 333                  if (throwErrors) {
 334                      throw e;
 335                  }
 336              }
 337          } else {
 338              try {
 339                  ret = s.fn.call(scope, this.type, args, s.obj);
 340              } catch(ex) {
 341                  this.lastError = ex;
 342                  YAHOO.log(this + " subscriber exception: " + ex, "error", "Event");
 343                  if (throwErrors) {
 344                      throw ex;
 345                  }
 346              }
 347          }
 348  
 349          return ret;
 350      },
 351  
 352      /**
 353       * Removes all listeners
 354       * @method unsubscribeAll
 355       * @return {int} The number of listeners unsubscribed
 356       */
 357      unsubscribeAll: function() {
 358          var l = this.subscribers.length, i;
 359          for (i=l-1; i>-1; i--) {
 360              this._delete(i);
 361          }
 362  
 363          this.subscribers=[];
 364  
 365          return l;
 366      },
 367  
 368      /**
 369       * @method _delete
 370       * @private
 371       */
 372      _delete: function(index) {
 373          var s = this.subscribers[index];
 374          if (s) {
 375              delete s.fn;
 376              delete s.obj;
 377          }
 378  
 379          // this.subscribers[index]=null;
 380          this.subscribers.splice(index, 1);
 381      },
 382  
 383      /**
 384       * @method toString
 385       */
 386      toString: function() {
 387           return "CustomEvent: " + "'" + this.type  + "', " +
 388               "context: " + this.scope;
 389  
 390      }
 391  };
 392  
 393  /////////////////////////////////////////////////////////////////////
 394  
 395  /**
 396   * Stores the subscriber information to be used when the event fires.
 397   * @param {Function} fn       The function to execute
 398   * @param {Object}   obj      An object to be passed along when the event fires
 399   * @param {boolean}  overrideContext If true, the obj passed in becomes the execution
 400   *                            context of the listener
 401   * @class Subscriber
 402   * @constructor
 403   */
 404  YAHOO.util.Subscriber = function(fn, obj, overrideContext) {
 405  
 406      /**
 407       * The callback that will be execute when the event fires
 408       * @property fn
 409       * @type function
 410       */
 411      this.fn = fn;
 412  
 413      /**
 414       * An optional custom object that will passed to the callback when
 415       * the event fires
 416       * @property obj
 417       * @type object
 418       */
 419      this.obj = YAHOO.lang.isUndefined(obj) ? null : obj;
 420  
 421      /**
 422       * The default execution context for the event listener is defined when the
 423       * event is created (usually the object which contains the event).
 424       * By setting overrideContext to true, the execution context becomes the custom
 425       * object passed in by the subscriber.  If overrideContext is an object, that
 426       * object becomes the context.
 427       * @property overrideContext
 428       * @type boolean|object
 429       */
 430      this.overrideContext = overrideContext;
 431  
 432  };
 433  
 434  /**
 435   * Returns the execution context for this listener.  If overrideContext was set to true
 436   * the custom obj will be the context.  If overrideContext is an object, that is the
 437   * context, otherwise the default context will be used.
 438   * @method getScope
 439   * @param {Object} defaultScope the context to use if this listener does not
 440   *                              override it.
 441   */
 442  YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
 443      if (this.overrideContext) {
 444          if (this.overrideContext === true) {
 445              return this.obj;
 446          } else {
 447              return this.overrideContext;
 448          }
 449      }
 450      return defaultScope;
 451  };
 452  
 453  /**
 454   * Returns true if the fn and obj match this objects properties.
 455   * Used by the unsubscribe method to match the right subscriber.
 456   *
 457   * @method contains
 458   * @param {Function} fn the function to execute
 459   * @param {Object} obj an object to be passed along when the event fires
 460   * @return {boolean} true if the supplied arguments match this
 461   *                   subscriber's signature.
 462   */
 463  YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
 464      if (obj) {
 465          return (this.fn == fn && this.obj == obj);
 466      } else {
 467          return (this.fn == fn);
 468      }
 469  };
 470  
 471  /**
 472   * @method toString
 473   */
 474  YAHOO.util.Subscriber.prototype.toString = function() {
 475      return "Subscriber { obj: " + this.obj  +
 476             ", overrideContext: " +  (this.overrideContext || "no") + " }";
 477  };
 478  
 479  /**
 480   * The Event Utility provides utilities for managing DOM Events and tools
 481   * for building event systems
 482   *
 483   * @module event
 484   * @title Event Utility
 485   * @namespace YAHOO.util
 486   * @requires yahoo
 487   */
 488  
 489  // The first instance of Event will win if it is loaded more than once.
 490  // @TODO this needs to be changed so that only the state data that needs to
 491  // be preserved is kept, while methods are overwritten/added as needed.
 492  // This means that the module pattern can't be used.
 493  if (!YAHOO.util.Event) {
 494  
 495  /**
 496   * The event utility provides functions to add and remove event listeners,
 497   * event cleansing.  It also tries to automatically remove listeners it
 498   * registers during the unload event.
 499   *
 500   * @class Event
 501   * @static
 502   */
 503      YAHOO.util.Event = function() {
 504  
 505          /**
 506           * True after the onload event has fired
 507           * @property loadComplete
 508           * @type boolean
 509           * @static
 510           * @private
 511           */
 512          var loadComplete =  false,
 513  
 514          /**
 515           * Cache of wrapped listeners
 516           * @property listeners
 517           * @type array
 518           * @static
 519           * @private
 520           */
 521          listeners = [],
 522  
 523  
 524          /**
 525           * User-defined unload function that will be fired before all events
 526           * are detached
 527           * @property unloadListeners
 528           * @type array
 529           * @static
 530           * @private
 531           */
 532          unloadListeners = [],
 533  
 534          /**
 535           * The number of times to poll after window.onload.  This number is
 536           * increased if additional late-bound handlers are requested after
 537           * the page load.
 538           * @property retryCount
 539           * @static
 540           * @private
 541           */
 542          retryCount = 0,
 543  
 544          /**
 545           * onAvailable listeners
 546           * @property onAvailStack
 547           * @static
 548           * @private
 549           */
 550          onAvailStack = [],
 551  
 552          /**
 553           * Counter for auto id generation
 554           * @property counter
 555           * @static
 556           * @private
 557           */
 558          counter = 0,
 559  
 560          /**
 561           * Normalized keycodes for webkit/safari
 562           * @property webkitKeymap
 563           * @type {int: int}
 564           * @private
 565           * @static
 566           * @final
 567           */
 568           webkitKeymap = {
 569              63232: 38, // up
 570              63233: 40, // down
 571              63234: 37, // left
 572              63235: 39, // right
 573              63276: 33, // page up
 574              63277: 34, // page down
 575              25: 9      // SHIFT-TAB (Safari provides a different key code in
 576                         // this case, even though the shiftKey modifier is set)
 577          },
 578  
 579          isIE = YAHOO.env.ua.ie,
 580  
 581          // String constants used by the addFocusListener and removeFocusListener methods
 582  
 583          FOCUSIN = "focusin",
 584          FOCUSOUT = "focusout";
 585  
 586          return {
 587  
 588              /**
 589               * The number of times we should look for elements that are not
 590               * in the DOM at the time the event is requested after the document
 591               * has been loaded.  The default is 500@amp;40 ms, so it will poll
 592               * for 20 seconds or until all outstanding handlers are bound
 593               * (whichever comes first).
 594               * @property POLL_RETRYS
 595               * @type int
 596               * @static
 597               * @final
 598               */
 599              POLL_RETRYS: 500,
 600  
 601              /**
 602               * The poll interval in milliseconds
 603               * @property POLL_INTERVAL
 604               * @type int
 605               * @static
 606               * @final
 607               */
 608              POLL_INTERVAL: 40,
 609  
 610              /**
 611               * Element to bind, int constant
 612               * @property EL
 613               * @type int
 614               * @static
 615               * @final
 616               */
 617              EL: 0,
 618  
 619              /**
 620               * Type of event, int constant
 621               * @property TYPE
 622               * @type int
 623               * @static
 624               * @final
 625               */
 626              TYPE: 1,
 627  
 628              /**
 629               * Function to execute, int constant
 630               * @property FN
 631               * @type int
 632               * @static
 633               * @final
 634               */
 635              FN: 2,
 636  
 637              /**
 638               * Function wrapped for context correction and cleanup, int constant
 639               * @property WFN
 640               * @type int
 641               * @static
 642               * @final
 643               */
 644              WFN: 3,
 645  
 646              /**
 647               * Object passed in by the user that will be returned as a
 648               * parameter to the callback, int constant.  Specific to
 649               * unload listeners
 650               * @property OBJ
 651               * @type int
 652               * @static
 653               * @final
 654               */
 655              UNLOAD_OBJ: 3,
 656  
 657              /**
 658               * Adjusted context, either the element we are registering the event
 659               * on or the custom object passed in by the listener, int constant
 660               * @property ADJ_SCOPE
 661               * @type int
 662               * @static
 663               * @final
 664               */
 665              ADJ_SCOPE: 4,
 666  
 667              /**
 668               * The original obj passed into addListener
 669               * @property OBJ
 670               * @type int
 671               * @static
 672               * @final
 673               */
 674              OBJ: 5,
 675  
 676              /**
 677               * The original context parameter passed into addListener
 678               * @property OVERRIDE
 679               * @type int
 680               * @static
 681               * @final
 682               */
 683              OVERRIDE: 6,
 684  
 685              /**
 686               * The original capture parameter passed into addListener
 687               * @property CAPTURE
 688               * @type int
 689               * @static
 690               * @final
 691               */
 692              CAPTURE: 7,
 693  
 694              /**
 695               * addListener/removeListener can throw errors in unexpected scenarios.
 696               * These errors are suppressed, the method returns false, and this property
 697               * is set
 698               * @property lastError
 699               * @static
 700               * @type Error
 701               */
 702              lastError: null,
 703  
 704              /**
 705               * Safari detection
 706               * @property isSafari
 707               * @private
 708               * @static
 709               * @deprecated use YAHOO.env.ua.webkit
 710               */
 711              isSafari: YAHOO.env.ua.webkit,
 712  
 713              /**
 714               * webkit version
 715               * @property webkit
 716               * @type string
 717               * @private
 718               * @static
 719               * @deprecated use YAHOO.env.ua.webkit
 720               */
 721              webkit: YAHOO.env.ua.webkit,
 722  
 723              /**
 724               * IE detection
 725               * @property isIE
 726               * @private
 727               * @static
 728               * @deprecated use YAHOO.env.ua.ie
 729               */
 730              isIE: isIE,
 731  
 732              /**
 733               * poll handle
 734               * @property _interval
 735               * @static
 736               * @private
 737               */
 738              _interval: null,
 739  
 740              /**
 741               * document readystate poll handle
 742               * @property _dri
 743               * @static
 744               * @private
 745               */
 746               _dri: null,
 747  
 748  
 749              /**
 750               * Map of special event types
 751               * @property _specialTypes
 752               * @static
 753               * @private
 754               */
 755              _specialTypes: {
 756                  focusin: (isIE ? "focusin" : "focus"),
 757                  focusout: (isIE ? "focusout" : "blur")
 758              },
 759  
 760  
 761              /**
 762               * True when the document is initially usable
 763               * @property DOMReady
 764               * @type boolean
 765               * @static
 766               */
 767              DOMReady: false,
 768  
 769              /**
 770               * Errors thrown by subscribers of custom events are caught
 771               * and the error message is written to the debug console.  If
 772               * this property is set to true, it will also re-throw the
 773               * error.
 774               * @property throwErrors
 775               * @type boolean
 776               * @default false
 777               */
 778              throwErrors: false,
 779  
 780  
 781              /**
 782               * @method startInterval
 783               * @static
 784               * @private
 785               */
 786              startInterval: function() {
 787                  if (!this._interval) {
 788                      // var self = this;
 789                      // var callback = function() { self._tryPreloadAttach(); };
 790                      // this._interval = setInterval(callback, this.POLL_INTERVAL);
 791                      this._interval = YAHOO.lang.later(this.POLL_INTERVAL, this, this._tryPreloadAttach, null, true);
 792                  }
 793              },
 794  
 795              /**
 796               * Executes the supplied callback when the item with the supplied
 797               * id is found.  This is meant to be used to execute behavior as
 798               * soon as possible as the page loads.  If you use this after the
 799               * initial page load it will poll for a fixed time for the element.
 800               * The number of times it will poll and the frequency are
 801               * configurable.  By default it will poll for 10 seconds.
 802               *
 803               * <p>The callback is executed with a single parameter:
 804               * the custom object parameter, if provided.</p>
 805               *
 806               * @method onAvailable
 807               *
 808               * @param {string||string[]}   id the id of the element, or an array
 809               * of ids to look for.
 810               * @param {function} fn what to execute when the element is found.
 811               * @param {object}   obj an optional object to be passed back as
 812               *                   a parameter to fn.
 813               * @param {boolean|object}  overrideContext If set to true, fn will execute
 814               *                   in the context of obj, if set to an object it
 815               *                   will execute in the context of that object
 816               * @param checkContent {boolean} check child node readiness (onContentReady)
 817               * @static
 818               */
 819              onAvailable: function(id, fn, obj, overrideContext, checkContent) {
 820  
 821                  var a = (YAHOO.lang.isString(id)) ? [id] : id;
 822  
 823                  for (var i=0; i<a.length; i=i+1) {
 824                      onAvailStack.push({id:         a[i],
 825                                         fn:         fn,
 826                                         obj:        obj,
 827                                         overrideContext:   overrideContext,
 828                                         checkReady: checkContent });
 829                  }
 830  
 831                  retryCount = this.POLL_RETRYS;
 832  
 833                  this.startInterval();
 834              },
 835  
 836              /**
 837               * Works the same way as onAvailable, but additionally checks the
 838               * state of sibling elements to determine if the content of the
 839               * available element is safe to modify.
 840               *
 841               * <p>The callback is executed with a single parameter:
 842               * the custom object parameter, if provided.</p>
 843               *
 844               * @method onContentReady
 845               *
 846               * @param {string}   id the id of the element to look for.
 847               * @param {function} fn what to execute when the element is ready.
 848               * @param {object}   obj an optional object to be passed back as
 849               *                   a parameter to fn.
 850               * @param {boolean|object}  overrideContext If set to true, fn will execute
 851               *                   in the context of obj.  If an object, fn will
 852               *                   exectute in the context of that object
 853               *
 854               * @static
 855               */
 856              onContentReady: function(id, fn, obj, overrideContext) {
 857                  this.onAvailable(id, fn, obj, overrideContext, true);
 858              },
 859  
 860              /**
 861               * Executes the supplied callback when the DOM is first usable.  This
 862               * will execute immediately if called after the DOMReady event has
 863               * fired.   @todo the DOMContentReady event does not fire when the
 864               * script is dynamically injected into the page.  This means the
 865               * DOMReady custom event will never fire in FireFox or Opera when the
 866               * library is injected.  It _will_ fire in Safari, and the IE
 867               * implementation would allow for us to fire it if the defered script
 868               * is not available.  We want this to behave the same in all browsers.
 869               * Is there a way to identify when the script has been injected
 870               * instead of included inline?  Is there a way to know whether the
 871               * window onload event has fired without having had a listener attached
 872               * to it when it did so?
 873               *
 874               * <p>The callback is a CustomEvent, so the signature is:</p>
 875               * <p>type &lt;string&gt;, args &lt;array&gt;, customobject &lt;object&gt;</p>
 876               * <p>For DOMReady events, there are no fire argments, so the
 877               * signature is:</p>
 878               * <p>"DOMReady", [], obj</p>
 879               *
 880               *
 881               * @method onDOMReady
 882               *
 883               * @param {function} fn what to execute when the element is found.
 884               * @param {object}   obj an optional object to be passed back as
 885               *                   a parameter to fn.
 886               * @param {boolean|object}  overrideContext If set to true, fn will execute
 887               *                   in the context of obj, if set to an object it
 888               *                   will execute in the context of that object
 889               *
 890               * @static
 891               */
 892              // onDOMReady: function(fn, obj, overrideContext) {
 893              onDOMReady: function() {
 894                  this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent, arguments);
 895              },
 896  
 897  
 898              /**
 899               * Appends an event handler
 900               *
 901               * @method _addListener
 902               *
 903               * @param {String|HTMLElement|Array|NodeList} el An id, an element
 904               *  reference, or a collection of ids and/or elements to assign the
 905               *  listener to.
 906               * @param {String}   sType     The type of event to append
 907               * @param {Function} fn        The method the event invokes
 908               * @param {Object}   obj    An arbitrary object that will be
 909               *                             passed as a parameter to the handler
 910               * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
 911               *                             the execution context of the listener. If an
 912               *                             object, this object becomes the execution
 913               *                             context.
 914               * @param {boolen}      capture capture or bubble phase
 915               * @return {Boolean} True if the action was successful or defered,
 916               *                        false if one or more of the elements
 917               *                        could not have the listener attached,
 918               *                        or if the operation throws an exception.
 919               * @private
 920               * @static
 921               */
 922              _addListener: function(el, sType, fn, obj, overrideContext, bCapture) {
 923  
 924                  if (!fn || !fn.call) {
 925                      YAHOO.log(sType + " addListener failed, invalid callback", "error", "Event");
 926                      return false;
 927                  }
 928  
 929                  // The el argument can be an array of elements or element ids.
 930                  if ( this._isValidCollection(el)) {
 931                      var ok = true;
 932                      for (var i=0,len=el.length; i<len; ++i) {
 933                          ok = this.on(el[i],
 934                                         sType,
 935                                         fn,
 936                                         obj,
 937                                         overrideContext) && ok;
 938                      }
 939                      return ok;
 940  
 941                  } else if (YAHOO.lang.isString(el)) {
 942                      var oEl = this.getEl(el);
 943                      // If the el argument is a string, we assume it is
 944                      // actually the id of the element.  If the page is loaded
 945                      // we convert el to the actual element, otherwise we
 946                      // defer attaching the event until onload event fires
 947  
 948                      // check to see if we need to delay hooking up the event
 949                      // until after the page loads.
 950                      if (oEl) {
 951                          el = oEl;
 952                      } else {
 953                          // defer adding the event until the element is available
 954                          this.onAvailable(el, function() {
 955                             YAHOO.util.Event._addListener(el, sType, fn, obj, overrideContext, bCapture);
 956                          });
 957  
 958                          return true;
 959                      }
 960                  }
 961  
 962                  // Element should be an html element or an array if we get
 963                  // here.
 964                  if (!el) {
 965                      // this.logger.debug("unable to attach event " + sType);
 966                      return false;
 967                  }
 968  
 969                  // we need to make sure we fire registered unload events
 970                  // prior to automatically unhooking them.  So we hang on to
 971                  // these instead of attaching them to the window and fire the
 972                  // handles explicitly during our one unload event.
 973                  if ("unload" == sType && obj !== this) {
 974                      unloadListeners[unloadListeners.length] =
 975                              [el, sType, fn, obj, overrideContext];
 976                      return true;
 977                  }
 978  
 979                  // this.logger.debug("Adding handler: " + el + ", " + sType);
 980  
 981                  // if the user chooses to override the context, we use the custom
 982                  // object passed in, otherwise the executing context will be the
 983                  // HTML element that the event is registered on
 984                  var context = el;
 985                  if (overrideContext) {
 986                      if (overrideContext === true) {
 987                          context = obj;
 988                      } else {
 989                          context = overrideContext;
 990                      }
 991                  }
 992  
 993                  // wrap the function so we can return the obj object when
 994                  // the event fires;
 995                  var wrappedFn = function(e) {
 996                          return fn.call(context, YAHOO.util.Event.getEvent(e, el),
 997                                  obj);
 998                      };
 999  
1000                  var li = [el, sType, fn, wrappedFn, context, obj, overrideContext, bCapture];
1001                  var index = listeners.length;
1002                  // cache the listener so we can try to automatically unload
1003                  listeners[index] = li;
1004  
1005                  try {
1006                      this._simpleAdd(el, sType, wrappedFn, bCapture);
1007                  } catch(ex) {
1008                      // handle an error trying to attach an event.  If it fails
1009                      // we need to clean up the cache
1010                      this.lastError = ex;
1011                      this.removeListener(el, sType, fn);
1012                      return false;
1013                  }
1014  
1015                  return true;
1016  
1017              },
1018  
1019              /**
1020               * Checks to see if the type requested is a special type
1021               * (as defined by the _specialTypes hash), and (if so) returns
1022               * the special type name.
1023               *
1024               * @method _getType
1025               *
1026               * @param {String}   sType     The type to look up
1027               * @private
1028               */
1029              _getType: function (type) {
1030  
1031                  return this._specialTypes[type] || type;
1032  
1033              },
1034  
1035  
1036              /**
1037               * Appends an event handler
1038               *
1039               * @method addListener
1040               *
1041               * @param {String|HTMLElement|Array|NodeList} el An id, an element
1042               *  reference, or a collection of ids and/or elements to assign the
1043               *  listener to.
1044               * @param {String}   sType     The type of event to append
1045               * @param {Function} fn        The method the event invokes
1046               * @param {Object}   obj    An arbitrary object that will be
1047               *                             passed as a parameter to the handler
1048               * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1049               *                             the execution context of the listener. If an
1050               *                             object, this object becomes the execution
1051               *                             context.
1052               * @return {Boolean} True if the action was successful or defered,
1053               *                        false if one or more of the elements
1054               *                        could not have the listener attached,
1055               *                        or if the operation throws an exception.
1056               * @static
1057               */
1058              addListener: function (el, sType, fn, obj, overrideContext) {
1059  
1060                  var capture = ((sType == FOCUSIN || sType == FOCUSOUT) && !YAHOO.env.ua.ie) ? true : false;
1061  
1062                  return this._addListener(el, this._getType(sType), fn, obj, overrideContext, capture);
1063  
1064              },
1065  
1066  
1067              /**
1068               * Attaches a focusin event listener to the specified element for
1069               * the purpose of listening for the focus event on the element's
1070               * descendants.
1071               * @method addFocusListener
1072               *
1073               * @param {String|HTMLElement|Array|NodeList} el An id, an element
1074               *  reference, or a collection of ids and/or elements to assign the
1075               *  listener to.
1076               * @param {Function} fn        The method the event invokes
1077               * @param {Object}   obj    An arbitrary object that will be
1078               *                             passed as a parameter to the handler
1079               * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1080               *                             the execution context of the listener. If an
1081               *                             object, this object becomes the execution
1082               *                             context.
1083               * @return {Boolean} True if the action was successful or defered,
1084               *                        false if one or more of the elements
1085               *                        could not have the listener attached,
1086               *                        or if the operation throws an exception.
1087               * @static
1088              * @deprecated use YAHOO.util.Event.on and specify "focusin" as the event type.
1089               */
1090              addFocusListener: function (el, fn, obj, overrideContext) {
1091                  return this.on(el, FOCUSIN, fn, obj, overrideContext);
1092              },
1093  
1094  
1095              /**
1096               * Removes a focusin event listener to the specified element for
1097               * the purpose of listening for the focus event on the element's
1098               * descendants.
1099               *
1100               * @method removeFocusListener
1101               *
1102               * @param {String|HTMLElement|Array|NodeList} el An id, an element
1103               *  reference, or a collection of ids and/or elements to remove
1104               *  the listener from.
1105               * @param {Function} fn the method the event invokes.  If fn is
1106               *  undefined, then all event handlers for the type of event are
1107               *  removed.
1108               * @return {boolean} true if the unbind was successful, false
1109               *  otherwise.
1110               * @static
1111               * @deprecated use YAHOO.util.Event.removeListener and specify "focusin" as the event type.
1112               */
1113              removeFocusListener: function (el, fn) {
1114                  return this.removeListener(el, FOCUSIN, fn);
1115              },
1116  
1117              /**
1118               * Attaches a focusout event listener to the specified element for
1119               * the purpose of listening for the blur event on the element's
1120               * descendants.
1121               *
1122               * @method addBlurListener
1123               *
1124               * @param {String|HTMLElement|Array|NodeList} el An id, an element
1125               *  reference, or a collection of ids and/or elements to assign the
1126               *  listener to.
1127               * @param {Function} fn        The method the event invokes
1128               * @param {Object}   obj    An arbitrary object that will be
1129               *                             passed as a parameter to the handler
1130               * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1131               *                             the execution context of the listener. If an
1132               *                             object, this object becomes the execution
1133               *                             context.
1134               * @return {Boolean} True if the action was successful or defered,
1135               *                        false if one or more of the elements
1136               *                        could not have the listener attached,
1137               *                        or if the operation throws an exception.
1138               * @static
1139               * @deprecated use YAHOO.util.Event.on and specify "focusout" as the event type.
1140               */
1141              addBlurListener: function (el, fn, obj, overrideContext) {
1142                  return this.on(el, FOCUSOUT, fn, obj, overrideContext);
1143              },
1144  
1145              /**
1146               * Removes a focusout event listener to the specified element for
1147               * the purpose of listening for the blur event on the element's
1148               * descendants.
1149               *
1150               * @method removeBlurListener
1151               *
1152               * @param {String|HTMLElement|Array|NodeList} el An id, an element
1153               *  reference, or a collection of ids and/or elements to remove
1154               *  the listener from.
1155               * @param {Function} fn the method the event invokes.  If fn is
1156               *  undefined, then all event handlers for the type of event are
1157               *  removed.
1158               * @return {boolean} true if the unbind was successful, false
1159               *  otherwise.
1160               * @static
1161               * @deprecated use YAHOO.util.Event.removeListener and specify "focusout" as the event type.
1162               */
1163              removeBlurListener: function (el, fn) {
1164                  return this.removeListener(el, FOCUSOUT, fn);
1165              },
1166  
1167              /**
1168               * Removes an event listener
1169               *
1170               * @method removeListener
1171               *
1172               * @param {String|HTMLElement|Array|NodeList} el An id, an element
1173               *  reference, or a collection of ids and/or elements to remove
1174               *  the listener from.
1175               * @param {String} sType the type of event to remove.
1176               * @param {Function} fn the method the event invokes.  If fn is
1177               *  undefined, then all event handlers for the type of event are
1178               *  removed.
1179               * @return {boolean} true if the unbind was successful, false
1180               *  otherwise.
1181               * @static
1182               */
1183              removeListener: function(el, sType, fn) {
1184                  var i, len, li;
1185  
1186                  sType = this._getType(sType);
1187  
1188                  // The el argument can be a string
1189                  if (typeof el == "string") {
1190                      el = this.getEl(el);
1191                  // The el argument can be an array of elements or element ids.
1192                  } else if ( this._isValidCollection(el)) {
1193                      var ok = true;
1194                      for (i=el.length-1; i>-1; i--) {
1195                          ok = ( this.removeListener(el[i], sType, fn) && ok );
1196                      }
1197                      return ok;
1198                  }
1199  
1200                  if (!fn || !fn.call) {
1201                      // this.logger.debug("Error, function is not valid " + fn);
1202                      //return false;
1203                      return this.purgeElement(el, false, sType);
1204                  }
1205  
1206                  if ("unload" == sType) {
1207  
1208                      for (i=unloadListeners.length-1; i>-1; i--) {
1209                          li = unloadListeners[i];
1210                          if (li &&
1211                              li[0] == el &&
1212                              li[1] == sType &&
1213                              li[2] == fn) {
1214                                  unloadListeners.splice(i, 1);
1215                                  // unloadListeners[i]=null;
1216                                  return true;
1217                          }
1218                      }
1219  
1220                      return false;
1221                  }
1222  
1223                  var cacheItem = null;
1224  
1225                  // The index is a hidden parameter; needed to remove it from
1226                  // the method signature because it was tempting users to
1227                  // try and take advantage of it, which is not possible.
1228                  var index = arguments[3];
1229  
1230                  if ("undefined" === typeof index) {
1231                      index = this._getCacheIndex(listeners, el, sType, fn);
1232                  }
1233  
1234                  if (index >= 0) {
1235                      cacheItem = listeners[index];
1236                  }
1237  
1238                  if (!el || !cacheItem) {
1239                      // this.logger.debug("cached listener not found");
1240                      return false;
1241                  }
1242  
1243                  // this.logger.debug("Removing handler: " + el + ", " + sType);
1244  
1245                  var bCapture = cacheItem[this.CAPTURE] === true ? true : false;
1246  
1247                  try {
1248                      this._simpleRemove(el, sType, cacheItem[this.WFN], bCapture);
1249                  } catch(ex) {
1250                      this.lastError = ex;
1251                      return false;
1252                  }
1253  
1254                  // removed the wrapped handler
1255                  delete listeners[index][this.WFN];
1256                  delete listeners[index][this.FN];
1257                  listeners.splice(index, 1);
1258                  // listeners[index]=null;
1259  
1260                  return true;
1261  
1262              },
1263  
1264              /**
1265               * Returns the event's target element.  Safari sometimes provides
1266               * a text node, and this is automatically resolved to the text
1267               * node's parent so that it behaves like other browsers.
1268               * @method getTarget
1269               * @param {Event} ev the event
1270               * @param {boolean} resolveTextNode when set to true the target's
1271               *                  parent will be returned if the target is a
1272               *                  text node.  @deprecated, the text node is
1273               *                  now resolved automatically
1274               * @return {HTMLElement} the event's target
1275               * @static
1276               */
1277              getTarget: function(ev, resolveTextNode) {
1278                  var t = ev.target || ev.srcElement;
1279                  return this.resolveTextNode(t);
1280              },
1281  
1282              /**
1283               * In some cases, some browsers will return a text node inside
1284               * the actual element that was targeted.  This normalizes the
1285               * return value for getTarget and getRelatedTarget.
1286               *
1287               * If accessing a property of the node throws an error, this is
1288               * probably the anonymous div wrapper Gecko adds inside text
1289               * nodes.  This likely will only occur when attempting to access
1290               * the relatedTarget.  In this case, we now return null because
1291               * the anonymous div is completely useless and we do not know
1292               * what the related target was because we can't even get to
1293               * the element's parent node.
1294               *
1295               * @method resolveTextNode
1296               * @param {HTMLElement} node node to resolve
1297               * @return {HTMLElement} the normized node
1298               * @static
1299               */
1300              resolveTextNode: function(n) {
1301                  try {
1302                      if (n && 3 == n.nodeType) {
1303                          return n.parentNode;
1304                      }
1305                  } catch(e) {
1306                      return null;
1307                  }
1308  
1309                  return n;
1310              },
1311  
1312              /**
1313               * Returns the event's pageX
1314               * @method getPageX
1315               * @param {Event} ev the event
1316               * @return {int} the event's pageX
1317               * @static
1318               */
1319              getPageX: function(ev) {
1320                  var x = ev.pageX;
1321                  if (!x && 0 !== x) {
1322                      x = ev.clientX || 0;
1323  
1324                      if ( this.isIE ) {
1325                          x += this._getScrollLeft();
1326                      }
1327                  }
1328  
1329                  return x;
1330              },
1331  
1332              /**
1333               * Returns the event's pageY
1334               * @method getPageY
1335               * @param {Event} ev the event
1336               * @return {int} the event's pageY
1337               * @static
1338               */
1339              getPageY: function(ev) {
1340                  var y = ev.pageY;
1341                  if (!y && 0 !== y) {
1342                      y = ev.clientY || 0;
1343  
1344                      if ( this.isIE ) {
1345                          y += this._getScrollTop();
1346                      }
1347                  }
1348  
1349  
1350                  return y;
1351              },
1352  
1353              /**
1354               * Returns the pageX and pageY properties as an indexed array.
1355               * @method getXY
1356               * @param {Event} ev the event
1357               * @return {[x, y]} the pageX and pageY properties of the event
1358               * @static
1359               */
1360              getXY: function(ev) {
1361                  return [this.getPageX(ev), this.getPageY(ev)];
1362              },
1363  
1364              /**
1365               * Returns the event's related target
1366               * @method getRelatedTarget
1367               * @param {Event} ev the event
1368               * @return {HTMLElement} the event's relatedTarget
1369               * @static
1370               */
1371              getRelatedTarget: function(ev) {
1372                  var t = ev.relatedTarget;
1373                  if (!t) {
1374                      if (ev.type == "mouseout") {
1375                          t = ev.toElement;
1376                      } else if (ev.type == "mouseover") {
1377                          t = ev.fromElement;
1378                      }
1379                  }
1380  
1381                  return this.resolveTextNode(t);
1382              },
1383  
1384              /**
1385               * Returns the time of the event.  If the time is not included, the
1386               * event is modified using the current time.
1387               * @method getTime
1388               * @param {Event} ev the event
1389               * @return {Date} the time of the event
1390               * @static
1391               */
1392              getTime: function(ev) {
1393                  if (!ev.time) {
1394                      var t = new Date().getTime();
1395                      try {
1396                          ev.time = t;
1397                      } catch(ex) {
1398                          this.lastError = ex;
1399                          return t;
1400                      }
1401                  }
1402  
1403                  return ev.time;
1404              },
1405  
1406              /**
1407               * Convenience method for stopPropagation + preventDefault
1408               * @method stopEvent
1409               * @param {Event} ev the event
1410               * @static
1411               */
1412              stopEvent: function(ev) {
1413                  this.stopPropagation(ev);
1414                  this.preventDefault(ev);
1415              },
1416  
1417              /**
1418               * Stops event propagation
1419               * @method stopPropagation
1420               * @param {Event} ev the event
1421               * @static
1422               */
1423              stopPropagation: function(ev) {
1424                  if (ev.stopPropagation) {
1425                      ev.stopPropagation();
1426                  } else {
1427                      ev.cancelBubble = true;
1428                  }
1429              },
1430  
1431              /**
1432               * Prevents the default behavior of the event
1433               * @method preventDefault
1434               * @param {Event} ev the event
1435               * @static
1436               */
1437              preventDefault: function(ev) {
1438                  if (ev.preventDefault) {
1439                      ev.preventDefault();
1440                  } else {
1441                      ev.returnValue = false;
1442                  }
1443              },
1444  
1445              /**
1446               * Finds the event in the window object, the caller's arguments, or
1447               * in the arguments of another method in the callstack.  This is
1448               * executed automatically for events registered through the event
1449               * manager, so the implementer should not normally need to execute
1450               * this function at all.
1451               * @method getEvent
1452               * @param {Event} e the event parameter from the handler
1453               * @param {HTMLElement} boundEl the element the listener is attached to
1454               * @return {Event} the event
1455               * @static
1456               */
1457              getEvent: function(e, boundEl) {
1458                  var ev = e || window.event;
1459  
1460                  if (!ev) {
1461                      var c = this.getEvent.caller;
1462                      while (c) {
1463                          ev = c.arguments[0];
1464                          if (ev && Event == ev.constructor) {
1465                              break;
1466                          }
1467                          c = c.caller;
1468                      }
1469                  }
1470  
1471                  return ev;
1472              },
1473  
1474              /**
1475               * Returns the charcode for an event
1476               * @method getCharCode
1477               * @param {Event} ev the event
1478               * @return {int} the event's charCode
1479               * @static
1480               */
1481              getCharCode: function(ev) {
1482                  var code = ev.keyCode || ev.charCode || 0;
1483  
1484                  // webkit key normalization
1485                  if (YAHOO.env.ua.webkit && (code in webkitKeymap)) {
1486                      code = webkitKeymap[code];
1487                  }
1488                  return code;
1489              },
1490  
1491              /**
1492               * Locating the saved event handler data by function ref
1493               *
1494               * @method _getCacheIndex
1495               * @static
1496               * @private
1497               */
1498              _getCacheIndex: function(a, el, sType, fn) {
1499                  for (var i=0, l=a.length; i<l; i=i+1) {
1500                      var li = a[i];
1501                      if ( li                 &&
1502                           li[this.FN] == fn  &&
1503                           li[this.EL] == el  &&
1504                           li[this.TYPE] == sType ) {
1505                          return i;
1506                      }
1507                  }
1508  
1509                  return -1;
1510              },
1511  
1512              /**
1513               * Generates an unique ID for the element if it does not already
1514               * have one.
1515               * @method generateId
1516               * @param el the element to create the id for
1517               * @return {string} the resulting id of the element
1518               * @static
1519               */
1520              generateId: function(el) {
1521                  var id = el.id;
1522  
1523                  if (!id) {
1524                      id = "yuievtautoid-" + counter;
1525                      ++counter;
1526                      el.id = id;
1527                  }
1528  
1529                  return id;
1530              },
1531  
1532  
1533              /**
1534               * We want to be able to use getElementsByTagName as a collection
1535               * to attach a group of events to.  Unfortunately, different
1536               * browsers return different types of collections.  This function
1537               * tests to determine if the object is array-like.  It will also
1538               * fail if the object is an array, but is empty.
1539               * @method _isValidCollection
1540               * @param o the object to test
1541               * @return {boolean} true if the object is array-like and populated
1542               * @static
1543               * @private
1544               */
1545              _isValidCollection: function(o) {
1546                  try {
1547                      return ( o                     && // o is something
1548                               typeof o !== "string" && // o is not a string
1549                               o.length              && // o is indexed
1550                               !o.tagName            && // o is not an HTML element
1551                               !o.alert              && // o is not a window
1552                               typeof o[0] !== "undefined" );
1553                  } catch(ex) {
1554                      YAHOO.log("node access error (xframe?)", "warn");
1555                      return false;
1556                  }
1557  
1558              },
1559  
1560              /**
1561               * @private
1562               * @property elCache
1563               * DOM element cache
1564               * @static
1565               * @deprecated Elements are not cached due to issues that arise when
1566               * elements are removed and re-added
1567               */
1568              elCache: {},
1569  
1570              /**
1571               * We cache elements bound by id because when the unload event
1572               * fires, we can no longer use document.getElementById
1573               * @method getEl
1574               * @static
1575               * @private
1576               * @deprecated Elements are not cached any longer
1577               */
1578              getEl: function(id) {
1579                  return (typeof id === "string") ? document.getElementById(id) : id;
1580              },
1581  
1582              /**
1583               * Clears the element cache
1584               * @deprecated Elements are not cached any longer
1585               * @method clearCache
1586               * @static
1587               * @private
1588               */
1589              clearCache: function() { },
1590  
1591              /**
1592               * Custom event the fires when the dom is initially usable
1593               * @event DOMReadyEvent
1594               */
1595              DOMReadyEvent: new YAHOO.util.CustomEvent("DOMReady", YAHOO, 0, 0, 1),
1596  
1597              /**
1598               * hook up any deferred listeners
1599               * @method _load
1600               * @static
1601               * @private
1602               */
1603              _load: function(e) {
1604  
1605                  if (!loadComplete) {
1606                      loadComplete = true;
1607                      var EU = YAHOO.util.Event;
1608  
1609                      // Just in case DOMReady did not go off for some reason
1610                      EU._ready();
1611  
1612                      // Available elements may not have been detected before the
1613                      // window load event fires. Try to find them now so that the
1614                      // the user is more likely to get the onAvailable notifications
1615                      // before the window load notification
1616                      EU._tryPreloadAttach();
1617  
1618                  }
1619              },
1620  
1621              /**
1622               * Fires the DOMReady event listeners the first time the document is
1623               * usable.
1624               * @method _ready
1625               * @static
1626               * @private
1627               */
1628              _ready: function(e) {
1629                  var EU = YAHOO.util.Event;
1630                  if (!EU.DOMReady) {
1631                      EU.DOMReady=true;
1632  
1633                      // Fire the content ready custom event
1634                      EU.DOMReadyEvent.fire();
1635  
1636                      // Remove the DOMContentLoaded (FF/Opera)
1637                      EU._simpleRemove(document, "DOMContentLoaded", EU._ready);
1638                  }
1639              },
1640  
1641              /**
1642               * Polling function that runs before the onload event fires,
1643               * attempting to attach to DOM Nodes as soon as they are
1644               * available
1645               * @method _tryPreloadAttach
1646               * @static
1647               * @private
1648               */
1649              _tryPreloadAttach: function() {
1650  
1651                  if (onAvailStack.length === 0) {
1652                      retryCount = 0;
1653                      if (this._interval) {
1654                          // clearInterval(this._interval);
1655                          this._interval.cancel();
1656                          this._interval = null;
1657                      }
1658                      return;
1659                  }
1660  
1661                  if (this.locked) {
1662                      return;
1663                  }
1664  
1665                  if (this.isIE) {
1666                      // Hold off if DOMReady has not fired and check current
1667                      // readyState to protect against the IE operation aborted
1668                      // issue.
1669                      if (!this.DOMReady) {
1670                          this.startInterval();
1671                          return;
1672                      }
1673                  }
1674  
1675                  this.locked = true;
1676  
1677                  // this.logger.debug("tryPreloadAttach");
1678  
1679                  // keep trying until after the page is loaded.  We need to
1680                  // check the page load state prior to trying to bind the
1681                  // elements so that we can be certain all elements have been
1682                  // tested appropriately
1683                  var tryAgain = !loadComplete;
1684                  if (!tryAgain) {
1685                      tryAgain = (retryCount > 0 && onAvailStack.length > 0);
1686                  }
1687  
1688                  // onAvailable
1689                  var notAvail = [];
1690  
1691                  var executeItem = function (el, item) {
1692                      var context = el;
1693                      if (item.overrideContext) {
1694                          if (item.overrideContext === true) {
1695                              context = item.obj;
1696                          } else {
1697                              context = item.overrideContext;
1698                          }
1699                      }
1700                      item.fn.call(context, item.obj);
1701                  };
1702  
1703                  var i, len, item, el, ready=[];
1704  
1705                  // onAvailable onContentReady
1706                  for (i=0, len=onAvailStack.length; i<len; i=i+1) {
1707                      item = onAvailStack[i];
1708                      if (item) {
1709                          el = this.getEl(item.id);
1710                          if (el) {
1711                              if (item.checkReady) {
1712                                  if (loadComplete || el.nextSibling || !tryAgain) {
1713                                      ready.push(item);
1714                                      onAvailStack[i] = null;
1715                                  }
1716                              } else {
1717                                  executeItem(el, item);
1718                                  onAvailStack[i] = null;
1719                              }
1720                          } else {
1721                              notAvail.push(item);
1722                          }
1723                      }
1724                  }
1725  
1726                  // make sure onContentReady fires after onAvailable
1727                  for (i=0, len=ready.length; i<len; i=i+1) {
1728                      item = ready[i];
1729                      executeItem(this.getEl(item.id), item);
1730                  }
1731  
1732  
1733                  retryCount--;
1734  
1735                  if (tryAgain) {
1736                      for (i=onAvailStack.length-1; i>-1; i--) {
1737                          item = onAvailStack[i];
1738                          if (!item || !item.id) {
1739                              onAvailStack.splice(i, 1);
1740                          }
1741                      }
1742  
1743                      this.startInterval();
1744                  } else {
1745                      if (this._interval) {
1746                          // clearInterval(this._interval);
1747                          this._interval.cancel();
1748                          this._interval = null;
1749                      }
1750                  }
1751  
1752                  this.locked = false;
1753  
1754              },
1755  
1756              /**
1757               * Removes all listeners attached to the given element via addListener.
1758               * Optionally, the node's children can also be purged.
1759               * Optionally, you can specify a specific type of event to remove.
1760               * @method purgeElement
1761               * @param {HTMLElement} el the element to purge
1762               * @param {boolean} recurse recursively purge this element's children
1763               * as well.  Use with caution.
1764               * @param {string} sType optional type of listener to purge. If
1765               * left out, all listeners will be removed
1766               * @static
1767               */
1768              purgeElement: function(el, recurse, sType) {
1769                  var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;
1770                  var elListeners = this.getListeners(oEl, sType), i, len;
1771                  if (elListeners) {
1772                      for (i=elListeners.length-1; i>-1; i--) {
1773                          var l = elListeners[i];
1774                          this.removeListener(oEl, l.type, l.fn);
1775                      }
1776                  }
1777  
1778                  if (recurse && oEl && oEl.childNodes) {
1779                      for (i=0,len=oEl.childNodes.length; i<len ; ++i) {
1780                          this.purgeElement(oEl.childNodes[i], recurse, sType);
1781                      }
1782                  }
1783              },
1784  
1785              /**
1786               * Returns all listeners attached to the given element via addListener.
1787               * Optionally, you can specify a specific type of event to return.
1788               * @method getListeners
1789               * @param el {HTMLElement|string} the element or element id to inspect
1790               * @param sType {string} optional type of listener to return. If
1791               * left out, all listeners will be returned
1792               * @return {Object} the listener. Contains the following fields:
1793               * &nbsp;&nbsp;type:   (string)   the type of event
1794               * &nbsp;&nbsp;fn:     (function) the callback supplied to addListener
1795               * &nbsp;&nbsp;obj:    (object)   the custom object supplied to addListener
1796               * &nbsp;&nbsp;adjust: (boolean|object)  whether or not to adjust the default context
1797               * &nbsp;&nbsp;scope: (boolean)  the derived context based on the adjust parameter
1798               * &nbsp;&nbsp;index:  (int)      its position in the Event util listener cache
1799               * @static
1800               */
1801              getListeners: function(el, sType) {
1802                  var results=[], searchLists;
1803                  if (!sType) {
1804                      searchLists = [listeners, unloadListeners];
1805                  } else if (sType === "unload") {
1806                      searchLists = [unloadListeners];
1807                  } else {
1808                      sType = this._getType(sType);
1809                      searchLists = [listeners];
1810                  }
1811  
1812                  var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;
1813  
1814                  for (var j=0;j<searchLists.length; j=j+1) {
1815                      var searchList = searchLists[j];
1816                      if (searchList) {
1817                          for (var i=0,len=searchList.length; i<len ; ++i) {
1818                              var l = searchList[i];
1819                              if ( l  && l[this.EL] === oEl &&
1820                                      (!sType || sType === l[this.TYPE]) ) {
1821                                  results.push({
1822                                      type:   l[this.TYPE],
1823                                      fn:     l[this.FN],
1824                                      obj:    l[this.OBJ],
1825                                      adjust: l[this.OVERRIDE],
1826                                      scope:  l[this.ADJ_SCOPE],
1827                                      index:  i
1828                                  });
1829                              }
1830                          }
1831                      }
1832                  }
1833  
1834                  return (results.length) ? results : null;
1835              },
1836  
1837              /**
1838               * Removes all listeners registered by pe.event.  Called
1839               * automatically during the unload event.
1840               * @method _unload
1841               * @static
1842               * @private
1843               */
1844              _unload: function(e) {
1845  
1846                  var EU = YAHOO.util.Event, i, j, l, len, index,
1847                           ul = unloadListeners.slice(), context;
1848  
1849                  // execute and clear stored unload listeners
1850                  for (i=0, len=unloadListeners.length; i<len; ++i) {
1851                      l = ul[i];
1852                      if (l) {
1853                          try {
1854                              context = window;
1855                              if (l[EU.ADJ_SCOPE]) {
1856                                  if (l[EU.ADJ_SCOPE] === true) {
1857                                      context = l[EU.UNLOAD_OBJ];
1858                                  } else {
1859                                      context = l[EU.ADJ_SCOPE];
1860                                  }
1861                              }
1862                              l[EU.FN].call(context, EU.getEvent(e, l[EU.EL]), l[EU.UNLOAD_OBJ] );
1863                          } catch(e1) {}
1864                          ul[i] = null;
1865                      }
1866                  }
1867  
1868                  l = null;
1869                  context = null;
1870                  unloadListeners = null;
1871  
1872                  // Remove listeners to handle IE memory leaks
1873                  // 2.5.0 listeners are removed for all browsers again.  FireFox preserves
1874                  // at least some listeners between page refreshes, potentially causing
1875                  // errors during page load (mouseover listeners firing before they
1876                  // should if the user moves the mouse at the correct moment).
1877                  if (listeners) {
1878                      for (j=listeners.length-1; j>-1; j--) {
1879                          l = listeners[j];
1880                          if (l) {
1881                              try {
1882                                  EU.removeListener(l[EU.EL], l[EU.TYPE], l[EU.FN], j);
1883                              } catch(e2) {}
1884                          }
1885                      }
1886                      l=null;
1887                  }
1888  
1889                  try {
1890                      EU._simpleRemove(window, "unload", EU._unload);
1891                      EU._simpleRemove(window, "load", EU._load);
1892                  } catch(e3) {}
1893  
1894              },
1895  
1896              /**
1897               * Returns scrollLeft
1898               * @method _getScrollLeft
1899               * @static
1900               * @private
1901               */
1902              _getScrollLeft: function() {
1903                  return this._getScroll()[1];
1904              },
1905  
1906              /**
1907               * Returns scrollTop
1908               * @method _getScrollTop
1909               * @static
1910               * @private
1911               */
1912              _getScrollTop: function() {
1913                  return this._getScroll()[0];
1914              },
1915  
1916              /**
1917               * Returns the scrollTop and scrollLeft.  Used to calculate the
1918               * pageX and pageY in Internet Explorer
1919               * @method _getScroll
1920               * @static
1921               * @private
1922               */
1923              _getScroll: function() {
1924                  var dd = document.documentElement, db = document.body;
1925                  if (dd && (dd.scrollTop || dd.scrollLeft)) {
1926                      return [dd.scrollTop, dd.scrollLeft];
1927                  } else if (db) {
1928                      return [db.scrollTop, db.scrollLeft];
1929                  } else {
1930                      return [0, 0];
1931                  }
1932              },
1933  
1934              /**
1935               * Used by old versions of CustomEvent, restored for backwards
1936               * compatibility
1937               * @method regCE
1938               * @private
1939               * @static
1940               * @deprecated still here for backwards compatibility
1941               */
1942              regCE: function() {},
1943  
1944              /**
1945               * Adds a DOM event directly without the caching, cleanup, context adj, etc
1946               *
1947               * @method _simpleAdd
1948               * @param {HTMLElement} el      the element to bind the handler to
1949               * @param {string}      sType   the type of event handler
1950               * @param {function}    fn      the callback to invoke
1951               * @param {boolen}      capture capture or bubble phase
1952               * @static
1953               * @private
1954               */
1955              _simpleAdd: function () {
1956                  if (window.addEventListener) {
1957                      return function(el, sType, fn, capture) {
1958                          el.addEventListener(sType, fn, (capture));
1959                      };
1960                  } else if (window.attachEvent) {
1961                      return function(el, sType, fn, capture) {
1962                          el.attachEvent("on" + sType, fn);
1963                      };
1964                  } else {
1965                      return function(){};
1966                  }
1967              }(),
1968  
1969              /**
1970               * Basic remove listener
1971               *
1972               * @method _simpleRemove
1973               * @param {HTMLElement} el      the element to bind the handler to
1974               * @param {string}      sType   the type of event handler
1975               * @param {function}    fn      the callback to invoke
1976               * @param {boolen}      capture capture or bubble phase
1977               * @static
1978               * @private
1979               */
1980              _simpleRemove: function() {
1981                  if (window.removeEventListener) {
1982                      return function (el, sType, fn, capture) {
1983                          el.removeEventListener(sType, fn, (capture));
1984                      };
1985                  } else if (window.detachEvent) {
1986                      return function (el, sType, fn) {
1987                          el.detachEvent("on" + sType, fn);
1988                      };
1989                  } else {
1990                      return function(){};
1991                  }
1992              }()
1993          };
1994  
1995      }();
1996  
1997      (function() {
1998          var EU = YAHOO.util.Event;
1999  
2000          /**
2001           * Appends an event handler.  This is an alias for <code>addListener</code>
2002           *
2003           * @method on
2004           *
2005           * @param {String|HTMLElement|Array|NodeList} el An id, an element
2006           *  reference, or a collection of ids and/or elements to assign the
2007           *  listener to.
2008           * @param {String}   sType     The type of event to append
2009           * @param {Function} fn        The method the event invokes
2010           * @param {Object}   obj    An arbitrary object that will be
2011           *                             passed as a parameter to the handler
2012           * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
2013           *                             the execution context of the listener. If an
2014           *                             object, this object becomes the execution
2015           *                             context.
2016           * @return {Boolean} True if the action was successful or defered,
2017           *                        false if one or more of the elements
2018           *                        could not have the listener attached,
2019           *                        or if the operation throws an exception.
2020           * @static
2021           */
2022          EU.on = EU.addListener;
2023  
2024          /**
2025           * YAHOO.util.Event.onFocus is an alias for addFocusListener
2026           * @method onFocus
2027           * @see addFocusListener
2028           * @static
2029           * @deprecated use YAHOO.util.Event.on and specify "focusin" as the event type.
2030           */
2031          EU.onFocus = EU.addFocusListener;
2032  
2033          /**
2034           * YAHOO.util.Event.onBlur is an alias for addBlurListener
2035           * @method onBlur
2036           * @see addBlurListener
2037           * @static
2038           * @deprecated use YAHOO.util.Event.on and specify "focusout" as the event type.
2039           */
2040          EU.onBlur = EU.addBlurListener;
2041  
2042  /*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
2043  
2044          // Internet Explorer: use the readyState of a defered script.
2045          // This isolates what appears to be a safe moment to manipulate
2046          // the DOM prior to when the document's readyState suggests
2047          // it is safe to do so.
2048          if (EU.isIE) {
2049              if (self !== self.top) {
2050                  document.onreadystatechange = function() {
2051                      if (document.readyState == 'complete') {
2052                          document.onreadystatechange = null;
2053                          EU._ready();
2054                      }
2055                  };
2056              } else {
2057  
2058                  // Process onAvailable/onContentReady items when the
2059                  // DOM is ready.
2060                  YAHOO.util.Event.onDOMReady(
2061                          YAHOO.util.Event._tryPreloadAttach,
2062                          YAHOO.util.Event, true);
2063  
2064                  var n = document.createElement('p');
2065  
2066                  EU._dri = setInterval(function() {
2067                      try {
2068                          // throws an error if doc is not ready
2069                          n.doScroll('left');
2070                          clearInterval(EU._dri);
2071                          EU._dri = null;
2072                          EU._ready();
2073                          n = null;
2074                      } catch (ex) {
2075                      }
2076                  }, EU.POLL_INTERVAL);
2077              }
2078  
2079          // The document's readyState in Safari currently will
2080          // change to loaded/complete before images are loaded.
2081          } else if (EU.webkit && EU.webkit < 525) {
2082  
2083              EU._dri = setInterval(function() {
2084                  var rs=document.readyState;
2085                  if ("loaded" == rs || "complete" == rs) {
2086                      clearInterval(EU._dri);
2087                      EU._dri = null;
2088                      EU._ready();
2089                  }
2090              }, EU.POLL_INTERVAL);
2091  
2092          // FireFox and Opera: These browsers provide a event for this
2093          // moment.  The latest WebKit releases now support this event.
2094          } else {
2095  
2096              EU._simpleAdd(document, "DOMContentLoaded", EU._ready);
2097  
2098          }
2099          /////////////////////////////////////////////////////////////
2100  
2101  
2102          EU._simpleAdd(window, "load", EU._load);
2103          EU._simpleAdd(window, "unload", EU._unload);
2104          EU._tryPreloadAttach();
2105      })();
2106  
2107  }
2108  /**
2109   * EventProvider is designed to be used with YAHOO.augment to wrap
2110   * CustomEvents in an interface that allows events to be subscribed to
2111   * and fired by name.  This makes it possible for implementing code to
2112   * subscribe to an event that either has not been created yet, or will
2113   * not be created at all.
2114   *
2115   * @Class EventProvider
2116   */
2117  YAHOO.util.EventProvider = function() { };
2118  
2119  YAHOO.util.EventProvider.prototype = {
2120  
2121      /**
2122       * Private storage of custom events
2123       * @property __yui_events
2124       * @type Object[]
2125       * @private
2126       */
2127      __yui_events: null,
2128  
2129      /**
2130       * Private storage of custom event subscribers
2131       * @property __yui_subscribers
2132       * @type Object[]
2133       * @private
2134       */
2135      __yui_subscribers: null,
2136  
2137      /**
2138       * Subscribe to a CustomEvent by event type
2139       *
2140       * @method subscribe
2141       * @param p_type     {string}   the type, or name of the event
2142       * @param p_fn       {function} the function to exectute when the event fires
2143       * @param p_obj      {Object}   An object to be passed along when the event
2144       *                              fires
2145       * @param overrideContext {boolean}  If true, the obj passed in becomes the
2146       *                              execution scope of the listener
2147       */
2148      subscribe: function(p_type, p_fn, p_obj, overrideContext) {
2149  
2150          this.__yui_events = this.__yui_events || {};
2151          var ce = this.__yui_events[p_type];
2152  
2153          if (ce) {
2154              ce.subscribe(p_fn, p_obj, overrideContext);
2155          } else {
2156              this.__yui_subscribers = this.__yui_subscribers || {};
2157              var subs = this.__yui_subscribers;
2158              if (!subs[p_type]) {
2159                  subs[p_type] = [];
2160              }
2161              subs[p_type].push(
2162                  { fn: p_fn, obj: p_obj, overrideContext: overrideContext } );
2163          }
2164      },
2165  
2166      /**
2167       * Unsubscribes one or more listeners the from the specified event
2168       * @method unsubscribe
2169       * @param p_type {string}   The type, or name of the event.  If the type
2170       *                          is not specified, it will attempt to remove
2171       *                          the listener from all hosted events.
2172       * @param p_fn   {Function} The subscribed function to unsubscribe, if not
2173       *                          supplied, all subscribers will be removed.
2174       * @param p_obj  {Object}   The custom object passed to subscribe.  This is
2175       *                        optional, but if supplied will be used to
2176       *                        disambiguate multiple listeners that are the same
2177       *                        (e.g., you subscribe many object using a function
2178       *                        that lives on the prototype)
2179       * @return {boolean} true if the subscriber was found and detached.
2180       */
2181      unsubscribe: function(p_type, p_fn, p_obj) {
2182          this.__yui_events = this.__yui_events || {};
2183          var evts = this.__yui_events;
2184          if (p_type) {
2185              var ce = evts[p_type];
2186              if (ce) {
2187                  return ce.unsubscribe(p_fn, p_obj);
2188              }
2189          } else {
2190              var ret = true;
2191              for (var i in evts) {
2192                  if (YAHOO.lang.hasOwnProperty(evts, i)) {
2193                      ret = ret && evts[i].unsubscribe(p_fn, p_obj);
2194                  }
2195              }
2196              return ret;
2197          }
2198  
2199          return false;
2200      },
2201  
2202      /**
2203       * Removes all listeners from the specified event.  If the event type
2204       * is not specified, all listeners from all hosted custom events will
2205       * be removed.
2206       * @method unsubscribeAll
2207       * @param p_type {string}   The type, or name of the event
2208       */
2209      unsubscribeAll: function(p_type) {
2210          return this.unsubscribe(p_type);
2211      },
2212  
2213      /**
2214       * Creates a new custom event of the specified type.  If a custom event
2215       * by that name already exists, it will not be re-created.  In either
2216       * case the custom event is returned.
2217       *
2218       * @method createEvent
2219       *
2220       * @param p_type {string} the type, or name of the event
2221       * @param p_config {object} optional config params.  Valid properties are:
2222       *
2223       *  <ul>
2224       *    <li>
2225       *      scope: defines the default execution scope.  If not defined
2226       *      the default scope will be this instance.
2227       *    </li>
2228       *    <li>
2229       *      silent: if true, the custom event will not generate log messages.
2230       *      This is false by default.
2231       *    </li>
2232       *    <li>
2233       *      fireOnce: if true, the custom event will only notify subscribers
2234       *      once regardless of the number of times the event is fired.  In
2235       *      addition, new subscribers will be executed immediately if the
2236       *      event has already fired.
2237       *      This is false by default.
2238       *    </li>
2239       *    <li>
2240       *      onSubscribeCallback: specifies a callback to execute when the
2241       *      event has a new subscriber.  This will fire immediately for
2242       *      each queued subscriber if any exist prior to the creation of
2243       *      the event.
2244       *    </li>
2245       *  </ul>
2246       *
2247       *  @return {CustomEvent} the custom event
2248       *
2249       */
2250      createEvent: function(p_type, p_config) {
2251  
2252          this.__yui_events = this.__yui_events || {};
2253          var opts = p_config || {},
2254              events = this.__yui_events, ce;
2255  
2256          if (events[p_type]) {
2257  YAHOO.log("EventProvider createEvent skipped: '"+p_type+"' already exists");
2258          } else {
2259  
2260              ce = new YAHOO.util.CustomEvent(p_type, opts.scope || this, opts.silent,
2261                           YAHOO.util.CustomEvent.FLAT, opts.fireOnce);
2262  
2263              events[p_type] = ce;
2264  
2265              if (opts.onSubscribeCallback) {
2266                  ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
2267              }
2268  
2269              this.__yui_subscribers = this.__yui_subscribers || {};
2270              var qs = this.__yui_subscribers[p_type];
2271  
2272              if (qs) {
2273                  for (var i=0; i<qs.length; ++i) {
2274                      ce.subscribe(qs[i].fn, qs[i].obj, qs[i].overrideContext);
2275                  }
2276              }
2277          }
2278  
2279          return events[p_type];
2280      },
2281  
2282  
2283     /**
2284       * Fire a custom event by name.  The callback functions will be executed
2285       * from the scope specified when the event was created, and with the
2286       * following parameters:
2287       *   <ul>
2288       *   <li>The first argument fire() was executed with</li>
2289       *   <li>The custom object (if any) that was passed into the subscribe()
2290       *       method</li>
2291       *   </ul>
2292       * @method fireEvent
2293       * @param p_type    {string}  the type, or name of the event
2294       * @param arguments {Object*} an arbitrary set of parameters to pass to
2295       *                            the handler.
2296       * @return {boolean} the return value from CustomEvent.fire
2297       *
2298       */
2299      fireEvent: function(p_type) {
2300  
2301          this.__yui_events = this.__yui_events || {};
2302          var ce = this.__yui_events[p_type];
2303  
2304          if (!ce) {
2305  YAHOO.log(p_type + "event fired before it was created.");
2306              return null;
2307          }
2308  
2309          var args = [];
2310          for (var i=1; i<arguments.length; ++i) {
2311              args.push(arguments[i]);
2312          }
2313          return ce.fire.apply(ce, args);
2314      },
2315  
2316      /**
2317       * Returns true if the custom event of the provided type has been created
2318       * with createEvent.
2319       * @method hasEvent
2320       * @param type {string} the type, or name of the event
2321       */
2322      hasEvent: function(type) {
2323          if (this.__yui_events) {
2324              if (this.__yui_events[type]) {
2325                  return true;
2326              }
2327          }
2328          return false;
2329      }
2330  
2331  };
2332  
2333  (function() {
2334  
2335      var Event = YAHOO.util.Event, Lang = YAHOO.lang;
2336  
2337  /**
2338  * KeyListener is a utility that provides an easy interface for listening for
2339  * keydown/keyup events fired against DOM elements.
2340  * @namespace YAHOO.util
2341  * @class KeyListener
2342  * @constructor
2343  * @param {HTMLElement} attachTo The element or element ID to which the key
2344  *                               event should be attached
2345  * @param {String}      attachTo The element or element ID to which the key
2346  *                               event should be attached
2347  * @param {Object}      keyData  The object literal representing the key(s)
2348  *                               to detect. Possible attributes are
2349  *                               shift(boolean), alt(boolean), ctrl(boolean)
2350  *                               and keys(either an int or an array of ints
2351  *                               representing keycodes).
2352  * @param {Function}    handler  The CustomEvent handler to fire when the
2353  *                               key event is detected
2354  * @param {Object}      handler  An object literal representing the handler.
2355  * @param {String}      event    Optional. The event (keydown or keyup) to
2356  *                               listen for. Defaults automatically to keydown.
2357  *
2358  * @knownissue the "keypress" event is completely broken in Safari 2.x and below.
2359  *             the workaround is use "keydown" for key listening.  However, if
2360  *             it is desired to prevent the default behavior of the keystroke,
2361  *             that can only be done on the keypress event.  This makes key
2362  *             handling quite ugly.
2363  * @knownissue keydown is also broken in Safari 2.x and below for the ESC key.
2364  *             There currently is no workaround other than choosing another
2365  *             key to listen for.
2366  */
2367  YAHOO.util.KeyListener = function(attachTo, keyData, handler, event) {
2368      if (!attachTo) {
2369          YAHOO.log("No attachTo element specified", "error");
2370      } else if (!keyData) {
2371          YAHOO.log("No keyData specified", "error");
2372      } else if (!handler) {
2373          YAHOO.log("No handler specified", "error");
2374      }
2375  
2376      if (!event) {
2377          event = YAHOO.util.KeyListener.KEYDOWN;
2378      }
2379  
2380      /**
2381      * The CustomEvent fired internally when a key is pressed
2382      * @event keyEvent
2383      * @private
2384      * @param {Object} keyData The object literal representing the key(s) to
2385      *                         detect. Possible attributes are shift(boolean),
2386      *                         alt(boolean), ctrl(boolean) and keys(either an
2387      *                         int or an array of ints representing keycodes).
2388      */
2389      var keyEvent = new YAHOO.util.CustomEvent("keyPressed");
2390  
2391      /**
2392      * The CustomEvent fired when the KeyListener is enabled via the enable()
2393      * function
2394      * @event enabledEvent
2395      * @param {Object} keyData The object literal representing the key(s) to
2396      *                         detect. Possible attributes are shift(boolean),
2397      *                         alt(boolean), ctrl(boolean) and keys(either an
2398      *                         int or an array of ints representing keycodes).
2399      */
2400      this.enabledEvent = new YAHOO.util.CustomEvent("enabled");
2401  
2402      /**
2403      * The CustomEvent fired when the KeyListener is disabled via the
2404      * disable() function
2405      * @event disabledEvent
2406      * @param {Object} keyData The object literal representing the key(s) to
2407      *                         detect. Possible attributes are shift(boolean),
2408      *                         alt(boolean), ctrl(boolean) and keys(either an
2409      *                         int or an array of ints representing keycodes).
2410      */
2411      this.disabledEvent = new YAHOO.util.CustomEvent("disabled");
2412  
2413      if (Lang.isString(attachTo)) {
2414          attachTo = document.getElementById(attachTo); // No Dom util
2415      }
2416  
2417      if (Lang.isFunction(handler)) {
2418          keyEvent.subscribe(handler);
2419      } else {
2420          keyEvent.subscribe(handler.fn, handler.scope, handler.correctScope);
2421      }
2422  
2423      /**
2424      * Handles the key event when a key is pressed.
2425      * @method handleKeyPress
2426      * @param {DOMEvent} e   The keypress DOM event
2427      * @param {Object}   obj The DOM event scope object
2428      * @private
2429      */
2430      function handleKeyPress(e, obj) {
2431          if (! keyData.shift) {
2432              keyData.shift = false;
2433          }
2434          if (! keyData.alt) {
2435              keyData.alt = false;
2436          }
2437          if (! keyData.ctrl) {
2438              keyData.ctrl = false;
2439          }
2440  
2441          // check held down modifying keys first
2442          if (e.shiftKey == keyData.shift &&
2443              e.altKey   == keyData.alt &&
2444              e.ctrlKey  == keyData.ctrl) { // if we pass this, all modifiers match
2445  
2446              var dataItem, keys = keyData.keys, key;
2447  
2448              if (YAHOO.lang.isArray(keys)) {
2449                  for (var i=0;i<keys.length;i++) {
2450                      dataItem = keys[i];
2451                      key = Event.getCharCode(e);
2452  
2453                      if (dataItem == key) {
2454                          keyEvent.fire(key, e);
2455                          break;
2456                      }
2457                  }
2458              } else {
2459                  key = Event.getCharCode(e);
2460                  if (keys == key ) {
2461                      keyEvent.fire(key, e);
2462                  }
2463              }
2464          }
2465      }
2466  
2467      /**
2468      * Enables the KeyListener by attaching the DOM event listeners to the
2469      * target DOM element
2470      * @method enable
2471      */
2472      this.enable = function() {
2473          if (! this.enabled) {
2474              Event.on(attachTo, event, handleKeyPress);
2475              this.enabledEvent.fire(keyData);
2476          }
2477          /**
2478          * Boolean indicating the enabled/disabled state of the Tooltip
2479          * @property enabled
2480          * @type Boolean
2481          */
2482          this.enabled = true;
2483      };
2484  
2485      /**
2486      * Disables the KeyListener by removing the DOM event listeners from the
2487      * target DOM element
2488      * @method disable
2489      */
2490      this.disable = function() {
2491          if (this.enabled) {
2492              Event.removeListener(attachTo, event, handleKeyPress);
2493              this.disabledEvent.fire(keyData);
2494          }
2495          this.enabled = false;
2496      };
2497  
2498      /**
2499      * Returns a String representation of the object.
2500      * @method toString
2501      * @return {String}  The string representation of the KeyListener
2502      */
2503      this.toString = function() {
2504          return "KeyListener [" + keyData.keys + "] " + attachTo.tagName +
2505                  (attachTo.id ? "[" + attachTo.id + "]" : "");
2506      };
2507  
2508  };
2509  
2510  var KeyListener = YAHOO.util.KeyListener;
2511  
2512  /**
2513   * Constant representing the DOM "keydown" event.
2514   * @property YAHOO.util.KeyListener.KEYDOWN
2515   * @static
2516   * @final
2517   * @type String
2518   */
2519  KeyListener.KEYDOWN = "keydown";
2520  
2521  /**
2522   * Constant representing the DOM "keyup" event.
2523   * @property YAHOO.util.KeyListener.KEYUP
2524   * @static
2525   * @final
2526   * @type String
2527   */
2528  KeyListener.KEYUP = "keyup";
2529  
2530  /**
2531   * keycode constants for a subset of the special keys
2532   * @property KEY
2533   * @static
2534   * @final
2535   */
2536  KeyListener.KEY = {
2537      ALT          : 18,
2538      BACK_SPACE   : 8,
2539      CAPS_LOCK    : 20,
2540      CONTROL      : 17,
2541      DELETE       : 46,
2542      DOWN         : 40,
2543      END          : 35,
2544      ENTER        : 13,
2545      ESCAPE       : 27,
2546      HOME         : 36,
2547      LEFT         : 37,
2548      META         : 224,
2549      NUM_LOCK     : 144,
2550      PAGE_DOWN    : 34,
2551      PAGE_UP      : 33,
2552      PAUSE        : 19,
2553      PRINTSCREEN  : 44,
2554      RIGHT        : 39,
2555      SCROLL_LOCK  : 145,
2556      SHIFT        : 16,
2557      SPACE        : 32,
2558      TAB          : 9,
2559      UP           : 38
2560  };
2561  
2562  })();
2563  YAHOO.register("event", YAHOO.util.Event, {version: "2.9.0", build: "2800"});
2564  
2565      YAHOO.util.Event.generateId = function(el) {
2566          if (!el.id) {
2567              el.id = Y.guid();
2568          }
2569          return el.id;
2570      };
2571      YAHOO.util.Event._load();
2572  }, '2.9.0' ,{"requires": ["yui2-yahoo"]});


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