[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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

   1  YUI.add('yui2-containercore', function(Y) { Y.use('yui2-container'); }, '3.3.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event"]});
   2  YUI.add('yui2-container', function(Y) {
   3      var YAHOO    = Y.YUI2;
   4      /*
   5  Copyright (c) 2011, Yahoo! Inc. All rights reserved.
   6  Code licensed under the BSD License:
   7  http://developer.yahoo.com/yui/license.html
   8  version: 2.9.0
   9  */
  10  (function () {
  11  
  12      /**
  13      * Config is a utility used within an Object to allow the implementer to
  14      * maintain a list of local configuration properties and listen for changes 
  15      * to those properties dynamically using CustomEvent. The initial values are 
  16      * also maintained so that the configuration can be reset at any given point 
  17      * to its initial state.
  18      * @namespace YAHOO.util
  19      * @class Config
  20      * @constructor
  21      * @param {Object} owner The owner Object to which this Config Object belongs
  22      */
  23      YAHOO.util.Config = function (owner) {
  24  
  25          if (owner) {
  26              this.init(owner);
  27          }
  28  
  29          if (!owner) {  YAHOO.log("No owner specified for Config object", "error", "Config"); }
  30  
  31      };
  32  
  33  
  34      var Lang = YAHOO.lang,
  35          CustomEvent = YAHOO.util.CustomEvent,
  36          Config = YAHOO.util.Config;
  37  
  38  
  39      /**
  40       * Constant representing the CustomEvent type for the config changed event.
  41       * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
  42       * @private
  43       * @static
  44       * @final
  45       */
  46      Config.CONFIG_CHANGED_EVENT = "configChanged";
  47      
  48      /**
  49       * Constant representing the boolean type string
  50       * @property YAHOO.util.Config.BOOLEAN_TYPE
  51       * @private
  52       * @static
  53       * @final
  54       */
  55      Config.BOOLEAN_TYPE = "boolean";
  56      
  57      Config.prototype = {
  58       
  59          /**
  60          * Object reference to the owner of this Config Object
  61          * @property owner
  62          * @type Object
  63          */
  64          owner: null,
  65          
  66          /**
  67          * Boolean flag that specifies whether a queue is currently 
  68          * being executed
  69          * @property queueInProgress
  70          * @type Boolean
  71          */
  72          queueInProgress: false,
  73          
  74          /**
  75          * Maintains the local collection of configuration property objects and 
  76          * their specified values
  77          * @property config
  78          * @private
  79          * @type Object
  80          */ 
  81          config: null,
  82          
  83          /**
  84          * Maintains the local collection of configuration property objects as 
  85          * they were initially applied.
  86          * This object is used when resetting a property.
  87          * @property initialConfig
  88          * @private
  89          * @type Object
  90          */ 
  91          initialConfig: null,
  92          
  93          /**
  94          * Maintains the local, normalized CustomEvent queue
  95          * @property eventQueue
  96          * @private
  97          * @type Object
  98          */ 
  99          eventQueue: null,
 100          
 101          /**
 102          * Custom Event, notifying subscribers when Config properties are set 
 103          * (setProperty is called without the silent flag
 104          * @event configChangedEvent
 105          */
 106          configChangedEvent: null,
 107      
 108          /**
 109          * Initializes the configuration Object and all of its local members.
 110          * @method init
 111          * @param {Object} owner The owner Object to which this Config 
 112          * Object belongs
 113          */
 114          init: function (owner) {
 115      
 116              this.owner = owner;
 117      
 118              this.configChangedEvent = 
 119                  this.createEvent(Config.CONFIG_CHANGED_EVENT);
 120      
 121              this.configChangedEvent.signature = CustomEvent.LIST;
 122              this.queueInProgress = false;
 123              this.config = {};
 124              this.initialConfig = {};
 125              this.eventQueue = [];
 126          
 127          },
 128          
 129          /**
 130          * Validates that the value passed in is a Boolean.
 131          * @method checkBoolean
 132          * @param {Object} val The value to validate
 133          * @return {Boolean} true, if the value is valid
 134          */ 
 135          checkBoolean: function (val) {
 136              return (typeof val == Config.BOOLEAN_TYPE);
 137          },
 138          
 139          /**
 140          * Validates that the value passed in is a number.
 141          * @method checkNumber
 142          * @param {Object} val The value to validate
 143          * @return {Boolean} true, if the value is valid
 144          */
 145          checkNumber: function (val) {
 146              return (!isNaN(val));
 147          },
 148          
 149          /**
 150          * Fires a configuration property event using the specified value. 
 151          * @method fireEvent
 152          * @private
 153          * @param {String} key The configuration property's name
 154          * @param {value} Object The value of the correct type for the property
 155          */ 
 156          fireEvent: function ( key, value ) {
 157              YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
 158              var property = this.config[key];
 159          
 160              if (property && property.event) {
 161                  property.event.fire(value);
 162              } 
 163          },
 164          
 165          /**
 166          * Adds a property to the Config Object's private config hash.
 167          * @method addProperty
 168          * @param {String} key The configuration property's name
 169          * @param {Object} propertyObject The Object containing all of this 
 170          * property's arguments
 171          */
 172          addProperty: function ( key, propertyObject ) {
 173              key = key.toLowerCase();
 174              YAHOO.log("Added property: " + key, "info", "Config");
 175          
 176              this.config[key] = propertyObject;
 177          
 178              propertyObject.event = this.createEvent(key, { scope: this.owner });
 179              propertyObject.event.signature = CustomEvent.LIST;
 180              
 181              
 182              propertyObject.key = key;
 183          
 184              if (propertyObject.handler) {
 185                  propertyObject.event.subscribe(propertyObject.handler, 
 186                      this.owner);
 187              }
 188          
 189              this.setProperty(key, propertyObject.value, true);
 190              
 191              if (! propertyObject.suppressEvent) {
 192                  this.queueProperty(key, propertyObject.value);
 193              }
 194              
 195          },
 196          
 197          /**
 198          * Returns a key-value configuration map of the values currently set in  
 199          * the Config Object.
 200          * @method getConfig
 201          * @return {Object} The current config, represented in a key-value map
 202          */
 203          getConfig: function () {
 204          
 205              var cfg = {},
 206                  currCfg = this.config,
 207                  prop,
 208                  property;
 209                  
 210              for (prop in currCfg) {
 211                  if (Lang.hasOwnProperty(currCfg, prop)) {
 212                      property = currCfg[prop];
 213                      if (property && property.event) {
 214                          cfg[prop] = property.value;
 215                      }
 216                  }
 217              }
 218  
 219              return cfg;
 220          },
 221          
 222          /**
 223          * Returns the value of specified property.
 224          * @method getProperty
 225          * @param {String} key The name of the property
 226          * @return {Object}  The value of the specified property
 227          */
 228          getProperty: function (key) {
 229              var property = this.config[key.toLowerCase()];
 230              if (property && property.event) {
 231                  return property.value;
 232              } else {
 233                  return undefined;
 234              }
 235          },
 236          
 237          /**
 238          * Resets the specified property's value to its initial value.
 239          * @method resetProperty
 240          * @param {String} key The name of the property
 241          * @return {Boolean} True is the property was reset, false if not
 242          */
 243          resetProperty: function (key) {
 244              key = key.toLowerCase();
 245  
 246              var property = this.config[key];
 247  
 248              if (property && property.event) {
 249                  if (key in this.initialConfig) {
 250                      this.setProperty(key, this.initialConfig[key]);
 251                      return true;
 252                  }
 253              } else {
 254                  return false;
 255              }
 256          },
 257          
 258          /**
 259          * Sets the value of a property. If the silent property is passed as 
 260          * true, the property's event will not be fired.
 261          * @method setProperty
 262          * @param {String} key The name of the property
 263          * @param {String} value The value to set the property to
 264          * @param {Boolean} silent Whether the value should be set silently, 
 265          * without firing the property event.
 266          * @return {Boolean} True, if the set was successful, false if it failed.
 267          */
 268          setProperty: function (key, value, silent) {
 269          
 270              var property;
 271          
 272              key = key.toLowerCase();
 273              YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
 274          
 275              if (this.queueInProgress && ! silent) {
 276                  // Currently running through a queue... 
 277                  this.queueProperty(key,value);
 278                  return true;
 279      
 280              } else {
 281                  property = this.config[key];
 282                  if (property && property.event) {
 283                      if (property.validator && !property.validator(value)) {
 284                          return false;
 285                      } else {
 286                          property.value = value;
 287                          if (! silent) {
 288                              this.fireEvent(key, value);
 289                              this.configChangedEvent.fire([key, value]);
 290                          }
 291                          return true;
 292                      }
 293                  } else {
 294                      return false;
 295                  }
 296              }
 297          },
 298          
 299          /**
 300          * Sets the value of a property and queues its event to execute. If the 
 301          * event is already scheduled to execute, it is
 302          * moved from its current position to the end of the queue.
 303          * @method queueProperty
 304          * @param {String} key The name of the property
 305          * @param {String} value The value to set the property to
 306          * @return {Boolean}  true, if the set was successful, false if 
 307          * it failed.
 308          */ 
 309          queueProperty: function (key, value) {
 310          
 311              key = key.toLowerCase();
 312              YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
 313          
 314              var property = this.config[key],
 315                  foundDuplicate = false,
 316                  iLen,
 317                  queueItem,
 318                  queueItemKey,
 319                  queueItemValue,
 320                  sLen,
 321                  supercedesCheck,
 322                  qLen,
 323                  queueItemCheck,
 324                  queueItemCheckKey,
 325                  queueItemCheckValue,
 326                  i,
 327                  s,
 328                  q;
 329                                  
 330              if (property && property.event) {
 331      
 332                  if (!Lang.isUndefined(value) && property.validator && 
 333                      !property.validator(value)) { // validator
 334                      return false;
 335                  } else {
 336          
 337                      if (!Lang.isUndefined(value)) {
 338                          property.value = value;
 339                      } else {
 340                          value = property.value;
 341                      }
 342          
 343                      foundDuplicate = false;
 344                      iLen = this.eventQueue.length;
 345          
 346                      for (i = 0; i < iLen; i++) {
 347                          queueItem = this.eventQueue[i];
 348          
 349                          if (queueItem) {
 350                              queueItemKey = queueItem[0];
 351                              queueItemValue = queueItem[1];
 352  
 353                              if (queueItemKey == key) {
 354      
 355                                  /*
 356                                      found a dupe... push to end of queue, null 
 357                                      current item, and break
 358                                  */
 359      
 360                                  this.eventQueue[i] = null;
 361      
 362                                  this.eventQueue.push(
 363                                      [key, (!Lang.isUndefined(value) ? 
 364                                      value : queueItemValue)]);
 365      
 366                                  foundDuplicate = true;
 367                                  break;
 368                              }
 369                          }
 370                      }
 371                      
 372                      // this is a refire, or a new property in the queue
 373      
 374                      if (! foundDuplicate && !Lang.isUndefined(value)) { 
 375                          this.eventQueue.push([key, value]);
 376                      }
 377                  }
 378          
 379                  if (property.supercedes) {
 380  
 381                      sLen = property.supercedes.length;
 382  
 383                      for (s = 0; s < sLen; s++) {
 384  
 385                          supercedesCheck = property.supercedes[s];
 386                          qLen = this.eventQueue.length;
 387  
 388                          for (q = 0; q < qLen; q++) {
 389                              queueItemCheck = this.eventQueue[q];
 390  
 391                              if (queueItemCheck) {
 392                                  queueItemCheckKey = queueItemCheck[0];
 393                                  queueItemCheckValue = queueItemCheck[1];
 394  
 395                                  if (queueItemCheckKey == 
 396                                      supercedesCheck.toLowerCase() ) {
 397  
 398                                      this.eventQueue.push([queueItemCheckKey, 
 399                                          queueItemCheckValue]);
 400  
 401                                      this.eventQueue[q] = null;
 402                                      break;
 403  
 404                                  }
 405                              }
 406                          }
 407                      }
 408                  }
 409  
 410                  YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
 411  
 412                  return true;
 413              } else {
 414                  return false;
 415              }
 416          },
 417          
 418          /**
 419          * Fires the event for a property using the property's current value.
 420          * @method refireEvent
 421          * @param {String} key The name of the property
 422          */
 423          refireEvent: function (key) {
 424      
 425              key = key.toLowerCase();
 426          
 427              var property = this.config[key];
 428      
 429              if (property && property.event && 
 430      
 431                  !Lang.isUndefined(property.value)) {
 432      
 433                  if (this.queueInProgress) {
 434      
 435                      this.queueProperty(key);
 436      
 437                  } else {
 438      
 439                      this.fireEvent(key, property.value);
 440      
 441                  }
 442      
 443              }
 444          },
 445          
 446          /**
 447          * Applies a key-value Object literal to the configuration, replacing  
 448          * any existing values, and queueing the property events.
 449          * Although the values will be set, fireQueue() must be called for their 
 450          * associated events to execute.
 451          * @method applyConfig
 452          * @param {Object} userConfig The configuration Object literal
 453          * @param {Boolean} init  When set to true, the initialConfig will 
 454          * be set to the userConfig passed in, so that calling a reset will 
 455          * reset the properties to the passed values.
 456          */
 457          applyConfig: function (userConfig, init) {
 458          
 459              var sKey,
 460                  oConfig;
 461  
 462              if (init) {
 463                  oConfig = {};
 464                  for (sKey in userConfig) {
 465                      if (Lang.hasOwnProperty(userConfig, sKey)) {
 466                          oConfig[sKey.toLowerCase()] = userConfig[sKey];
 467                      }
 468                  }
 469                  this.initialConfig = oConfig;
 470              }
 471  
 472              for (sKey in userConfig) {
 473                  if (Lang.hasOwnProperty(userConfig, sKey)) {
 474                      this.queueProperty(sKey, userConfig[sKey]);
 475                  }
 476              }
 477          },
 478          
 479          /**
 480          * Refires the events for all configuration properties using their 
 481          * current values.
 482          * @method refresh
 483          */
 484          refresh: function () {
 485  
 486              var prop;
 487  
 488              for (prop in this.config) {
 489                  if (Lang.hasOwnProperty(this.config, prop)) {
 490                      this.refireEvent(prop);
 491                  }
 492              }
 493          },
 494          
 495          /**
 496          * Fires the normalized list of queued property change events
 497          * @method fireQueue
 498          */
 499          fireQueue: function () {
 500          
 501              var i, 
 502                  queueItem,
 503                  key,
 504                  value,
 505                  property;
 506          
 507              this.queueInProgress = true;
 508              for (i = 0;i < this.eventQueue.length; i++) {
 509                  queueItem = this.eventQueue[i];
 510                  if (queueItem) {
 511          
 512                      key = queueItem[0];
 513                      value = queueItem[1];
 514                      property = this.config[key];
 515  
 516                      property.value = value;
 517  
 518                      // Clear out queue entry, to avoid it being 
 519                      // re-added to the queue by any queueProperty/supercedes
 520                      // calls which are invoked during fireEvent
 521                      this.eventQueue[i] = null;
 522  
 523                      this.fireEvent(key,value);
 524                  }
 525              }
 526              
 527              this.queueInProgress = false;
 528              this.eventQueue = [];
 529          },
 530          
 531          /**
 532          * Subscribes an external handler to the change event for any 
 533          * given property. 
 534          * @method subscribeToConfigEvent
 535          * @param {String} key The property name
 536          * @param {Function} handler The handler function to use subscribe to 
 537          * the property's event
 538          * @param {Object} obj The Object to use for scoping the event handler 
 539          * (see CustomEvent documentation)
 540          * @param {Boolean} overrideContext Optional. If true, will override
 541          * "this" within the handler to map to the scope Object passed into the
 542          * method.
 543          * @return {Boolean} True, if the subscription was successful, 
 544          * otherwise false.
 545          */ 
 546          subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
 547      
 548              var property = this.config[key.toLowerCase()];
 549      
 550              if (property && property.event) {
 551                  if (!Config.alreadySubscribed(property.event, handler, obj)) {
 552                      property.event.subscribe(handler, obj, overrideContext);
 553                  }
 554                  return true;
 555              } else {
 556                  return false;
 557              }
 558      
 559          },
 560          
 561          /**
 562          * Unsubscribes an external handler from the change event for any 
 563          * given property. 
 564          * @method unsubscribeFromConfigEvent
 565          * @param {String} key The property name
 566          * @param {Function} handler The handler function to use subscribe to 
 567          * the property's event
 568          * @param {Object} obj The Object to use for scoping the event 
 569          * handler (see CustomEvent documentation)
 570          * @return {Boolean} True, if the unsubscription was successful, 
 571          * otherwise false.
 572          */
 573          unsubscribeFromConfigEvent: function (key, handler, obj) {
 574              var property = this.config[key.toLowerCase()];
 575              if (property && property.event) {
 576                  return property.event.unsubscribe(handler, obj);
 577              } else {
 578                  return false;
 579              }
 580          },
 581          
 582          /**
 583          * Returns a string representation of the Config object
 584          * @method toString
 585          * @return {String} The Config object in string format.
 586          */
 587          toString: function () {
 588              var output = "Config";
 589              if (this.owner) {
 590                  output += " [" + this.owner.toString() + "]";
 591              }
 592              return output;
 593          },
 594          
 595          /**
 596          * Returns a string representation of the Config object's current 
 597          * CustomEvent queue
 598          * @method outputEventQueue
 599          * @return {String} The string list of CustomEvents currently queued 
 600          * for execution
 601          */
 602          outputEventQueue: function () {
 603  
 604              var output = "",
 605                  queueItem,
 606                  q,
 607                  nQueue = this.eventQueue.length;
 608                
 609              for (q = 0; q < nQueue; q++) {
 610                  queueItem = this.eventQueue[q];
 611                  if (queueItem) {
 612                      output += queueItem[0] + "=" + queueItem[1] + ", ";
 613                  }
 614              }
 615              return output;
 616          },
 617  
 618          /**
 619          * Sets all properties to null, unsubscribes all listeners from each 
 620          * property's change event and all listeners from the configChangedEvent.
 621          * @method destroy
 622          */
 623          destroy: function () {
 624  
 625              var oConfig = this.config,
 626                  sProperty,
 627                  oProperty;
 628  
 629  
 630              for (sProperty in oConfig) {
 631              
 632                  if (Lang.hasOwnProperty(oConfig, sProperty)) {
 633  
 634                      oProperty = oConfig[sProperty];
 635  
 636                      oProperty.event.unsubscribeAll();
 637                      oProperty.event = null;
 638  
 639                  }
 640              
 641              }
 642              
 643              this.configChangedEvent.unsubscribeAll();
 644              
 645              this.configChangedEvent = null;
 646              this.owner = null;
 647              this.config = null;
 648              this.initialConfig = null;
 649              this.eventQueue = null;
 650          
 651          }
 652  
 653      };
 654      
 655      
 656      
 657      /**
 658      * Checks to determine if a particular function/Object pair are already 
 659      * subscribed to the specified CustomEvent
 660      * @method YAHOO.util.Config.alreadySubscribed
 661      * @static
 662      * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check 
 663      * the subscriptions
 664      * @param {Function} fn The function to look for in the subscribers list
 665      * @param {Object} obj The execution scope Object for the subscription
 666      * @return {Boolean} true, if the function/Object pair is already subscribed 
 667      * to the CustomEvent passed in
 668      */
 669      Config.alreadySubscribed = function (evt, fn, obj) {
 670      
 671          var nSubscribers = evt.subscribers.length,
 672              subsc,
 673              i;
 674  
 675          if (nSubscribers > 0) {
 676              i = nSubscribers - 1;
 677              do {
 678                  subsc = evt.subscribers[i];
 679                  if (subsc && subsc.obj == obj && subsc.fn == fn) {
 680                      return true;
 681                  }
 682              }
 683              while (i--);
 684          }
 685  
 686          return false;
 687  
 688      };
 689  
 690      YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
 691  
 692  }());
 693  (function () {
 694  
 695      /**
 696      * The Container family of components is designed to enable developers to 
 697      * create different kinds of content-containing modules on the web. Module 
 698      * and Overlay are the most basic containers, and they can be used directly 
 699      * or extended to build custom containers. Also part of the Container family 
 700      * are four UI controls that extend Module and Overlay: Tooltip, Panel, 
 701      * Dialog, and SimpleDialog.
 702      * @module container
 703      * @title Container
 704      * @requires yahoo, dom, event 
 705      * @optional dragdrop, animation, button
 706      */
 707      
 708      /**
 709      * Module is a JavaScript representation of the Standard Module Format. 
 710      * Standard Module Format is a simple standard for markup containers where 
 711      * child nodes representing the header, body, and footer of the content are 
 712      * denoted using the CSS classes "hd", "bd", and "ft" respectively. 
 713      * Module is the base class for all other classes in the YUI 
 714      * Container package.
 715      * @namespace YAHOO.widget
 716      * @class Module
 717      * @constructor
 718      * @param {String} el The element ID representing the Module <em>OR</em>
 719      * @param {HTMLElement} el The element representing the Module
 720      * @param {Object} userConfig The configuration Object literal containing 
 721      * the configuration that should be set for this module. See configuration 
 722      * documentation for more details.
 723      */
 724      YAHOO.widget.Module = function (el, userConfig) {
 725          if (el) {
 726              this.init(el, userConfig);
 727          } else {
 728              YAHOO.log("No element or element ID specified" + 
 729                  " for Module instantiation", "error");
 730          }
 731      };
 732  
 733      var Dom = YAHOO.util.Dom,
 734          Config = YAHOO.util.Config,
 735          Event = YAHOO.util.Event,
 736          CustomEvent = YAHOO.util.CustomEvent,
 737          Module = YAHOO.widget.Module,
 738          UA = YAHOO.env.ua,
 739  
 740          m_oModuleTemplate,
 741          m_oHeaderTemplate,
 742          m_oBodyTemplate,
 743          m_oFooterTemplate,
 744  
 745          /**
 746          * Constant representing the name of the Module's events
 747          * @property EVENT_TYPES
 748          * @private
 749          * @final
 750          * @type Object
 751          */
 752          EVENT_TYPES = {
 753              "BEFORE_INIT": "beforeInit",
 754              "INIT": "init",
 755              "APPEND": "append",
 756              "BEFORE_RENDER": "beforeRender",
 757              "RENDER": "render",
 758              "CHANGE_HEADER": "changeHeader",
 759              "CHANGE_BODY": "changeBody",
 760              "CHANGE_FOOTER": "changeFooter",
 761              "CHANGE_CONTENT": "changeContent",
 762              "DESTROY": "destroy",
 763              "BEFORE_SHOW": "beforeShow",
 764              "SHOW": "show",
 765              "BEFORE_HIDE": "beforeHide",
 766              "HIDE": "hide"
 767          },
 768              
 769          /**
 770          * Constant representing the Module's configuration properties
 771          * @property DEFAULT_CONFIG
 772          * @private
 773          * @final
 774          * @type Object
 775          */
 776          DEFAULT_CONFIG = {
 777          
 778              "VISIBLE": { 
 779                  key: "visible", 
 780                  value: true, 
 781                  validator: YAHOO.lang.isBoolean 
 782              },
 783  
 784              "EFFECT": {
 785                  key: "effect",
 786                  suppressEvent: true,
 787                  supercedes: ["visible"]
 788              },
 789  
 790              "MONITOR_RESIZE": {
 791                  key: "monitorresize",
 792                  value: true
 793              },
 794  
 795              "APPEND_TO_DOCUMENT_BODY": {
 796                  key: "appendtodocumentbody",
 797                  value: false
 798              }
 799          };
 800  
 801      /**
 802      * Constant representing the prefix path to use for non-secure images
 803      * @property YAHOO.widget.Module.IMG_ROOT
 804      * @static
 805      * @final
 806      * @type String
 807      */
 808      Module.IMG_ROOT = null;
 809      
 810      /**
 811      * Constant representing the prefix path to use for securely served images
 812      * @property YAHOO.widget.Module.IMG_ROOT_SSL
 813      * @static
 814      * @final
 815      * @type String
 816      */
 817      Module.IMG_ROOT_SSL = null;
 818      
 819      /**
 820      * Constant for the default CSS class name that represents a Module
 821      * @property YAHOO.widget.Module.CSS_MODULE
 822      * @static
 823      * @final
 824      * @type String
 825      */
 826      Module.CSS_MODULE = "yui-module";
 827      
 828      /**
 829      * CSS classname representing the module header. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
 830      * @property YAHOO.widget.Module.CSS_HEADER
 831      * @static
 832      * @final
 833      * @type String
 834      */
 835      Module.CSS_HEADER = "hd";
 836  
 837      /**
 838      * CSS classname representing the module body. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
 839      * @property YAHOO.widget.Module.CSS_BODY
 840      * @static
 841      * @final
 842      * @type String
 843      */
 844      Module.CSS_BODY = "bd";
 845      
 846      /**
 847      * CSS classname representing the module footer. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
 848      * @property YAHOO.widget.Module.CSS_FOOTER
 849      * @static
 850      * @final
 851      * @type String
 852      */
 853      Module.CSS_FOOTER = "ft";
 854      
 855      /**
 856      * Constant representing the url for the "src" attribute of the iframe 
 857      * used to monitor changes to the browser's base font size
 858      * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
 859      * @static
 860      * @final
 861      * @type String
 862      */
 863      Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
 864  
 865      /**
 866      * Constant representing the buffer amount (in pixels) to use when positioning
 867      * the text resize monitor offscreen. The resize monitor is positioned
 868      * offscreen by an amount eqaul to its offsetHeight + the buffer value.
 869      * 
 870      * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
 871      * @static
 872      * @type Number
 873      */
 874      // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
 875      Module.RESIZE_MONITOR_BUFFER = 1;
 876  
 877      /**
 878      * Singleton CustomEvent fired when the font size is changed in the browser.
 879      * Opera's "zoom" functionality currently does not support text 
 880      * size detection.
 881      * @event YAHOO.widget.Module.textResizeEvent
 882      */
 883      Module.textResizeEvent = new CustomEvent("textResize");
 884  
 885      /**
 886       * Helper utility method, which forces a document level 
 887       * redraw for Opera, which can help remove repaint
 888       * irregularities after applying DOM changes.
 889       *
 890       * @method YAHOO.widget.Module.forceDocumentRedraw
 891       * @static
 892       */
 893      Module.forceDocumentRedraw = function() {
 894          var docEl = document.documentElement;
 895          if (docEl) {
 896              docEl.className += " ";
 897              docEl.className = YAHOO.lang.trim(docEl.className);
 898          }
 899      };
 900  
 901      function createModuleTemplate() {
 902  
 903          if (!m_oModuleTemplate) {
 904              m_oModuleTemplate = document.createElement("div");
 905              
 906              m_oModuleTemplate.innerHTML = ("<div class=\"" + 
 907                  Module.CSS_HEADER + "\"></div>" + "<div class=\"" + 
 908                  Module.CSS_BODY + "\"></div><div class=\"" + 
 909                  Module.CSS_FOOTER + "\"></div>");
 910  
 911              m_oHeaderTemplate = m_oModuleTemplate.firstChild;
 912              m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
 913              m_oFooterTemplate = m_oBodyTemplate.nextSibling;
 914          }
 915  
 916          return m_oModuleTemplate;
 917      }
 918  
 919      function createHeader() {
 920          if (!m_oHeaderTemplate) {
 921              createModuleTemplate();
 922          }
 923          return (m_oHeaderTemplate.cloneNode(false));
 924      }
 925  
 926      function createBody() {
 927          if (!m_oBodyTemplate) {
 928              createModuleTemplate();
 929          }
 930          return (m_oBodyTemplate.cloneNode(false));
 931      }
 932  
 933      function createFooter() {
 934          if (!m_oFooterTemplate) {
 935              createModuleTemplate();
 936          }
 937          return (m_oFooterTemplate.cloneNode(false));
 938      }
 939  
 940      Module.prototype = {
 941  
 942          /**
 943          * The class's constructor function
 944          * @property contructor
 945          * @type Function
 946          */
 947          constructor: Module,
 948          
 949          /**
 950          * The main module element that contains the header, body, and footer
 951          * @property element
 952          * @type HTMLElement
 953          */
 954          element: null,
 955  
 956          /**
 957          * The header element, denoted with CSS class "hd"
 958          * @property header
 959          * @type HTMLElement
 960          */
 961          header: null,
 962  
 963          /**
 964          * The body element, denoted with CSS class "bd"
 965          * @property body
 966          * @type HTMLElement
 967          */
 968          body: null,
 969  
 970          /**
 971          * The footer element, denoted with CSS class "ft"
 972          * @property footer
 973          * @type HTMLElement
 974          */
 975          footer: null,
 976  
 977          /**
 978          * The id of the element
 979          * @property id
 980          * @type String
 981          */
 982          id: null,
 983  
 984          /**
 985          * A string representing the root path for all images created by
 986          * a Module instance.
 987          * @deprecated It is recommend that any images for a Module be applied
 988          * via CSS using the "background-image" property.
 989          * @property imageRoot
 990          * @type String
 991          */
 992          imageRoot: Module.IMG_ROOT,
 993  
 994          /**
 995          * Initializes the custom events for Module which are fired 
 996          * automatically at appropriate times by the Module class.
 997          * @method initEvents
 998          */
 999          initEvents: function () {
1000  
1001              var SIGNATURE = CustomEvent.LIST;
1002  
1003              /**
1004              * CustomEvent fired prior to class initalization.
1005              * @event beforeInitEvent
1006              * @param {class} classRef class reference of the initializing 
1007              * class, such as this.beforeInitEvent.fire(Module)
1008              */
1009              this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1010              this.beforeInitEvent.signature = SIGNATURE;
1011  
1012              /**
1013              * CustomEvent fired after class initalization.
1014              * @event initEvent
1015              * @param {class} classRef class reference of the initializing 
1016              * class, such as this.beforeInitEvent.fire(Module)
1017              */  
1018              this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1019              this.initEvent.signature = SIGNATURE;
1020  
1021              /**
1022              * CustomEvent fired when the Module is appended to the DOM
1023              * @event appendEvent
1024              */
1025              this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1026              this.appendEvent.signature = SIGNATURE;
1027  
1028              /**
1029              * CustomEvent fired before the Module is rendered
1030              * @event beforeRenderEvent
1031              */
1032              this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1033              this.beforeRenderEvent.signature = SIGNATURE;
1034          
1035              /**
1036              * CustomEvent fired after the Module is rendered
1037              * @event renderEvent
1038              */
1039              this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1040              this.renderEvent.signature = SIGNATURE;
1041          
1042              /**
1043              * CustomEvent fired when the header content of the Module 
1044              * is modified
1045              * @event changeHeaderEvent
1046              * @param {String/HTMLElement} content String/element representing 
1047              * the new header content
1048              */
1049              this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1050              this.changeHeaderEvent.signature = SIGNATURE;
1051              
1052              /**
1053              * CustomEvent fired when the body content of the Module is modified
1054              * @event changeBodyEvent
1055              * @param {String/HTMLElement} content String/element representing 
1056              * the new body content
1057              */  
1058              this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1059              this.changeBodyEvent.signature = SIGNATURE;
1060              
1061              /**
1062              * CustomEvent fired when the footer content of the Module 
1063              * is modified
1064              * @event changeFooterEvent
1065              * @param {String/HTMLElement} content String/element representing 
1066              * the new footer content
1067              */
1068              this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1069              this.changeFooterEvent.signature = SIGNATURE;
1070          
1071              /**
1072              * CustomEvent fired when the content of the Module is modified
1073              * @event changeContentEvent
1074              */
1075              this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1076              this.changeContentEvent.signature = SIGNATURE;
1077  
1078              /**
1079              * CustomEvent fired when the Module is destroyed
1080              * @event destroyEvent
1081              */
1082              this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
1083              this.destroyEvent.signature = SIGNATURE;
1084  
1085              /**
1086              * CustomEvent fired before the Module is shown
1087              * @event beforeShowEvent
1088              */
1089              this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1090              this.beforeShowEvent.signature = SIGNATURE;
1091  
1092              /**
1093              * CustomEvent fired after the Module is shown
1094              * @event showEvent
1095              */
1096              this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1097              this.showEvent.signature = SIGNATURE;
1098  
1099              /**
1100              * CustomEvent fired before the Module is hidden
1101              * @event beforeHideEvent
1102              */
1103              this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1104              this.beforeHideEvent.signature = SIGNATURE;
1105  
1106              /**
1107              * CustomEvent fired after the Module is hidden
1108              * @event hideEvent
1109              */
1110              this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1111              this.hideEvent.signature = SIGNATURE;
1112          }, 
1113  
1114          /**
1115          * String identifying whether the current platform is windows or mac. This property
1116          * currently only identifies these 2 platforms, and returns false otherwise. 
1117          * @property platform
1118          * @deprecated Use YAHOO.env.ua
1119          * @type {String|Boolean}
1120          */
1121          platform: function () {
1122              var ua = navigator.userAgent.toLowerCase();
1123  
1124              if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1125                  return "windows";
1126              } else if (ua.indexOf("macintosh") != -1) {
1127                  return "mac";
1128              } else {
1129                  return false;
1130              }
1131          }(),
1132          
1133          /**
1134          * String representing the user-agent of the browser
1135          * @deprecated Use YAHOO.env.ua
1136          * @property browser
1137          * @type {String|Boolean}
1138          */
1139          browser: function () {
1140              var ua = navigator.userAgent.toLowerCase();
1141              /*
1142                   Check Opera first in case of spoof and check Safari before
1143                   Gecko since Safari's user agent string includes "like Gecko"
1144              */
1145              if (ua.indexOf('opera') != -1) { 
1146                  return 'opera';
1147              } else if (ua.indexOf('msie 7') != -1) {
1148                  return 'ie7';
1149              } else if (ua.indexOf('msie') != -1) {
1150                  return 'ie';
1151              } else if (ua.indexOf('safari') != -1) { 
1152                  return 'safari';
1153              } else if (ua.indexOf('gecko') != -1) {
1154                  return 'gecko';
1155              } else {
1156                  return false;
1157              }
1158          }(),
1159          
1160          /**
1161          * Boolean representing whether or not the current browsing context is 
1162          * secure (https)
1163          * @property isSecure
1164          * @type Boolean
1165          */
1166          isSecure: function () {
1167              if (window.location.href.toLowerCase().indexOf("https") === 0) {
1168                  return true;
1169              } else {
1170                  return false;
1171              }
1172          }(),
1173          
1174          /**
1175          * Initializes the custom events for Module which are fired 
1176          * automatically at appropriate times by the Module class.
1177          */
1178          initDefaultConfig: function () {
1179              // Add properties //
1180              /**
1181              * Specifies whether the Module is visible on the page.
1182              * @config visible
1183              * @type Boolean
1184              * @default true
1185              */
1186              this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1187                  handler: this.configVisible, 
1188                  value: DEFAULT_CONFIG.VISIBLE.value, 
1189                  validator: DEFAULT_CONFIG.VISIBLE.validator
1190              });
1191  
1192              /**
1193              * <p>
1194              * Object or array of objects representing the ContainerEffect 
1195              * classes that are active for animating the container.
1196              * </p>
1197              * <p>
1198              * <strong>NOTE:</strong> Although this configuration 
1199              * property is introduced at the Module level, an out of the box
1200              * implementation is not shipped for the Module class so setting
1201              * the proroperty on the Module class has no effect. The Overlay 
1202              * class is the first class to provide out of the box ContainerEffect 
1203              * support.
1204              * </p>
1205              * @config effect
1206              * @type Object
1207              * @default null
1208              */
1209              this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1210                  handler: this.configEffect,
1211                  suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent, 
1212                  supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1213              });
1214  
1215              /**
1216              * Specifies whether to create a special proxy iframe to monitor 
1217              * for user font resizing in the document
1218              * @config monitorresize
1219              * @type Boolean
1220              * @default true
1221              */
1222              this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1223                  handler: this.configMonitorResize,
1224                  value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1225              });
1226  
1227              /**
1228              * Specifies if the module should be rendered as the first child 
1229              * of document.body or appended as the last child when render is called
1230              * with document.body as the "appendToNode".
1231              * <p>
1232              * Appending to the body while the DOM is still being constructed can 
1233              * lead to Operation Aborted errors in IE hence this flag is set to 
1234              * false by default.
1235              * </p>
1236              * 
1237              * @config appendtodocumentbody
1238              * @type Boolean
1239              * @default false
1240              */
1241              this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1242                  value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1243              });
1244          },
1245  
1246          /**
1247          * The Module class's initialization method, which is executed for
1248          * Module and all of its subclasses. This method is automatically 
1249          * called by the constructor, and  sets up all DOM references for 
1250          * pre-existing markup, and creates required markup if it is not 
1251          * already present.
1252          * <p>
1253          * If the element passed in does not have an id, one will be generated
1254          * for it.
1255          * </p>
1256          * @method init
1257          * @param {String} el The element ID representing the Module <em>OR</em>
1258          * @param {HTMLElement} el The element representing the Module
1259          * @param {Object} userConfig The configuration Object literal 
1260          * containing the configuration that should be set for this module. 
1261          * See configuration documentation for more details.
1262          */
1263          init: function (el, userConfig) {
1264  
1265              var elId, child;
1266  
1267              this.initEvents();
1268              this.beforeInitEvent.fire(Module);
1269  
1270              /**
1271              * The Module's Config object used for monitoring 
1272              * configuration properties.
1273              * @property cfg
1274              * @type YAHOO.util.Config
1275              */
1276              this.cfg = new Config(this);
1277  
1278              if (this.isSecure) {
1279                  this.imageRoot = Module.IMG_ROOT_SSL;
1280              }
1281  
1282              if (typeof el == "string") {
1283                  elId = el;
1284                  el = document.getElementById(el);
1285                  if (! el) {
1286                      el = (createModuleTemplate()).cloneNode(false);
1287                      el.id = elId;
1288                  }
1289              }
1290  
1291              this.id = Dom.generateId(el);
1292              this.element = el;
1293  
1294              child = this.element.firstChild;
1295  
1296              if (child) {
1297                  var fndHd = false, fndBd = false, fndFt = false;
1298                  do {
1299                      // We're looking for elements
1300                      if (1 == child.nodeType) {
1301                          if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1302                              this.header = child;
1303                              fndHd = true;
1304                          } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1305                              this.body = child;
1306                              fndBd = true;
1307                          } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1308                              this.footer = child;
1309                              fndFt = true;
1310                          }
1311                      }
1312                  } while ((child = child.nextSibling));
1313              }
1314  
1315              this.initDefaultConfig();
1316  
1317              Dom.addClass(this.element, Module.CSS_MODULE);
1318  
1319              if (userConfig) {
1320                  this.cfg.applyConfig(userConfig, true);
1321              }
1322  
1323              /*
1324                  Subscribe to the fireQueue() method of Config so that any 
1325                  queued configuration changes are excecuted upon render of 
1326                  the Module
1327              */ 
1328  
1329              if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1330                  this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1331              }
1332  
1333              this.initEvent.fire(Module);
1334          },
1335  
1336          /**
1337          * Initialize an empty IFRAME that is placed out of the visible area 
1338          * that can be used to detect text resize.
1339          * @method initResizeMonitor
1340          */
1341          initResizeMonitor: function () {
1342  
1343              var isGeckoWin = (UA.gecko && this.platform == "windows");
1344              if (isGeckoWin) {
1345                  // Help prevent spinning loading icon which 
1346                  // started with FireFox 2.0.0.8/Win
1347                  var self = this;
1348                  setTimeout(function(){self._initResizeMonitor();}, 0);
1349              } else {
1350                  this._initResizeMonitor();
1351              }
1352          },
1353  
1354          /**
1355           * Create and initialize the text resize monitoring iframe.
1356           * 
1357           * @protected
1358           * @method _initResizeMonitor
1359           */
1360          _initResizeMonitor : function() {
1361  
1362              var oDoc, 
1363                  oIFrame, 
1364                  sHTML;
1365  
1366              function fireTextResize() {
1367                  Module.textResizeEvent.fire();
1368              }
1369  
1370              if (!UA.opera) {
1371                  oIFrame = Dom.get("_yuiResizeMonitor");
1372  
1373                  var supportsCWResize = this._supportsCWResize();
1374  
1375                  if (!oIFrame) {
1376                      oIFrame = document.createElement("iframe");
1377  
1378                      if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1379                          oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1380                      }
1381  
1382                      if (!supportsCWResize) {
1383                          // Can't monitor on contentWindow, so fire from inside iframe
1384                          sHTML = ["<html><head><script ",
1385                                   "type=\"text/javascript\">",
1386                                   "window.onresize=function(){window.parent.",
1387                                   "YAHOO.widget.Module.textResizeEvent.",
1388                                   "fire();};<",
1389                                   "\/script></head>",
1390                                   "<body></body></html>"].join('');
1391  
1392                          oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1393                      }
1394  
1395                      oIFrame.id = "_yuiResizeMonitor";
1396                      oIFrame.title = "Text Resize Monitor";
1397                      oIFrame.tabIndex = -1;
1398                      oIFrame.setAttribute("role", "presentation");
1399  
1400                      /*
1401                          Need to set "position" property before inserting the 
1402                          iframe into the document or Safari's status bar will 
1403                          forever indicate the iframe is loading 
1404                          (See YUILibrary bug #1723064)
1405                      */
1406                      oIFrame.style.position = "absolute";
1407                      oIFrame.style.visibility = "hidden";
1408  
1409                      var db = document.body,
1410                          fc = db.firstChild;
1411                      if (fc) {
1412                          db.insertBefore(oIFrame, fc);
1413                      } else {
1414                          db.appendChild(oIFrame);
1415                      }
1416  
1417                      // Setting the background color fixes an issue with IE6/IE7, where
1418                      // elements in the DOM, with -ve margin-top which positioned them 
1419                      // offscreen (so they would be overlapped by the iframe and its -ve top
1420                      // setting), would have their -ve margin-top ignored, when the iframe 
1421                      // was added.
1422                      oIFrame.style.backgroundColor = "transparent";
1423  
1424                      oIFrame.style.borderWidth = "0";
1425                      oIFrame.style.width = "2em";
1426                      oIFrame.style.height = "2em";
1427                      oIFrame.style.left = "0";
1428                      oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1429                      oIFrame.style.visibility = "visible";
1430  
1431                      /*
1432                         Don't open/close the document for Gecko like we used to, since it
1433                         leads to duplicate cookies. (See YUILibrary bug #1721755)
1434                      */
1435                      if (UA.webkit) {
1436                          oDoc = oIFrame.contentWindow.document;
1437                          oDoc.open();
1438                          oDoc.close();
1439                      }
1440                  }
1441  
1442                  if (oIFrame && oIFrame.contentWindow) {
1443                      Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1444  
1445                      if (!Module.textResizeInitialized) {
1446                          if (supportsCWResize) {
1447                              if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1448                                  /*
1449                                       This will fail in IE if document.domain has 
1450                                       changed, so we must change the listener to 
1451                                       use the oIFrame element instead
1452                                  */
1453                                  Event.on(oIFrame, "resize", fireTextResize);
1454                              }
1455                          }
1456                          Module.textResizeInitialized = true;
1457                      }
1458                      this.resizeMonitor = oIFrame;
1459                  }
1460              }
1461          },
1462  
1463          /**
1464           * Text resize monitor helper method.
1465           * Determines if the browser supports resize events on iframe content windows.
1466           * 
1467           * @private
1468           * @method _supportsCWResize
1469           */
1470          _supportsCWResize : function() {
1471              /*
1472                  Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1473                  Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1474  
1475                  We don't want to start sniffing for patch versions, so fire textResize the same
1476                  way on all FF2 flavors
1477               */
1478              var bSupported = true;
1479              if (UA.gecko && UA.gecko <= 1.8) {
1480                  bSupported = false;
1481              }
1482              return bSupported;
1483          },
1484  
1485          /**
1486          * Event handler fired when the resize monitor element is resized.
1487          * @method onDomResize
1488          * @param {DOMEvent} e The DOM resize event
1489          * @param {Object} obj The scope object passed to the handler
1490          */
1491          onDomResize: function (e, obj) {
1492  
1493              var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1494  
1495              this.resizeMonitor.style.top = nTop + "px";
1496              this.resizeMonitor.style.left = "0";
1497          },
1498  
1499          /**
1500          * Sets the Module's header content to the markup specified, or appends 
1501          * the passed element to the header. 
1502          * 
1503          * If no header is present, one will 
1504          * be automatically created. An empty string can be passed to the method
1505          * to clear the contents of the header.
1506          * 
1507          * @method setHeader
1508          * @param {HTML} headerContent The markup used to set the header content.
1509          * As a convenience, non HTMLElement objects can also be passed into 
1510          * the method, and will be treated as strings, with the header innerHTML
1511          * set to their default toString implementations. 
1512          * 
1513          * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1514          * 
1515          * <em>OR</em>
1516          * @param {HTMLElement} headerContent The HTMLElement to append to 
1517          * <em>OR</em>
1518          * @param {DocumentFragment} headerContent The document fragment 
1519          * containing elements which are to be added to the header
1520          */
1521          setHeader: function (headerContent) {
1522              var oHeader = this.header || (this.header = createHeader());
1523  
1524              if (headerContent.nodeName) {
1525                  oHeader.innerHTML = "";
1526                  oHeader.appendChild(headerContent);
1527              } else {
1528                  oHeader.innerHTML = headerContent;
1529              }
1530  
1531              if (this._rendered) {
1532                  this._renderHeader();
1533              }
1534  
1535              this.changeHeaderEvent.fire(headerContent);
1536              this.changeContentEvent.fire();
1537  
1538          },
1539  
1540          /**
1541          * Appends the passed element to the header. If no header is present, 
1542          * one will be automatically created.
1543          * @method appendToHeader
1544          * @param {HTMLElement | DocumentFragment} element The element to 
1545          * append to the header. In the case of a document fragment, the
1546          * children of the fragment will be appended to the header.
1547          */
1548          appendToHeader: function (element) {
1549              var oHeader = this.header || (this.header = createHeader());
1550  
1551              oHeader.appendChild(element);
1552  
1553              this.changeHeaderEvent.fire(element);
1554              this.changeContentEvent.fire();
1555  
1556          },
1557  
1558          /**
1559          * Sets the Module's body content to the HTML specified. 
1560          * 
1561          * If no body is present, one will be automatically created. 
1562          * 
1563          * An empty string can be passed to the method to clear the contents of the body.
1564          * @method setBody
1565          * @param {HTML} bodyContent The HTML used to set the body content 
1566          * As a convenience, non HTMLElement objects can also be passed into 
1567          * the method, and will be treated as strings, with the body innerHTML
1568          * set to their default toString implementations.
1569          * 
1570          * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1571          * 
1572          * <em>OR</em>
1573          * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1574          * child of the body element.
1575          * <em>OR</em>
1576          * @param {DocumentFragment} bodyContent The document fragment 
1577          * containing elements which are to be added to the body
1578          */
1579          setBody: function (bodyContent) {
1580              var oBody = this.body || (this.body = createBody());
1581  
1582              if (bodyContent.nodeName) {
1583                  oBody.innerHTML = "";
1584                  oBody.appendChild(bodyContent);
1585              } else {
1586                  oBody.innerHTML = bodyContent;
1587              }
1588  
1589              if (this._rendered) {
1590                  this._renderBody();
1591              }
1592  
1593              this.changeBodyEvent.fire(bodyContent);
1594              this.changeContentEvent.fire();
1595          },
1596  
1597          /**
1598          * Appends the passed element to the body. If no body is present, one 
1599          * will be automatically created.
1600          * @method appendToBody
1601          * @param {HTMLElement | DocumentFragment} element The element to 
1602          * append to the body. In the case of a document fragment, the
1603          * children of the fragment will be appended to the body.
1604          * 
1605          */
1606          appendToBody: function (element) {
1607              var oBody = this.body || (this.body = createBody());
1608          
1609              oBody.appendChild(element);
1610  
1611              this.changeBodyEvent.fire(element);
1612              this.changeContentEvent.fire();
1613  
1614          },
1615  
1616          /**
1617          * Sets the Module's footer content to the HTML specified, or appends 
1618          * the passed element to the footer. If no footer is present, one will 
1619          * be automatically created. An empty string can be passed to the method
1620          * to clear the contents of the footer.
1621          * @method setFooter
1622          * @param {HTML} footerContent The HTML used to set the footer 
1623          * As a convenience, non HTMLElement objects can also be passed into 
1624          * the method, and will be treated as strings, with the footer innerHTML
1625          * set to their default toString implementations.
1626          * 
1627          * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1628          * 
1629          * <em>OR</em>
1630          * @param {HTMLElement} footerContent The HTMLElement to append to 
1631          * the footer
1632          * <em>OR</em>
1633          * @param {DocumentFragment} footerContent The document fragment containing 
1634          * elements which are to be added to the footer
1635          */
1636          setFooter: function (footerContent) {
1637  
1638              var oFooter = this.footer || (this.footer = createFooter());
1639  
1640              if (footerContent.nodeName) {
1641                  oFooter.innerHTML = "";
1642                  oFooter.appendChild(footerContent);
1643              } else {
1644                  oFooter.innerHTML = footerContent;
1645              }
1646  
1647              if (this._rendered) {
1648                  this._renderFooter();
1649              }
1650  
1651              this.changeFooterEvent.fire(footerContent);
1652              this.changeContentEvent.fire();
1653          },
1654  
1655          /**
1656          * Appends the passed element to the footer. If no footer is present, 
1657          * one will be automatically created.
1658          * @method appendToFooter
1659          * @param {HTMLElement | DocumentFragment} element The element to 
1660          * append to the footer. In the case of a document fragment, the
1661          * children of the fragment will be appended to the footer
1662          */
1663          appendToFooter: function (element) {
1664  
1665              var oFooter = this.footer || (this.footer = createFooter());
1666  
1667              oFooter.appendChild(element);
1668  
1669              this.changeFooterEvent.fire(element);
1670              this.changeContentEvent.fire();
1671  
1672          },
1673  
1674          /**
1675          * Renders the Module by inserting the elements that are not already 
1676          * in the main Module into their correct places. Optionally appends 
1677          * the Module to the specified node prior to the render's execution. 
1678          * <p>
1679          * For Modules without existing markup, the appendToNode argument 
1680          * is REQUIRED. If this argument is ommitted and the current element is 
1681          * not present in the document, the function will return false, 
1682          * indicating that the render was a failure.
1683          * </p>
1684          * <p>
1685          * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1686          * then the module is rendered as the first child of the body element, 
1687          * and not appended to it, to avoid Operation Aborted errors in IE when 
1688          * rendering the module before window's load event is fired. You can 
1689          * use the appendtodocumentbody configuration property to change this 
1690          * to append to document.body if required.
1691          * </p>
1692          * @method render
1693          * @param {String} appendToNode The element id to which the Module 
1694          * should be appended to prior to rendering <em>OR</em>
1695          * @param {HTMLElement} appendToNode The element to which the Module 
1696          * should be appended to prior to rendering
1697          * @param {HTMLElement} moduleElement OPTIONAL. The element that 
1698          * represents the actual Standard Module container.
1699          * @return {Boolean} Success or failure of the render
1700          */
1701          render: function (appendToNode, moduleElement) {
1702  
1703              var me = this;
1704  
1705              function appendTo(parentNode) {
1706                  if (typeof parentNode == "string") {
1707                      parentNode = document.getElementById(parentNode);
1708                  }
1709  
1710                  if (parentNode) {
1711                      me._addToParent(parentNode, me.element);
1712                      me.appendEvent.fire();
1713                  }
1714              }
1715  
1716              this.beforeRenderEvent.fire();
1717  
1718              if (! moduleElement) {
1719                  moduleElement = this.element;
1720              }
1721  
1722              if (appendToNode) {
1723                  appendTo(appendToNode);
1724              } else { 
1725                  // No node was passed in. If the element is not already in the Dom, this fails
1726                  if (! Dom.inDocument(this.element)) {
1727                      YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
1728                      return false;
1729                  }
1730              }
1731  
1732              this._renderHeader(moduleElement);
1733              this._renderBody(moduleElement);
1734              this._renderFooter(moduleElement);
1735  
1736              this._rendered = true;
1737  
1738              this.renderEvent.fire();
1739              return true;
1740          },
1741  
1742          /**
1743           * Renders the currently set header into it's proper position under the 
1744           * module element. If the module element is not provided, "this.element" 
1745           * is used.
1746           * 
1747           * @method _renderHeader
1748           * @protected
1749           * @param {HTMLElement} moduleElement Optional. A reference to the module element
1750           */
1751          _renderHeader: function(moduleElement){
1752              moduleElement = moduleElement || this.element;
1753  
1754              // Need to get everything into the DOM if it isn't already
1755              if (this.header && !Dom.inDocument(this.header)) {
1756                  // There is a header, but it's not in the DOM yet. Need to add it.
1757                  var firstChild = moduleElement.firstChild;
1758                  if (firstChild) {
1759                      moduleElement.insertBefore(this.header, firstChild);
1760                  } else {
1761                      moduleElement.appendChild(this.header);
1762                  }
1763              }
1764          },
1765  
1766          /**
1767           * Renders the currently set body into it's proper position under the 
1768           * module element. If the module element is not provided, "this.element" 
1769           * is used.
1770           * 
1771           * @method _renderBody
1772           * @protected
1773           * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1774           */
1775          _renderBody: function(moduleElement){
1776              moduleElement = moduleElement || this.element;
1777  
1778              if (this.body && !Dom.inDocument(this.body)) {
1779                  // There is a body, but it's not in the DOM yet. Need to add it.
1780                  if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1781                      moduleElement.insertBefore(this.body, this.footer);
1782                  } else {
1783                      moduleElement.appendChild(this.body);
1784                  }
1785              }
1786          },
1787  
1788          /**
1789           * Renders the currently set footer into it's proper position under the 
1790           * module element. If the module element is not provided, "this.element" 
1791           * is used.
1792           * 
1793           * @method _renderFooter
1794           * @protected
1795           * @param {HTMLElement} moduleElement Optional. A reference to the module element
1796           */
1797          _renderFooter: function(moduleElement){
1798              moduleElement = moduleElement || this.element;
1799  
1800              if (this.footer && !Dom.inDocument(this.footer)) {
1801                  // There is a footer, but it's not in the DOM yet. Need to add it.
1802                  moduleElement.appendChild(this.footer);
1803              }
1804          },
1805  
1806          /**
1807          * Removes the Module element from the DOM, sets all child elements to null, and purges the bounding element of event listeners.
1808          * @method destroy
1809          * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners. 
1810          * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
1811          */
1812          destroy: function (shallowPurge) {
1813  
1814              var parent,
1815                  purgeChildren = !(shallowPurge);
1816  
1817              if (this.element) {
1818                  Event.purgeElement(this.element, purgeChildren);
1819                  parent = this.element.parentNode;
1820              }
1821  
1822              if (parent) {
1823                  parent.removeChild(this.element);
1824              }
1825          
1826              this.element = null;
1827              this.header = null;
1828              this.body = null;
1829              this.footer = null;
1830  
1831              Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1832  
1833              this.cfg.destroy();
1834              this.cfg = null;
1835  
1836              this.destroyEvent.fire();
1837          },
1838  
1839          /**
1840          * Shows the Module element by setting the visible configuration 
1841          * property to true. Also fires two events: beforeShowEvent prior to 
1842          * the visibility change, and showEvent after.
1843          * @method show
1844          */
1845          show: function () {
1846              this.cfg.setProperty("visible", true);
1847          },
1848  
1849          /**
1850          * Hides the Module element by setting the visible configuration 
1851          * property to false. Also fires two events: beforeHideEvent prior to 
1852          * the visibility change, and hideEvent after.
1853          * @method hide
1854          */
1855          hide: function () {
1856              this.cfg.setProperty("visible", false);
1857          },
1858          
1859          // BUILT-IN EVENT HANDLERS FOR MODULE //
1860          /**
1861          * Default event handler for changing the visibility property of a 
1862          * Module. By default, this is achieved by switching the "display" style 
1863          * between "block" and "none".
1864          * This method is responsible for firing showEvent and hideEvent.
1865          * @param {String} type The CustomEvent type (usually the property name)
1866          * @param {Object[]} args The CustomEvent arguments. For configuration 
1867          * handlers, args[0] will equal the newly applied value for the property.
1868          * @param {Object} obj The scope object. For configuration handlers, 
1869          * this will usually equal the owner.
1870          * @method configVisible
1871          */
1872          configVisible: function (type, args, obj) {
1873              var visible = args[0];
1874              if (visible) {
1875                  if(this.beforeShowEvent.fire()) {
1876                      Dom.setStyle(this.element, "display", "block");
1877                      this.showEvent.fire();
1878                  }
1879              } else {
1880                  if (this.beforeHideEvent.fire()) {
1881                      Dom.setStyle(this.element, "display", "none");
1882                      this.hideEvent.fire();
1883                  }
1884              }
1885          },
1886  
1887          /**
1888          * Default event handler for the "effect" configuration property
1889          * @param {String} type The CustomEvent type (usually the property name)
1890          * @param {Object[]} args The CustomEvent arguments. For configuration 
1891          * handlers, args[0] will equal the newly applied value for the property.
1892          * @param {Object} obj The scope object. For configuration handlers, 
1893          * this will usually equal the owner.
1894          * @method configEffect
1895          */
1896          configEffect: function (type, args, obj) {
1897              this._cachedEffects = (this.cacheEffects) ? this._createEffects(args[0]) : null;
1898          },
1899  
1900          /**
1901           * If true, ContainerEffects (and Anim instances) are cached when "effect" is set, and reused. 
1902           * If false, new instances are created each time the container is hidden or shown, as was the 
1903           * behavior prior to 2.9.0. 
1904           *
1905           * @property cacheEffects
1906           * @since 2.9.0
1907           * @default true
1908           * @type boolean
1909           */
1910          cacheEffects : true,
1911  
1912          /**
1913           * Creates an array of ContainerEffect instances from the provided configs
1914           * 
1915           * @method _createEffects
1916           * @param {Array|Object} effectCfg An effect configuration or array of effect configurations
1917           * @return {Array} An array of ContainerEffect instances.
1918           * @protected
1919           */
1920          _createEffects: function(effectCfg) {
1921              var effectInstances = null,
1922                  n, 
1923                  i,
1924                  eff;
1925  
1926              if (effectCfg) {
1927                  if (effectCfg instanceof Array) {
1928                      effectInstances = [];
1929                      n = effectCfg.length;
1930                      for (i = 0; i < n; i++) {
1931                          eff = effectCfg[i];
1932                          if (eff.effect) {
1933                              effectInstances[effectInstances.length] = eff.effect(this, eff.duration);
1934                          }
1935                      }
1936                  } else if (effectCfg.effect) {
1937                      effectInstances = [effectCfg.effect(this, effectCfg.duration)];
1938                  }
1939              }
1940  
1941              return effectInstances;
1942          },
1943  
1944          /**
1945          * Default event handler for the "monitorresize" configuration property
1946          * @param {String} type The CustomEvent type (usually the property name)
1947          * @param {Object[]} args The CustomEvent arguments. For configuration 
1948          * handlers, args[0] will equal the newly applied value for the property.
1949          * @param {Object} obj The scope object. For configuration handlers, 
1950          * this will usually equal the owner.
1951          * @method configMonitorResize
1952          */
1953          configMonitorResize: function (type, args, obj) {
1954              var monitor = args[0];
1955              if (monitor) {
1956                  this.initResizeMonitor();
1957              } else {
1958                  Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1959                  this.resizeMonitor = null;
1960              }
1961          },
1962  
1963          /**
1964           * This method is a protected helper, used when constructing the DOM structure for the module 
1965           * to account for situations which may cause Operation Aborted errors in IE. It should not 
1966           * be used for general DOM construction.
1967           * <p>
1968           * If the parentNode is not document.body, the element is appended as the last element.
1969           * </p>
1970           * <p>
1971           * If the parentNode is document.body the element is added as the first child to help
1972           * prevent Operation Aborted errors in IE.
1973           * </p>
1974           *
1975           * @param {parentNode} The HTML element to which the element will be added
1976           * @param {element} The HTML element to be added to parentNode's children
1977           * @method _addToParent
1978           * @protected
1979           */
1980          _addToParent: function(parentNode, element) {
1981              if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1982                  parentNode.insertBefore(element, parentNode.firstChild);
1983              } else {
1984                  parentNode.appendChild(element);
1985              }
1986          },
1987  
1988          /**
1989          * Returns a String representation of the Object.
1990          * @method toString
1991          * @return {String} The string representation of the Module
1992          */
1993          toString: function () {
1994              return "Module " + this.id;
1995          }
1996      };
1997  
1998      YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1999  
2000  }());
2001  (function () {
2002  
2003      /**
2004      * Overlay is a Module that is absolutely positioned above the page flow. It 
2005      * has convenience methods for positioning and sizing, as well as options for 
2006      * controlling zIndex and constraining the Overlay's position to the current 
2007      * visible viewport. Overlay also contains a dynamicly generated IFRAME which 
2008      * is placed beneath it for Internet Explorer 6 and 5.x so that it will be 
2009      * properly rendered above SELECT elements.
2010      * @namespace YAHOO.widget
2011      * @class Overlay
2012      * @extends YAHOO.widget.Module
2013      * @param {String} el The element ID representing the Overlay <em>OR</em>
2014      * @param {HTMLElement} el The element representing the Overlay
2015      * @param {Object} userConfig The configuration object literal containing 
2016      * the configuration that should be set for this Overlay. See configuration 
2017      * documentation for more details.
2018      * @constructor
2019      */
2020      YAHOO.widget.Overlay = function (el, userConfig) {
2021          YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
2022      };
2023  
2024      var Lang = YAHOO.lang,
2025          CustomEvent = YAHOO.util.CustomEvent,
2026          Module = YAHOO.widget.Module,
2027          Event = YAHOO.util.Event,
2028          Dom = YAHOO.util.Dom,
2029          Config = YAHOO.util.Config,
2030          UA = YAHOO.env.ua,
2031          Overlay = YAHOO.widget.Overlay,
2032  
2033          _SUBSCRIBE = "subscribe",
2034          _UNSUBSCRIBE = "unsubscribe",
2035          _CONTAINED = "contained",
2036  
2037          m_oIFrameTemplate,
2038  
2039          /**
2040          * Constant representing the name of the Overlay's events
2041          * @property EVENT_TYPES
2042          * @private
2043          * @final
2044          * @type Object
2045          */
2046          EVENT_TYPES = {
2047              "BEFORE_MOVE": "beforeMove",
2048              "MOVE": "move"
2049          },
2050  
2051          /**
2052          * Constant representing the Overlay's configuration properties
2053          * @property DEFAULT_CONFIG
2054          * @private
2055          * @final
2056          * @type Object
2057          */
2058          DEFAULT_CONFIG = {
2059  
2060              "X": { 
2061                  key: "x", 
2062                  validator: Lang.isNumber, 
2063                  suppressEvent: true, 
2064                  supercedes: ["iframe"]
2065              },
2066  
2067              "Y": { 
2068                  key: "y", 
2069                  validator: Lang.isNumber, 
2070                  suppressEvent: true, 
2071                  supercedes: ["iframe"]
2072              },
2073  
2074              "XY": { 
2075                  key: "xy", 
2076                  suppressEvent: true, 
2077                  supercedes: ["iframe"] 
2078              },
2079  
2080              "CONTEXT": { 
2081                  key: "context", 
2082                  suppressEvent: true, 
2083                  supercedes: ["iframe"] 
2084              },
2085  
2086              "FIXED_CENTER": { 
2087                  key: "fixedcenter", 
2088                  value: false, 
2089                  supercedes: ["iframe", "visible"] 
2090              },
2091  
2092              "WIDTH": { 
2093                  key: "width",
2094                  suppressEvent: true,
2095                  supercedes: ["context", "fixedcenter", "iframe"]
2096              }, 
2097  
2098              "HEIGHT": { 
2099                  key: "height", 
2100                  suppressEvent: true, 
2101                  supercedes: ["context", "fixedcenter", "iframe"] 
2102              },
2103  
2104              "AUTO_FILL_HEIGHT" : {
2105                  key: "autofillheight",
2106                  supercedes: ["height"],
2107                  value:"body"
2108              },
2109  
2110              "ZINDEX": { 
2111                  key: "zindex", 
2112                  value: null 
2113              },
2114  
2115              "CONSTRAIN_TO_VIEWPORT": { 
2116                  key: "constraintoviewport", 
2117                  value: false, 
2118                  validator: Lang.isBoolean, 
2119                  supercedes: ["iframe", "x", "y", "xy"]
2120              }, 
2121  
2122              "IFRAME": { 
2123                  key: "iframe", 
2124                  value: (UA.ie == 6 ? true : false), 
2125                  validator: Lang.isBoolean, 
2126                  supercedes: ["zindex"] 
2127              },
2128  
2129              "PREVENT_CONTEXT_OVERLAP": {
2130                  key: "preventcontextoverlap",
2131                  value: false,
2132                  validator: Lang.isBoolean,  
2133                  supercedes: ["constraintoviewport"]
2134              }
2135  
2136          };
2137  
2138      /**
2139      * The URL that will be placed in the iframe
2140      * @property YAHOO.widget.Overlay.IFRAME_SRC
2141      * @static
2142      * @final
2143      * @type String
2144      */
2145      Overlay.IFRAME_SRC = "javascript:false;";
2146  
2147      /**
2148      * Number representing how much the iframe shim should be offset from each 
2149      * side of an Overlay instance, in pixels.
2150      * @property YAHOO.widget.Overlay.IFRAME_SRC
2151      * @default 3
2152      * @static
2153      * @final
2154      * @type Number
2155      */
2156      Overlay.IFRAME_OFFSET = 3;
2157  
2158      /**
2159      * Number representing the minimum distance an Overlay instance should be 
2160      * positioned relative to the boundaries of the browser's viewport, in pixels.
2161      * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2162      * @default 10
2163      * @static
2164      * @final
2165      * @type Number
2166      */
2167      Overlay.VIEWPORT_OFFSET = 10;
2168  
2169      /**
2170      * Constant representing the top left corner of an element, used for 
2171      * configuring the context element alignment
2172      * @property YAHOO.widget.Overlay.TOP_LEFT
2173      * @static
2174      * @final
2175      * @type String
2176      */
2177      Overlay.TOP_LEFT = "tl";
2178  
2179      /**
2180      * Constant representing the top right corner of an element, used for 
2181      * configuring the context element alignment
2182      * @property YAHOO.widget.Overlay.TOP_RIGHT
2183      * @static
2184      * @final
2185      * @type String
2186      */
2187      Overlay.TOP_RIGHT = "tr";
2188  
2189      /**
2190      * Constant representing the top bottom left corner of an element, used for 
2191      * configuring the context element alignment
2192      * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2193      * @static
2194      * @final
2195      * @type String
2196      */
2197      Overlay.BOTTOM_LEFT = "bl";
2198  
2199      /**
2200      * Constant representing the bottom right corner of an element, used for 
2201      * configuring the context element alignment
2202      * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2203      * @static
2204      * @final
2205      * @type String
2206      */
2207      Overlay.BOTTOM_RIGHT = "br";
2208  
2209      Overlay.PREVENT_OVERLAP_X = {
2210          "tltr": true,
2211          "blbr": true,
2212          "brbl": true,
2213          "trtl": true
2214      };
2215              
2216      Overlay.PREVENT_OVERLAP_Y = {
2217          "trbr": true,
2218          "tlbl": true,
2219          "bltl": true,
2220          "brtr": true
2221      };
2222  
2223      /**
2224      * Constant representing the default CSS class used for an Overlay
2225      * @property YAHOO.widget.Overlay.CSS_OVERLAY
2226      * @static
2227      * @final
2228      * @type String
2229      */
2230      Overlay.CSS_OVERLAY = "yui-overlay";
2231  
2232      /**
2233      * Constant representing the default hidden CSS class used for an Overlay. This class is 
2234      * applied to the overlay's outer DIV whenever it's hidden.
2235      *
2236      * @property YAHOO.widget.Overlay.CSS_HIDDEN
2237      * @static
2238      * @final
2239      * @type String
2240      */
2241      Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2242  
2243      /**
2244      * Constant representing the default CSS class used for an Overlay iframe shim.
2245      * 
2246      * @property YAHOO.widget.Overlay.CSS_IFRAME
2247      * @static
2248      * @final
2249      * @type String
2250      */
2251      Overlay.CSS_IFRAME = "yui-overlay-iframe";
2252  
2253      /**
2254       * Constant representing the names of the standard module elements
2255       * used in the overlay.
2256       * @property YAHOO.widget.Overlay.STD_MOD_RE
2257       * @static
2258       * @final
2259       * @type RegExp
2260       */
2261      Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2262  
2263      /**
2264      * A singleton CustomEvent used for reacting to the DOM event for 
2265      * window scroll
2266      * @event YAHOO.widget.Overlay.windowScrollEvent
2267      */
2268      Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2269  
2270      /**
2271      * A singleton CustomEvent used for reacting to the DOM event for
2272      * window resize
2273      * @event YAHOO.widget.Overlay.windowResizeEvent
2274      */
2275      Overlay.windowResizeEvent = new CustomEvent("windowResize");
2276  
2277      /**
2278      * The DOM event handler used to fire the CustomEvent for window scroll
2279      * @method YAHOO.widget.Overlay.windowScrollHandler
2280      * @static
2281      * @param {DOMEvent} e The DOM scroll event
2282      */
2283      Overlay.windowScrollHandler = function (e) {
2284          var t = Event.getTarget(e);
2285  
2286          // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2287          // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2288          // - IE doesn't recognize scroll registered on the document.
2289          //
2290          // Also, when document view is scrolled, IE doesn't provide a target, 
2291          // rest of the browsers set target to window.document, apart from opera 
2292          // which sets target to window.
2293          if (!t || t === window || t === window.document) {
2294              if (UA.ie) {
2295  
2296                  if (! window.scrollEnd) {
2297                      window.scrollEnd = -1;
2298                  }
2299  
2300                  clearTimeout(window.scrollEnd);
2301          
2302                  window.scrollEnd = setTimeout(function () { 
2303                      Overlay.windowScrollEvent.fire(); 
2304                  }, 1);
2305          
2306              } else {
2307                  Overlay.windowScrollEvent.fire();
2308              }
2309          }
2310      };
2311  
2312      /**
2313      * The DOM event handler used to fire the CustomEvent for window resize
2314      * @method YAHOO.widget.Overlay.windowResizeHandler
2315      * @static
2316      * @param {DOMEvent} e The DOM resize event
2317      */
2318      Overlay.windowResizeHandler = function (e) {
2319  
2320          if (UA.ie) {
2321              if (! window.resizeEnd) {
2322                  window.resizeEnd = -1;
2323              }
2324  
2325              clearTimeout(window.resizeEnd);
2326  
2327              window.resizeEnd = setTimeout(function () {
2328                  Overlay.windowResizeEvent.fire(); 
2329              }, 100);
2330          } else {
2331              Overlay.windowResizeEvent.fire();
2332          }
2333      };
2334  
2335      /**
2336      * A boolean that indicated whether the window resize and scroll events have 
2337      * already been subscribed to.
2338      * @property YAHOO.widget.Overlay._initialized
2339      * @private
2340      * @type Boolean
2341      */
2342      Overlay._initialized = null;
2343  
2344      if (Overlay._initialized === null) {
2345          Event.on(window, "scroll", Overlay.windowScrollHandler);
2346          Event.on(window, "resize", Overlay.windowResizeHandler);
2347          Overlay._initialized = true;
2348      }
2349  
2350      /**
2351       * Internal map of special event types, which are provided
2352       * by the instance. It maps the event type to the custom event 
2353       * instance. Contains entries for the "windowScroll", "windowResize" and
2354       * "textResize" static container events.
2355       *
2356       * @property YAHOO.widget.Overlay._TRIGGER_MAP
2357       * @type Object
2358       * @static
2359       * @private
2360       */
2361      Overlay._TRIGGER_MAP = {
2362          "windowScroll" : Overlay.windowScrollEvent,
2363          "windowResize" : Overlay.windowResizeEvent,
2364          "textResize"   : Module.textResizeEvent
2365      };
2366  
2367      YAHOO.extend(Overlay, Module, {
2368  
2369          /**
2370           * <p>
2371           * Array of default event types which will trigger
2372           * context alignment for the Overlay class.
2373           * </p>
2374           * <p>The array is empty by default for Overlay,
2375           * but maybe populated in future releases, so classes extending
2376           * Overlay which need to define their own set of CONTEXT_TRIGGERS
2377           * should concatenate their super class's prototype.CONTEXT_TRIGGERS 
2378           * value with their own array of values.
2379           * </p>
2380           * <p>
2381           * E.g.:
2382           * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2383           * </p>
2384           * 
2385           * @property CONTEXT_TRIGGERS
2386           * @type Array
2387           * @final
2388           */
2389          CONTEXT_TRIGGERS : [],
2390  
2391          /**
2392          * The Overlay initialization method, which is executed for Overlay and  
2393          * all of its subclasses. This method is automatically called by the 
2394          * constructor, and  sets up all DOM references for pre-existing markup, 
2395          * and creates required markup if it is not already present.
2396          * @method init
2397          * @param {String} el The element ID representing the Overlay <em>OR</em>
2398          * @param {HTMLElement} el The element representing the Overlay
2399          * @param {Object} userConfig The configuration object literal 
2400          * containing the configuration that should be set for this Overlay. 
2401          * See configuration documentation for more details.
2402          */
2403          init: function (el, userConfig) {
2404  
2405              /*
2406                   Note that we don't pass the user config in here yet because we
2407                   only want it executed once, at the lowest subclass level
2408              */
2409  
2410              Overlay.superclass.init.call(this, el/*, userConfig*/);
2411  
2412              this.beforeInitEvent.fire(Overlay);
2413  
2414              Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2415  
2416              if (userConfig) {
2417                  this.cfg.applyConfig(userConfig, true);
2418              }
2419  
2420              if (this.platform == "mac" && UA.gecko) {
2421  
2422                  if (! Config.alreadySubscribed(this.showEvent,
2423                      this.showMacGeckoScrollbars, this)) {
2424  
2425                      this.showEvent.subscribe(this.showMacGeckoScrollbars, 
2426                          this, true);
2427  
2428                  }
2429  
2430                  if (! Config.alreadySubscribed(this.hideEvent, 
2431                      this.hideMacGeckoScrollbars, this)) {
2432  
2433                      this.hideEvent.subscribe(this.hideMacGeckoScrollbars, 
2434                          this, true);
2435  
2436                  }
2437              }
2438  
2439              this.initEvent.fire(Overlay);
2440          },
2441          
2442          /**
2443          * Initializes the custom events for Overlay which are fired  
2444          * automatically at appropriate times by the Overlay class.
2445          * @method initEvents
2446          */
2447          initEvents: function () {
2448  
2449              Overlay.superclass.initEvents.call(this);
2450  
2451              var SIGNATURE = CustomEvent.LIST;
2452  
2453              /**
2454              * CustomEvent fired before the Overlay is moved.
2455              * @event beforeMoveEvent
2456              * @param {Number} x x coordinate
2457              * @param {Number} y y coordinate
2458              */
2459              this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2460              this.beforeMoveEvent.signature = SIGNATURE;
2461  
2462              /**
2463              * CustomEvent fired after the Overlay is moved.
2464              * @event moveEvent
2465              * @param {Number} x x coordinate
2466              * @param {Number} y y coordinate
2467              */
2468              this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2469              this.moveEvent.signature = SIGNATURE;
2470  
2471          },
2472          
2473          /**
2474          * Initializes the class's configurable properties which can be changed 
2475          * using the Overlay's Config object (cfg).
2476          * @method initDefaultConfig
2477          */
2478          initDefaultConfig: function () {
2479      
2480              Overlay.superclass.initDefaultConfig.call(this);
2481  
2482              var cfg = this.cfg;
2483  
2484              // Add overlay config properties //
2485              
2486              /**
2487              * The absolute x-coordinate position of the Overlay
2488              * @config x
2489              * @type Number
2490              * @default null
2491              */
2492              cfg.addProperty(DEFAULT_CONFIG.X.key, { 
2493      
2494                  handler: this.configX, 
2495                  validator: DEFAULT_CONFIG.X.validator, 
2496                  suppressEvent: DEFAULT_CONFIG.X.suppressEvent, 
2497                  supercedes: DEFAULT_CONFIG.X.supercedes
2498      
2499              });
2500  
2501              /**
2502              * The absolute y-coordinate position of the Overlay
2503              * @config y
2504              * @type Number
2505              * @default null
2506              */
2507              cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2508  
2509                  handler: this.configY, 
2510                  validator: DEFAULT_CONFIG.Y.validator, 
2511                  suppressEvent: DEFAULT_CONFIG.Y.suppressEvent, 
2512                  supercedes: DEFAULT_CONFIG.Y.supercedes
2513  
2514              });
2515  
2516              /**
2517              * An array with the absolute x and y positions of the Overlay
2518              * @config xy
2519              * @type Number[]
2520              * @default null
2521              */
2522              cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2523                  handler: this.configXY, 
2524                  suppressEvent: DEFAULT_CONFIG.XY.suppressEvent, 
2525                  supercedes: DEFAULT_CONFIG.XY.supercedes
2526              });
2527  
2528              /**
2529              * <p>
2530              * The array of context arguments for context-sensitive positioning. 
2531              * </p>
2532              *
2533              * <p>
2534              * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2535              * the 5 array elements described in detail below:
2536              * </p>
2537              *
2538              * <dl>
2539              * <dt>contextElementOrId &#60;String|HTMLElement&#62;</dt>
2540              * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2541              * <dt>overlayCorner &#60;String&#62;</dt>
2542              * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the 
2543              * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are: 
2544              * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2545              * <dt>contextCorner &#60;String&#62;</dt>
2546              * <dd>The corner of the context element which is to be used for alignment. Supported string values are the same ones listed for the "overlayCorner" entry above.</dd>
2547              * <dt>arrayOfTriggerEvents (optional) &#60;Array[String|CustomEvent]&#62;</dt>
2548              * <dd>
2549              * <p>
2550              * By default, context alignment is a one time operation, aligning the Overlay to the context element when context configuration property is set, or when the <a href="#method_align">align</a> 
2551              * method is invoked. However, you can use the optional "arrayOfTriggerEvents" entry to define the list of events which should force the overlay to re-align itself with the context element. 
2552              * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2553              * </p>
2554              * <p>
2555              * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2556              * 3 static container event types are also currently supported : <code>"windowResize", "windowScroll", "textResize"</code> (defined in <a href="#property__TRIGGER_MAP">_TRIGGER_MAP</a> private property).
2557              * </p>
2558              * </dd>
2559              * <dt>xyOffset &#60;Number[]&#62;</dt>
2560              * <dd>
2561              * A 2 element Array specifying the X and Y pixel amounts by which the Overlay should be offset from the aligned corner. e.g. [5,0] offsets the Overlay 5 pixels to the left, <em>after</em> aligning the given context corners.
2562              * NOTE: If using this property and no triggers need to be defined, the arrayOfTriggerEvents property should be set to null to maintain correct array positions for the arguments. 
2563              * </dd>
2564              * </dl>
2565              *
2566              * <p>
2567              * For example, setting this property to <code>["img1", "tl", "bl"]</code> will 
2568              * align the Overlay's top left corner to the bottom left corner of the
2569              * context element with id "img1".
2570              * </p>
2571              * <p>
2572              * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will 
2573              * align the Overlay's top left corner to the bottom left corner of the
2574              * context element with id "img1", and then offset it by 5 pixels on the Y axis (providing a 5 pixel gap between the bottom of the context element and top of the overlay).
2575              * </p>
2576              * <p>
2577              * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2578              * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2579              * </p>
2580              *
2581              * @config context
2582              * @type Array
2583              * @default null
2584              */
2585              cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2586                  handler: this.configContext, 
2587                  suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent, 
2588                  supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2589              });
2590  
2591              /**
2592              * Determines whether or not the Overlay should be anchored 
2593              * to the center of the viewport.
2594              * 
2595              * <p>This property can be set to:</p>
2596              * 
2597              * <dl>
2598              * <dt>true</dt>
2599              * <dd>
2600              * To enable fixed center positioning
2601              * <p>
2602              * When enabled, the overlay will 
2603              * be positioned in the center of viewport when initially displayed, and 
2604              * will remain in the center of the viewport whenever the window is 
2605              * scrolled or resized.
2606              * </p>
2607              * <p>
2608              * If the overlay is too big for the viewport, 
2609              * it's top left corner will be aligned with the top left corner of the viewport.
2610              * </p>
2611              * </dd>
2612              * <dt>false</dt>
2613              * <dd>
2614              * To disable fixed center positioning.
2615              * <p>In this case the overlay can still be 
2616              * centered as a one-off operation, by invoking the <code>center()</code> method,
2617              * however it will not remain centered when the window is scrolled/resized.
2618              * </dd>
2619              * <dt>"contained"<dt>
2620              * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2621              * <p>However, unlike setting the property to <code>true</code>, 
2622              * when the property is set to <code>"contained"</code>, if the overlay is 
2623              * too big for the viewport, it will not get automatically centered when the 
2624              * user scrolls or resizes the window (until the window is large enough to contain the 
2625              * overlay). This is useful in cases where the Overlay has both header and footer 
2626              * UI controls which the user may need to access.
2627              * </p>
2628              * </dd>
2629              * </dl>
2630              *
2631              * @config fixedcenter
2632              * @type Boolean | String
2633              * @default false
2634              */
2635              cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2636                  handler: this.configFixedCenter,
2637                  value: DEFAULT_CONFIG.FIXED_CENTER.value, 
2638                  validator: DEFAULT_CONFIG.FIXED_CENTER.validator, 
2639                  supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2640              });
2641      
2642              /**
2643              * CSS width of the Overlay.
2644              * @config width
2645              * @type String
2646              * @default null
2647              */
2648              cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2649                  handler: this.configWidth, 
2650                  suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent, 
2651                  supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2652              });
2653  
2654              /**
2655              * CSS height of the Overlay.
2656              * @config height
2657              * @type String
2658              * @default null
2659              */
2660              cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2661                  handler: this.configHeight, 
2662                  suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent, 
2663                  supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2664              });
2665  
2666              /**
2667              * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2668              * Supported values are "header", "body", "footer".
2669              *
2670              * @config autofillheight
2671              * @type String
2672              * @default null
2673              */
2674              cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2675                  handler: this.configAutoFillHeight, 
2676                  value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2677                  validator : this._validateAutoFill,
2678                  supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2679              });
2680  
2681              /**
2682              * CSS z-index of the Overlay.
2683              * @config zIndex
2684              * @type Number
2685              * @default null
2686              */
2687              cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2688                  handler: this.configzIndex,
2689                  value: DEFAULT_CONFIG.ZINDEX.value
2690              });
2691  
2692              /**
2693              * True if the Overlay should be prevented from being positioned 
2694              * out of the viewport.
2695              * @config constraintoviewport
2696              * @type Boolean
2697              * @default false
2698              */
2699              cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2700  
2701                  handler: this.configConstrainToViewport, 
2702                  value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value, 
2703                  validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator, 
2704                  supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2705  
2706              });
2707  
2708              /**
2709              * @config iframe
2710              * @description Boolean indicating whether or not the Overlay should 
2711              * have an IFRAME shim; used to prevent SELECT elements from 
2712              * poking through an Overlay instance in IE6.  When set to "true", 
2713              * the iframe shim is created when the Overlay instance is intially
2714              * made visible.
2715              * @type Boolean
2716              * @default true for IE6 and below, false for all other browsers.
2717              */
2718              cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2719  
2720                  handler: this.configIframe, 
2721                  value: DEFAULT_CONFIG.IFRAME.value, 
2722                  validator: DEFAULT_CONFIG.IFRAME.validator, 
2723                  supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2724  
2725              });
2726  
2727              /**
2728              * @config preventcontextoverlap
2729              * @description Boolean indicating whether or not the Overlay should overlap its 
2730              * context element (defined using the "context" configuration property) when the 
2731              * "constraintoviewport" configuration property is set to "true".
2732              * @type Boolean
2733              * @default false
2734              */
2735              cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2736                  value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value, 
2737                  validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator, 
2738                  supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2739              });
2740          },
2741  
2742          /**
2743          * Moves the Overlay to the specified position. This function is  
2744          * identical to calling this.cfg.setProperty("xy", [x,y]);
2745          * @method moveTo
2746          * @param {Number} x The Overlay's new x position
2747          * @param {Number} y The Overlay's new y position
2748          */
2749          moveTo: function (x, y) {
2750              this.cfg.setProperty("xy", [x, y]);
2751          },
2752  
2753          /**
2754          * Adds a CSS class ("hide-scrollbars") and removes a CSS class 
2755          * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X 
2756          * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2757          * @method hideMacGeckoScrollbars
2758          */
2759          hideMacGeckoScrollbars: function () {
2760              Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2761          },
2762  
2763          /**
2764          * Adds a CSS class ("show-scrollbars") and removes a CSS class 
2765          * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X 
2766          * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2767          * @method showMacGeckoScrollbars
2768          */
2769          showMacGeckoScrollbars: function () {
2770              Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2771          },
2772  
2773          /**
2774           * Internal implementation to set the visibility of the overlay in the DOM.
2775           *
2776           * @method _setDomVisibility
2777           * @param {boolean} visible Whether to show or hide the Overlay's outer element
2778           * @protected
2779           */
2780          _setDomVisibility : function(show) {
2781              Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2782              var hiddenClass = Overlay.CSS_HIDDEN;
2783  
2784              if (show) {
2785                  Dom.removeClass(this.element, hiddenClass);
2786              } else {
2787                  Dom.addClass(this.element, hiddenClass);
2788              }
2789          },
2790  
2791          // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2792          /**
2793          * The default event handler fired when the "visible" property is 
2794          * changed.  This method is responsible for firing showEvent
2795          * and hideEvent.
2796          * @method configVisible
2797          * @param {String} type The CustomEvent type (usually the property name)
2798          * @param {Object[]} args The CustomEvent arguments. For configuration
2799          * handlers, args[0] will equal the newly applied value for the property.
2800          * @param {Object} obj The scope object. For configuration handlers, 
2801          * this will usually equal the owner.
2802          */
2803          configVisible: function (type, args, obj) {
2804  
2805              var visible = args[0],
2806                  currentVis = Dom.getStyle(this.element, "visibility"),
2807                  effects = this._cachedEffects || this._createEffects(this.cfg.getProperty("effect")),
2808                  isMacGecko = (this.platform == "mac" && UA.gecko),
2809                  alreadySubscribed = Config.alreadySubscribed,
2810                  ei, e, j, k, h,
2811                  nEffectInstances;
2812  
2813              if (currentVis == "inherit") {
2814                  e = this.element.parentNode;
2815  
2816                  while (e.nodeType != 9 && e.nodeType != 11) {
2817                      currentVis = Dom.getStyle(e, "visibility");
2818  
2819                      if (currentVis != "inherit") {
2820                          break;
2821                      }
2822  
2823                      e = e.parentNode;
2824                  }
2825  
2826                  if (currentVis == "inherit") {
2827                      currentVis = "visible";
2828                  }
2829              }
2830  
2831              if (visible) { // Show
2832  
2833                  if (isMacGecko) {
2834                      this.showMacGeckoScrollbars();
2835                  }
2836  
2837                  if (effects) { // Animate in
2838                      if (visible) { // Animate in if not showing
2839  
2840                           // Fading out is a bit of a hack, but didn't want to risk doing 
2841                           // something broader (e.g a generic this._animatingOut) for 2.9.0
2842  
2843                          if (currentVis != "visible" || currentVis === "" || this._fadingOut) {
2844                              if (this.beforeShowEvent.fire()) {
2845  
2846                                  nEffectInstances = effects.length;
2847  
2848                                  for (j = 0; j < nEffectInstances; j++) {
2849                                      ei = effects[j];
2850                                      if (j === 0 && !alreadySubscribed(ei.animateInCompleteEvent, this.showEvent.fire, this.showEvent)) {
2851                                          ei.animateInCompleteEvent.subscribe(this.showEvent.fire, this.showEvent, true);
2852                                      }
2853                                      ei.animateIn();
2854                                  }
2855                              }
2856                          }
2857                      }
2858                  } else { // Show
2859                      if (currentVis != "visible" || currentVis === "") {
2860                          if (this.beforeShowEvent.fire()) {
2861                              this._setDomVisibility(true);
2862                              this.cfg.refireEvent("iframe");
2863                              this.showEvent.fire();
2864                          }
2865                      } else {
2866                          this._setDomVisibility(true);
2867                      }
2868                  }
2869              } else { // Hide
2870  
2871                  if (isMacGecko) {
2872                      this.hideMacGeckoScrollbars();
2873                  }
2874  
2875                  if (effects) { // Animate out if showing
2876                      if (currentVis == "visible" || this._fadingIn) {
2877                          if (this.beforeHideEvent.fire()) {
2878                              nEffectInstances = effects.length;
2879                              for (k = 0; k < nEffectInstances; k++) {
2880                                  h = effects[k];
2881          
2882                                  if (k === 0 && !alreadySubscribed(h.animateOutCompleteEvent, this.hideEvent.fire, this.hideEvent)) {
2883                                      h.animateOutCompleteEvent.subscribe(this.hideEvent.fire, this.hideEvent, true);
2884                                  }
2885                                  h.animateOut();
2886                              }
2887                          }
2888  
2889                      } else if (currentVis === "") {
2890                          this._setDomVisibility(false);
2891                      }
2892  
2893                  } else { // Simple hide
2894  
2895                      if (currentVis == "visible" || currentVis === "") {
2896                          if (this.beforeHideEvent.fire()) {
2897                              this._setDomVisibility(false);
2898                              this.hideEvent.fire();
2899                          }
2900                      } else {
2901                          this._setDomVisibility(false);
2902                      }
2903                  }
2904              }
2905          },
2906  
2907          /**
2908          * Fixed center event handler used for centering on scroll/resize, but only if 
2909          * the overlay is visible and, if "fixedcenter" is set to "contained", only if 
2910          * the overlay fits within the viewport.
2911          *
2912          * @method doCenterOnDOMEvent
2913          */
2914          doCenterOnDOMEvent: function () {
2915              var cfg = this.cfg,
2916                  fc = cfg.getProperty("fixedcenter");
2917  
2918              if (cfg.getProperty("visible")) {
2919                  if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2920                      this.center();
2921                  }
2922              }
2923          },
2924  
2925          /**
2926           * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET) 
2927           * will fit entirely inside the viewport, in both dimensions - width and height.
2928           * 
2929           * @method fitsInViewport
2930           * @return boolean true if the Overlay will fit, false if not
2931           */
2932          fitsInViewport : function() {
2933              var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2934                  element = this.element,
2935                  elementWidth = element.offsetWidth,
2936                  elementHeight = element.offsetHeight,
2937                  viewportWidth = Dom.getViewportWidth(),
2938                  viewportHeight = Dom.getViewportHeight();
2939  
2940              return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2941          },
2942  
2943          /**
2944          * The default event handler fired when the "fixedcenter" property 
2945          * is changed.
2946          * @method configFixedCenter
2947          * @param {String} type The CustomEvent type (usually the property name)
2948          * @param {Object[]} args The CustomEvent arguments. For configuration 
2949          * handlers, args[0] will equal the newly applied value for the property.
2950          * @param {Object} obj The scope object. For configuration handlers, 
2951          * this will usually equal the owner.
2952          */
2953          configFixedCenter: function (type, args, obj) {
2954  
2955              var val = args[0],
2956                  alreadySubscribed = Config.alreadySubscribed,
2957                  windowResizeEvent = Overlay.windowResizeEvent,
2958                  windowScrollEvent = Overlay.windowScrollEvent;
2959  
2960              if (val) {
2961                  this.center();
2962  
2963                  if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2964                      this.beforeShowEvent.subscribe(this.center);
2965                  }
2966  
2967                  if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2968                      windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2969                  }
2970  
2971                  if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2972                      windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2973                  }
2974  
2975              } else {
2976                  this.beforeShowEvent.unsubscribe(this.center);
2977  
2978                  windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2979                  windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2980              }
2981          },
2982  
2983          /**
2984          * The default event handler fired when the "height" property is changed.
2985          * @method configHeight
2986          * @param {String} type The CustomEvent type (usually the property name)
2987          * @param {Object[]} args The CustomEvent arguments. For configuration 
2988          * handlers, args[0] will equal the newly applied value for the property.
2989          * @param {Object} obj The scope object. For configuration handlers, 
2990          * this will usually equal the owner.
2991          */
2992          configHeight: function (type, args, obj) {
2993  
2994              var height = args[0],
2995                  el = this.element;
2996  
2997              Dom.setStyle(el, "height", height);
2998              this.cfg.refireEvent("iframe");
2999          },
3000  
3001          /**
3002           * The default event handler fired when the "autofillheight" property is changed.
3003           * @method configAutoFillHeight
3004           *
3005           * @param {String} type The CustomEvent type (usually the property name)
3006           * @param {Object[]} args The CustomEvent arguments. For configuration 
3007           * handlers, args[0] will equal the newly applied value for the property.
3008           * @param {Object} obj The scope object. For configuration handlers, 
3009           * this will usually equal the owner.
3010           */
3011          configAutoFillHeight: function (type, args, obj) {
3012              var fillEl = args[0],
3013                  cfg = this.cfg,
3014                  autoFillHeight = "autofillheight",
3015                  height = "height",
3016                  currEl = cfg.getProperty(autoFillHeight),
3017                  autoFill = this._autoFillOnHeightChange;
3018  
3019              cfg.unsubscribeFromConfigEvent(height, autoFill);
3020              Module.textResizeEvent.unsubscribe(autoFill);
3021              this.changeContentEvent.unsubscribe(autoFill);
3022  
3023              if (currEl && fillEl !== currEl && this[currEl]) {
3024                  Dom.setStyle(this[currEl], height, "");
3025              }
3026  
3027              if (fillEl) {
3028                  fillEl = Lang.trim(fillEl.toLowerCase());
3029  
3030                  cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
3031                  Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
3032                  this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
3033  
3034                  cfg.setProperty(autoFillHeight, fillEl, true);
3035              }
3036          },
3037  
3038          /**
3039          * The default event handler fired when the "width" property is changed.
3040          * @method configWidth
3041          * @param {String} type The CustomEvent type (usually the property name)
3042          * @param {Object[]} args The CustomEvent arguments. For configuration 
3043          * handlers, args[0] will equal the newly applied value for the property.
3044          * @param {Object} obj The scope object. For configuration handlers, 
3045          * this will usually equal the owner.
3046          */
3047          configWidth: function (type, args, obj) {
3048  
3049              var width = args[0],
3050                  el = this.element;
3051  
3052              Dom.setStyle(el, "width", width);
3053              this.cfg.refireEvent("iframe");
3054          },
3055  
3056          /**
3057          * The default event handler fired when the "zIndex" property is changed.
3058          * @method configzIndex
3059          * @param {String} type The CustomEvent type (usually the property name)
3060          * @param {Object[]} args The CustomEvent arguments. For configuration 
3061          * handlers, args[0] will equal the newly applied value for the property.
3062          * @param {Object} obj The scope object. For configuration handlers, 
3063          * this will usually equal the owner.
3064          */
3065          configzIndex: function (type, args, obj) {
3066  
3067              var zIndex = args[0],
3068                  el = this.element;
3069  
3070              if (! zIndex) {
3071                  zIndex = Dom.getStyle(el, "zIndex");
3072                  if (! zIndex || isNaN(zIndex)) {
3073                      zIndex = 0;
3074                  }
3075              }
3076  
3077              if (this.iframe || this.cfg.getProperty("iframe") === true) {
3078                  if (zIndex <= 0) {
3079                      zIndex = 1;
3080                  }
3081              }
3082  
3083              Dom.setStyle(el, "zIndex", zIndex);
3084              this.cfg.setProperty("zIndex", zIndex, true);
3085  
3086              if (this.iframe) {
3087                  this.stackIframe();
3088              }
3089          },
3090  
3091          /**
3092          * The default event handler fired when the "xy" property is changed.
3093          * @method configXY
3094          * @param {String} type The CustomEvent type (usually the property name)
3095          * @param {Object[]} args The CustomEvent arguments. For configuration 
3096          * handlers, args[0] will equal the newly applied value for the property.
3097          * @param {Object} obj The scope object. For configuration handlers, 
3098          * this will usually equal the owner.
3099          */
3100          configXY: function (type, args, obj) {
3101  
3102              var pos = args[0],
3103                  x = pos[0],
3104                  y = pos[1];
3105  
3106              this.cfg.setProperty("x", x);
3107              this.cfg.setProperty("y", y);
3108  
3109              this.beforeMoveEvent.fire([x, y]);
3110  
3111              x = this.cfg.getProperty("x");
3112              y = this.cfg.getProperty("y");
3113  
3114              YAHOO.log(("xy: " + [x, y]), "iframe");
3115  
3116              this.cfg.refireEvent("iframe");
3117              this.moveEvent.fire([x, y]);
3118          },
3119  
3120          /**
3121          * The default event handler fired when the "x" property is changed.
3122          * @method configX
3123          * @param {String} type The CustomEvent type (usually the property name)
3124          * @param {Object[]} args The CustomEvent arguments. For configuration 
3125          * handlers, args[0] will equal the newly applied value for the property.
3126          * @param {Object} obj The scope object. For configuration handlers, 
3127          * this will usually equal the owner.
3128          */
3129          configX: function (type, args, obj) {
3130  
3131              var x = args[0],
3132                  y = this.cfg.getProperty("y");
3133  
3134              this.cfg.setProperty("x", x, true);
3135              this.cfg.setProperty("y", y, true);
3136  
3137              this.beforeMoveEvent.fire([x, y]);
3138  
3139              x = this.cfg.getProperty("x");
3140              y = this.cfg.getProperty("y");
3141  
3142              Dom.setX(this.element, x, true);
3143  
3144              this.cfg.setProperty("xy", [x, y], true);
3145  
3146              this.cfg.refireEvent("iframe");
3147              this.moveEvent.fire([x, y]);
3148          },
3149  
3150          /**
3151          * The default event handler fired when the "y" property is changed.
3152          * @method configY
3153          * @param {String} type The CustomEvent type (usually the property name)
3154          * @param {Object[]} args The CustomEvent arguments. For configuration 
3155          * handlers, args[0] will equal the newly applied value for the property.
3156          * @param {Object} obj The scope object. For configuration handlers, 
3157          * this will usually equal the owner.
3158          */
3159          configY: function (type, args, obj) {
3160  
3161              var x = this.cfg.getProperty("x"),
3162                  y = args[0];
3163  
3164              this.cfg.setProperty("x", x, true);
3165              this.cfg.setProperty("y", y, true);
3166  
3167              this.beforeMoveEvent.fire([x, y]);
3168  
3169              x = this.cfg.getProperty("x");
3170              y = this.cfg.getProperty("y");
3171  
3172              Dom.setY(this.element, y, true);
3173  
3174              this.cfg.setProperty("xy", [x, y], true);
3175  
3176              this.cfg.refireEvent("iframe");
3177              this.moveEvent.fire([x, y]);
3178          },
3179          
3180          /**
3181          * Shows the iframe shim, if it has been enabled.
3182          * @method showIframe
3183          */
3184          showIframe: function () {
3185  
3186              var oIFrame = this.iframe,
3187                  oParentNode;
3188  
3189              if (oIFrame) {
3190                  oParentNode = this.element.parentNode;
3191  
3192                  if (oParentNode != oIFrame.parentNode) {
3193                      this._addToParent(oParentNode, oIFrame);
3194                  }
3195                  oIFrame.style.display = "block";
3196              }
3197          },
3198  
3199          /**
3200          * Hides the iframe shim, if it has been enabled.
3201          * @method hideIframe
3202          */
3203          hideIframe: function () {
3204              if (this.iframe) {
3205                  this.iframe.style.display = "none";
3206              }
3207          },
3208  
3209          /**
3210          * Syncronizes the size and position of iframe shim to that of its 
3211          * corresponding Overlay instance.
3212          * @method syncIframe
3213          */
3214          syncIframe: function () {
3215  
3216              var oIFrame = this.iframe,
3217                  oElement = this.element,
3218                  nOffset = Overlay.IFRAME_OFFSET,
3219                  nDimensionOffset = (nOffset * 2),
3220                  aXY;
3221  
3222              if (oIFrame) {
3223                  // Size <iframe>
3224                  oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3225                  oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3226  
3227                  // Position <iframe>
3228                  aXY = this.cfg.getProperty("xy");
3229  
3230                  if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3231                      this.syncPosition();
3232                      aXY = this.cfg.getProperty("xy");
3233                  }
3234                  Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3235              }
3236          },
3237  
3238          /**
3239           * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3240           * the Overlay element. The zindex of the iframe is set to be one less 
3241           * than the Overlay element's zindex.
3242           * 
3243           * <p>NOTE: This method will not bump up the zindex of the Overlay element
3244           * to ensure that the iframe shim has a non-negative zindex.
3245           * If you require the iframe zindex to be 0 or higher, the zindex of 
3246           * the Overlay element should be set to a value greater than 0, before 
3247           * this method is called.
3248           * </p>
3249           * @method stackIframe
3250           */
3251          stackIframe: function () {
3252              if (this.iframe) {
3253                  var overlayZ = Dom.getStyle(this.element, "zIndex");
3254                  if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3255                      Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3256                  }
3257              }
3258          },
3259  
3260          /**
3261          * The default event handler fired when the "iframe" property is changed.
3262          * @method configIframe
3263          * @param {String} type The CustomEvent type (usually the property name)
3264          * @param {Object[]} args The CustomEvent arguments. For configuration 
3265          * handlers, args[0] will equal the newly applied value for the property.
3266          * @param {Object} obj The scope object. For configuration handlers, 
3267          * this will usually equal the owner.
3268          */
3269          configIframe: function (type, args, obj) {
3270  
3271              var bIFrame = args[0];
3272  
3273              function createIFrame() {
3274  
3275                  var oIFrame = this.iframe,
3276                      oElement = this.element,
3277                      oParent;
3278  
3279                  if (!oIFrame) {
3280                      if (!m_oIFrameTemplate) {
3281                          m_oIFrameTemplate = document.createElement("iframe");
3282  
3283                          if (this.isSecure) {
3284                              m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3285                          }
3286  
3287                          /*
3288                              Set the opacity of the <iframe> to 0 so that it 
3289                              doesn't modify the opacity of any transparent 
3290                              elements that may be on top of it (like a shadow).
3291                          */
3292                          if (UA.ie) {
3293                              m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3294                              /*
3295                                   Need to set the "frameBorder" property to 0 
3296                                   supress the default <iframe> border in IE.  
3297                                   Setting the CSS "border" property alone 
3298                                   doesn't supress it.
3299                              */
3300                              m_oIFrameTemplate.frameBorder = 0;
3301                          }
3302                          else {
3303                              m_oIFrameTemplate.style.opacity = "0";
3304                          }
3305  
3306                          m_oIFrameTemplate.style.position = "absolute";
3307                          m_oIFrameTemplate.style.border = "none";
3308                          m_oIFrameTemplate.style.margin = "0";
3309                          m_oIFrameTemplate.style.padding = "0";
3310                          m_oIFrameTemplate.style.display = "none";
3311                          m_oIFrameTemplate.tabIndex = -1;
3312                          m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3313                      }
3314  
3315                      oIFrame = m_oIFrameTemplate.cloneNode(false);
3316                      oIFrame.id = this.id + "_f";
3317                      oParent = oElement.parentNode;
3318  
3319                      var parentNode = oParent || document.body;
3320  
3321                      this._addToParent(parentNode, oIFrame);
3322                      this.iframe = oIFrame;
3323                  }
3324  
3325                  /*
3326                       Show the <iframe> before positioning it since the "setXY" 
3327                       method of DOM requires the element be in the document 
3328                       and visible.
3329                  */
3330                  this.showIframe();
3331  
3332                  /*
3333                       Syncronize the size and position of the <iframe> to that 
3334                       of the Overlay.
3335                  */
3336                  this.syncIframe();
3337                  this.stackIframe();
3338  
3339                  // Add event listeners to update the <iframe> when necessary
3340                  if (!this._hasIframeEventListeners) {
3341                      this.showEvent.subscribe(this.showIframe);
3342                      this.hideEvent.subscribe(this.hideIframe);
3343                      this.changeContentEvent.subscribe(this.syncIframe);
3344  
3345                      this._hasIframeEventListeners = true;
3346                  }
3347              }
3348  
3349              function onBeforeShow() {
3350                  createIFrame.call(this);
3351                  this.beforeShowEvent.unsubscribe(onBeforeShow);
3352                  this._iframeDeferred = false;
3353              }
3354  
3355              if (bIFrame) { // <iframe> shim is enabled
3356  
3357                  if (this.cfg.getProperty("visible")) {
3358                      createIFrame.call(this);
3359                  } else {
3360                      if (!this._iframeDeferred) {
3361                          this.beforeShowEvent.subscribe(onBeforeShow);
3362                          this._iframeDeferred = true;
3363                      }
3364                  }
3365  
3366              } else {    // <iframe> shim is disabled
3367                  this.hideIframe();
3368  
3369                  if (this._hasIframeEventListeners) {
3370                      this.showEvent.unsubscribe(this.showIframe);
3371                      this.hideEvent.unsubscribe(this.hideIframe);
3372                      this.changeContentEvent.unsubscribe(this.syncIframe);
3373  
3374                      this._hasIframeEventListeners = false;
3375                  }
3376              }
3377          },
3378  
3379          /**
3380           * Set's the container's XY value from DOM if not already set.
3381           * 
3382           * Differs from syncPosition, in that the XY value is only sync'd with DOM if 
3383           * not already set. The method also refire's the XY config property event, so any
3384           * beforeMove, Move event listeners are invoked.
3385           * 
3386           * @method _primeXYFromDOM
3387           * @protected
3388           */
3389          _primeXYFromDOM : function() {
3390              if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3391                  // Set CFG XY based on DOM XY
3392                  this.syncPosition();
3393                  // Account for XY being set silently in syncPosition (no moveTo fired/called)
3394                  this.cfg.refireEvent("xy");
3395                  this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3396              }
3397          },
3398  
3399          /**
3400          * The default event handler fired when the "constraintoviewport" 
3401          * property is changed.
3402          * @method configConstrainToViewport
3403          * @param {String} type The CustomEvent type (usually the property name)
3404          * @param {Object[]} args The CustomEvent arguments. For configuration 
3405          * handlers, args[0] will equal the newly applied value for 
3406          * the property.
3407          * @param {Object} obj The scope object. For configuration handlers, 
3408          * this will usually equal the owner.
3409          */
3410          configConstrainToViewport: function (type, args, obj) {
3411              var val = args[0];
3412  
3413              if (val) {
3414                  if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3415                      this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3416                  }
3417                  if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3418                      this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3419                  }
3420              } else {
3421                  this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3422                  this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3423              }
3424          },
3425  
3426           /**
3427          * The default event handler fired when the "context" property
3428          * is changed.
3429          *
3430          * @method configContext
3431          * @param {String} type The CustomEvent type (usually the property name)
3432          * @param {Object[]} args The CustomEvent arguments. For configuration 
3433          * handlers, args[0] will equal the newly applied value for the property.
3434          * @param {Object} obj The scope object. For configuration handlers, 
3435          * this will usually equal the owner.
3436          */
3437          configContext: function (type, args, obj) {
3438  
3439              var contextArgs = args[0],
3440                  contextEl,
3441                  elementMagnetCorner,
3442                  contextMagnetCorner,
3443                  triggers,
3444                  offset,
3445                  defTriggers = this.CONTEXT_TRIGGERS;
3446  
3447              if (contextArgs) {
3448  
3449                  contextEl = contextArgs[0];
3450                  elementMagnetCorner = contextArgs[1];
3451                  contextMagnetCorner = contextArgs[2];
3452                  triggers = contextArgs[3];
3453                  offset = contextArgs[4];
3454  
3455                  if (defTriggers && defTriggers.length > 0) {
3456                      triggers = (triggers || []).concat(defTriggers);
3457                  }
3458  
3459                  if (contextEl) {
3460                      if (typeof contextEl == "string") {
3461                          this.cfg.setProperty("context", [
3462                                  document.getElementById(contextEl), 
3463                                  elementMagnetCorner,
3464                                  contextMagnetCorner,
3465                                  triggers,
3466                                  offset],
3467                                  true);
3468                      }
3469  
3470                      if (elementMagnetCorner && contextMagnetCorner) {
3471                          this.align(elementMagnetCorner, contextMagnetCorner, offset);
3472                      }
3473  
3474                      if (this._contextTriggers) {
3475                          // Unsubscribe Old Set
3476                          this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3477                      }
3478  
3479                      if (triggers) {
3480                          // Subscribe New Set
3481                          this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3482                          this._contextTriggers = triggers;
3483                      }
3484                  }
3485              }
3486          },
3487  
3488          /**
3489           * Custom Event handler for context alignment triggers. Invokes the align method
3490           * 
3491           * @method _alignOnTrigger
3492           * @protected
3493           * 
3494           * @param {String} type The event type (not used by the default implementation)
3495           * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3496           */
3497          _alignOnTrigger: function(type, args) {
3498              this.align();
3499          },
3500  
3501          /**
3502           * Helper method to locate the custom event instance for the event name string
3503           * passed in. As a convenience measure, any custom events passed in are returned.
3504           *
3505           * @method _findTriggerCE
3506           * @private
3507           *
3508           * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a 
3509           * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3510           */
3511          _findTriggerCE : function(t) {
3512              var tce = null;
3513              if (t instanceof CustomEvent) {
3514                  tce = t;
3515              } else if (Overlay._TRIGGER_MAP[t]) {
3516                  tce = Overlay._TRIGGER_MAP[t];
3517              }
3518              return tce;
3519          },
3520  
3521          /**
3522           * Utility method that subscribes or unsubscribes the given 
3523           * function from the list of trigger events provided.
3524           *
3525           * @method _processTriggers
3526           * @protected 
3527           *
3528           * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings 
3529           * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be 
3530           * subscribed/unsubscribed respectively.
3531           *
3532           * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3533           * we are subscribing or unsubscribing trigger listeners
3534           * 
3535           * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3536           * Context is always set to the overlay instance, and no additional object argument 
3537           * get passed to the subscribed function.
3538           */
3539          _processTriggers : function(triggers, mode, fn) {
3540              var t, tce;
3541  
3542              for (var i = 0, l = triggers.length; i < l; ++i) {
3543                  t = triggers[i];
3544                  tce = this._findTriggerCE(t);
3545                  if (tce) {
3546                      tce[mode](fn, this, true);
3547                  } else {
3548                      this[mode](t, fn);
3549                  }
3550              }
3551          },
3552  
3553          // END BUILT-IN PROPERTY EVENT HANDLERS //
3554          /**
3555          * Aligns the Overlay to its context element using the specified corner 
3556          * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, 
3557          * and BOTTOM_RIGHT.
3558          * @method align
3559          * @param {String} elementAlign  The String representing the corner of 
3560          * the Overlay that should be aligned to the context element
3561          * @param {String} contextAlign  The corner of the context element 
3562          * that the elementAlign corner should stick to.
3563          * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3564          * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the 
3565          * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3566          */
3567          align: function (elementAlign, contextAlign, xyOffset) {
3568  
3569              var contextArgs = this.cfg.getProperty("context"),
3570                  me = this,
3571                  context,
3572                  element,
3573                  contextRegion;
3574  
3575              function doAlign(v, h) {
3576  
3577                  var alignX = null, alignY = null;
3578  
3579                  switch (elementAlign) {
3580      
3581                      case Overlay.TOP_LEFT:
3582                          alignX = h;
3583                          alignY = v;
3584                          break;
3585          
3586                      case Overlay.TOP_RIGHT:
3587                          alignX = h - element.offsetWidth;
3588                          alignY = v;
3589                          break;
3590          
3591                      case Overlay.BOTTOM_LEFT:
3592                          alignX = h;
3593                          alignY = v - element.offsetHeight;
3594                          break;
3595          
3596                      case Overlay.BOTTOM_RIGHT:
3597                          alignX = h - element.offsetWidth; 
3598                          alignY = v - element.offsetHeight;
3599                          break;
3600                  }
3601  
3602                  if (alignX !== null && alignY !== null) {
3603                      if (xyOffset) {
3604                          alignX += xyOffset[0];
3605                          alignY += xyOffset[1];
3606                      }
3607                      me.moveTo(alignX, alignY);
3608                  }
3609              }
3610  
3611              if (contextArgs) {
3612                  context = contextArgs[0];
3613                  element = this.element;
3614                  me = this;
3615  
3616                  if (! elementAlign) {
3617                      elementAlign = contextArgs[1];
3618                  }
3619  
3620                  if (! contextAlign) {
3621                      contextAlign = contextArgs[2];
3622                  }
3623  
3624                  if (!xyOffset && contextArgs[4]) {
3625                      xyOffset = contextArgs[4];
3626                  }
3627  
3628                  if (element && context) {
3629                      contextRegion = Dom.getRegion(context);
3630  
3631                      switch (contextAlign) {
3632      
3633                          case Overlay.TOP_LEFT:
3634                              doAlign(contextRegion.top, contextRegion.left);
3635                              break;
3636          
3637                          case Overlay.TOP_RIGHT:
3638                              doAlign(contextRegion.top, contextRegion.right);
3639                              break;
3640          
3641                          case Overlay.BOTTOM_LEFT:
3642                              doAlign(contextRegion.bottom, contextRegion.left);
3643                              break;
3644          
3645                          case Overlay.BOTTOM_RIGHT:
3646                              doAlign(contextRegion.bottom, contextRegion.right);
3647                              break;
3648                      }
3649                  }
3650              }
3651          },
3652  
3653          /**
3654          * The default event handler executed when the moveEvent is fired, if the 
3655          * "constraintoviewport" is set to true.
3656          * @method enforceConstraints
3657          * @param {String} type The CustomEvent type (usually the property name)
3658          * @param {Object[]} args The CustomEvent arguments. For configuration 
3659          * handlers, args[0] will equal the newly applied value for the property.
3660          * @param {Object} obj The scope object. For configuration handlers, 
3661          * this will usually equal the owner.
3662          */
3663          enforceConstraints: function (type, args, obj) {
3664              var pos = args[0];
3665  
3666              var cXY = this.getConstrainedXY(pos[0], pos[1]);
3667              this.cfg.setProperty("x", cXY[0], true);
3668              this.cfg.setProperty("y", cXY[1], true);
3669              this.cfg.setProperty("xy", cXY, true);
3670          },
3671  
3672          /**
3673           * Shared implementation method for getConstrainedX and getConstrainedY.
3674           * 
3675           * <p>
3676           * Given a coordinate value, returns the calculated coordinate required to 
3677           * position the Overlay if it is to be constrained to the viewport, based on the 
3678           * current element size, viewport dimensions, scroll values and preventoverlap 
3679           * settings
3680           * </p>
3681           *
3682           * @method _getConstrainedPos
3683           * @protected
3684           * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3685           * @param {Number} The coordinate value which needs to be constrained
3686           * @return {Number} The constrained coordinate value
3687           */
3688          _getConstrainedPos: function(pos, val) {
3689  
3690              var overlayEl = this.element,
3691  
3692                  buffer = Overlay.VIEWPORT_OFFSET,
3693  
3694                  x = (pos == "x"),
3695  
3696                  overlaySize      = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3697                  viewportSize     = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3698                  docScroll        = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3699                  overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3700  
3701                  context = this.cfg.getProperty("context"),
3702  
3703                  bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3704                  bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3705  
3706                  minConstraint = docScroll + buffer,
3707                  maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3708  
3709                  constrainedVal = val;
3710  
3711              if (val < minConstraint || val > maxConstraint) {
3712                  if (bPreventContextOverlap) {
3713                      constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3714                  } else {
3715                      if (bOverlayFitsInViewport) {
3716                          if (val < minConstraint) {
3717                              constrainedVal = minConstraint;
3718                          } else if (val > maxConstraint) {
3719                              constrainedVal = maxConstraint;
3720                          }
3721                      } else {
3722                          constrainedVal = minConstraint;
3723                      }
3724                  }
3725              }
3726  
3727              return constrainedVal;
3728          },
3729  
3730          /**
3731           * Helper method, used to position the Overlap to prevent overlap with the 
3732           * context element (used when preventcontextoverlap is enabled)
3733           *
3734           * @method _preventOverlap
3735           * @protected
3736           * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3737           * @param {HTMLElement} contextEl The context element
3738           * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3739           * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3740           * @param {Object} docScroll  The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3741           *
3742           * @return {Number} The new coordinate value which was set to prevent overlap
3743           */
3744          _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3745              
3746              var x = (pos == "x"),
3747  
3748                  buffer = Overlay.VIEWPORT_OFFSET,
3749  
3750                  overlay = this,
3751  
3752                  contextElPos   = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3753                  contextElSize  = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3754  
3755                  minRegionSize = contextElPos - buffer,
3756                  maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3757  
3758                  bFlipped = false,
3759  
3760                  flip = function () {
3761                      var flippedVal;
3762  
3763                      if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3764                          flippedVal = (contextElPos - overlaySize);
3765                      } else {
3766                          flippedVal = (contextElPos + contextElSize);
3767                      }
3768  
3769                      overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3770  
3771                      return flippedVal;
3772                  },
3773  
3774                  setPosition = function () {
3775  
3776                      var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3777                          position;
3778  
3779                      if (overlaySize > displayRegionSize) {
3780                          if (bFlipped) {
3781                              /*
3782                                   All possible positions and values have been 
3783                                   tried, but none were successful, so fall back 
3784                                   to the original size and position.
3785                              */
3786                              flip();
3787                          } else {
3788                              flip();
3789                              bFlipped = true;
3790                              position = setPosition();
3791                          }
3792                      }
3793  
3794                      return position;
3795                  };
3796  
3797              setPosition();
3798  
3799              return this.cfg.getProperty(pos);
3800          },
3801  
3802          /**
3803           * Given x coordinate value, returns the calculated x coordinate required to 
3804           * position the Overlay if it is to be constrained to the viewport, based on the 
3805           * current element size, viewport dimensions and scroll values.
3806           *
3807           * @param {Number} x The X coordinate value to be constrained
3808           * @return {Number} The constrained x coordinate
3809           */        
3810          getConstrainedX: function (x) {
3811              return this._getConstrainedPos("x", x);
3812          },
3813  
3814          /**
3815           * Given y coordinate value, returns the calculated y coordinate required to 
3816           * position the Overlay if it is to be constrained to the viewport, based on the 
3817           * current element size, viewport dimensions and scroll values.
3818           *
3819           * @param {Number} y The Y coordinate value to be constrained
3820           * @return {Number} The constrained y coordinate
3821           */        
3822          getConstrainedY : function (y) {
3823              return this._getConstrainedPos("y", y);
3824          },
3825  
3826          /**
3827           * Given x, y coordinate values, returns the calculated coordinates required to 
3828           * position the Overlay if it is to be constrained to the viewport, based on the 
3829           * current element size, viewport dimensions and scroll values.
3830           *
3831           * @param {Number} x The X coordinate value to be constrained
3832           * @param {Number} y The Y coordinate value to be constrained
3833           * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3834           */
3835          getConstrainedXY: function(x, y) {
3836              return [this.getConstrainedX(x), this.getConstrainedY(y)];
3837          },
3838  
3839          /**
3840          * Centers the container in the viewport.
3841          * @method center
3842          */
3843          center: function () {
3844  
3845              var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3846                  elementWidth = this.element.offsetWidth,
3847                  elementHeight = this.element.offsetHeight,
3848                  viewPortWidth = Dom.getViewportWidth(),
3849                  viewPortHeight = Dom.getViewportHeight(),
3850                  x,
3851                  y;
3852  
3853              if (elementWidth < viewPortWidth) {
3854                  x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3855              } else {
3856                  x = nViewportOffset + Dom.getDocumentScrollLeft();
3857              }
3858  
3859              if (elementHeight < viewPortHeight) {
3860                  y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3861              } else {
3862                  y = nViewportOffset + Dom.getDocumentScrollTop();
3863              }
3864  
3865              this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3866              this.cfg.refireEvent("iframe");
3867  
3868              if (UA.webkit) {
3869                  this.forceContainerRedraw();
3870              }
3871          },
3872  
3873          /**
3874          * Synchronizes the Panel's "xy", "x", and "y" properties with the 
3875          * Panel's position in the DOM. This is primarily used to update  
3876          * position information during drag & drop.
3877          * @method syncPosition
3878          */
3879          syncPosition: function () {
3880  
3881              var pos = Dom.getXY(this.element);
3882  
3883              this.cfg.setProperty("x", pos[0], true);
3884              this.cfg.setProperty("y", pos[1], true);
3885              this.cfg.setProperty("xy", pos, true);
3886  
3887          },
3888  
3889          /**
3890          * Event handler fired when the resize monitor element is resized.
3891          * @method onDomResize
3892          * @param {DOMEvent} e The resize DOM event
3893          * @param {Object} obj The scope object
3894          */
3895          onDomResize: function (e, obj) {
3896  
3897              var me = this;
3898  
3899              Overlay.superclass.onDomResize.call(this, e, obj);
3900  
3901              setTimeout(function () {
3902                  me.syncPosition();
3903                  me.cfg.refireEvent("iframe");
3904                  me.cfg.refireEvent("context");
3905              }, 0);
3906          },
3907  
3908          /**
3909           * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3910           *
3911           * @method _getComputedHeight
3912           * @private
3913           * @param {HTMLElement} el The element for which the content height needs to be determined
3914           * @return {Number} The content box height of the given element, or null if it could not be determined.
3915           */
3916          _getComputedHeight : (function() {
3917  
3918              if (document.defaultView && document.defaultView.getComputedStyle) {
3919                  return function(el) {
3920                      var height = null;
3921                      if (el.ownerDocument && el.ownerDocument.defaultView) {
3922                          var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3923                          if (computed) {
3924                              height = parseInt(computed.height, 10);
3925                          }
3926                      }
3927                      return (Lang.isNumber(height)) ? height : null;
3928                  };
3929              } else {
3930                  return function(el) {
3931                      var height = null;
3932                      if (el.style.pixelHeight) {
3933                          height = el.style.pixelHeight;
3934                      }
3935                      return (Lang.isNumber(height)) ? height : null;
3936                  };
3937              }
3938          })(),
3939  
3940          /**
3941           * autofillheight validator. Verifies that the autofill value is either null 
3942           * or one of the strings : "body", "header" or "footer".
3943           *
3944           * @method _validateAutoFillHeight
3945           * @protected
3946           * @param {String} val
3947           * @return true, if valid, false otherwise
3948           */
3949          _validateAutoFillHeight : function(val) {
3950              return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3951          },
3952  
3953          /**
3954           * The default custom event handler executed when the overlay's height is changed, 
3955           * if the autofillheight property has been set.
3956           *
3957           * @method _autoFillOnHeightChange
3958           * @protected
3959           * @param {String} type The event type
3960           * @param {Array} args The array of arguments passed to event subscribers
3961           * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3962           * out the containers height
3963           */
3964          _autoFillOnHeightChange : function(type, args, el) {
3965              var height = this.cfg.getProperty("height");
3966              if ((height && height !== "auto") || (height === 0)) {
3967                  this.fillHeight(el);
3968              }
3969          },
3970  
3971          /**
3972           * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3973           * otherwise returns the offsetHeight
3974           * @method _getPreciseHeight
3975           * @private
3976           * @param {HTMLElement} el
3977           * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3978           */
3979          _getPreciseHeight : function(el) {
3980              var height = el.offsetHeight;
3981  
3982              if (el.getBoundingClientRect) {
3983                  var rect = el.getBoundingClientRect();
3984                  height = rect.bottom - rect.top;
3985              }
3986  
3987              return height;
3988          },
3989  
3990          /**
3991           * <p>
3992           * Sets the height on the provided header, body or footer element to 
3993           * fill out the height of the container. It determines the height of the 
3994           * containers content box, based on it's configured height value, and 
3995           * sets the height of the autofillheight element to fill out any 
3996           * space remaining after the other standard module element heights 
3997           * have been accounted for.
3998           * </p>
3999           * <p><strong>NOTE:</strong> This method is not designed to work if an explicit 
4000           * height has not been set on the container, since for an "auto" height container, 
4001           * the heights of the header/body/footer will drive the height of the container.</p>
4002           *
4003           * @method fillHeight
4004           * @param {HTMLElement} el The element which should be resized to fill out the height
4005           * of the container element.
4006           */
4007          fillHeight : function(el) {
4008              if (el) {
4009                  var container = this.innerElement || this.element,
4010                      containerEls = [this.header, this.body, this.footer],
4011                      containerEl,
4012                      total = 0,
4013                      filled = 0,
4014                      remaining = 0,
4015                      validEl = false;
4016  
4017                  for (var i = 0, l = containerEls.length; i < l; i++) {
4018                      containerEl = containerEls[i];
4019                      if (containerEl) {
4020                          if (el !== containerEl) {
4021                              filled += this._getPreciseHeight(containerEl);
4022                          } else {
4023                              validEl = true;
4024                          }
4025                      }
4026                  }
4027  
4028                  if (validEl) {
4029  
4030                      if (UA.ie || UA.opera) {
4031                          // Need to set height to 0, to allow height to be reduced
4032                          Dom.setStyle(el, 'height', 0 + 'px');
4033                      }
4034  
4035                      total = this._getComputedHeight(container);
4036  
4037                      // Fallback, if we can't get computed value for content height
4038                      if (total === null) {
4039                          Dom.addClass(container, "yui-override-padding");
4040                          total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4041                          Dom.removeClass(container, "yui-override-padding");
4042                      }
4043      
4044                      remaining = Math.max(total - filled, 0);
4045      
4046                      Dom.setStyle(el, "height", remaining + "px");
4047      
4048                      // Re-adjust height if required, to account for el padding and border
4049                      if (el.offsetHeight != remaining) {
4050                          remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4051                      }
4052                      Dom.setStyle(el, "height", remaining + "px");
4053                  }
4054              }
4055          },
4056  
4057          /**
4058          * Places the Overlay on top of all other instances of 
4059          * YAHOO.widget.Overlay.
4060          * @method bringToTop
4061          */
4062          bringToTop: function () {
4063  
4064              var aOverlays = [],
4065                  oElement = this.element;
4066  
4067              function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4068  
4069                  var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4070                      sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4071  
4072                      nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4073                      nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4074  
4075                  if (nZIndex1 > nZIndex2) {
4076                      return -1;
4077                  } else if (nZIndex1 < nZIndex2) {
4078                      return 1;
4079                  } else {
4080                      return 0;
4081                  }
4082              }
4083  
4084              function isOverlayElement(p_oElement) {
4085  
4086                  var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4087                      Panel = YAHOO.widget.Panel;
4088  
4089                  if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4090                      if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4091                          aOverlays[aOverlays.length] = p_oElement.parentNode;
4092                      } else {
4093                          aOverlays[aOverlays.length] = p_oElement;
4094                      }
4095                  }
4096              }
4097  
4098              Dom.getElementsBy(isOverlayElement, "div", document.body);
4099  
4100              aOverlays.sort(compareZIndexDesc);
4101  
4102              var oTopOverlay = aOverlays[0],
4103                  nTopZIndex;
4104  
4105              if (oTopOverlay) {
4106                  nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4107  
4108                  if (!isNaN(nTopZIndex)) {
4109                      var bRequiresBump = false;
4110  
4111                      if (oTopOverlay != oElement) {
4112                          bRequiresBump = true;
4113                      } else if (aOverlays.length > 1) {
4114                          var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4115                          // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4116                          if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4117                              bRequiresBump = true;
4118                          }
4119                      }
4120                      if (bRequiresBump) {
4121                          this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4122                      }
4123                  }
4124              }
4125          },
4126  
4127          /**
4128          * Removes the Overlay element from the DOM and sets all child 
4129          * elements to null.
4130          * @method destroy
4131          * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners. 
4132          * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
4133          */
4134          destroy: function (shallowPurge) {
4135  
4136              if (this.iframe) {
4137                  this.iframe.parentNode.removeChild(this.iframe);
4138              }
4139  
4140              this.iframe = null;
4141  
4142              Overlay.windowResizeEvent.unsubscribe(
4143                  this.doCenterOnDOMEvent, this);
4144      
4145              Overlay.windowScrollEvent.unsubscribe(
4146                  this.doCenterOnDOMEvent, this);
4147  
4148              Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4149  
4150              if (this._contextTriggers) {
4151                  // Unsubscribe context triggers - to cover context triggers which listen for global
4152                  // events such as windowResize and windowScroll. Easier just to unsubscribe all
4153                  this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4154              }
4155  
4156              Overlay.superclass.destroy.call(this, shallowPurge);
4157          },
4158  
4159          /**
4160           * Can be used to force the container to repaint/redraw it's contents.
4161           * <p>
4162           * By default applies and then removes a 1px bottom margin through the 
4163           * application/removal of a "yui-force-redraw" class.
4164           * </p>
4165           * <p>
4166           * It is currently used by Overlay to force a repaint for webkit 
4167           * browsers, when centering.
4168           * </p>
4169           * @method forceContainerRedraw
4170           */
4171          forceContainerRedraw : function() {
4172              var c = this;
4173              Dom.addClass(c.element, "yui-force-redraw");
4174              setTimeout(function() {
4175                  Dom.removeClass(c.element, "yui-force-redraw");
4176              }, 0);
4177          },
4178  
4179          /**
4180          * Returns a String representation of the object.
4181          * @method toString
4182          * @return {String} The string representation of the Overlay.
4183          */
4184          toString: function () {
4185              return "Overlay " + this.id;
4186          }
4187  
4188      });
4189  }());
4190  (function () {
4191  
4192      /**
4193      * OverlayManager is used for maintaining the focus status of 
4194      * multiple Overlays.
4195      * @namespace YAHOO.widget
4196      * @namespace YAHOO.widget
4197      * @class OverlayManager
4198      * @constructor
4199      * @param {Array} overlays Optional. A collection of Overlays to register 
4200      * with the manager.
4201      * @param {Object} userConfig  The object literal representing the user 
4202      * configuration of the OverlayManager
4203      */
4204      YAHOO.widget.OverlayManager = function (userConfig) {
4205          this.init(userConfig);
4206      };
4207  
4208      var Overlay = YAHOO.widget.Overlay,
4209          Event = YAHOO.util.Event,
4210          Dom = YAHOO.util.Dom,
4211          Config = YAHOO.util.Config,
4212          CustomEvent = YAHOO.util.CustomEvent,
4213          OverlayManager = YAHOO.widget.OverlayManager;
4214  
4215      /**
4216      * The CSS class representing a focused Overlay
4217      * @property OverlayManager.CSS_FOCUSED
4218      * @static
4219      * @final
4220      * @type String
4221      */
4222      OverlayManager.CSS_FOCUSED = "focused";
4223  
4224      OverlayManager.prototype = {
4225  
4226          /**
4227          * The class's constructor function
4228          * @property contructor
4229          * @type Function
4230          */
4231          constructor: OverlayManager,
4232  
4233          /**
4234          * The array of Overlays that are currently registered
4235          * @property overlays
4236          * @type YAHOO.widget.Overlay[]
4237          */
4238          overlays: null,
4239  
4240          /**
4241          * Initializes the default configuration of the OverlayManager
4242          * @method initDefaultConfig
4243          */
4244          initDefaultConfig: function () {
4245              /**
4246              * The collection of registered Overlays in use by 
4247              * the OverlayManager
4248              * @config overlays
4249              * @type YAHOO.widget.Overlay[]
4250              * @default null
4251              */
4252              this.cfg.addProperty("overlays", { suppressEvent: true } );
4253  
4254              /**
4255              * The default DOM event that should be used to focus an Overlay
4256              * @config focusevent
4257              * @type String
4258              * @default "mousedown"
4259              */
4260              this.cfg.addProperty("focusevent", { value: "mousedown" } );
4261          },
4262  
4263          /**
4264          * Initializes the OverlayManager
4265          * @method init
4266          * @param {Overlay[]} overlays Optional. A collection of Overlays to 
4267          * register with the manager.
4268          * @param {Object} userConfig  The object literal representing the user 
4269          * configuration of the OverlayManager
4270          */
4271          init: function (userConfig) {
4272  
4273              /**
4274              * The OverlayManager's Config object used for monitoring 
4275              * configuration properties.
4276              * @property cfg
4277              * @type Config
4278              */
4279              this.cfg = new Config(this);
4280  
4281              this.initDefaultConfig();
4282  
4283              if (userConfig) {
4284                  this.cfg.applyConfig(userConfig, true);
4285              }
4286              this.cfg.fireQueue();
4287  
4288              /**
4289              * The currently activated Overlay
4290              * @property activeOverlay
4291              * @private
4292              * @type YAHOO.widget.Overlay
4293              */
4294              var activeOverlay = null;
4295  
4296              /**
4297              * Returns the currently focused Overlay
4298              * @method getActive
4299              * @return {Overlay} The currently focused Overlay
4300              */
4301              this.getActive = function () {
4302                  return activeOverlay;
4303              };
4304  
4305              /**
4306              * Focuses the specified Overlay
4307              * @method focus
4308              * @param {Overlay} overlay The Overlay to focus
4309              * @param {String} overlay The id of the Overlay to focus
4310              */
4311              this.focus = function (overlay) {
4312                  var o = this.find(overlay);
4313                  if (o) {
4314                      o.focus();
4315                  }
4316              };
4317  
4318              /**
4319              * Removes the specified Overlay from the manager
4320              * @method remove
4321              * @param {Overlay} overlay The Overlay to remove
4322              * @param {String} overlay The id of the Overlay to remove
4323              */
4324              this.remove = function (overlay) {
4325  
4326                  var o = this.find(overlay), 
4327                          originalZ;
4328  
4329                  if (o) {
4330                      if (activeOverlay == o) {
4331                          activeOverlay = null;
4332                      }
4333  
4334                      var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4335  
4336                      if (!bDestroyed) {
4337                          // Set it's zindex so that it's sorted to the end.
4338                          originalZ = Dom.getStyle(o.element, "zIndex");
4339                          o.cfg.setProperty("zIndex", -1000, true);
4340                      }
4341  
4342                      this.overlays.sort(this.compareZIndexDesc);
4343                      this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4344  
4345                      o.hideEvent.unsubscribe(o.blur);
4346                      o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4347                      o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4348                      o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4349  
4350                      if (!bDestroyed) {
4351                          Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4352                          o.cfg.setProperty("zIndex", originalZ, true);
4353                          o.cfg.setProperty("manager", null);
4354                      }
4355  
4356                      /* _managed Flag for custom or existing. Don't want to remove existing */
4357                      if (o.focusEvent._managed) { o.focusEvent = null; }
4358                      if (o.blurEvent._managed) { o.blurEvent = null; }
4359  
4360                      if (o.focus._managed) { o.focus = null; }
4361                      if (o.blur._managed) { o.blur = null; }
4362                  }
4363              };
4364  
4365              /**
4366              * Removes focus from all registered Overlays in the manager
4367              * @method blurAll
4368              */
4369              this.blurAll = function () {
4370  
4371                  var nOverlays = this.overlays.length,
4372                      i;
4373  
4374                  if (nOverlays > 0) {
4375                      i = nOverlays - 1;
4376                      do {
4377                          this.overlays[i].blur();
4378                      }
4379                      while(i--);
4380                  }
4381              };
4382  
4383              /**
4384               * Updates the state of the OverlayManager and overlay, as a result of the overlay
4385               * being blurred.
4386               * 
4387               * @method _manageBlur
4388               * @param {Overlay} overlay The overlay instance which got blurred.
4389               * @protected
4390               */
4391              this._manageBlur = function (overlay) {
4392                  var changed = false;
4393                  if (activeOverlay == overlay) {
4394                      Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4395                      activeOverlay = null;
4396                      changed = true;
4397                  }
4398                  return changed;
4399              };
4400  
4401              /**
4402               * Updates the state of the OverlayManager and overlay, as a result of the overlay 
4403               * receiving focus.
4404               *
4405               * @method _manageFocus
4406               * @param {Overlay} overlay The overlay instance which got focus.
4407               * @protected
4408               */
4409              this._manageFocus = function(overlay) {
4410                  var changed = false;
4411                  if (activeOverlay != overlay) {
4412                      if (activeOverlay) {
4413                          activeOverlay.blur();
4414                      }
4415                      activeOverlay = overlay;
4416                      this.bringToTop(activeOverlay);
4417                      Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4418                      changed = true;
4419                  }
4420                  return changed;
4421              };
4422  
4423              var overlays = this.cfg.getProperty("overlays");
4424  
4425              if (! this.overlays) {
4426                  this.overlays = [];
4427              }
4428  
4429              if (overlays) {
4430                  this.register(overlays);
4431                  this.overlays.sort(this.compareZIndexDesc);
4432              }
4433          },
4434  
4435          /**
4436          * @method _onOverlayElementFocus
4437          * @description Event handler for the DOM event that is used to focus 
4438          * the Overlay instance as specified by the "focusevent" 
4439          * configuration property.
4440          * @private
4441          * @param {Event} p_oEvent Object representing the DOM event 
4442          * object passed back by the event utility (Event).
4443          */
4444          _onOverlayElementFocus: function (p_oEvent) {
4445  
4446              var oTarget = Event.getTarget(p_oEvent),
4447                  oClose = this.close;
4448  
4449              if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4450                  this.blur();
4451              } else {
4452                  this.focus();
4453              }
4454          },
4455  
4456          /**
4457          * @method _onOverlayDestroy
4458          * @description "destroy" event handler for the Overlay.
4459          * @private
4460          * @param {String} p_sType String representing the name of the event  
4461          * that was fired.
4462          * @param {Array} p_aArgs Array of arguments sent when the event 
4463          * was fired.
4464          * @param {Overlay} p_oOverlay Object representing the overlay that 
4465          * fired the event.
4466          */
4467          _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4468              this.remove(p_oOverlay);
4469          },
4470  
4471          /**
4472          * @method _onOverlayFocusHandler
4473          *
4474          * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4475          *
4476          * @private
4477          * @param {String} p_sType String representing the name of the event  
4478          * that was fired.
4479          * @param {Array} p_aArgs Array of arguments sent when the event 
4480          * was fired.
4481          * @param {Overlay} p_oOverlay Object representing the overlay that 
4482          * fired the event.
4483          */
4484          _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4485              this._manageFocus(p_oOverlay);
4486          },
4487  
4488          /**
4489          * @method _onOverlayBlurHandler
4490          * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4491          *
4492          * @private
4493          * @param {String} p_sType String representing the name of the event  
4494          * that was fired.
4495          * @param {Array} p_aArgs Array of arguments sent when the event 
4496          * was fired.
4497          * @param {Overlay} p_oOverlay Object representing the overlay that 
4498          * fired the event.
4499          */
4500          _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4501              this._manageBlur(p_oOverlay);
4502          },
4503  
4504          /**
4505           * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4506           * monitor focus state.
4507           * 
4508           * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe 
4509           * to the existing focusEvent, however if a focusEvent or focus method does not exist
4510           * on the instance, the _bindFocus method will add them, and the focus method will 
4511           * update the OverlayManager's state directly.
4512           * 
4513           * @method _bindFocus
4514           * @param {Overlay} overlay The overlay for which focus needs to be managed
4515           * @protected
4516           */
4517          _bindFocus : function(overlay) {
4518              var mgr = this;
4519  
4520              if (!overlay.focusEvent) {
4521                  overlay.focusEvent = overlay.createEvent("focus");
4522                  overlay.focusEvent.signature = CustomEvent.LIST;
4523                  overlay.focusEvent._managed = true;
4524              } else {
4525                  overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4526              }
4527  
4528              if (!overlay.focus) {
4529                  Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4530                  overlay.focus = function () {
4531                      if (mgr._manageFocus(this)) {
4532                          // For Panel/Dialog
4533                          if (this.cfg.getProperty("visible") && this.focusFirst) {
4534                              this.focusFirst();
4535                          }
4536                          this.focusEvent.fire();
4537                      }
4538                  };
4539                  overlay.focus._managed = true;
4540              }
4541          },
4542  
4543          /**
4544           * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4545           * monitor blur state.
4546           *
4547           * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe 
4548           * to the existing blurEvent, however if a blurEvent or blur method does not exist
4549           * on the instance, the _bindBlur method will add them, and the blur method 
4550           * update the OverlayManager's state directly.
4551           *
4552           * @method _bindBlur
4553           * @param {Overlay} overlay The overlay for which blur needs to be managed
4554           * @protected
4555           */
4556          _bindBlur : function(overlay) {
4557              var mgr = this;
4558  
4559              if (!overlay.blurEvent) {
4560                  overlay.blurEvent = overlay.createEvent("blur");
4561                  overlay.blurEvent.signature = CustomEvent.LIST;
4562                  overlay.focusEvent._managed = true;
4563              } else {
4564                  overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4565              }
4566  
4567              if (!overlay.blur) {
4568                  overlay.blur = function () {
4569                      if (mgr._manageBlur(this)) {
4570                          this.blurEvent.fire();
4571                      }
4572                  };
4573                  overlay.blur._managed = true;
4574              }
4575  
4576              overlay.hideEvent.subscribe(overlay.blur);
4577          },
4578  
4579          /**
4580           * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4581           * to be removed for the OverlayManager when destroyed.
4582           * 
4583           * @method _bindDestroy
4584           * @param {Overlay} overlay The overlay instance being managed
4585           * @protected
4586           */
4587          _bindDestroy : function(overlay) {
4588              var mgr = this;
4589              overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4590          },
4591  
4592          /**
4593           * Ensures the zIndex configuration property on the managed overlay based instance
4594           * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4595           *
4596           * @method _syncZIndex
4597           * @param {Overlay} overlay The overlay instance being managed
4598           * @protected
4599           */
4600          _syncZIndex : function(overlay) {
4601              var zIndex = Dom.getStyle(overlay.element, "zIndex");
4602              if (!isNaN(zIndex)) {
4603                  overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4604              } else {
4605                  overlay.cfg.setProperty("zIndex", 0);
4606              }
4607          },
4608  
4609          /**
4610          * Registers an Overlay or an array of Overlays with the manager. Upon 
4611          * registration, the Overlay receives functions for focus and blur, 
4612          * along with CustomEvents for each.
4613          *
4614          * @method register
4615          * @param {Overlay} overlay  An Overlay to register with the manager.
4616          * @param {Overlay[]} overlay  An array of Overlays to register with 
4617          * the manager.
4618          * @return {boolean} true if any Overlays are registered.
4619          */
4620          register: function (overlay) {
4621  
4622              var registered = false,
4623                  i,
4624                  n;
4625  
4626              if (overlay instanceof Overlay) {
4627  
4628                  overlay.cfg.addProperty("manager", { value: this } );
4629  
4630                  this._bindFocus(overlay);
4631                  this._bindBlur(overlay);
4632                  this._bindDestroy(overlay);
4633                  this._syncZIndex(overlay);
4634  
4635                  this.overlays.push(overlay);
4636                  this.bringToTop(overlay);
4637  
4638                  registered = true;
4639  
4640              } else if (overlay instanceof Array) {
4641  
4642                  for (i = 0, n = overlay.length; i < n; i++) {
4643                      registered = this.register(overlay[i]) || registered;
4644                  }
4645  
4646              }
4647  
4648              return registered;
4649          },
4650  
4651          /**
4652          * Places the specified Overlay instance on top of all other 
4653          * Overlay instances.
4654          * @method bringToTop
4655          * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an 
4656          * Overlay instance.
4657          * @param {String} p_oOverlay String representing the id of an 
4658          * Overlay instance.
4659          */        
4660          bringToTop: function (p_oOverlay) {
4661  
4662              var oOverlay = this.find(p_oOverlay),
4663                  nTopZIndex,
4664                  oTopOverlay,
4665                  aOverlays;
4666  
4667              if (oOverlay) {
4668  
4669                  aOverlays = this.overlays;
4670                  aOverlays.sort(this.compareZIndexDesc);
4671  
4672                  oTopOverlay = aOverlays[0];
4673  
4674                  if (oTopOverlay) {
4675                      nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4676  
4677                      if (!isNaN(nTopZIndex)) {
4678  
4679                          var bRequiresBump = false;
4680  
4681                          if (oTopOverlay !== oOverlay) {
4682                              bRequiresBump = true;
4683                          } else if (aOverlays.length > 1) {
4684                              var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4685                              // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4686                              if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4687                                  bRequiresBump = true;
4688                              }
4689                          }
4690  
4691                          if (bRequiresBump) {
4692                              oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4693                          }
4694                      }
4695                      aOverlays.sort(this.compareZIndexDesc);
4696                  }
4697              }
4698          },
4699  
4700          /**
4701          * Attempts to locate an Overlay by instance or ID.
4702          * @method find
4703          * @param {Overlay} overlay  An Overlay to locate within the manager
4704          * @param {String} overlay  An Overlay id to locate within the manager
4705          * @return {Overlay} The requested Overlay, if found, or null if it 
4706          * cannot be located.
4707          */
4708          find: function (overlay) {
4709  
4710              var isInstance = overlay instanceof Overlay,
4711                  overlays = this.overlays,
4712                  n = overlays.length,
4713                  found = null,
4714                  o,
4715                  i;
4716  
4717              if (isInstance || typeof overlay == "string") {
4718                  for (i = n-1; i >= 0; i--) {
4719                      o = overlays[i];
4720                      if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4721                          found = o;
4722                          break;
4723                      }
4724                  }
4725              }
4726  
4727              return found;
4728          },
4729  
4730          /**
4731          * Used for sorting the manager's Overlays by z-index.
4732          * @method compareZIndexDesc
4733          * @private
4734          * @return {Number} 0, 1, or -1, depending on where the Overlay should 
4735          * fall in the stacking order.
4736          */
4737          compareZIndexDesc: function (o1, o2) {
4738  
4739              var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4740                  zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4741  
4742              if (zIndex1 === null && zIndex2 === null) {
4743                  return 0;
4744              } else if (zIndex1 === null){
4745                  return 1;
4746              } else if (zIndex2 === null) {
4747                  return -1;
4748              } else if (zIndex1 > zIndex2) {
4749                  return -1;
4750              } else if (zIndex1 < zIndex2) {
4751                  return 1;
4752              } else {
4753                  return 0;
4754              }
4755          },
4756  
4757          /**
4758          * Shows all Overlays in the manager.
4759          * @method showAll
4760          */
4761          showAll: function () {
4762              var overlays = this.overlays,
4763                  n = overlays.length,
4764                  i;
4765  
4766              for (i = n - 1; i >= 0; i--) {
4767                  overlays[i].show();
4768              }
4769          },
4770  
4771          /**
4772          * Hides all Overlays in the manager.
4773          * @method hideAll
4774          */
4775          hideAll: function () {
4776              var overlays = this.overlays,
4777                  n = overlays.length,
4778                  i;
4779  
4780              for (i = n - 1; i >= 0; i--) {
4781                  overlays[i].hide();
4782              }
4783          },
4784  
4785          /**
4786          * Returns a string representation of the object.
4787          * @method toString
4788          * @return {String} The string representation of the OverlayManager
4789          */
4790          toString: function () {
4791              return "OverlayManager";
4792          }
4793      };
4794  }());
4795  (function () {
4796  
4797      /**
4798      * Tooltip is an implementation of Overlay that behaves like an OS tooltip, 
4799      * displaying when the user mouses over a particular element, and 
4800      * disappearing on mouse out.
4801      * @namespace YAHOO.widget
4802      * @class Tooltip
4803      * @extends YAHOO.widget.Overlay
4804      * @constructor
4805      * @param {String} el The element ID representing the Tooltip <em>OR</em>
4806      * @param {HTMLElement} el The element representing the Tooltip
4807      * @param {Object} userConfig The configuration object literal containing 
4808      * the configuration that should be set for this Overlay. See configuration 
4809      * documentation for more details.
4810      */
4811      YAHOO.widget.Tooltip = function (el, userConfig) {
4812          YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4813      };
4814  
4815      var Lang = YAHOO.lang,
4816          Event = YAHOO.util.Event,
4817          CustomEvent = YAHOO.util.CustomEvent,
4818          Dom = YAHOO.util.Dom,
4819          Tooltip = YAHOO.widget.Tooltip,
4820          UA = YAHOO.env.ua,
4821          bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
4822  
4823          m_oShadowTemplate,
4824  
4825          /**
4826          * Constant representing the Tooltip's configuration properties
4827          * @property DEFAULT_CONFIG
4828          * @private
4829          * @final
4830          * @type Object
4831          */
4832          DEFAULT_CONFIG = {
4833  
4834              "PREVENT_OVERLAP": { 
4835                  key: "preventoverlap", 
4836                  value: true, 
4837                  validator: Lang.isBoolean, 
4838                  supercedes: ["x", "y", "xy"] 
4839              },
4840  
4841              "SHOW_DELAY": { 
4842                  key: "showdelay", 
4843                  value: 200, 
4844                  validator: Lang.isNumber 
4845              }, 
4846  
4847              "AUTO_DISMISS_DELAY": { 
4848                  key: "autodismissdelay", 
4849                  value: 5000, 
4850                  validator: Lang.isNumber 
4851              }, 
4852  
4853              "HIDE_DELAY": { 
4854                  key: "hidedelay", 
4855                  value: 250, 
4856                  validator: Lang.isNumber 
4857              }, 
4858  
4859              "TEXT": { 
4860                  key: "text", 
4861                  suppressEvent: true 
4862              }, 
4863  
4864              "CONTAINER": { 
4865                  key: "container"
4866              },
4867  
4868              "DISABLED": {
4869                  key: "disabled",
4870                  value: false,
4871                  suppressEvent: true
4872              },
4873  
4874              "XY_OFFSET": {
4875                  key: "xyoffset",
4876                  value: [0, 25],
4877                  suppressEvent: true
4878              }
4879          },
4880  
4881          /**
4882          * Constant representing the name of the Tooltip's events
4883          * @property EVENT_TYPES
4884          * @private
4885          * @final
4886          * @type Object
4887          */
4888          EVENT_TYPES = {
4889              "CONTEXT_MOUSE_OVER": "contextMouseOver",
4890              "CONTEXT_MOUSE_OUT": "contextMouseOut",
4891              "CONTEXT_TRIGGER": "contextTrigger"
4892          };
4893  
4894      /**
4895      * Constant representing the Tooltip CSS class
4896      * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4897      * @static
4898      * @final
4899      * @type String
4900      */
4901      Tooltip.CSS_TOOLTIP = "yui-tt";
4902  
4903      function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
4904  
4905          var oConfig = this.cfg,
4906              sCurrentWidth = oConfig.getProperty("width");
4907  
4908          if (sCurrentWidth == sForcedWidth) {
4909              oConfig.setProperty("width", sOriginalWidth);
4910          }
4911      }
4912  
4913      /* 
4914          changeContent event handler that sets a Tooltip instance's "width"
4915          configuration property to the value of its root HTML 
4916          elements's offsetWidth if a specific width has not been set.
4917      */
4918  
4919      function setWidthToOffsetWidth(p_sType, p_aArgs) {
4920  
4921          if ("_originalWidth" in this) {
4922              restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
4923          }
4924  
4925          var oBody = document.body,
4926              oConfig = this.cfg,
4927              sOriginalWidth = oConfig.getProperty("width"),
4928              sNewWidth,
4929              oClone;
4930  
4931          if ((!sOriginalWidth || sOriginalWidth == "auto") && 
4932              (oConfig.getProperty("container") != oBody || 
4933              oConfig.getProperty("x") >= Dom.getViewportWidth() || 
4934              oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4935  
4936              oClone = this.element.cloneNode(true);
4937              oClone.style.visibility = "hidden";
4938              oClone.style.top = "0px";
4939              oClone.style.left = "0px";
4940  
4941              oBody.appendChild(oClone);
4942  
4943              sNewWidth = (oClone.offsetWidth + "px");
4944  
4945              oBody.removeChild(oClone);
4946              oClone = null;
4947  
4948              oConfig.setProperty("width", sNewWidth);
4949              oConfig.refireEvent("xy");
4950  
4951              this._originalWidth = sOriginalWidth || "";
4952              this._forcedWidth = sNewWidth;
4953          }
4954      }
4955  
4956      // "onDOMReady" that renders the ToolTip
4957  
4958      function onDOMReady(p_sType, p_aArgs, p_oObject) {
4959          this.render(p_oObject);
4960      }
4961  
4962      //  "init" event handler that automatically renders the Tooltip
4963  
4964      function onInit() {
4965          Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4966      }
4967  
4968      YAHOO.extend(Tooltip, YAHOO.widget.Overlay, { 
4969  
4970          /**
4971          * The Tooltip initialization method. This method is automatically 
4972          * called by the constructor. A Tooltip is automatically rendered by 
4973          * the init method, and it also is set to be invisible by default, 
4974          * and constrained to viewport by default as well.
4975          * @method init
4976          * @param {String} el The element ID representing the Tooltip <em>OR</em>
4977          * @param {HTMLElement} el The element representing the Tooltip
4978          * @param {Object} userConfig The configuration object literal 
4979          * containing the configuration that should be set for this Tooltip. 
4980          * See configuration documentation for more details.
4981          */
4982          init: function (el, userConfig) {
4983  
4984              this.logger = new YAHOO.widget.LogWriter(this.toString());
4985  
4986              Tooltip.superclass.init.call(this, el);
4987  
4988              this.beforeInitEvent.fire(Tooltip);
4989  
4990              Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
4991  
4992              if (userConfig) {
4993                  this.cfg.applyConfig(userConfig, true);
4994              }
4995  
4996              this.cfg.queueProperty("visible", false);
4997              this.cfg.queueProperty("constraintoviewport", true);
4998  
4999              this.setBody("");
5000  
5001              this.subscribe("changeContent", setWidthToOffsetWidth);
5002              this.subscribe("init", onInit);
5003              this.subscribe("render", this.onRender);
5004  
5005              this.initEvent.fire(Tooltip);
5006          },
5007  
5008          /**
5009          * Initializes the custom events for Tooltip
5010          * @method initEvents
5011          */
5012          initEvents: function () {
5013  
5014              Tooltip.superclass.initEvents.call(this);
5015              var SIGNATURE = CustomEvent.LIST;
5016  
5017              /**
5018              * CustomEvent fired when user mouses over a context element. Returning false from
5019              * a subscriber to this event will prevent the tooltip from being displayed for
5020              * the current context element.
5021              * 
5022              * @event contextMouseOverEvent
5023              * @param {HTMLElement} context The context element which the user just moused over
5024              * @param {DOMEvent} e The DOM event object, associated with the mouse over
5025              */
5026              this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
5027              this.contextMouseOverEvent.signature = SIGNATURE;
5028  
5029              /**
5030              * CustomEvent fired when the user mouses out of a context element.
5031              * 
5032              * @event contextMouseOutEvent
5033              * @param {HTMLElement} context The context element which the user just moused out of
5034              * @param {DOMEvent} e The DOM event object, associated with the mouse out
5035              */
5036              this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
5037              this.contextMouseOutEvent.signature = SIGNATURE;
5038  
5039              /**
5040              * CustomEvent fired just before the tooltip is displayed for the current context.
5041              * <p>
5042              *  You can subscribe to this event if you need to set up the text for the 
5043              *  tooltip based on the context element for which it is about to be displayed.
5044              * </p>
5045              * <p>This event differs from the beforeShow event in following respects:</p>
5046              * <ol>
5047              *   <li>
5048              *    When moving from one context element to another, if the tooltip is not
5049              *    hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
5050              *    be fired when the tooltip is displayed for the new context since it is already visible.
5051              *    However the contextTrigger event is always fired before displaying the tooltip for
5052              *    a new context.
5053              *   </li>
5054              *   <li>
5055              *    The trigger event provides access to the context element, allowing you to 
5056              *    set the text of the tooltip based on context element for which the tooltip is
5057              *    triggered.
5058              *   </li>
5059              * </ol>
5060              * <p>
5061              *  It is not possible to prevent the tooltip from being displayed
5062              *  using this event. You can use the contextMouseOverEvent if you need to prevent
5063              *  the tooltip from being displayed.
5064              * </p>
5065              * @event contextTriggerEvent
5066              * @param {HTMLElement} context The context element for which the tooltip is triggered
5067              */
5068              this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
5069              this.contextTriggerEvent.signature = SIGNATURE;
5070          },
5071  
5072          /**
5073          * Initializes the class's configurable properties which can be 
5074          * changed using the Overlay's Config object (cfg).
5075          * @method initDefaultConfig
5076          */
5077          initDefaultConfig: function () {
5078  
5079              Tooltip.superclass.initDefaultConfig.call(this);
5080  
5081              /**
5082              * Specifies whether the Tooltip should be kept from overlapping 
5083              * its context element.
5084              * @config preventoverlap
5085              * @type Boolean
5086              * @default true
5087              */
5088              this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
5089                  value: DEFAULT_CONFIG.PREVENT_OVERLAP.value, 
5090                  validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator, 
5091                  supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
5092              });
5093  
5094              /**
5095              * The number of milliseconds to wait before showing a Tooltip 
5096              * on mouseover.
5097              * @config showdelay
5098              * @type Number
5099              * @default 200
5100              */
5101              this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
5102                  handler: this.configShowDelay,
5103                  value: 200, 
5104                  validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5105              });
5106  
5107              /**
5108              * The number of milliseconds to wait before automatically 
5109              * dismissing a Tooltip after the mouse has been resting on the 
5110              * context element.
5111              * @config autodismissdelay
5112              * @type Number
5113              * @default 5000
5114              */
5115              this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
5116                  handler: this.configAutoDismissDelay,
5117                  value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
5118                  validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
5119              });
5120  
5121              /**
5122              * The number of milliseconds to wait before hiding a Tooltip 
5123              * after mouseout.
5124              * @config hidedelay
5125              * @type Number
5126              * @default 250
5127              */
5128              this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
5129                  handler: this.configHideDelay,
5130                  value: DEFAULT_CONFIG.HIDE_DELAY.value, 
5131                  validator: DEFAULT_CONFIG.HIDE_DELAY.validator
5132              });
5133  
5134              /**
5135              * Specifies the Tooltip's text. The text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source. 
5136              * @config text
5137              * @type HTML
5138              * @default null
5139              */
5140              this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
5141                  handler: this.configText,
5142                  suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
5143              });
5144  
5145              /**
5146              * Specifies the container element that the Tooltip's markup 
5147              * should be rendered into.
5148              * @config container
5149              * @type HTMLElement/String
5150              * @default document.body
5151              */
5152              this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
5153                  handler: this.configContainer,
5154                  value: document.body
5155              });
5156  
5157              /**
5158              * Specifies whether or not the tooltip is disabled. Disabled tooltips
5159              * will not be displayed. If the tooltip is driven by the title attribute
5160              * of the context element, the title attribute will still be removed for 
5161              * disabled tooltips, to prevent default tooltip behavior.
5162              * 
5163              * @config disabled
5164              * @type Boolean
5165              * @default false
5166              */
5167              this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
5168                  handler: this.configContainer,
5169                  value: DEFAULT_CONFIG.DISABLED.value,
5170                  supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5171              });
5172  
5173              /**
5174              * Specifies the XY offset from the mouse position, where the tooltip should be displayed, specified
5175              * as a 2 element array (e.g. [10, 20]); 
5176              *
5177              * @config xyoffset
5178              * @type Array
5179              * @default [0, 25]
5180              */
5181              this.cfg.addProperty(DEFAULT_CONFIG.XY_OFFSET.key, {
5182                  value: DEFAULT_CONFIG.XY_OFFSET.value.concat(),
5183                  supressEvent: DEFAULT_CONFIG.XY_OFFSET.suppressEvent 
5184              });
5185  
5186              /**
5187              * Specifies the element or elements that the Tooltip should be 
5188              * anchored to on mouseover.
5189              * @config context
5190              * @type HTMLElement[]/String[]
5191              * @default null
5192              */ 
5193  
5194              /**
5195              * String representing the width of the Tooltip.  <em>Please note:
5196              * </em> As of version 2.3 if either no value or a value of "auto" 
5197              * is specified, and the Toolip's "container" configuration property
5198              * is set to something other than <code>document.body</code> or 
5199              * its "context" element resides outside the immediately visible 
5200              * portion of the document, the width of the Tooltip will be 
5201              * calculated based on the offsetWidth of its root HTML and set just 
5202              * before it is made visible.  The original value will be 
5203              * restored when the Tooltip is hidden. This ensures the Tooltip is 
5204              * rendered at a usable width.  For more information see 
5205              * YUILibrary bug #1685496 and YUILibrary 
5206              * bug #1735423.
5207              * @config width
5208              * @type String
5209              * @default null
5210              */
5211          
5212          },
5213          
5214          // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5215          
5216          /**
5217          * The default event handler fired when the "text" property is changed.
5218          * @method configText
5219          * @param {String} type The CustomEvent type (usually the property name)
5220          * @param {Object[]} args The CustomEvent arguments. For configuration 
5221          * handlers, args[0] will equal the newly applied value for the property.
5222          * @param {Object} obj The scope object. For configuration handlers, 
5223          * this will usually equal the owner.
5224          */
5225          configText: function (type, args, obj) {
5226              var text = args[0];
5227              if (text) {
5228                  this.setBody(text);
5229              }
5230          },
5231          
5232          /**
5233          * The default event handler fired when the "container" property 
5234          * is changed.
5235          * @method configContainer
5236          * @param {String} type The CustomEvent type (usually the property name)
5237          * @param {Object[]} args The CustomEvent arguments. For 
5238          * configuration handlers, args[0] will equal the newly applied value 
5239          * for the property.
5240          * @param {Object} obj The scope object. For configuration handlers,
5241          * this will usually equal the owner.
5242          */
5243          configContainer: function (type, args, obj) {
5244              var container = args[0];
5245  
5246              if (typeof container == 'string') {
5247                  this.cfg.setProperty("container", document.getElementById(container), true);
5248              }
5249          },
5250          
5251          /**
5252          * @method _removeEventListeners
5253          * @description Removes all of the DOM event handlers from the HTML
5254          *  element(s) that trigger the display of the tooltip.
5255          * @protected
5256          */
5257          _removeEventListeners: function () {
5258          
5259              var aElements = this._context,
5260                  nElements,
5261                  oElement,
5262                  i;
5263  
5264              if (aElements) {
5265                  nElements = aElements.length;
5266                  if (nElements > 0) {
5267                      i = nElements - 1;
5268                      do {
5269                          oElement = aElements[i];
5270                          Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
5271                          Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
5272                          Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
5273                      }
5274                      while (i--);
5275                  }
5276              }
5277          },
5278          
5279          /**
5280          * The default event handler fired when the "context" property 
5281          * is changed.
5282          * @method configContext
5283          * @param {String} type The CustomEvent type (usually the property name)
5284          * @param {Object[]} args The CustomEvent arguments. For configuration 
5285          * handlers, args[0] will equal the newly applied value for the property.
5286          * @param {Object} obj The scope object. For configuration handlers,
5287          * this will usually equal the owner.
5288          */
5289          configContext: function (type, args, obj) {
5290  
5291              var context = args[0],
5292                  aElements,
5293                  nElements,
5294                  oElement,
5295                  i;
5296  
5297              if (context) {
5298  
5299                  // Normalize parameter into an array
5300                  if (! (context instanceof Array)) {
5301                      if (typeof context == "string") {
5302                          this.cfg.setProperty("context", [document.getElementById(context)], true);
5303                      } else { // Assuming this is an element
5304                          this.cfg.setProperty("context", [context], true);
5305                      }
5306                      context = this.cfg.getProperty("context");
5307                  }
5308  
5309                  // Remove any existing mouseover/mouseout listeners
5310                  this._removeEventListeners();
5311  
5312                  // Add mouseover/mouseout listeners to context elements
5313                  this._context = context;
5314  
5315                  aElements = this._context;
5316  
5317                  if (aElements) {
5318                      nElements = aElements.length;
5319                      if (nElements > 0) {
5320                          i = nElements - 1;
5321                          do {
5322                              oElement = aElements[i];
5323                              Event.on(oElement, "mouseover", this.onContextMouseOver, this);
5324                              Event.on(oElement, "mousemove", this.onContextMouseMove, this);
5325                              Event.on(oElement, "mouseout", this.onContextMouseOut, this);
5326                          }
5327                          while (i--);
5328                      }
5329                  }
5330              }
5331          },
5332  
5333          // END BUILT-IN PROPERTY EVENT HANDLERS //
5334  
5335          // BEGIN BUILT-IN DOM EVENT HANDLERS //
5336  
5337          /**
5338          * The default event handler fired when the user moves the mouse while 
5339          * over the context element.
5340          * @method onContextMouseMove
5341          * @param {DOMEvent} e The current DOM event
5342          * @param {Object} obj The object argument
5343          */
5344          onContextMouseMove: function (e, obj) {
5345              obj.pageX = Event.getPageX(e);
5346              obj.pageY = Event.getPageY(e);
5347          },
5348  
5349          /**
5350          * The default event handler fired when the user mouses over the 
5351          * context element.
5352          * @method onContextMouseOver
5353          * @param {DOMEvent} e The current DOM event
5354          * @param {Object} obj The object argument
5355          */
5356          onContextMouseOver: function (e, obj) {
5357              var context = this;
5358  
5359              if (context.title) {
5360                  obj._tempTitle = context.title;
5361                  context.title = "";
5362              }
5363  
5364              // Fire first, to honor disabled set in the listner
5365              if (obj.fireEvent("contextMouseOver", context, e) !== false && !obj.cfg.getProperty("disabled")) {
5366  
5367                  // Stop the tooltip from being hidden (set on last mouseout)
5368                  if (obj.hideProcId) {
5369                      clearTimeout(obj.hideProcId);
5370                      obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
5371                      obj.hideProcId = null;
5372                  }
5373  
5374                  Event.on(context, "mousemove", obj.onContextMouseMove, obj);
5375  
5376                  /**
5377                  * The unique process ID associated with the thread responsible 
5378                  * for showing the Tooltip.
5379                  * @type int
5380                  */
5381                  obj.showProcId = obj.doShow(e, context);
5382                  obj.logger.log("Setting show tooltip timeout: " + obj.showProcId, "time");
5383              }
5384          },
5385  
5386          /**
5387          * The default event handler fired when the user mouses out of 
5388          * the context element.
5389          * @method onContextMouseOut
5390          * @param {DOMEvent} e The current DOM event
5391          * @param {Object} obj The object argument
5392          */
5393          onContextMouseOut: function (e, obj) {
5394              var el = this;
5395  
5396              if (obj._tempTitle) {
5397                  el.title = obj._tempTitle;
5398                  obj._tempTitle = null;
5399              }
5400  
5401              if (obj.showProcId) {
5402                  clearTimeout(obj.showProcId);
5403                  obj.logger.log("Clearing show timer: " + obj.showProcId, "time");
5404                  obj.showProcId = null;
5405              }
5406  
5407              if (obj.hideProcId) {
5408                  clearTimeout(obj.hideProcId);
5409                  obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
5410                  obj.hideProcId = null;
5411              }
5412  
5413              obj.fireEvent("contextMouseOut", el, e);
5414  
5415              obj.hideProcId = setTimeout(function () {
5416                  obj.hide();
5417              }, obj.cfg.getProperty("hidedelay"));
5418          },
5419  
5420          // END BUILT-IN DOM EVENT HANDLERS //
5421  
5422          /**
5423          * Processes the showing of the Tooltip by setting the timeout delay 
5424          * and offset of the Tooltip.
5425          * @method doShow
5426          * @param {DOMEvent} e The current DOM event
5427          * @param {HTMLElement} context The current context element
5428          * @return {Number} The process ID of the timeout function associated 
5429          * with doShow
5430          */
5431          doShow: function (e, context) {
5432  
5433              var offset = this.cfg.getProperty("xyoffset"),
5434                  xOffset = offset[0],
5435                  yOffset = offset[1],
5436                  me = this;
5437  
5438              if (UA.opera && context.tagName && 
5439                  context.tagName.toUpperCase() == "A") {
5440                  yOffset += 12;
5441              }
5442  
5443              return setTimeout(function () {
5444  
5445                  var txt = me.cfg.getProperty("text");
5446  
5447                  // title does not over-ride text
5448                  if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
5449                      me.setBody(me._tempTitle);
5450                  } else {
5451                      me.cfg.refireEvent("text");
5452                  }
5453  
5454                  me.logger.log("Show tooltip", "time");
5455                  me.moveTo(me.pageX + xOffset, me.pageY + yOffset);
5456  
5457                  if (me.cfg.getProperty("preventoverlap")) {
5458                      me.preventOverlap(me.pageX, me.pageY);
5459                  }
5460  
5461                  Event.removeListener(context, "mousemove", me.onContextMouseMove);
5462  
5463                  me.contextTriggerEvent.fire(context);
5464  
5465                  me.show();
5466  
5467                  me.hideProcId = me.doHide();
5468                  me.logger.log("Hide tooltip time active: " + me.hideProcId, "time");
5469  
5470              }, this.cfg.getProperty("showdelay"));
5471          },
5472  
5473          /**
5474          * Sets the timeout for the auto-dismiss delay, which by default is 5 
5475          * seconds, meaning that a tooltip will automatically dismiss itself 
5476          * after 5 seconds of being displayed.
5477          * @method doHide
5478          */
5479          doHide: function () {
5480  
5481              var me = this;
5482  
5483              me.logger.log("Setting hide tooltip timeout", "time");
5484  
5485              return setTimeout(function () {
5486  
5487                  me.logger.log("Hide tooltip", "time");
5488                  me.hide();
5489  
5490              }, this.cfg.getProperty("autodismissdelay"));
5491  
5492          },
5493  
5494          /**
5495          * Fired when the Tooltip is moved, this event handler is used to 
5496          * prevent the Tooltip from overlapping with its context element.
5497          * @method preventOverlay
5498          * @param {Number} pageX The x coordinate position of the mouse pointer
5499          * @param {Number} pageY The y coordinate position of the mouse pointer
5500          */
5501          preventOverlap: function (pageX, pageY) {
5502          
5503              var height = this.element.offsetHeight,
5504                  mousePoint = new YAHOO.util.Point(pageX, pageY),
5505                  elementRegion = Dom.getRegion(this.element);
5506          
5507              elementRegion.top -= 5;
5508              elementRegion.left -= 5;
5509              elementRegion.right += 5;
5510              elementRegion.bottom += 5;
5511          
5512              this.logger.log("context " + elementRegion, "ttip");
5513              this.logger.log("mouse " + mousePoint, "ttip");
5514          
5515              if (elementRegion.contains(mousePoint)) {
5516                  this.logger.log("OVERLAP", "warn");
5517                  this.cfg.setProperty("y", (pageY - height - 5));
5518              }
5519          },
5520  
5521  
5522          /**
5523          * @method onRender
5524          * @description "render" event handler for the Tooltip.
5525          * @param {String} p_sType String representing the name of the event  
5526          * that was fired.
5527          * @param {Array} p_aArgs Array of arguments sent when the event 
5528          * was fired.
5529          */
5530          onRender: function (p_sType, p_aArgs) {
5531      
5532              function sizeShadow() {
5533      
5534                  var oElement = this.element,
5535                      oShadow = this.underlay;
5536              
5537                  if (oShadow) {
5538                      oShadow.style.width = (oElement.offsetWidth + 6) + "px";
5539                      oShadow.style.height = (oElement.offsetHeight + 1) + "px"; 
5540                  }
5541              
5542              }
5543  
5544              function addShadowVisibleClass() {
5545                  Dom.addClass(this.underlay, "yui-tt-shadow-visible");
5546  
5547                  if (UA.ie) {
5548                      this.forceUnderlayRedraw();
5549                  }
5550              }
5551  
5552              function removeShadowVisibleClass() {
5553                  Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
5554              }
5555  
5556              function createShadow() {
5557      
5558                  var oShadow = this.underlay,
5559                      oElement,
5560                      Module,
5561                      nIE,
5562                      me;
5563      
5564                  if (!oShadow) {
5565      
5566                      oElement = this.element;
5567                      Module = YAHOO.widget.Module;
5568                      nIE = UA.ie;
5569                      me = this;
5570  
5571                      if (!m_oShadowTemplate) {
5572                          m_oShadowTemplate = document.createElement("div");
5573                          m_oShadowTemplate.className = "yui-tt-shadow";
5574                      }
5575  
5576                      oShadow = m_oShadowTemplate.cloneNode(false);
5577  
5578                      oElement.appendChild(oShadow);
5579  
5580                      this.underlay = oShadow;
5581  
5582                      // Backward compatibility, even though it's probably 
5583                      // intended to be "private", it isn't marked as such in the api docs
5584                      this._shadow = this.underlay;
5585  
5586                      addShadowVisibleClass.call(this);
5587  
5588                      this.subscribe("beforeShow", addShadowVisibleClass);
5589                      this.subscribe("hide", removeShadowVisibleClass);
5590  
5591                      if (bIEQuirks) {
5592                          window.setTimeout(function () { 
5593                              sizeShadow.call(me); 
5594                          }, 0);
5595      
5596                          this.cfg.subscribeToConfigEvent("width", sizeShadow);
5597                          this.cfg.subscribeToConfigEvent("height", sizeShadow);
5598                          this.subscribe("changeContent", sizeShadow);
5599  
5600                          Module.textResizeEvent.subscribe(sizeShadow, this, true);
5601                          this.subscribe("destroy", function () {
5602                              Module.textResizeEvent.unsubscribe(sizeShadow, this);
5603                          });
5604                      }
5605                  }
5606              }
5607  
5608              function onBeforeShow() {
5609                  createShadow.call(this);
5610                  this.unsubscribe("beforeShow", onBeforeShow);
5611              }
5612  
5613              if (this.cfg.getProperty("visible")) {
5614                  createShadow.call(this);
5615              } else {
5616                  this.subscribe("beforeShow", onBeforeShow);
5617              }
5618          
5619          },
5620  
5621          /**
5622           * Forces the underlay element to be repainted, through the application/removal
5623           * of a yui-force-redraw class to the underlay element.
5624           * 
5625           * @method forceUnderlayRedraw
5626           */
5627          forceUnderlayRedraw : function() {
5628              var tt = this;
5629              Dom.addClass(tt.underlay, "yui-force-redraw");
5630              setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
5631          },
5632  
5633          /**
5634          * Removes the Tooltip element from the DOM and sets all child 
5635          * elements to null.
5636          * @method destroy
5637          */
5638          destroy: function () {
5639          
5640              // Remove any existing mouseover/mouseout listeners
5641              this._removeEventListeners();
5642  
5643              Tooltip.superclass.destroy.call(this);  
5644          
5645          },
5646          
5647          /**
5648          * Returns a string representation of the object.
5649          * @method toString
5650          * @return {String} The string representation of the Tooltip
5651          */
5652          toString: function () {
5653              return "Tooltip " + this.id;
5654          }
5655      
5656      });
5657  
5658  }());
5659  (function () {
5660  
5661      /**
5662      * Panel is an implementation of Overlay that behaves like an OS window, 
5663      * with a draggable header and an optional close icon at the top right.
5664      * @namespace YAHOO.widget
5665      * @class Panel
5666      * @extends YAHOO.widget.Overlay
5667      * @constructor
5668      * @param {String} el The element ID representing the Panel <em>OR</em>
5669      * @param {HTMLElement} el The element representing the Panel
5670      * @param {Object} userConfig The configuration object literal containing 
5671      * the configuration that should be set for this Panel. See configuration 
5672      * documentation for more details.
5673      */
5674      YAHOO.widget.Panel = function (el, userConfig) {
5675          YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5676      };
5677  
5678      var _currentModal = null;
5679  
5680      var Lang = YAHOO.lang,
5681          Util = YAHOO.util,
5682          Dom = Util.Dom,
5683          Event = Util.Event,
5684          CustomEvent = Util.CustomEvent,
5685          KeyListener = YAHOO.util.KeyListener,
5686          Config = Util.Config,
5687          Overlay = YAHOO.widget.Overlay,
5688          Panel = YAHOO.widget.Panel,
5689          UA = YAHOO.env.ua,
5690  
5691          bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
5692  
5693          m_oMaskTemplate,
5694          m_oUnderlayTemplate,
5695          m_oCloseIconTemplate,
5696  
5697          /**
5698          * Constant representing the name of the Panel's events
5699          * @property EVENT_TYPES
5700          * @private
5701          * @final
5702          * @type Object
5703          */
5704          EVENT_TYPES = {
5705              "BEFORE_SHOW_MASK" : "beforeShowMask",
5706              "BEFORE_HIDE_MASK" : "beforeHideMask",
5707              "SHOW_MASK": "showMask",
5708              "HIDE_MASK": "hideMask",
5709              "DRAG": "drag"
5710          },
5711  
5712          /**
5713          * Constant representing the Panel's configuration properties
5714          * @property DEFAULT_CONFIG
5715          * @private
5716          * @final
5717          * @type Object
5718          */
5719          DEFAULT_CONFIG = {
5720  
5721              "CLOSE": { 
5722                  key: "close", 
5723                  value: true, 
5724                  validator: Lang.isBoolean, 
5725                  supercedes: ["visible"] 
5726              },
5727  
5728              "DRAGGABLE": {
5729                  key: "draggable", 
5730                  value: (Util.DD ? true : false), 
5731                  validator: Lang.isBoolean, 
5732                  supercedes: ["visible"]  
5733              },
5734  
5735              "DRAG_ONLY" : {
5736                  key: "dragonly",
5737                  value: false,
5738                  validator: Lang.isBoolean,
5739                  supercedes: ["draggable"]
5740              },
5741  
5742              "UNDERLAY": { 
5743                  key: "underlay", 
5744                  value: "shadow", 
5745                  supercedes: ["visible"] 
5746              },
5747  
5748              "MODAL": { 
5749                  key: "modal", 
5750                  value: false, 
5751                  validator: Lang.isBoolean, 
5752                  supercedes: ["visible", "zindex"]
5753              },
5754  
5755              "KEY_LISTENERS": {
5756                  key: "keylisteners",
5757                  suppressEvent: true,
5758                  supercedes: ["visible"]
5759              },
5760  
5761              "STRINGS" : {
5762                  key: "strings",
5763                  supercedes: ["close"],
5764                  validator: Lang.isObject,
5765                  value: {
5766                      close: "Close"
5767                  }
5768              }
5769          };
5770  
5771      /**
5772      * Constant representing the default CSS class used for a Panel
5773      * @property YAHOO.widget.Panel.CSS_PANEL
5774      * @static
5775      * @final
5776      * @type String
5777      */
5778      Panel.CSS_PANEL = "yui-panel";
5779      
5780      /**
5781      * Constant representing the default CSS class used for a Panel's 
5782      * wrapping container
5783      * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5784      * @static
5785      * @final
5786      * @type String
5787      */
5788      Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5789  
5790      /**
5791       * Constant representing the default set of focusable elements 
5792       * on the pagewhich Modal Panels will prevent access to, when
5793       * the modal mask is displayed
5794       * 
5795       * @property YAHOO.widget.Panel.FOCUSABLE
5796       * @static
5797       * @type Array
5798       */
5799      Panel.FOCUSABLE = [
5800          "a",
5801          "button",
5802          "select",
5803          "textarea",
5804          "input",
5805          "iframe"
5806      ];
5807  
5808      // Private CustomEvent listeners
5809  
5810      /* 
5811          "beforeRender" event handler that creates an empty header for a Panel 
5812          instance if its "draggable" configuration property is set to "true" 
5813          and no header has been created.
5814      */
5815  
5816      function createHeader(p_sType, p_aArgs) {
5817          if (!this.header && this.cfg.getProperty("draggable")) {
5818              this.setHeader("&#160;");
5819          }
5820      }
5821  
5822      /* 
5823          "hide" event handler that sets a Panel instance's "width"
5824          configuration property back to its original value before 
5825          "setWidthToOffsetWidth" was called.
5826      */
5827  
5828      function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5829  
5830          var sOriginalWidth = p_oObject[0],
5831              sNewWidth = p_oObject[1],
5832              oConfig = this.cfg,
5833              sCurrentWidth = oConfig.getProperty("width");
5834  
5835          if (sCurrentWidth == sNewWidth) {
5836              oConfig.setProperty("width", sOriginalWidth);
5837          }
5838  
5839          this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5840      }
5841  
5842      /* 
5843          "beforeShow" event handler that sets a Panel instance's "width"
5844          configuration property to the value of its root HTML 
5845          elements's offsetWidth
5846      */
5847  
5848      function setWidthToOffsetWidth(p_sType, p_aArgs) {
5849  
5850          var oConfig,
5851              sOriginalWidth,
5852              sNewWidth;
5853  
5854          if (bIEQuirks) {
5855  
5856              oConfig = this.cfg;
5857              sOriginalWidth = oConfig.getProperty("width");
5858              
5859              if (!sOriginalWidth || sOriginalWidth == "auto") {
5860      
5861                  sNewWidth = (this.element.offsetWidth + "px");
5862      
5863                  oConfig.setProperty("width", sNewWidth);
5864  
5865                  this.subscribe("hide", restoreOriginalWidth, 
5866                      [(sOriginalWidth || ""), sNewWidth]);
5867              
5868              }
5869          }
5870      }
5871  
5872      YAHOO.extend(Panel, Overlay, {
5873  
5874          /**
5875          * The Overlay initialization method, which is executed for Overlay and 
5876          * all of its subclasses. This method is automatically called by the 
5877          * constructor, and  sets up all DOM references for pre-existing markup, 
5878          * and creates required markup if it is not already present.
5879          * @method init
5880          * @param {String} el The element ID representing the Overlay <em>OR</em>
5881          * @param {HTMLElement} el The element representing the Overlay
5882          * @param {Object} userConfig The configuration object literal 
5883          * containing the configuration that should be set for this Overlay. 
5884          * See configuration documentation for more details.
5885          */
5886          init: function (el, userConfig) {
5887              /*
5888                   Note that we don't pass the user config in here yet because 
5889                   we only want it executed once, at the lowest subclass level
5890              */
5891  
5892              Panel.superclass.init.call(this, el/*, userConfig*/);
5893  
5894              this.beforeInitEvent.fire(Panel);
5895  
5896              Dom.addClass(this.element, Panel.CSS_PANEL);
5897  
5898              this.buildWrapper();
5899  
5900              if (userConfig) {
5901                  this.cfg.applyConfig(userConfig, true);
5902              }
5903  
5904              this.subscribe("showMask", this._addFocusHandlers);
5905              this.subscribe("hideMask", this._removeFocusHandlers);
5906              this.subscribe("beforeRender", createHeader);
5907  
5908              this.subscribe("render", function() {
5909                  this.setFirstLastFocusable();
5910                  this.subscribe("changeContent", this.setFirstLastFocusable);
5911              });
5912  
5913              this.subscribe("show", this._focusOnShow);
5914  
5915              this.initEvent.fire(Panel);
5916          },
5917  
5918          /**
5919           * @method _onElementFocus
5920           * @private
5921           *
5922           * "focus" event handler for a focuable element. Used to automatically
5923           * blur the element when it receives focus to ensure that a Panel
5924           * instance's modality is not compromised.
5925           *
5926           * @param {Event} e The DOM event object
5927           */
5928          _onElementFocus : function(e){
5929  
5930              if(_currentModal === this) {
5931  
5932                  var target = Event.getTarget(e),
5933                      doc = document.documentElement,
5934                      insideDoc = (target !== doc && target !== window);
5935  
5936                  // mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on 
5937                  // the documentElement, when the document scrollbars are clicked on
5938                  if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
5939                      try {
5940                          this._focusFirstModal();
5941                      } catch(err){
5942                          // Just in case we fail to focus
5943                          try {
5944                              if (insideDoc && target !== document.body) {
5945                                  target.blur();
5946                              }
5947                          } catch(err2) { }
5948                      }
5949                  }
5950              }
5951          },
5952  
5953          /**
5954           * Focuses on the first element if present, otherwise falls back to the focus mechanisms used for 
5955           * modality. This method does not try/catch focus failures. The caller is responsible for catching exceptions,
5956           * and taking remedial measures.
5957           * 
5958           * @method _focusFirstModal
5959           */
5960          _focusFirstModal : function() {
5961              var el = this.firstElement;
5962              if (el) {
5963                  el.focus();
5964              } else {
5965                  if (this._modalFocus) {
5966                      this._modalFocus.focus();
5967                  } else {
5968                      this.innerElement.focus();
5969                  }
5970              }
5971          },
5972  
5973          /** 
5974           *  @method _addFocusHandlers
5975           *  @protected
5976           *  
5977           *  "showMask" event handler that adds a "focus" event handler to all
5978           *  focusable elements in the document to enforce a Panel instance's 
5979           *  modality from being compromised.
5980           *
5981           *  @param p_sType {String} Custom event type
5982           *  @param p_aArgs {Array} Custom event arguments
5983           */
5984          _addFocusHandlers: function(p_sType, p_aArgs) {
5985              if (!this.firstElement) {
5986                  if (UA.webkit || UA.opera) {
5987                      if (!this._modalFocus) {
5988                          this._createHiddenFocusElement();
5989                      }
5990                  } else {
5991                      this.innerElement.tabIndex = 0;
5992                  }
5993              }
5994              this._setTabLoop(this.firstElement, this.lastElement);
5995              Event.onFocus(document.documentElement, this._onElementFocus, this, true);
5996              _currentModal = this;
5997          },
5998  
5999          /**
6000           * Creates a hidden focusable element, used to focus on,
6001           * to enforce modality for browsers in which focus cannot
6002           * be applied to the container box.
6003           * 
6004           * @method _createHiddenFocusElement
6005           * @private
6006           */
6007          _createHiddenFocusElement : function() {
6008              var e = document.createElement("button");
6009              e.style.height = "1px";
6010              e.style.width = "1px";
6011              e.style.position = "absolute";
6012              e.style.left = "-10000em";
6013              e.style.opacity = 0;
6014              e.tabIndex = -1;
6015              this.innerElement.appendChild(e);
6016              this._modalFocus = e;
6017          },
6018  
6019          /**
6020           *  @method _removeFocusHandlers
6021           *  @protected
6022           *
6023           *  "hideMask" event handler that removes all "focus" event handlers added 
6024           *  by the "addFocusEventHandlers" method.
6025           *
6026           *  @param p_sType {String} Event type
6027           *  @param p_aArgs {Array} Event Arguments
6028           */
6029          _removeFocusHandlers: function(p_sType, p_aArgs) {
6030              Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
6031  
6032              if (_currentModal == this) {
6033                  _currentModal = null;
6034              }
6035          },
6036  
6037          /**
6038           * Focus handler for the show event
6039           *
6040           * @method _focusOnShow
6041           * @param {String} type Event Type
6042           * @param {Array} args Event arguments
6043           * @param {Object} obj Additional data 
6044           */
6045          _focusOnShow : function(type, args, obj) {
6046  
6047              if (args && args[1]) {
6048                  Event.stopEvent(args[1]);
6049              }
6050  
6051              if (!this.focusFirst(type, args, obj)) {
6052                  if (this.cfg.getProperty("modal")) {
6053                      this._focusFirstModal();
6054                  }
6055              }
6056          },
6057  
6058          /**
6059           * Sets focus to the first element in the Panel.
6060           *
6061           * @method focusFirst
6062           * @return {Boolean} true, if successfully focused, false otherwise 
6063           */
6064          focusFirst: function (type, args, obj) {
6065              var el = this.firstElement, focused = false;
6066  
6067              if (args && args[1]) {
6068                  Event.stopEvent(args[1]);
6069              }
6070  
6071              if (el) {
6072                  try {
6073                      el.focus();
6074                      focused = true;
6075                  } catch(err) {
6076                      // Ignore
6077                  }
6078              }
6079  
6080              return focused;
6081          },
6082  
6083          /**
6084           * Sets focus to the last element in the Panel.
6085           *
6086           * @method focusLast
6087           * @return {Boolean} true, if successfully focused, false otherwise
6088           */
6089          focusLast: function (type, args, obj) {
6090              var el = this.lastElement, focused = false;
6091  
6092              if (args && args[1]) {
6093                  Event.stopEvent(args[1]);
6094              }
6095  
6096              if (el) {
6097                  try {
6098                      el.focus();
6099                      focused = true;
6100                  } catch(err) {
6101                      // Ignore
6102                  }
6103              }
6104  
6105              return focused;
6106          },
6107  
6108          /**
6109           * Protected internal method for setTabLoop, which can be used by 
6110           * subclasses to jump in and modify the arguments passed in if required.
6111           *
6112           * @method _setTabLoop
6113           * @param {HTMLElement} firstElement
6114           * @param {HTMLElement} lastElement
6115           * @protected
6116           *
6117           */
6118          _setTabLoop : function(firstElement, lastElement) {
6119              this.setTabLoop(firstElement, lastElement);
6120          },
6121  
6122          /**
6123           * Sets up a tab, shift-tab loop between the first and last elements
6124           * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
6125           * instance properties, which are reset everytime this method is invoked.
6126           *
6127           * @method setTabLoop
6128           * @param {HTMLElement} firstElement
6129           * @param {HTMLElement} lastElement
6130           *
6131           */
6132          setTabLoop : function(firstElement, lastElement) {
6133  
6134              var backTab = this.preventBackTab, tab = this.preventTabOut,
6135                  showEvent = this.showEvent, hideEvent = this.hideEvent;
6136  
6137              if (backTab) {
6138                  backTab.disable();
6139                  showEvent.unsubscribe(backTab.enable, backTab);
6140                  hideEvent.unsubscribe(backTab.disable, backTab);
6141                  backTab = this.preventBackTab = null;
6142              }
6143  
6144              if (tab) {
6145                  tab.disable();
6146                  showEvent.unsubscribe(tab.enable, tab);
6147                  hideEvent.unsubscribe(tab.disable,tab);
6148                  tab = this.preventTabOut = null;
6149              }
6150  
6151              if (firstElement) {
6152                  this.preventBackTab = new KeyListener(firstElement, 
6153                      {shift:true, keys:9},
6154                      {fn:this.focusLast, scope:this, correctScope:true}
6155                  );
6156                  backTab = this.preventBackTab;
6157  
6158                  showEvent.subscribe(backTab.enable, backTab, true);
6159                  hideEvent.subscribe(backTab.disable,backTab, true);
6160              }
6161  
6162              if (lastElement) {
6163                  this.preventTabOut = new KeyListener(lastElement, 
6164                      {shift:false, keys:9}, 
6165                      {fn:this.focusFirst, scope:this, correctScope:true}
6166                  );
6167                  tab = this.preventTabOut;
6168  
6169                  showEvent.subscribe(tab.enable, tab, true);
6170                  hideEvent.subscribe(tab.disable,tab, true);
6171              }
6172          },
6173  
6174          /**
6175           * Returns an array of the currently focusable items which reside within
6176           * Panel. The set of focusable elements the method looks for are defined
6177           * in the Panel.FOCUSABLE static property
6178           *
6179           * @method getFocusableElements
6180           * @param {HTMLElement} root element to start from.
6181           */
6182          getFocusableElements : function(root) {
6183  
6184              root = root || this.innerElement;
6185  
6186              var focusable = {}, panel = this;
6187              for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
6188                  focusable[Panel.FOCUSABLE[i]] = true;
6189              }
6190  
6191              // Not looking by Tag, since we want elements in DOM order
6192              
6193              return Dom.getElementsBy(function(el) { return panel._testIfFocusable(el, focusable); }, null, root);
6194          },
6195  
6196          /**
6197           * This is the test method used by getFocusableElements, to determine which elements to 
6198           * include in the focusable elements list. Users may override this to customize behavior.
6199           *
6200           * @method _testIfFocusable
6201           * @param {Object} el The element being tested
6202           * @param {Object} focusable The hash of known focusable elements, created by an array-to-map operation on Panel.FOCUSABLE
6203           * @protected
6204           */
6205          _testIfFocusable: function(el, focusable) {
6206              if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
6207                  return true;
6208              }
6209              return false;
6210          },
6211  
6212          /**
6213           * Sets the firstElement and lastElement instance properties
6214           * to the first and last focusable elements in the Panel.
6215           *
6216           * @method setFirstLastFocusable
6217           */
6218          setFirstLastFocusable : function() {
6219  
6220              this.firstElement = null;
6221              this.lastElement = null;
6222  
6223              var elements = this.getFocusableElements();
6224              this.focusableElements = elements;
6225  
6226              if (elements.length > 0) {
6227                  this.firstElement = elements[0];
6228                  this.lastElement = elements[elements.length - 1];
6229              }
6230  
6231              if (this.cfg.getProperty("modal")) {
6232                  this._setTabLoop(this.firstElement, this.lastElement);
6233              }
6234          },
6235  
6236          /**
6237           * Initializes the custom events for Module which are fired 
6238           * automatically at appropriate times by the Module class.
6239           */
6240          initEvents: function () {
6241              Panel.superclass.initEvents.call(this);
6242  
6243              var SIGNATURE = CustomEvent.LIST;
6244  
6245              /**
6246              * CustomEvent fired after the modality mask is shown
6247              * @event showMaskEvent
6248              */
6249              this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
6250              this.showMaskEvent.signature = SIGNATURE;
6251  
6252              /**
6253              * CustomEvent fired before the modality mask is shown. Subscribers can return false to prevent the
6254              * mask from being shown
6255              * @event beforeShowMaskEvent
6256              */
6257              this.beforeShowMaskEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW_MASK);
6258              this.beforeShowMaskEvent.signature = SIGNATURE;
6259  
6260              /**
6261              * CustomEvent fired after the modality mask is hidden
6262              * @event hideMaskEvent
6263              */
6264              this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
6265              this.hideMaskEvent.signature = SIGNATURE;
6266  
6267              /**
6268              * CustomEvent fired before the modality mask is hidden. Subscribers can return false to prevent the
6269              * mask from being hidden
6270              * @event beforeHideMaskEvent
6271              */
6272              this.beforeHideMaskEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE_MASK);
6273              this.beforeHideMaskEvent.signature = SIGNATURE;
6274  
6275              /**
6276              * CustomEvent when the Panel is dragged
6277              * @event dragEvent
6278              */
6279              this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
6280              this.dragEvent.signature = SIGNATURE;
6281          },
6282  
6283          /**
6284           * Initializes the class's configurable properties which can be changed 
6285           * using the Panel's Config object (cfg).
6286           * @method initDefaultConfig
6287           */
6288          initDefaultConfig: function () {
6289              Panel.superclass.initDefaultConfig.call(this);
6290  
6291              // Add panel config properties //
6292  
6293              /**
6294              * True if the Panel should display a "close" button
6295              * @config close
6296              * @type Boolean
6297              * @default true
6298              */
6299              this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, { 
6300                  handler: this.configClose, 
6301                  value: DEFAULT_CONFIG.CLOSE.value, 
6302                  validator: DEFAULT_CONFIG.CLOSE.validator, 
6303                  supercedes: DEFAULT_CONFIG.CLOSE.supercedes 
6304              });
6305  
6306              /**
6307              * Boolean specifying if the Panel should be draggable.  The default 
6308              * value is "true" if the Drag and Drop utility is included, 
6309              * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a 
6310              * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7 
6311              * (Quirks Mode) where Panels that either don't have a value set for 
6312              * their "width" configuration property, or their "width" 
6313              * configuration property is set to "auto" will only be draggable by
6314              * placing the mouse on the text of the Panel's header element.
6315              * To fix this bug, draggable Panels missing a value for their 
6316              * "width" configuration property, or whose "width" configuration 
6317              * property is set to "auto" will have it set to the value of 
6318              * their root HTML element's offsetWidth before they are made 
6319              * visible.  The calculated width is then removed when the Panel is   
6320              * hidden. <em>This fix is only applied to draggable Panels in IE 6 
6321              * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For 
6322              * more information on this issue see:
6323              * YUILibrary bugs #1726972 and #1589210.
6324              * @config draggable
6325              * @type Boolean
6326              * @default true
6327              */
6328              this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
6329                  handler: this.configDraggable,
6330                  value: (Util.DD) ? true : false,
6331                  validator: DEFAULT_CONFIG.DRAGGABLE.validator,
6332                  supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
6333              });
6334  
6335              /**
6336              * Boolean specifying if the draggable Panel should be drag only, not interacting with drop 
6337              * targets on the page.
6338              * <p>
6339              * When set to true, draggable Panels will not check to see if they are over drop targets,
6340              * or fire the DragDrop events required to support drop target interaction (onDragEnter, 
6341              * onDragOver, onDragOut, onDragDrop etc.).
6342              * If the Panel is not designed to be dropped on any target elements on the page, then this 
6343              * flag can be set to true to improve performance.
6344              * </p>
6345              * <p>
6346              * When set to false, all drop target related events will be fired.
6347              * </p>
6348              * <p>
6349              * The property is set to false by default to maintain backwards compatibility but should be 
6350              * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
6351              * 
6352              * @config dragOnly
6353              * @type Boolean
6354              * @default false
6355              */
6356              this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, { 
6357                  value: DEFAULT_CONFIG.DRAG_ONLY.value, 
6358                  validator: DEFAULT_CONFIG.DRAG_ONLY.validator, 
6359                  supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes 
6360              });
6361  
6362              /**
6363              * Sets the type of underlay to display for the Panel. Valid values 
6364              * are "shadow," "matte," and "none".  <strong>PLEASE NOTE:</strong> 
6365              * The creation of the underlay element is deferred until the Panel 
6366              * is initially made visible.  For Gecko-based browsers on Mac
6367              * OS X the underlay elment is always created as it is used as a 
6368              * shim to prevent Aqua scrollbars below a Panel instance from poking 
6369              * through it (See YUILibrary bug #1723530).
6370              * @config underlay
6371              * @type String
6372              * @default shadow
6373              */
6374              this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, { 
6375                  handler: this.configUnderlay, 
6376                  value: DEFAULT_CONFIG.UNDERLAY.value, 
6377                  supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes 
6378              });
6379          
6380              /**
6381              * True if the Panel should be displayed in a modal fashion, 
6382              * automatically creating a transparent mask over the document that
6383              * will not be removed until the Panel is dismissed.
6384              * @config modal
6385              * @type Boolean
6386              * @default false
6387              */
6388              this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, { 
6389                  handler: this.configModal, 
6390                  value: DEFAULT_CONFIG.MODAL.value,
6391                  validator: DEFAULT_CONFIG.MODAL.validator, 
6392                  supercedes: DEFAULT_CONFIG.MODAL.supercedes 
6393              });
6394  
6395              /**
6396              * A KeyListener (or array of KeyListeners) that will be enabled 
6397              * when the Panel is shown, and disabled when the Panel is hidden.
6398              * @config keylisteners
6399              * @type YAHOO.util.KeyListener[]
6400              * @default null
6401              */
6402              this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, { 
6403                  handler: this.configKeyListeners, 
6404                  suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent, 
6405                  supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes 
6406              });
6407  
6408              /**
6409              * UI Strings used by the Panel. The strings are inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
6410              * 
6411              * @config strings
6412              * @type Object
6413              * @default An object literal with the properties shown below:
6414              *     <dl>
6415              *         <dt>close</dt><dd><em>HTML</em> : The markup to use as the label for the close icon. Defaults to "Close".</dd>
6416              *     </dl>
6417              */
6418              this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, { 
6419                  value:DEFAULT_CONFIG.STRINGS.value,
6420                  handler:this.configStrings,
6421                  validator:DEFAULT_CONFIG.STRINGS.validator,
6422                  supercedes:DEFAULT_CONFIG.STRINGS.supercedes
6423              });
6424          },
6425  
6426          // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6427          
6428          /**
6429          * The default event handler fired when the "close" property is changed.
6430          * The method controls the appending or hiding of the close icon at the 
6431          * top right of the Panel.
6432          * @method configClose
6433          * @param {String} type The CustomEvent type (usually the property name)
6434          * @param {Object[]} args The CustomEvent arguments. For configuration 
6435          * handlers, args[0] will equal the newly applied value for the property.
6436          * @param {Object} obj The scope object. For configuration handlers, 
6437          * this will usually equal the owner.
6438          */
6439          configClose: function (type, args, obj) {
6440  
6441              var val = args[0],
6442                  oClose = this.close,
6443                  strings = this.cfg.getProperty("strings"),
6444                  fc;
6445  
6446              if (val) {
6447                  if (!oClose) {
6448  
6449                      if (!m_oCloseIconTemplate) {
6450                          m_oCloseIconTemplate = document.createElement("a");
6451                          m_oCloseIconTemplate.className = "container-close";
6452                          m_oCloseIconTemplate.href = "#";
6453                      }
6454  
6455                      oClose = m_oCloseIconTemplate.cloneNode(true);
6456  
6457                      fc = this.innerElement.firstChild;
6458  
6459                      if (fc) {
6460                          this.innerElement.insertBefore(oClose, fc);
6461                      } else {
6462                          this.innerElement.appendChild(oClose);
6463                      }
6464  
6465                      oClose.innerHTML = (strings && strings.close) ? strings.close : "&#160;";
6466  
6467                      Event.on(oClose, "click", this._doClose, this, true);
6468  
6469                      this.close = oClose;
6470  
6471                  } else {
6472                      oClose.style.display = "block";
6473                  }
6474  
6475              } else {
6476                  if (oClose) {
6477                      oClose.style.display = "none";
6478                  }
6479              }
6480  
6481          },
6482  
6483          /**
6484           * Event handler for the close icon
6485           * 
6486           * @method _doClose
6487           * @protected
6488           * 
6489           * @param {DOMEvent} e
6490           */
6491          _doClose : function (e) {
6492              Event.preventDefault(e);
6493              this.hide();
6494          },
6495  
6496          /**
6497          * The default event handler fired when the "draggable" property 
6498          * is changed.
6499          * @method configDraggable
6500          * @param {String} type The CustomEvent type (usually the property name)
6501          * @param {Object[]} args The CustomEvent arguments. For configuration 
6502          * handlers, args[0] will equal the newly applied value for the property.
6503          * @param {Object} obj The scope object. For configuration handlers, 
6504          * this will usually equal the owner.
6505          */
6506          configDraggable: function (type, args, obj) {
6507              var val = args[0];
6508  
6509              if (val) {
6510                  if (!Util.DD) {
6511                      YAHOO.log("DD dependency not met.", "error");
6512                      this.cfg.setProperty("draggable", false);
6513                      return;
6514                  }
6515  
6516                  if (this.header) {
6517                      Dom.setStyle(this.header, "cursor", "move");
6518                      this.registerDragDrop();
6519                  }
6520  
6521                  this.subscribe("beforeShow", setWidthToOffsetWidth);
6522  
6523              } else {
6524  
6525                  if (this.dd) {
6526                      this.dd.unreg();
6527                  }
6528  
6529                  if (this.header) {
6530                      Dom.setStyle(this.header,"cursor","auto");
6531                  }
6532  
6533                  this.unsubscribe("beforeShow", setWidthToOffsetWidth);
6534              }
6535          },
6536        
6537          /**
6538          * The default event handler fired when the "underlay" property 
6539          * is changed.
6540          * @method configUnderlay
6541          * @param {String} type The CustomEvent type (usually the property name)
6542          * @param {Object[]} args The CustomEvent arguments. For configuration 
6543          * handlers, args[0] will equal the newly applied value for the property.
6544          * @param {Object} obj The scope object. For configuration handlers, 
6545          * this will usually equal the owner.
6546          */
6547          configUnderlay: function (type, args, obj) {
6548  
6549              var bMacGecko = (this.platform == "mac" && UA.gecko),
6550                  sUnderlay = args[0].toLowerCase(),
6551                  oUnderlay = this.underlay,
6552                  oElement = this.element;
6553  
6554              function createUnderlay() {
6555                  var bNew = false;
6556                  if (!oUnderlay) { // create if not already in DOM
6557  
6558                      if (!m_oUnderlayTemplate) {
6559                          m_oUnderlayTemplate = document.createElement("div");
6560                          m_oUnderlayTemplate.className = "underlay";
6561                      }
6562  
6563                      oUnderlay = m_oUnderlayTemplate.cloneNode(false);
6564                      this.element.appendChild(oUnderlay);
6565  
6566                      this.underlay = oUnderlay;
6567  
6568                      if (bIEQuirks) {
6569                          this.sizeUnderlay();
6570                          this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
6571                          this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
6572  
6573                          this.changeContentEvent.subscribe(this.sizeUnderlay);
6574                          YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
6575                      }
6576  
6577                      if (UA.webkit && UA.webkit < 420) {
6578                          this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
6579                      }
6580  
6581                      bNew = true;
6582                  }
6583              }
6584  
6585              function onBeforeShow() {
6586                  var bNew = createUnderlay.call(this);
6587                  if (!bNew && bIEQuirks) {
6588                      this.sizeUnderlay();
6589                  }
6590                  this._underlayDeferred = false;
6591                  this.beforeShowEvent.unsubscribe(onBeforeShow);
6592              }
6593  
6594              function destroyUnderlay() {
6595                  if (this._underlayDeferred) {
6596                      this.beforeShowEvent.unsubscribe(onBeforeShow);
6597                      this._underlayDeferred = false;
6598                  }
6599  
6600                  if (oUnderlay) {
6601                      this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
6602                      this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
6603                      this.changeContentEvent.unsubscribe(this.sizeUnderlay);
6604                      this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
6605                      YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
6606  
6607                      this.element.removeChild(oUnderlay);
6608  
6609                      this.underlay = null;
6610                  }
6611              }
6612  
6613              switch (sUnderlay) {
6614                  case "shadow":
6615                      Dom.removeClass(oElement, "matte");
6616                      Dom.addClass(oElement, "shadow");
6617                      break;
6618                  case "matte":
6619                      if (!bMacGecko) {
6620                          destroyUnderlay.call(this);
6621                      }
6622                      Dom.removeClass(oElement, "shadow");
6623                      Dom.addClass(oElement, "matte");
6624                      break;
6625                  default:
6626                      if (!bMacGecko) {
6627                          destroyUnderlay.call(this);
6628                      }
6629                      Dom.removeClass(oElement, "shadow");
6630                      Dom.removeClass(oElement, "matte");
6631                      break;
6632              }
6633  
6634              if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
6635                  if (this.cfg.getProperty("visible")) {
6636                      var bNew = createUnderlay.call(this);
6637                      if (!bNew && bIEQuirks) {
6638                          this.sizeUnderlay();
6639                      }
6640                  } else {
6641                      if (!this._underlayDeferred) {
6642                          this.beforeShowEvent.subscribe(onBeforeShow);
6643                          this._underlayDeferred = true;
6644                      }
6645                  }
6646              }
6647          },
6648          
6649          /**
6650          * The default event handler fired when the "modal" property is 
6651          * changed. This handler subscribes or unsubscribes to the show and hide
6652          * events to handle the display or hide of the modality mask.
6653          * @method configModal
6654          * @param {String} type The CustomEvent type (usually the property name)
6655          * @param {Object[]} args The CustomEvent arguments. For configuration 
6656          * handlers, args[0] will equal the newly applied value for the property.
6657          * @param {Object} obj The scope object. For configuration handlers, 
6658          * this will usually equal the owner.
6659          */
6660          configModal: function (type, args, obj) {
6661  
6662              var modal = args[0];
6663              if (modal) {
6664                  if (!this._hasModalityEventListeners) {
6665  
6666                      this.subscribe("beforeShow", this.buildMask);
6667                      this.subscribe("beforeShow", this.bringToTop);
6668                      this.subscribe("beforeShow", this.showMask);
6669                      this.subscribe("hide", this.hideMask);
6670  
6671                      Overlay.windowResizeEvent.subscribe(this.sizeMask, 
6672                          this, true);
6673  
6674                      this._hasModalityEventListeners = true;
6675                  }
6676              } else {
6677                  if (this._hasModalityEventListeners) {
6678  
6679                      if (this.cfg.getProperty("visible")) {
6680                          this.hideMask();
6681                          this.removeMask();
6682                      }
6683  
6684                      this.unsubscribe("beforeShow", this.buildMask);
6685                      this.unsubscribe("beforeShow", this.bringToTop);
6686                      this.unsubscribe("beforeShow", this.showMask);
6687                      this.unsubscribe("hide", this.hideMask);
6688  
6689                      Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6690  
6691                      this._hasModalityEventListeners = false;
6692                  }
6693              }
6694          },
6695  
6696          /**
6697          * Removes the modality mask.
6698          * @method removeMask
6699          */
6700          removeMask: function () {
6701  
6702              var oMask = this.mask,
6703                  oParentNode;
6704  
6705              if (oMask) {
6706                  /*
6707                      Hide the mask before destroying it to ensure that DOM
6708                      event handlers on focusable elements get removed.
6709                  */
6710                  this.hideMask();
6711  
6712                  oParentNode = oMask.parentNode;
6713                  if (oParentNode) {
6714                      oParentNode.removeChild(oMask);
6715                  }
6716  
6717                  this.mask = null;
6718              }
6719          },
6720          
6721          /**
6722          * The default event handler fired when the "keylisteners" property 
6723          * is changed.
6724          * @method configKeyListeners
6725          * @param {String} type The CustomEvent type (usually the property name)
6726          * @param {Object[]} args The CustomEvent arguments. For configuration
6727          * handlers, args[0] will equal the newly applied value for the property.
6728          * @param {Object} obj The scope object. For configuration handlers, 
6729          * this will usually equal the owner.
6730          */
6731          configKeyListeners: function (type, args, obj) {
6732  
6733              var listeners = args[0],
6734                  listener,
6735                  nListeners,
6736                  i;
6737          
6738              if (listeners) {
6739  
6740                  if (listeners instanceof Array) {
6741  
6742                      nListeners = listeners.length;
6743  
6744                      for (i = 0; i < nListeners; i++) {
6745  
6746                          listener = listeners[i];
6747          
6748                          if (!Config.alreadySubscribed(this.showEvent, 
6749                              listener.enable, listener)) {
6750  
6751                              this.showEvent.subscribe(listener.enable, 
6752                                  listener, true);
6753  
6754                          }
6755  
6756                          if (!Config.alreadySubscribed(this.hideEvent, 
6757                              listener.disable, listener)) {
6758  
6759                              this.hideEvent.subscribe(listener.disable, 
6760                                  listener, true);
6761  
6762                              this.destroyEvent.subscribe(listener.disable, 
6763                                  listener, true);
6764                          }
6765                      }
6766  
6767                  } else {
6768  
6769                      if (!Config.alreadySubscribed(this.showEvent, 
6770                          listeners.enable, listeners)) {
6771  
6772                          this.showEvent.subscribe(listeners.enable, 
6773                              listeners, true);
6774                      }
6775  
6776                      if (!Config.alreadySubscribed(this.hideEvent, 
6777                          listeners.disable, listeners)) {
6778  
6779                          this.hideEvent.subscribe(listeners.disable, 
6780                              listeners, true);
6781  
6782                          this.destroyEvent.subscribe(listeners.disable, 
6783                              listeners, true);
6784  
6785                      }
6786  
6787                  }
6788  
6789              }
6790  
6791          },
6792  
6793          /**
6794          * The default handler for the "strings" property
6795          * @method configStrings
6796          */
6797          configStrings : function(type, args, obj) {
6798              var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
6799              this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
6800          },
6801  
6802          /**
6803          * The default event handler fired when the "height" property is changed.
6804          * @method configHeight
6805          * @param {String} type The CustomEvent type (usually the property name)
6806          * @param {Object[]} args The CustomEvent arguments. For configuration 
6807          * handlers, args[0] will equal the newly applied value for the property.
6808          * @param {Object} obj The scope object. For configuration handlers, 
6809          * this will usually equal the owner.
6810          */
6811          configHeight: function (type, args, obj) {
6812              var height = args[0],
6813                  el = this.innerElement;
6814  
6815              Dom.setStyle(el, "height", height);
6816              this.cfg.refireEvent("iframe");
6817          },
6818  
6819          /**
6820           * The default custom event handler executed when the Panel's height is changed, 
6821           * if the autofillheight property has been set.
6822           *
6823           * @method _autoFillOnHeightChange
6824           * @protected
6825           * @param {String} type The event type
6826           * @param {Array} args The array of arguments passed to event subscribers
6827           * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
6828           * out the containers height
6829           */
6830          _autoFillOnHeightChange : function(type, args, el) {
6831              Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
6832              if (bIEQuirks) {
6833                  var panel = this;
6834                  setTimeout(function() {
6835                      panel.sizeUnderlay();
6836                  },0);
6837              }
6838          },
6839  
6840          /**
6841          * The default event handler fired when the "width" property is changed.
6842          * @method configWidth
6843          * @param {String} type The CustomEvent type (usually the property name)
6844          * @param {Object[]} args The CustomEvent arguments. For configuration 
6845          * handlers, args[0] will equal the newly applied value for the property.
6846          * @param {Object} obj The scope object. For configuration handlers, 
6847          * this will usually equal the owner.
6848          */
6849          configWidth: function (type, args, obj) {
6850      
6851              var width = args[0],
6852                  el = this.innerElement;
6853      
6854              Dom.setStyle(el, "width", width);
6855              this.cfg.refireEvent("iframe");
6856      
6857          },
6858          
6859          /**
6860          * The default event handler fired when the "zIndex" property is changed.
6861          * @method configzIndex
6862          * @param {String} type The CustomEvent type (usually the property name)
6863          * @param {Object[]} args The CustomEvent arguments. For configuration 
6864          * handlers, args[0] will equal the newly applied value for the property.
6865          * @param {Object} obj The scope object. For configuration handlers, 
6866          * this will usually equal the owner.
6867          */
6868          configzIndex: function (type, args, obj) {
6869              Panel.superclass.configzIndex.call(this, type, args, obj);
6870  
6871              if (this.mask || this.cfg.getProperty("modal") === true) {
6872                  var panelZ = Dom.getStyle(this.element, "zIndex");
6873                  if (!panelZ || isNaN(panelZ)) {
6874                      panelZ = 0;
6875                  }
6876  
6877                  if (panelZ === 0) {
6878                      // Recursive call to configzindex (which should be stopped
6879                      // from going further because panelZ should no longer === 0)
6880                      this.cfg.setProperty("zIndex", 1);
6881                  } else {
6882                      this.stackMask();
6883                  }
6884              }
6885          },
6886  
6887          // END BUILT-IN PROPERTY EVENT HANDLERS //
6888          /**
6889          * Builds the wrapping container around the Panel that is used for 
6890          * positioning the shadow and matte underlays. The container element is 
6891          * assigned to a  local instance variable called container, and the 
6892          * element is reinserted inside of it.
6893          * @method buildWrapper
6894          */
6895          buildWrapper: function () {
6896  
6897              var elementParent = this.element.parentNode,
6898                  originalElement = this.element,
6899                  wrapper = document.createElement("div");
6900  
6901              wrapper.className = Panel.CSS_PANEL_CONTAINER;
6902              wrapper.id = originalElement.id + "_c";
6903  
6904              if (elementParent) {
6905                  elementParent.insertBefore(wrapper, originalElement);
6906              }
6907  
6908              wrapper.appendChild(originalElement);
6909  
6910              this.element = wrapper;
6911              this.innerElement = originalElement;
6912  
6913              Dom.setStyle(this.innerElement, "visibility", "inherit");
6914          },
6915  
6916          /**
6917          * Adjusts the size of the shadow based on the size of the element.
6918          * @method sizeUnderlay
6919          */
6920          sizeUnderlay: function () {
6921              var oUnderlay = this.underlay,
6922                  oElement;
6923  
6924              if (oUnderlay) {
6925                  oElement = this.element;
6926                  oUnderlay.style.width = oElement.offsetWidth + "px";
6927                  oUnderlay.style.height = oElement.offsetHeight + "px";
6928              }
6929          },
6930  
6931          /**
6932          * Registers the Panel's header for drag & drop capability.
6933          * @method registerDragDrop
6934          */
6935          registerDragDrop: function () {
6936  
6937              var me = this;
6938  
6939              if (this.header) {
6940  
6941                  if (!Util.DD) {
6942                      YAHOO.log("DD dependency not met.", "error");
6943                      return;
6944                  }
6945  
6946                  var bDragOnly = (this.cfg.getProperty("dragonly") === true);
6947  
6948                  /**
6949                   * The YAHOO.util.DD instance, used to implement the draggable header for the panel if draggable is enabled
6950                   *
6951                   * @property dd
6952                   * @type YAHOO.util.DD
6953                   */
6954                  this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
6955  
6956                  if (!this.header.id) {
6957                      this.header.id = this.id + "_h";
6958                  }
6959  
6960                  this.dd.startDrag = function () {
6961  
6962                      var offsetHeight,
6963                          offsetWidth,
6964                          viewPortWidth,
6965                          viewPortHeight,
6966                          scrollX,
6967                          scrollY;
6968  
6969                      if (YAHOO.env.ua.ie == 6) {
6970                          Dom.addClass(me.element,"drag");
6971                      }
6972  
6973                      if (me.cfg.getProperty("constraintoviewport")) {
6974  
6975                          var nViewportOffset = Overlay.VIEWPORT_OFFSET;
6976  
6977                          offsetHeight = me.element.offsetHeight;
6978                          offsetWidth = me.element.offsetWidth;
6979  
6980                          viewPortWidth = Dom.getViewportWidth();
6981                          viewPortHeight = Dom.getViewportHeight();
6982  
6983                          scrollX = Dom.getDocumentScrollLeft();
6984                          scrollY = Dom.getDocumentScrollTop();
6985  
6986                          if (offsetHeight + nViewportOffset < viewPortHeight) {
6987                              this.minY = scrollY + nViewportOffset;
6988                              this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
6989                          } else {
6990                              this.minY = scrollY + nViewportOffset;
6991                              this.maxY = scrollY + nViewportOffset;
6992                          }
6993  
6994                          if (offsetWidth + nViewportOffset < viewPortWidth) {
6995                              this.minX = scrollX + nViewportOffset;
6996                              this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
6997                          } else {
6998                              this.minX = scrollX + nViewportOffset;
6999                              this.maxX = scrollX + nViewportOffset;
7000                          }
7001  
7002                          this.constrainX = true;
7003                          this.constrainY = true;
7004                      } else {
7005                          this.constrainX = false;
7006                          this.constrainY = false;
7007                      }
7008  
7009                      me.dragEvent.fire("startDrag", arguments);
7010                  };
7011  
7012                  this.dd.onDrag = function () {
7013                      me.syncPosition();
7014                      me.cfg.refireEvent("iframe");
7015                      if (this.platform == "mac" && YAHOO.env.ua.gecko) {
7016                          this.showMacGeckoScrollbars();
7017                      }
7018  
7019                      me.dragEvent.fire("onDrag", arguments);
7020                  };
7021  
7022                  this.dd.endDrag = function () {
7023  
7024                      if (YAHOO.env.ua.ie == 6) {
7025                          Dom.removeClass(me.element,"drag");
7026                      }
7027  
7028                      me.dragEvent.fire("endDrag", arguments);
7029                      me.moveEvent.fire(me.cfg.getProperty("xy"));
7030  
7031                  };
7032  
7033                  this.dd.setHandleElId(this.header.id);
7034                  this.dd.addInvalidHandleType("INPUT");
7035                  this.dd.addInvalidHandleType("SELECT");
7036                  this.dd.addInvalidHandleType("TEXTAREA");
7037              }
7038          },
7039          
7040          /**
7041          * Builds the mask that is laid over the document when the Panel is 
7042          * configured to be modal.
7043          * @method buildMask
7044          */
7045          buildMask: function () {
7046              var oMask = this.mask;
7047              if (!oMask) {
7048                  if (!m_oMaskTemplate) {
7049                      m_oMaskTemplate = document.createElement("div");
7050                      m_oMaskTemplate.className = "mask";
7051                      m_oMaskTemplate.innerHTML = "&#160;";
7052                  }
7053                  oMask = m_oMaskTemplate.cloneNode(true);
7054                  oMask.id = this.id + "_mask";
7055  
7056                  document.body.insertBefore(oMask, document.body.firstChild);
7057  
7058                  this.mask = oMask;
7059  
7060                  if (YAHOO.env.ua.gecko && this.platform == "mac") {
7061                      Dom.addClass(this.mask, "block-scrollbars");
7062                  }
7063  
7064                  // Stack mask based on the element zindex
7065                  this.stackMask();
7066              }
7067          },
7068  
7069          /**
7070          * Hides the modality mask.
7071          * @method hideMask
7072          */
7073          hideMask: function () {
7074              if (this.cfg.getProperty("modal") && this.mask && this.beforeHideMaskEvent.fire()) {
7075                  this.mask.style.display = "none";
7076                  Dom.removeClass(document.body, "masked");
7077                  this.hideMaskEvent.fire();
7078              }
7079          },
7080  
7081          /**
7082          * Shows the modality mask.
7083          * @method showMask
7084          */
7085          showMask: function () {
7086              if (this.cfg.getProperty("modal") && this.mask && this.beforeShowMaskEvent.fire()) {
7087                  Dom.addClass(document.body, "masked");
7088                  this.sizeMask();
7089                  this.mask.style.display = "block";
7090                  this.showMaskEvent.fire();
7091              }
7092          },
7093  
7094          /**
7095          * Sets the size of the modality mask to cover the entire scrollable 
7096          * area of the document
7097          * @method sizeMask
7098          */
7099          sizeMask: function () {
7100              if (this.mask) {
7101  
7102                  // Shrink mask first, so it doesn't affect the document size.
7103                  var mask = this.mask,
7104                      viewWidth = Dom.getViewportWidth(),
7105                      viewHeight = Dom.getViewportHeight();
7106  
7107                  if (mask.offsetHeight > viewHeight) {
7108                      mask.style.height = viewHeight + "px";
7109                  }
7110  
7111                  if (mask.offsetWidth > viewWidth) {
7112                      mask.style.width = viewWidth + "px";
7113                  }
7114  
7115                  // Then size it to the document
7116                  mask.style.height = Dom.getDocumentHeight() + "px";
7117                  mask.style.width = Dom.getDocumentWidth() + "px";
7118              }
7119          },
7120  
7121          /**
7122           * Sets the zindex of the mask, if it exists, based on the zindex of 
7123           * the Panel element. The zindex of the mask is set to be one less 
7124           * than the Panel element's zindex.
7125           * 
7126           * <p>NOTE: This method will not bump up the zindex of the Panel
7127           * to ensure that the mask has a non-negative zindex. If you require the
7128           * mask zindex to be 0 or higher, the zindex of the Panel 
7129           * should be set to a value higher than 0, before this method is called.
7130           * </p>
7131           * @method stackMask
7132           */
7133          stackMask: function() {
7134              if (this.mask) {
7135                  var panelZ = Dom.getStyle(this.element, "zIndex");
7136                  if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
7137                      Dom.setStyle(this.mask, "zIndex", panelZ - 1);
7138                  }
7139              }
7140          },
7141  
7142          /**
7143          * Renders the Panel by inserting the elements that are not already in 
7144          * the main Panel into their correct places. Optionally appends the 
7145          * Panel to the specified node prior to the render's execution. NOTE: 
7146          * For Panels without existing markup, the appendToNode argument is 
7147          * REQUIRED. If this argument is ommitted and the current element is 
7148          * not present in the document, the function will return false, 
7149          * indicating that the render was a failure.
7150          * @method render
7151          * @param {String} appendToNode The element id to which the Module 
7152          * should be appended to prior to rendering <em>OR</em>
7153          * @param {HTMLElement} appendToNode The element to which the Module 
7154          * should be appended to prior to rendering
7155          * @return {boolean} Success or failure of the render
7156          */
7157          render: function (appendToNode) {
7158              return Panel.superclass.render.call(this, appendToNode, this.innerElement);
7159          },
7160  
7161          /**
7162           * Renders the currently set header into it's proper position under the 
7163           * module element. If the module element is not provided, "this.innerElement" 
7164           * is used.
7165           *
7166           * @method _renderHeader
7167           * @protected
7168           * @param {HTMLElement} moduleElement Optional. A reference to the module element
7169           */
7170          _renderHeader: function(moduleElement){
7171              moduleElement = moduleElement || this.innerElement;
7172              Panel.superclass._renderHeader.call(this, moduleElement);
7173          },
7174  
7175          /**
7176           * Renders the currently set body into it's proper position under the 
7177           * module element. If the module element is not provided, "this.innerElement" 
7178           * is used.
7179           * 
7180           * @method _renderBody
7181           * @protected
7182           * @param {HTMLElement} moduleElement Optional. A reference to the module element.
7183           */
7184          _renderBody: function(moduleElement){
7185              moduleElement = moduleElement || this.innerElement;
7186              Panel.superclass._renderBody.call(this, moduleElement);
7187          },
7188  
7189          /**
7190           * Renders the currently set footer into it's proper position under the 
7191           * module element. If the module element is not provided, "this.innerElement" 
7192           * is used.
7193           *
7194           * @method _renderFooter
7195           * @protected
7196           * @param {HTMLElement} moduleElement Optional. A reference to the module element
7197           */
7198          _renderFooter: function(moduleElement){
7199              moduleElement = moduleElement || this.innerElement;
7200              Panel.superclass._renderFooter.call(this, moduleElement);
7201          },
7202  
7203          /**
7204          * Removes the Panel element from the DOM and sets all child elements
7205          * to null.
7206          * @method destroy
7207          * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners. 
7208          * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
7209          */
7210          destroy: function (shallowPurge) {
7211              Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
7212              this.removeMask();
7213              if (this.close) {
7214                  Event.purgeElement(this.close);
7215              }
7216              Panel.superclass.destroy.call(this, shallowPurge);  
7217          },
7218  
7219          /**
7220           * Forces the underlay element to be repainted through the application/removal 
7221           * of a yui-force-redraw class to the underlay element.
7222           *
7223           * @method forceUnderlayRedraw
7224           */
7225          forceUnderlayRedraw : function () {
7226              var u = this.underlay;
7227              Dom.addClass(u, "yui-force-redraw");
7228              setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
7229          },
7230  
7231          /**
7232          * Returns a String representation of the object.
7233          * @method toString
7234          * @return {String} The string representation of the Panel.
7235          */
7236          toString: function () {
7237              return "Panel " + this.id;
7238          }
7239      
7240      });
7241  
7242  }());
7243  (function () {
7244  
7245      /**
7246      * <p>
7247      * Dialog is an implementation of Panel that can be used to submit form 
7248      * data.
7249      * </p>
7250      * <p>
7251      * Built-in functionality for buttons with event handlers is included. 
7252      * If the optional YUI Button dependancy is included on the page, the buttons
7253      * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
7254      * will be created.
7255      * </p>
7256      * <p>
7257      * Forms can be processed in 3 ways -- via an asynchronous Connection utility call, 
7258      * a simple form POST or GET, or manually. The YUI Connection utility should be
7259      * included if you're using the default "async" postmethod, but is not required if
7260      * you're using any of the other postmethod values.
7261      * </p>
7262      * @namespace YAHOO.widget
7263      * @class Dialog
7264      * @extends YAHOO.widget.Panel
7265      * @constructor
7266      * @param {String} el The element ID representing the Dialog <em>OR</em>
7267      * @param {HTMLElement} el The element representing the Dialog
7268      * @param {Object} userConfig The configuration object literal containing 
7269      * the configuration that should be set for this Dialog. See configuration 
7270      * documentation for more details.
7271      */
7272      YAHOO.widget.Dialog = function (el, userConfig) {
7273          YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
7274      };
7275  
7276      var Event = YAHOO.util.Event,
7277          CustomEvent = YAHOO.util.CustomEvent,
7278          Dom = YAHOO.util.Dom,
7279          Dialog = YAHOO.widget.Dialog,
7280          Lang = YAHOO.lang,
7281  
7282          /**
7283           * Constant representing the name of the Dialog's events
7284           * @property EVENT_TYPES
7285           * @private
7286           * @final
7287           * @type Object
7288           */
7289          EVENT_TYPES = {
7290              "BEFORE_SUBMIT": "beforeSubmit",
7291              "SUBMIT": "submit",
7292              "MANUAL_SUBMIT": "manualSubmit",
7293              "ASYNC_SUBMIT": "asyncSubmit",
7294              "FORM_SUBMIT": "formSubmit",
7295              "CANCEL": "cancel"
7296          },
7297  
7298          /**
7299          * Constant representing the Dialog's configuration properties
7300          * @property DEFAULT_CONFIG
7301          * @private
7302          * @final
7303          * @type Object
7304          */
7305          DEFAULT_CONFIG = {
7306  
7307              "POST_METHOD": { 
7308                  key: "postmethod", 
7309                  value: "async"
7310              },
7311  
7312              "POST_DATA" : {
7313                  key: "postdata",
7314                  value: null
7315              },
7316  
7317              "BUTTONS": {
7318                  key: "buttons",
7319                  value: "none",
7320                  supercedes: ["visible"]
7321              },
7322  
7323              "HIDEAFTERSUBMIT" : {
7324                  key: "hideaftersubmit",
7325                  value: true
7326              }
7327  
7328          };
7329  
7330      /**
7331      * Constant representing the default CSS class used for a Dialog
7332      * @property YAHOO.widget.Dialog.CSS_DIALOG
7333      * @static
7334      * @final
7335      * @type String
7336      */
7337      Dialog.CSS_DIALOG = "yui-dialog";
7338  
7339      function removeButtonEventHandlers() {
7340  
7341          var aButtons = this._aButtons,
7342              nButtons,
7343              oButton,
7344              i;
7345  
7346          if (Lang.isArray(aButtons)) {
7347              nButtons = aButtons.length;
7348  
7349              if (nButtons > 0) {
7350                  i = nButtons - 1;
7351                  do {
7352                      oButton = aButtons[i];
7353  
7354                      if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
7355                          oButton.destroy();
7356                      }
7357                      else if (oButton.tagName.toUpperCase() == "BUTTON") {
7358                          Event.purgeElement(oButton);
7359                          Event.purgeElement(oButton, false);
7360                      }
7361                  }
7362                  while (i--);
7363              }
7364          }
7365      }
7366  
7367      YAHOO.extend(Dialog, YAHOO.widget.Panel, { 
7368  
7369          /**
7370          * @property form
7371          * @description Object reference to the Dialog's 
7372          * <code>&#60;form&#62;</code> element.
7373          * @default null 
7374          * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7375          * level-one-html.html#ID-40002357">HTMLFormElement</a>
7376          */
7377          form: null,
7378      
7379          /**
7380          * Initializes the class's configurable properties which can be changed 
7381          * using the Dialog's Config object (cfg).
7382          * @method initDefaultConfig
7383          */
7384          initDefaultConfig: function () {
7385              Dialog.superclass.initDefaultConfig.call(this);
7386  
7387              /**
7388              * The internally maintained callback object for use with the 
7389              * Connection utility. The format of the callback object is 
7390              * similar to Connection Manager's callback object and is 
7391              * simply passed through to Connection Manager when the async 
7392              * request is made.
7393              * @property callback
7394              * @type Object
7395              */
7396              this.callback = {
7397  
7398                  /**
7399                  * The function to execute upon success of the 
7400                  * Connection submission (when the form does not
7401                  * contain a file input element).
7402                  * 
7403                  * @property callback.success
7404                  * @type Function
7405                  */
7406                  success: null,
7407  
7408                  /**
7409                  * The function to execute upon failure of the 
7410                  * Connection submission
7411                  * @property callback.failure
7412                  * @type Function
7413                  */
7414                  failure: null,
7415  
7416                  /**
7417                  *<p>
7418                  * The function to execute upon success of the 
7419                  * Connection submission, when the form contains
7420                  * a file input element.
7421                  * </p>
7422                  * <p>
7423                  * <em>NOTE:</em> Connection manager will not
7424                  * invoke the success or failure handlers for the file
7425                  * upload use case. This will be the only callback
7426                  * handler invoked.
7427                  * </p>
7428                  * <p>
7429                  * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
7430                  * Connection Manager documenation on file uploads</a>.
7431                  * </p>
7432                  * @property callback.upload
7433                  * @type Function
7434                  */
7435  
7436                  /**
7437                  * The arbitrary argument or arguments to pass to the Connection 
7438                  * callback functions
7439                  * @property callback.argument
7440                  * @type Object
7441                  */
7442                  argument: null
7443  
7444              };
7445  
7446              // Add form dialog config properties //
7447              /**
7448              * The method to use for posting the Dialog's form. Possible values 
7449              * are "async", "form", and "manual".
7450              * @config postmethod
7451              * @type String
7452              * @default async
7453              */
7454              this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
7455                  handler: this.configPostMethod, 
7456                  value: DEFAULT_CONFIG.POST_METHOD.value, 
7457                  validator: function (val) {
7458                      if (val != "form" && val != "async" && val != "none" && 
7459                          val != "manual") {
7460                          return false;
7461                      } else {
7462                          return true;
7463                      }
7464                  }
7465              });
7466  
7467              /**
7468              * Any additional post data which needs to be sent when using the 
7469              * <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
7470              * The format for the post data string is defined by Connection Manager's 
7471              * <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a> 
7472              * method.
7473              * @config postdata
7474              * @type String
7475              * @default null
7476              */
7477              this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
7478                  value: DEFAULT_CONFIG.POST_DATA.value
7479              });
7480  
7481              /**
7482              * This property is used to configure whether or not the 
7483              * dialog should be automatically hidden after submit.
7484              * 
7485              * @config hideaftersubmit
7486              * @type Boolean
7487              * @default true
7488              */
7489              this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
7490                  value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
7491              });
7492  
7493              /**
7494              * Array of object literals, each containing a set of properties 
7495              * defining a button to be appended into the Dialog's footer.
7496              *
7497              * <p>Each button object in the buttons array can have three properties:</p>
7498              * <dl>
7499              *    <dt>text:</dt>
7500              *    <dd>
7501              *       The text that will display on the face of the button. The text can 
7502              *       include HTML, as long as it is compliant with HTML Button specifications. The text is added to the DOM as HTML,
7503              *       and should be escaped by the implementor if coming from an external source. 
7504              *    </dd>
7505              *    <dt>handler:</dt>
7506              *    <dd>Can be either:
7507              *    <ol>
7508              *       <li>A reference to a function that should fire when the 
7509              *       button is clicked.  (In this case scope of this function is 
7510              *       always its Dialog instance.)</li>
7511              *
7512              *       <li>An object literal representing the code to be 
7513              *       executed when the button is clicked.
7514              *       
7515              *       <p>Format:</p>
7516              *
7517              *       <p>
7518              *       <code>{
7519              *       <br>
7520              *       <strong>fn:</strong> Function, &#47;&#47;
7521              *       The handler to call when  the event fires.
7522              *       <br>
7523              *       <strong>obj:</strong> Object, &#47;&#47; 
7524              *       An  object to pass back to the handler.
7525              *       <br>
7526              *       <strong>scope:</strong> Object &#47;&#47; 
7527              *       The object to use for the scope of the handler.
7528              *       <br>
7529              *       }</code>
7530              *       </p>
7531              *       </li>
7532              *     </ol>
7533              *     </dd>
7534              *     <dt>isDefault:</dt>
7535              *     <dd>
7536              *        An optional boolean value that specifies that a button 
7537              *        should be highlighted and focused by default.
7538              *     </dd>
7539              * </dl>
7540              *
7541              * <em>NOTE:</em>If the YUI Button Widget is included on the page, 
7542              * the buttons created will be instances of YAHOO.widget.Button. 
7543              * Otherwise, HTML Buttons (<code>&#60;BUTTON&#62;</code>) will be 
7544              * created.
7545              *
7546              * @config buttons
7547              * @type {Array|String}
7548              * @default "none"
7549              */
7550              this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
7551                  handler: this.configButtons,
7552                  value: DEFAULT_CONFIG.BUTTONS.value,
7553                  supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
7554              }); 
7555  
7556          },
7557  
7558          /**
7559          * Initializes the custom events for Dialog which are fired 
7560          * automatically at appropriate times by the Dialog class.
7561          * @method initEvents
7562          */
7563          initEvents: function () {
7564              Dialog.superclass.initEvents.call(this);
7565  
7566              var SIGNATURE = CustomEvent.LIST;
7567  
7568              /**
7569              * CustomEvent fired prior to submission
7570              * @event beforeSubmitEvent
7571              */ 
7572              this.beforeSubmitEvent = 
7573                  this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
7574              this.beforeSubmitEvent.signature = SIGNATURE;
7575              
7576              /**
7577              * CustomEvent fired after submission
7578              * @event submitEvent
7579              */
7580              this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
7581              this.submitEvent.signature = SIGNATURE;
7582          
7583              /**
7584              * CustomEvent fired for manual submission, before the generic submit event is fired
7585              * @event manualSubmitEvent
7586              */
7587              this.manualSubmitEvent = 
7588                  this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
7589              this.manualSubmitEvent.signature = SIGNATURE;
7590  
7591              /**
7592              * CustomEvent fired after asynchronous submission, before the generic submit event is fired
7593              *
7594              * @event asyncSubmitEvent
7595              * @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
7596              */
7597              this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
7598              this.asyncSubmitEvent.signature = SIGNATURE;
7599  
7600              /**
7601              * CustomEvent fired after form-based submission, before the generic submit event is fired
7602              * @event formSubmitEvent
7603              */
7604              this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
7605              this.formSubmitEvent.signature = SIGNATURE;
7606  
7607              /**
7608              * CustomEvent fired after cancel
7609              * @event cancelEvent
7610              */
7611              this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
7612              this.cancelEvent.signature = SIGNATURE;
7613          
7614          },
7615          
7616          /**
7617          * The Dialog initialization method, which is executed for Dialog and 
7618          * all of its subclasses. This method is automatically called by the 
7619          * constructor, and  sets up all DOM references for pre-existing markup, 
7620          * and creates required markup if it is not already present.
7621          * 
7622          * @method init
7623          * @param {String} el The element ID representing the Dialog <em>OR</em>
7624          * @param {HTMLElement} el The element representing the Dialog
7625          * @param {Object} userConfig The configuration object literal 
7626          * containing the configuration that should be set for this Dialog. 
7627          * See configuration documentation for more details.
7628          */
7629          init: function (el, userConfig) {
7630  
7631              /*
7632                   Note that we don't pass the user config in here yet because 
7633                   we only want it executed once, at the lowest subclass level
7634              */
7635  
7636              Dialog.superclass.init.call(this, el/*, userConfig*/); 
7637  
7638              this.beforeInitEvent.fire(Dialog);
7639  
7640              Dom.addClass(this.element, Dialog.CSS_DIALOG);
7641  
7642              this.cfg.setProperty("visible", false);
7643  
7644              if (userConfig) {
7645                  this.cfg.applyConfig(userConfig, true);
7646              }
7647  
7648              //this.showEvent.subscribe(this.focusFirst, this, true);
7649              this.beforeHideEvent.subscribe(this.blurButtons, this, true);
7650  
7651              this.subscribe("changeBody", this.registerForm);
7652  
7653              this.initEvent.fire(Dialog);
7654          },
7655  
7656          /**
7657          * Submits the Dialog's form depending on the value of the 
7658          * "postmethod" configuration property.  <strong>Please note:
7659          * </strong> As of version 2.3 this method will automatically handle 
7660          * asyncronous file uploads should the Dialog instance's form contain 
7661          * <code>&#60;input type="file"&#62;</code> elements.  If a Dialog 
7662          * instance will be handling asyncronous file uploads, its 
7663          * <code>callback</code> property will need to be setup with a 
7664          * <code>upload</code> handler rather than the standard 
7665          * <code>success</code> and, or <code>failure</code> handlers.  For more 
7666          * information, see the <a href="http://developer.yahoo.com/yui/
7667          * connection/#file">Connection Manager documenation on file uploads</a>.
7668          * @method doSubmit
7669          */
7670          doSubmit: function () {
7671  
7672              var Connect = YAHOO.util.Connect,
7673                  oForm = this.form,
7674                  bUseFileUpload = false,
7675                  bUseSecureFileUpload = false,
7676                  aElements,
7677                  nElements,
7678                  i,
7679                  formAttrs;
7680  
7681              switch (this.cfg.getProperty("postmethod")) {
7682  
7683                  case "async":
7684                      aElements = oForm.elements;
7685                      nElements = aElements.length;
7686  
7687                      if (nElements > 0) {
7688                          i = nElements - 1;
7689                          do {
7690                              if (aElements[i].type == "file") {
7691                                  bUseFileUpload = true;
7692                                  break;
7693                              }
7694                          }
7695                          while(i--);
7696                      }
7697  
7698                      if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
7699                          bUseSecureFileUpload = true;
7700                      }
7701  
7702                      formAttrs = this._getFormAttributes(oForm);
7703  
7704                      Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
7705  
7706                      var postData = this.cfg.getProperty("postdata");
7707                      var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
7708  
7709                      this.asyncSubmitEvent.fire(c);
7710  
7711                      break;
7712  
7713                  case "form":
7714                      oForm.submit();
7715                      this.formSubmitEvent.fire();
7716                      break;
7717  
7718                  case "none":
7719                  case "manual":
7720                      this.manualSubmitEvent.fire();
7721                      break;
7722              }
7723          },
7724  
7725          /**
7726           * Retrieves important attributes (currently method and action) from
7727           * the form element, accounting for any elements which may have the same name 
7728           * as the attributes. Defaults to "POST" and "" for method and action respectively
7729           * if the attribute cannot be retrieved.
7730           *
7731           * @method _getFormAttributes
7732           * @protected
7733           * @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
7734           * @return {Object} Object literal, with method and action String properties.
7735           */
7736          _getFormAttributes : function(oForm){
7737              var attrs = {
7738                  method : null,
7739                  action : null
7740              };
7741  
7742              if (oForm) {
7743                  if (oForm.getAttributeNode) {
7744                      var action = oForm.getAttributeNode("action");
7745                      var method = oForm.getAttributeNode("method");
7746  
7747                      if (action) {
7748                          attrs.action = action.value;
7749                      }
7750  
7751                      if (method) {
7752                          attrs.method = method.value;
7753                      }
7754  
7755                  } else {
7756                      attrs.action = oForm.getAttribute("action");
7757                      attrs.method = oForm.getAttribute("method");
7758                  }
7759              }
7760  
7761              attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
7762              attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
7763  
7764              return attrs;
7765          },
7766  
7767          /**
7768          * Prepares the Dialog's internal FORM object, creating one if one is
7769          * not currently present.
7770          * @method registerForm
7771          */
7772          registerForm: function() {
7773  
7774              var form = this.element.getElementsByTagName("form")[0];
7775  
7776              if (this.form) {
7777                  if (this.form == form && Dom.isAncestor(this.element, this.form)) {
7778                      return;
7779                  } else {
7780                      Event.purgeElement(this.form);
7781                      this.form = null;
7782                  }
7783              }
7784  
7785              if (!form) {
7786                  form = document.createElement("form");
7787                  form.name = "frm_" + this.id;
7788                  this.body.appendChild(form);
7789              }
7790  
7791              if (form) {
7792                  this.form = form;
7793                  Event.on(form, "submit", this._submitHandler, this, true);
7794              }
7795          },
7796  
7797          /**
7798           * Internal handler for the form submit event
7799           *
7800           * @method _submitHandler
7801           * @protected
7802           * @param {DOMEvent} e The DOM Event object
7803           */
7804          _submitHandler : function(e) {
7805              Event.stopEvent(e);
7806              this.submit();
7807              this.form.blur();
7808          },
7809  
7810          /**
7811           * Sets up a tab, shift-tab loop between the first and last elements
7812           * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
7813           * instance properties, which are reset everytime this method is invoked.
7814           *
7815           * @method setTabLoop
7816           * @param {HTMLElement} firstElement
7817           * @param {HTMLElement} lastElement
7818           *
7819           */
7820          setTabLoop : function(firstElement, lastElement) {
7821  
7822              firstElement = firstElement || this.firstButton;
7823              lastElement = lastElement || this.lastButton;
7824  
7825              Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
7826          },
7827  
7828          /**
7829           * Protected internal method for setTabLoop, which can be used by 
7830           * subclasses to jump in and modify the arguments passed in if required.
7831           *
7832           * @method _setTabLoop
7833           * @param {HTMLElement} firstElement
7834           * @param {HTMLElement} lastElement
7835           * @protected
7836           */
7837          _setTabLoop : function(firstElement, lastElement) {
7838              firstElement = firstElement || this.firstButton;
7839              lastElement = this.lastButton || lastElement;
7840  
7841              this.setTabLoop(firstElement, lastElement);
7842          },
7843  
7844          /**
7845           * Configures instance properties, pointing to the 
7846           * first and last focusable elements in the Dialog's form.
7847           *
7848           * @method setFirstLastFocusable
7849           */
7850          setFirstLastFocusable : function() {
7851  
7852              Dialog.superclass.setFirstLastFocusable.call(this);
7853  
7854              var i, l, el, elements = this.focusableElements;
7855  
7856              this.firstFormElement = null;
7857              this.lastFormElement = null;
7858  
7859              if (this.form && elements && elements.length > 0) {
7860                  l = elements.length;
7861  
7862                  for (i = 0; i < l; ++i) {
7863                      el = elements[i];
7864                      if (this.form === el.form) {
7865                          this.firstFormElement = el;
7866                          break;
7867                      }
7868                  }
7869  
7870                  for (i = l-1; i >= 0; --i) {
7871                      el = elements[i];
7872                      if (this.form === el.form) {
7873                          this.lastFormElement = el;
7874                          break;
7875                      }
7876                  }
7877              }
7878          },
7879  
7880          // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7881          /**
7882          * The default event handler fired when the "close" property is 
7883          * changed. The method controls the appending or hiding of the close
7884          * icon at the top right of the Dialog.
7885          * @method configClose
7886          * @param {String} type The CustomEvent type (usually the property name)
7887          * @param {Object[]} args The CustomEvent arguments. For 
7888          * configuration handlers, args[0] will equal the newly applied value 
7889          * for the property.
7890          * @param {Object} obj The scope object. For configuration handlers, 
7891          * this will usually equal the owner.
7892          */
7893          configClose: function (type, args, obj) {
7894              Dialog.superclass.configClose.apply(this, arguments);
7895          },
7896  
7897          /**
7898           * Event handler for the close icon
7899           * 
7900           * @method _doClose
7901           * @protected
7902           * 
7903           * @param {DOMEvent} e
7904           */
7905           _doClose : function(e) {
7906              Event.preventDefault(e);
7907              this.cancel();
7908          },
7909  
7910          /**
7911          * The default event handler for the "buttons" configuration property
7912          * @method configButtons
7913          * @param {String} type The CustomEvent type (usually the property name)
7914          * @param {Object[]} args The CustomEvent arguments. For configuration 
7915          * handlers, args[0] will equal the newly applied value for the property.
7916          * @param {Object} obj The scope object. For configuration handlers, 
7917          * this will usually equal the owner.
7918          */
7919          configButtons: function (type, args, obj) {
7920  
7921              var Button = YAHOO.widget.Button,
7922                  aButtons = args[0],
7923                  oInnerElement = this.innerElement,
7924                  oButton,
7925                  oButtonEl,
7926                  oYUIButton,
7927                  nButtons,
7928                  oSpan,
7929                  oFooter,
7930                  i;
7931  
7932              removeButtonEventHandlers.call(this);
7933  
7934              this._aButtons = null;
7935  
7936              if (Lang.isArray(aButtons)) {
7937  
7938                  oSpan = document.createElement("span");
7939                  oSpan.className = "button-group";
7940                  nButtons = aButtons.length;
7941  
7942                  this._aButtons = [];
7943                  this.defaultHtmlButton = null;
7944  
7945                  for (i = 0; i < nButtons; i++) {
7946                      oButton = aButtons[i];
7947  
7948                      if (Button) {
7949                          oYUIButton = new Button({ label: oButton.text, type:oButton.type });
7950                          oYUIButton.appendTo(oSpan);
7951  
7952                          oButtonEl = oYUIButton.get("element");
7953  
7954                          if (oButton.isDefault) {
7955                              oYUIButton.addClass("default");
7956                              this.defaultHtmlButton = oButtonEl;
7957                          }
7958  
7959                          if (Lang.isFunction(oButton.handler)) {
7960  
7961                              oYUIButton.set("onclick", { 
7962                                  fn: oButton.handler, 
7963                                  obj: this, 
7964                                  scope: this 
7965                              });
7966  
7967                          } else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
7968  
7969                              oYUIButton.set("onclick", { 
7970                                  fn: oButton.handler.fn, 
7971                                  obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this), 
7972                                  scope: (oButton.handler.scope || this) 
7973                              });
7974  
7975                          }
7976  
7977                          this._aButtons[this._aButtons.length] = oYUIButton;
7978  
7979                      } else {
7980  
7981                          oButtonEl = document.createElement("button");
7982                          oButtonEl.setAttribute("type", "button");
7983  
7984                          if (oButton.isDefault) {
7985                              oButtonEl.className = "default";
7986                              this.defaultHtmlButton = oButtonEl;
7987                          }
7988  
7989                          oButtonEl.innerHTML = oButton.text;
7990  
7991                          if (Lang.isFunction(oButton.handler)) {
7992                              Event.on(oButtonEl, "click", oButton.handler, this, true);
7993                          } else if (Lang.isObject(oButton.handler) && 
7994                              Lang.isFunction(oButton.handler.fn)) {
7995      
7996                              Event.on(oButtonEl, "click", 
7997                                  oButton.handler.fn, 
7998                                  ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this), 
7999                                  (oButton.handler.scope || this));
8000                          }
8001  
8002                          oSpan.appendChild(oButtonEl);
8003                          this._aButtons[this._aButtons.length] = oButtonEl;
8004                      }
8005  
8006                      oButton.htmlButton = oButtonEl;
8007  
8008                      if (i === 0) {
8009                          this.firstButton = oButtonEl;
8010                      }
8011  
8012                      if (i == (nButtons - 1)) {
8013                          this.lastButton = oButtonEl;
8014                      }
8015                  }
8016  
8017                  this.setFooter(oSpan);
8018  
8019                  oFooter = this.footer;
8020  
8021                  if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
8022                      oInnerElement.appendChild(oFooter);
8023                  }
8024  
8025                  this.buttonSpan = oSpan;
8026  
8027              } else { // Do cleanup
8028                  oSpan = this.buttonSpan;
8029                  oFooter = this.footer;
8030                  if (oSpan && oFooter) {
8031                      oFooter.removeChild(oSpan);
8032                      this.buttonSpan = null;
8033                      this.firstButton = null;
8034                      this.lastButton = null;
8035                      this.defaultHtmlButton = null;
8036                  }
8037              }
8038  
8039              this.changeContentEvent.fire();
8040          },
8041  
8042          /**
8043          * @method getButtons
8044          * @description Returns an array containing each of the Dialog's 
8045          * buttons, by default an array of HTML <code>&#60;BUTTON&#62;</code> 
8046          * elements.  If the Dialog's buttons were created using the 
8047          * YAHOO.widget.Button class (via the inclusion of the optional Button 
8048          * dependency on the page), an array of YAHOO.widget.Button instances 
8049          * is returned.
8050          * @return {Array}
8051          */
8052          getButtons: function () {
8053              return this._aButtons || null;
8054          },
8055  
8056          /**
8057           * <p>
8058           * Sets focus to the first focusable element in the Dialog's form if found, 
8059           * else, the default button if found, else the first button defined via the 
8060           * "buttons" configuration property.
8061           * </p>
8062           * <p>
8063           * This method is invoked when the Dialog is made visible.
8064           * </p>
8065           * @method focusFirst
8066           * @return {Boolean} true, if focused. false if not
8067           */
8068          focusFirst: function (type, args, obj) {
8069  
8070              var el = this.firstFormElement, 
8071                  focused = false;
8072  
8073              if (args && args[1]) {
8074                  Event.stopEvent(args[1]);
8075  
8076                  // When tabbing here, use firstElement instead of firstFormElement
8077                  if (args[0] === 9 && this.firstElement) {
8078                      el = this.firstElement;
8079                  }
8080              }
8081  
8082              if (el) {
8083                  try {
8084                      el.focus();
8085                      focused = true;
8086                  } catch(oException) {
8087                      // Ignore
8088                  }
8089              } else {
8090                  if (this.defaultHtmlButton) {
8091                      focused = this.focusDefaultButton();
8092                  } else {
8093                      focused = this.focusFirstButton();
8094                  }
8095              }
8096              return focused;
8097          },
8098  
8099          /**
8100          * Sets focus to the last element in the Dialog's form or the last 
8101          * button defined via the "buttons" configuration property.
8102          * @method focusLast
8103          * @return {Boolean} true, if focused. false if not
8104          */
8105          focusLast: function (type, args, obj) {
8106  
8107              var aButtons = this.cfg.getProperty("buttons"),
8108                  el = this.lastFormElement,
8109                  focused = false;
8110  
8111              if (args && args[1]) {
8112                  Event.stopEvent(args[1]);
8113  
8114                  // When tabbing here, use lastElement instead of lastFormElement
8115                  if (args[0] === 9 && this.lastElement) {
8116                      el = this.lastElement;
8117                  }
8118              }
8119  
8120              if (aButtons && Lang.isArray(aButtons)) {
8121                  focused = this.focusLastButton();
8122              } else {
8123                  if (el) {
8124                      try {
8125                          el.focus();
8126                          focused = true;
8127                      } catch(oException) {
8128                          // Ignore
8129                      }
8130                  }
8131              }
8132  
8133              return focused;
8134          },
8135  
8136          /**
8137           * Helper method to normalize button references. It either returns the 
8138           * YUI Button instance for the given element if found,
8139           * or the passes back the HTMLElement reference if a corresponding YUI Button
8140           * reference is not found or YAHOO.widget.Button does not exist on the page.
8141           *
8142           * @method _getButton
8143           * @private
8144           * @param {HTMLElement} button
8145           * @return {YAHOO.widget.Button|HTMLElement}
8146           */
8147          _getButton : function(button) {
8148              var Button = YAHOO.widget.Button;
8149  
8150              // If we have an HTML button and YUI Button is on the page, 
8151              // get the YUI Button reference if available.
8152              if (Button && button && button.nodeName && button.id) {
8153                  button = Button.getButton(button.id) || button;
8154              }
8155  
8156              return button;
8157          },
8158  
8159          /**
8160          * Sets the focus to the button that is designated as the default via 
8161          * the "buttons" configuration property. By default, this method is 
8162          * called when the Dialog is made visible.
8163          * @method focusDefaultButton
8164          * @return {Boolean} true if focused, false if not
8165          */
8166          focusDefaultButton: function () {
8167              var button = this._getButton(this.defaultHtmlButton), 
8168                           focused = false;
8169              
8170              if (button) {
8171                  /*
8172                      Place the call to the "focus" method inside a try/catch
8173                      block to prevent IE from throwing JavaScript errors if
8174                      the element is disabled or hidden.
8175                  */
8176                  try {
8177                      button.focus();
8178                      focused = true;
8179                  } catch(oException) {
8180                  }
8181              }
8182              return focused;
8183          },
8184  
8185          /**
8186          * Blurs all the buttons defined via the "buttons" 
8187          * configuration property.
8188          * @method blurButtons
8189          */
8190          blurButtons: function () {
8191              
8192              var aButtons = this.cfg.getProperty("buttons"),
8193                  nButtons,
8194                  oButton,
8195                  oElement,
8196                  i;
8197  
8198              if (aButtons && Lang.isArray(aButtons)) {
8199                  nButtons = aButtons.length;
8200                  if (nButtons > 0) {
8201                      i = (nButtons - 1);
8202                      do {
8203                          oButton = aButtons[i];
8204                          if (oButton) {
8205                              oElement = this._getButton(oButton.htmlButton);
8206                              if (oElement) {
8207                                  /*
8208                                      Place the call to the "blur" method inside  
8209                                      a try/catch block to prevent IE from  
8210                                      throwing JavaScript errors if the element 
8211                                      is disabled or hidden.
8212                                  */
8213                                  try {
8214                                      oElement.blur();
8215                                  } catch(oException) {
8216                                      // ignore
8217                                  }
8218                              }
8219                          }
8220                      } while(i--);
8221                  }
8222              }
8223          },
8224  
8225          /**
8226          * Sets the focus to the first button created via the "buttons"
8227          * configuration property.
8228          * @method focusFirstButton
8229          * @return {Boolean} true, if focused. false if not
8230          */
8231          focusFirstButton: function () {
8232  
8233              var aButtons = this.cfg.getProperty("buttons"),
8234                  oButton,
8235                  oElement,
8236                  focused = false;
8237  
8238              if (aButtons && Lang.isArray(aButtons)) {
8239                  oButton = aButtons[0];
8240                  if (oButton) {
8241                      oElement = this._getButton(oButton.htmlButton);
8242                      if (oElement) {
8243                          /*
8244                              Place the call to the "focus" method inside a 
8245                              try/catch block to prevent IE from throwing 
8246                              JavaScript errors if the element is disabled 
8247                              or hidden.
8248                          */
8249                          try {
8250                              oElement.focus();
8251                              focused = true;
8252                          } catch(oException) {
8253                              // ignore
8254                          }
8255                      }
8256                  }
8257              }
8258  
8259              return focused;
8260          },
8261  
8262          /**
8263          * Sets the focus to the last button created via the "buttons" 
8264          * configuration property.
8265          * @method focusLastButton
8266          * @return {Boolean} true, if focused. false if not
8267          */
8268          focusLastButton: function () {
8269  
8270              var aButtons = this.cfg.getProperty("buttons"),
8271                  nButtons,
8272                  oButton,
8273                  oElement, 
8274                  focused = false;
8275  
8276              if (aButtons && Lang.isArray(aButtons)) {
8277                  nButtons = aButtons.length;
8278                  if (nButtons > 0) {
8279                      oButton = aButtons[(nButtons - 1)];
8280  
8281                      if (oButton) {
8282                          oElement = this._getButton(oButton.htmlButton);
8283                          if (oElement) {
8284                              /*
8285                                  Place the call to the "focus" method inside a 
8286                                  try/catch block to prevent IE from throwing 
8287                                  JavaScript errors if the element is disabled
8288                                  or hidden.
8289                              */
8290          
8291                              try {
8292                                  oElement.focus();
8293                                  focused = true;
8294                              } catch(oException) {
8295                                  // Ignore
8296                              }
8297                          }
8298                      }
8299                  }
8300              }
8301  
8302              return focused;
8303          },
8304  
8305          /**
8306          * The default event handler for the "postmethod" configuration property
8307          * @method configPostMethod
8308          * @param {String} type The CustomEvent type (usually the property name)
8309          * @param {Object[]} args The CustomEvent arguments. For 
8310          * configuration handlers, args[0] will equal the newly applied value 
8311          * for the property.
8312          * @param {Object} obj The scope object. For configuration handlers, 
8313          * this will usually equal the owner.
8314          */
8315          configPostMethod: function (type, args, obj) {
8316              this.registerForm();
8317          },
8318  
8319          // END BUILT-IN PROPERTY EVENT HANDLERS //
8320          
8321          /**
8322          * Built-in function hook for writing a validation function that will 
8323          * be checked for a "true" value prior to a submit. This function, as 
8324          * implemented by default, always returns true, so it should be 
8325          * overridden if validation is necessary.
8326          * @method validate
8327          */
8328          validate: function () {
8329              return true;
8330          },
8331  
8332          /**
8333          * Executes a submit of the Dialog if validation 
8334          * is successful. By default the Dialog is hidden
8335          * after submission, but you can set the "hideaftersubmit"
8336          * configuration property to false, to prevent the Dialog
8337          * from being hidden.
8338          * 
8339          * @method submit
8340          */
8341          submit: function () {
8342              if (this.validate()) {
8343                  if (this.beforeSubmitEvent.fire()) {
8344                      this.doSubmit();
8345                      this.submitEvent.fire();
8346      
8347                      if (this.cfg.getProperty("hideaftersubmit")) {
8348                          this.hide();
8349                      }
8350      
8351                      return true;
8352                  } else {
8353                      return false;
8354                  }
8355              } else {
8356                  return false;
8357              }
8358          },
8359  
8360          /**
8361          * Executes the cancel of the Dialog followed by a hide.
8362          * @method cancel
8363          */
8364          cancel: function () {
8365              this.cancelEvent.fire();
8366              this.hide();
8367          },
8368          
8369          /**
8370          * Returns a JSON-compatible data structure representing the data 
8371          * currently contained in the form.
8372          * @method getData
8373          * @return {Object} A JSON object reprsenting the data of the 
8374          * current form.
8375          */
8376          getData: function () {
8377  
8378              var oForm = this.form,
8379                  aElements,
8380                  nTotalElements,
8381                  oData,
8382                  sName,
8383                  oElement,
8384                  nElements,
8385                  sType,
8386                  sTagName,
8387                  aOptions,
8388                  nOptions,
8389                  aValues,
8390                  oOption,
8391                  oRadio,
8392                  oCheckbox,
8393                  valueAttr,
8394                  i,
8395                  n;    
8396      
8397              function isFormElement(p_oElement) {
8398                  var sTag = p_oElement.tagName.toUpperCase();
8399                  return ((sTag == "INPUT" || sTag == "TEXTAREA" || 
8400                          sTag == "SELECT") && p_oElement.name == sName);
8401              }
8402  
8403              if (oForm) {
8404  
8405                  aElements = oForm.elements;
8406                  nTotalElements = aElements.length;
8407                  oData = {};
8408  
8409                  for (i = 0; i < nTotalElements; i++) {
8410                      sName = aElements[i].name;
8411  
8412                      /*
8413                          Using "Dom.getElementsBy" to safeguard user from JS 
8414                          errors that result from giving a form field (or set of 
8415                          fields) the same name as a native method of a form 
8416                          (like "submit") or a DOM collection (such as the "item"
8417                          method). Originally tried accessing fields via the 
8418                          "namedItem" method of the "element" collection, but 
8419                          discovered that it won't return a collection of fields 
8420                          in Gecko.
8421                      */
8422  
8423                      oElement = Dom.getElementsBy(isFormElement, "*", oForm);
8424                      nElements = oElement.length;
8425  
8426                      if (nElements > 0) {
8427                          if (nElements == 1) {
8428                              oElement = oElement[0];
8429  
8430                              sType = oElement.type;
8431                              sTagName = oElement.tagName.toUpperCase();
8432  
8433                              switch (sTagName) {
8434                                  case "INPUT":
8435                                      if (sType == "checkbox") {
8436                                          oData[sName] = oElement.checked;
8437                                      } else if (sType != "radio") {
8438                                          oData[sName] = oElement.value;
8439                                      }
8440                                      break;
8441  
8442                                  case "TEXTAREA":
8443                                      oData[sName] = oElement.value;
8444                                      break;
8445      
8446                                  case "SELECT":
8447                                      aOptions = oElement.options;
8448                                      nOptions = aOptions.length;
8449                                      aValues = [];
8450      
8451                                      for (n = 0; n < nOptions; n++) {
8452                                          oOption = aOptions[n];
8453                                          if (oOption.selected) {
8454                                              valueAttr = oOption.attributes.value;
8455                                              aValues[aValues.length] = (valueAttr && valueAttr.specified) ? oOption.value : oOption.text;
8456                                          }
8457                                      }
8458                                      oData[sName] = aValues;
8459                                      break;
8460                              }
8461          
8462                          } else {
8463                              sType = oElement[0].type;
8464                              switch (sType) {
8465                                  case "radio":
8466                                      for (n = 0; n < nElements; n++) {
8467                                          oRadio = oElement[n];
8468                                          if (oRadio.checked) {
8469                                              oData[sName] = oRadio.value;
8470                                              break;
8471                                          }
8472                                      }
8473                                      break;
8474          
8475                                  case "checkbox":
8476                                      aValues = [];
8477                                      for (n = 0; n < nElements; n++) {
8478                                          oCheckbox = oElement[n];
8479                                          if (oCheckbox.checked) {
8480                                              aValues[aValues.length] =  oCheckbox.value;
8481                                          }
8482                                      }
8483                                      oData[sName] = aValues;
8484                                      break;
8485                              }
8486                          }
8487                      }
8488                  }
8489              }
8490  
8491              return oData;
8492          },
8493  
8494          /**
8495          * Removes the Panel element from the DOM and sets all child elements 
8496          * to null.
8497          * @method destroy
8498          * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners. 
8499          * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
8500          */
8501          destroy: function (shallowPurge) {
8502              removeButtonEventHandlers.call(this);
8503  
8504              this._aButtons = null;
8505  
8506              var aForms = this.element.getElementsByTagName("form"),
8507                  oForm;
8508  
8509              if (aForms.length > 0) {
8510                  oForm = aForms[0];
8511  
8512                  if (oForm) {
8513                      Event.purgeElement(oForm);
8514                      if (oForm.parentNode) {
8515                          oForm.parentNode.removeChild(oForm);
8516                      }
8517                      this.form = null;
8518                  }
8519              }
8520              Dialog.superclass.destroy.call(this, shallowPurge);
8521          },
8522  
8523          /**
8524          * Returns a string representation of the object.
8525          * @method toString
8526          * @return {String} The string representation of the Dialog
8527          */
8528          toString: function () {
8529              return "Dialog " + this.id;
8530          }
8531      
8532      });
8533  
8534  }());
8535  (function () {
8536  
8537      /**
8538      * SimpleDialog is a simple implementation of Dialog that can be used to 
8539      * submit a single value. Forms can be processed in 3 ways -- via an 
8540      * asynchronous Connection utility call, a simple form POST or GET, 
8541      * or manually.
8542      * @namespace YAHOO.widget
8543      * @class SimpleDialog
8544      * @extends YAHOO.widget.Dialog
8545      * @constructor
8546      * @param {String} el The element ID representing the SimpleDialog 
8547      * <em>OR</em>
8548      * @param {HTMLElement} el The element representing the SimpleDialog
8549      * @param {Object} userConfig The configuration object literal containing 
8550      * the configuration that should be set for this SimpleDialog. See 
8551      * configuration documentation for more details.
8552      */
8553      YAHOO.widget.SimpleDialog = function (el, userConfig) {
8554      
8555          YAHOO.widget.SimpleDialog.superclass.constructor.call(this, 
8556              el, userConfig);
8557      
8558      };
8559  
8560      var Dom = YAHOO.util.Dom,
8561          SimpleDialog = YAHOO.widget.SimpleDialog,
8562      
8563          /**
8564          * Constant representing the SimpleDialog's configuration properties
8565          * @property DEFAULT_CONFIG
8566          * @private
8567          * @final
8568          * @type Object
8569          */
8570          DEFAULT_CONFIG = {
8571          
8572              "ICON": { 
8573                  key: "icon", 
8574                  value: "none", 
8575                  suppressEvent: true  
8576              },
8577          
8578              "TEXT": { 
8579                  key: "text", 
8580                  value: "", 
8581                  suppressEvent: true, 
8582                  supercedes: ["icon"] 
8583              }
8584          
8585          };
8586  
8587      /**
8588      * Constant for the standard network icon for a blocking action
8589      * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
8590      * @static
8591      * @final
8592      * @type String
8593      */
8594      SimpleDialog.ICON_BLOCK = "blckicon";
8595      
8596      /**
8597      * Constant for the standard network icon for alarm
8598      * @property YAHOO.widget.SimpleDialog.ICON_ALARM
8599      * @static
8600      * @final
8601      * @type String
8602      */
8603      SimpleDialog.ICON_ALARM = "alrticon";
8604      
8605      /**
8606      * Constant for the standard network icon for help
8607      * @property YAHOO.widget.SimpleDialog.ICON_HELP
8608      * @static
8609      * @final
8610      * @type String
8611      */
8612      SimpleDialog.ICON_HELP  = "hlpicon";
8613      
8614      /**
8615      * Constant for the standard network icon for info
8616      * @property YAHOO.widget.SimpleDialog.ICON_INFO
8617      * @static
8618      * @final
8619      * @type String
8620      */
8621      SimpleDialog.ICON_INFO  = "infoicon";
8622      
8623      /**
8624      * Constant for the standard network icon for warn
8625      * @property YAHOO.widget.SimpleDialog.ICON_WARN
8626      * @static
8627      * @final
8628      * @type String
8629      */
8630      SimpleDialog.ICON_WARN  = "warnicon";
8631      
8632      /**
8633      * Constant for the standard network icon for a tip
8634      * @property YAHOO.widget.SimpleDialog.ICON_TIP
8635      * @static
8636      * @final
8637      * @type String
8638      */
8639      SimpleDialog.ICON_TIP   = "tipicon";
8640  
8641      /**
8642      * Constant representing the name of the CSS class applied to the element 
8643      * created by the "icon" configuration property.
8644      * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
8645      * @static
8646      * @final
8647      * @type String
8648      */
8649      SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
8650      
8651      /**
8652      * Constant representing the default CSS class used for a SimpleDialog
8653      * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
8654      * @static
8655      * @final
8656      * @type String
8657      */
8658      SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
8659  
8660      
8661      YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
8662      
8663          /**
8664          * Initializes the class's configurable properties which can be changed 
8665          * using the SimpleDialog's Config object (cfg).
8666          * @method initDefaultConfig
8667          */
8668          initDefaultConfig: function () {
8669          
8670              SimpleDialog.superclass.initDefaultConfig.call(this);
8671          
8672              // Add dialog config properties //
8673          
8674              /**
8675              * Sets the informational icon for the SimpleDialog
8676              * @config icon
8677              * @type String
8678              * @default "none"
8679              */
8680              this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
8681                  handler: this.configIcon,
8682                  value: DEFAULT_CONFIG.ICON.value,
8683                  suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
8684              });
8685          
8686              /**
8687              * Sets the text for the SimpleDialog. The text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
8688              * @config text
8689              * @type HTML
8690              * @default ""
8691              */
8692              this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, { 
8693                  handler: this.configText, 
8694                  value: DEFAULT_CONFIG.TEXT.value, 
8695                  suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent, 
8696                  supercedes: DEFAULT_CONFIG.TEXT.supercedes 
8697              });
8698          
8699          },
8700          
8701          
8702          /**
8703          * The SimpleDialog initialization method, which is executed for 
8704          * SimpleDialog and all of its subclasses. This method is automatically 
8705          * called by the constructor, and  sets up all DOM references for 
8706          * pre-existing markup, and creates required markup if it is not 
8707          * already present.
8708          * @method init
8709          * @param {String} el The element ID representing the SimpleDialog 
8710          * <em>OR</em>
8711          * @param {HTMLElement} el The element representing the SimpleDialog
8712          * @param {Object} userConfig The configuration object literal 
8713          * containing the configuration that should be set for this 
8714          * SimpleDialog. See configuration documentation for more details.
8715          */
8716          init: function (el, userConfig) {
8717  
8718              /*
8719                  Note that we don't pass the user config in here yet because we 
8720                  only want it executed once, at the lowest subclass level
8721              */
8722  
8723              SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
8724          
8725              this.beforeInitEvent.fire(SimpleDialog);
8726          
8727              Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
8728          
8729              this.cfg.queueProperty("postmethod", "manual");
8730          
8731              if (userConfig) {
8732                  this.cfg.applyConfig(userConfig, true);
8733              }
8734          
8735              this.beforeRenderEvent.subscribe(function () {
8736                  if (! this.body) {
8737                      this.setBody("");
8738                  }
8739              }, this, true);
8740          
8741              this.initEvent.fire(SimpleDialog);
8742          
8743          },
8744          
8745          /**
8746          * Prepares the SimpleDialog's internal FORM object, creating one if one 
8747          * is not currently present, and adding the value hidden field.
8748          * @method registerForm
8749          */
8750          registerForm: function () {
8751              SimpleDialog.superclass.registerForm.call(this);
8752  
8753              var doc = this.form.ownerDocument,
8754                  input = doc.createElement("input");
8755  
8756              input.type = "hidden";
8757              input.name = this.id;
8758              input.value = "";
8759  
8760              this.form.appendChild(input);
8761          },
8762  
8763          // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
8764          
8765          /**
8766          * Fired when the "icon" property is set.
8767          * @method configIcon
8768          * @param {String} type The CustomEvent type (usually the property name)
8769          * @param {Object[]} args The CustomEvent arguments. For configuration 
8770          * handlers, args[0] will equal the newly applied value for the property.
8771          * @param {Object} obj The scope object. For configuration handlers, 
8772          * this will usually equal the owner.
8773          */
8774          configIcon: function (type,args,obj) {
8775          
8776              var sIcon = args[0],
8777                  oBody = this.body,
8778                  sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
8779                  aElements,
8780                  oIcon,
8781                  oIconParent;
8782          
8783              if (sIcon && sIcon != "none") {
8784  
8785                  aElements = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
8786  
8787                  if (aElements.length === 1) {
8788  
8789                      oIcon = aElements[0];
8790                      oIconParent = oIcon.parentNode;
8791  
8792                      if (oIconParent) {
8793  
8794                          oIconParent.removeChild(oIcon);
8795  
8796                          oIcon = null;
8797  
8798                      }
8799  
8800                  }
8801  
8802  
8803                  if (sIcon.indexOf(".") == -1) {
8804  
8805                      oIcon = document.createElement("span");
8806                      oIcon.className = (sCSSClass + " " + sIcon);
8807                      oIcon.innerHTML = "&#160;";
8808  
8809                  } else {
8810  
8811                      oIcon = document.createElement("img");
8812                      oIcon.src = (this.imageRoot + sIcon);
8813                      oIcon.className = sCSSClass;
8814  
8815                  }
8816                  
8817  
8818                  if (oIcon) {
8819                  
8820                      oBody.insertBefore(oIcon, oBody.firstChild);
8821                  
8822                  }
8823  
8824              }
8825  
8826          },
8827  
8828          /**
8829          * Fired when the "text" property is set.
8830          * @method configText
8831          * @param {String} type The CustomEvent type (usually the property name)
8832          * @param {Object[]} args The CustomEvent arguments. For configuration 
8833          * handlers, args[0] will equal the newly applied value for the property.
8834          * @param {Object} obj The scope object. For configuration handlers, 
8835          * this will usually equal the owner.
8836          */
8837          configText: function (type,args,obj) {
8838              var text = args[0];
8839              if (text) {
8840                  this.setBody(text);
8841                  this.cfg.refireEvent("icon");
8842              }
8843          },
8844          
8845          // END BUILT-IN PROPERTY EVENT HANDLERS //
8846          
8847          /**
8848          * Returns a string representation of the object.
8849          * @method toString
8850          * @return {String} The string representation of the SimpleDialog
8851          */
8852          toString: function () {
8853              return "SimpleDialog " + this.id;
8854          }
8855  
8856          /**
8857          * <p>
8858          * Sets the SimpleDialog's body content to the HTML specified. 
8859          * If no body is present, one will be automatically created. 
8860          * An empty string can be passed to the method to clear the contents of the body.
8861          * </p>
8862          * <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
8863          * and <a href="#config_icon">icon</a> configuration properties to set the contents
8864          * of it's body element in accordance with the UI design for a SimpleDialog (an 
8865          * icon and message text). Calling setBody on the SimpleDialog will not enforce this 
8866          * UI design constraint and will replace the entire contents of the SimpleDialog body. 
8867          * It should only be used if you wish the replace the default icon/text body structure 
8868          * of a SimpleDialog with your own custom markup.</p>
8869          * 
8870          * @method setBody
8871          * @param {HTML} bodyContent The HTML used to set the body. 
8872          * As a convenience, non HTMLElement objects can also be passed into 
8873          * the method, and will be treated as strings, with the body innerHTML
8874          * set to their default toString implementations.
8875          * 
8876          * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
8877          * 
8878          * <em>OR</em>
8879          * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
8880          * <em>OR</em>
8881          * @param {DocumentFragment} bodyContent The document fragment 
8882          * containing elements which are to be added to the body
8883          */
8884      });
8885  
8886  }());
8887  (function () {
8888  
8889      /**
8890      * ContainerEffect encapsulates animation transitions that are executed when 
8891      * an Overlay is shown or hidden.
8892      * @namespace YAHOO.widget
8893      * @class ContainerEffect
8894      * @constructor
8895      * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation 
8896      * should be associated with
8897      * @param {Object} attrIn The object literal representing the animation 
8898      * arguments to be used for the animate-in transition. The arguments for 
8899      * this literal are: attributes(object, see YAHOO.util.Anim for description), 
8900      * duration(Number), and method(i.e. Easing.easeIn).
8901      * @param {Object} attrOut The object literal representing the animation 
8902      * arguments to be used for the animate-out transition. The arguments for  
8903      * this literal are: attributes(object, see YAHOO.util.Anim for description), 
8904      * duration(Number), and method(i.e. Easing.easeIn).
8905      * @param {HTMLElement} targetElement Optional. The target element that  
8906      * should be animated during the transition. Defaults to overlay.element.
8907      * @param {class} Optional. The animation class to instantiate. Defaults to 
8908      * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
8909      */
8910      YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
8911  
8912          if (!animClass) {
8913              animClass = YAHOO.util.Anim;
8914          }
8915  
8916          /**
8917          * The overlay to animate
8918          * @property overlay
8919          * @type YAHOO.widget.Overlay
8920          */
8921          this.overlay = overlay;
8922      
8923          /**
8924          * The animation attributes to use when transitioning into view
8925          * @property attrIn
8926          * @type Object
8927          */
8928          this.attrIn = attrIn;
8929      
8930          /**
8931          * The animation attributes to use when transitioning out of view
8932          * @property attrOut
8933          * @type Object
8934          */
8935          this.attrOut = attrOut;
8936      
8937          /**
8938          * The target element to be animated
8939          * @property targetElement
8940          * @type HTMLElement
8941          */
8942          this.targetElement = targetElement || overlay.element;
8943      
8944          /**
8945          * The animation class to use for animating the overlay
8946          * @property animClass
8947          * @type class
8948          */
8949          this.animClass = animClass;
8950      };
8951  
8952      var Dom = YAHOO.util.Dom,
8953          CustomEvent = YAHOO.util.CustomEvent,
8954          ContainerEffect = YAHOO.widget.ContainerEffect;
8955  
8956      /**
8957      * A pre-configured ContainerEffect instance that can be used for fading 
8958      * an overlay in and out.
8959      * @method FADE
8960      * @static
8961      * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8962      * @param {Number} dur The duration of the animation
8963      * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8964      */
8965      ContainerEffect.FADE = function (overlay, dur) {
8966  
8967          var Easing = YAHOO.util.Easing,
8968              fin = {
8969                  attributes: {opacity:{from:0, to:1}},
8970                  duration: dur,
8971                  method: Easing.easeIn
8972              },
8973              fout = {
8974                  attributes: {opacity:{to:0}},
8975                  duration: dur,
8976                  method: Easing.easeOut
8977              },
8978              fade = new ContainerEffect(overlay, fin, fout, overlay.element);
8979  
8980          fade.handleUnderlayStart = function() {
8981              var underlay = this.overlay.underlay;
8982              if (underlay && YAHOO.env.ua.ie) {
8983                  var hasFilters = (underlay.filters && underlay.filters.length > 0);
8984                  if(hasFilters) {
8985                      Dom.addClass(overlay.element, "yui-effect-fade");
8986                  }
8987              }
8988          };
8989  
8990          fade.handleUnderlayComplete = function() {
8991              var underlay = this.overlay.underlay;
8992              if (underlay && YAHOO.env.ua.ie) {
8993                  Dom.removeClass(overlay.element, "yui-effect-fade");
8994              }
8995          };
8996  
8997          fade.handleStartAnimateIn = function (type, args, obj) {
8998              obj.overlay._fadingIn = true;
8999  
9000              Dom.addClass(obj.overlay.element, "hide-select");
9001  
9002              if (!obj.overlay.underlay) {
9003                  obj.overlay.cfg.refireEvent("underlay");
9004              }
9005  
9006              obj.handleUnderlayStart();
9007  
9008              obj.overlay._setDomVisibility(true);
9009              Dom.setStyle(obj.overlay.element, "opacity", 0);
9010          };
9011  
9012          fade.handleCompleteAnimateIn = function (type,args,obj) {
9013              obj.overlay._fadingIn = false;
9014              
9015              Dom.removeClass(obj.overlay.element, "hide-select");
9016  
9017              if (obj.overlay.element.style.filter) {
9018                  obj.overlay.element.style.filter = null;
9019              }
9020  
9021              obj.handleUnderlayComplete();
9022  
9023              obj.overlay.cfg.refireEvent("iframe");
9024              obj.animateInCompleteEvent.fire();
9025          };
9026  
9027          fade.handleStartAnimateOut = function (type, args, obj) {
9028              obj.overlay._fadingOut = true;
9029              Dom.addClass(obj.overlay.element, "hide-select");
9030              obj.handleUnderlayStart();
9031          };
9032  
9033          fade.handleCompleteAnimateOut =  function (type, args, obj) {
9034              obj.overlay._fadingOut = false;
9035              Dom.removeClass(obj.overlay.element, "hide-select");
9036  
9037              if (obj.overlay.element.style.filter) {
9038                  obj.overlay.element.style.filter = null;
9039              }
9040              obj.overlay._setDomVisibility(false);
9041              Dom.setStyle(obj.overlay.element, "opacity", 1);
9042  
9043              obj.handleUnderlayComplete();
9044  
9045              obj.overlay.cfg.refireEvent("iframe");
9046              obj.animateOutCompleteEvent.fire();
9047          };
9048  
9049          fade.init();
9050          return fade;
9051      };
9052      
9053      
9054      /**
9055      * A pre-configured ContainerEffect instance that can be used for sliding an 
9056      * overlay in and out.
9057      * @method SLIDE
9058      * @static
9059      * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
9060      * @param {Number} dur The duration of the animation
9061      * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
9062      */
9063      ContainerEffect.SLIDE = function (overlay, dur) {
9064          var Easing = YAHOO.util.Easing,
9065  
9066              x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
9067              y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
9068              clientWidth = Dom.getClientWidth(),
9069              offsetWidth = overlay.element.offsetWidth,
9070  
9071              sin =  { 
9072                  attributes: { points: { to: [x, y] } },
9073                  duration: dur,
9074                  method: Easing.easeIn 
9075              },
9076  
9077              sout = {
9078                  attributes: { points: { to: [(clientWidth + 25), y] } },
9079                  duration: dur,
9080                  method: Easing.easeOut 
9081              },
9082  
9083              slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
9084  
9085          slide.handleStartAnimateIn = function (type,args,obj) {
9086              obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
9087              obj.overlay.element.style.top  = y + "px";
9088          };
9089  
9090          slide.handleTweenAnimateIn = function (type, args, obj) {
9091          
9092              var pos = Dom.getXY(obj.overlay.element),
9093                  currentX = pos[0],
9094                  currentY = pos[1];
9095          
9096              if (Dom.getStyle(obj.overlay.element, "visibility") == 
9097                  "hidden" && currentX < x) {
9098  
9099                  obj.overlay._setDomVisibility(true);
9100  
9101              }
9102          
9103              obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
9104              obj.overlay.cfg.refireEvent("iframe");
9105          };
9106          
9107          slide.handleCompleteAnimateIn = function (type, args, obj) {
9108              obj.overlay.cfg.setProperty("xy", [x, y], true);
9109              obj.startX = x;
9110              obj.startY = y;
9111              obj.overlay.cfg.refireEvent("iframe");
9112              obj.animateInCompleteEvent.fire();
9113          };
9114  
9115          slide.handleStartAnimateOut = function (type, args, obj) {
9116      
9117              var vw = Dom.getViewportWidth(),
9118                  pos = Dom.getXY(obj.overlay.element),
9119                  yso = pos[1];
9120      
9121              obj.animOut.attributes.points.to = [(vw + 25), yso];
9122          };
9123          
9124          slide.handleTweenAnimateOut = function (type, args, obj) {
9125      
9126              var pos = Dom.getXY(obj.overlay.element),
9127                  xto = pos[0],
9128                  yto = pos[1];
9129          
9130              obj.overlay.cfg.setProperty("xy", [xto, yto], true);
9131              obj.overlay.cfg.refireEvent("iframe");
9132          };
9133          
9134          slide.handleCompleteAnimateOut = function (type, args, obj) {
9135              obj.overlay._setDomVisibility(false);
9136  
9137              obj.overlay.cfg.setProperty("xy", [x, y]);
9138              obj.animateOutCompleteEvent.fire();
9139          };
9140  
9141          slide.init();
9142          return slide;
9143      };
9144  
9145      ContainerEffect.prototype = {
9146  
9147          /**
9148          * Initializes the animation classes and events.
9149          * @method init
9150          */
9151          init: function () {
9152  
9153              this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
9154              this.beforeAnimateInEvent.signature = CustomEvent.LIST;
9155              
9156              this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
9157              this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
9158          
9159              this.animateInCompleteEvent = this.createEvent("animateInComplete");
9160              this.animateInCompleteEvent.signature = CustomEvent.LIST;
9161          
9162              this.animateOutCompleteEvent = this.createEvent("animateOutComplete");
9163              this.animateOutCompleteEvent.signature = CustomEvent.LIST;
9164  
9165              this.animIn = new this.animClass(
9166                  this.targetElement, 
9167                  this.attrIn.attributes, 
9168                  this.attrIn.duration, 
9169                  this.attrIn.method);
9170  
9171              this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
9172              this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
9173              this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);
9174          
9175              this.animOut = new this.animClass(
9176                  this.targetElement, 
9177                  this.attrOut.attributes, 
9178                  this.attrOut.duration, 
9179                  this.attrOut.method);
9180  
9181              this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
9182              this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
9183              this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, this);
9184  
9185          },
9186  
9187          /**
9188          * Triggers the in-animation.
9189          * @method animateIn
9190          */
9191          animateIn: function () {
9192              this._stopAnims(this.lastFrameOnStop);
9193              this.beforeAnimateInEvent.fire();
9194              this.animIn.animate();
9195          },
9196  
9197          /**
9198          * Triggers the out-animation.
9199          * @method animateOut
9200          */
9201          animateOut: function () {
9202              this._stopAnims(this.lastFrameOnStop);
9203              this.beforeAnimateOutEvent.fire();
9204              this.animOut.animate();
9205          },
9206          
9207          /**
9208           * Flag to define whether Anim should jump to the last frame,
9209           * when animateIn or animateOut is stopped.
9210           *
9211           * @property lastFrameOnStop
9212           * @default true
9213           * @type boolean
9214           */
9215          lastFrameOnStop : true,
9216  
9217          /**
9218           * Stops both animIn and animOut instances, if in progress.
9219           *
9220           * @method _stopAnims
9221           * @param {boolean} finish If true, animation will jump to final frame.
9222           * @protected
9223           */
9224          _stopAnims : function(finish) {
9225              if (this.animOut && this.animOut.isAnimated()) {
9226                  this.animOut.stop(finish);
9227              }
9228  
9229              if (this.animIn && this.animIn.isAnimated()) {
9230                  this.animIn.stop(finish);
9231              }
9232          },
9233  
9234          /**
9235          * The default onStart handler for the in-animation.
9236          * @method handleStartAnimateIn
9237          * @param {String} type The CustomEvent type
9238          * @param {Object[]} args The CustomEvent arguments
9239          * @param {Object} obj The scope object
9240          */
9241          handleStartAnimateIn: function (type, args, obj) { },
9242  
9243          /**
9244          * The default onTween handler for the in-animation.
9245          * @method handleTweenAnimateIn
9246          * @param {String} type The CustomEvent type
9247          * @param {Object[]} args The CustomEvent arguments
9248          * @param {Object} obj The scope object
9249          */
9250          handleTweenAnimateIn: function (type, args, obj) { },
9251  
9252          /**
9253          * The default onComplete handler for the in-animation.
9254          * @method handleCompleteAnimateIn
9255          * @param {String} type The CustomEvent type
9256          * @param {Object[]} args The CustomEvent arguments
9257          * @param {Object} obj The scope object
9258          */
9259          handleCompleteAnimateIn: function (type, args, obj) { },
9260  
9261          /**
9262          * The default onStart handler for the out-animation.
9263          * @method handleStartAnimateOut
9264          * @param {String} type The CustomEvent type
9265          * @param {Object[]} args The CustomEvent arguments
9266          * @param {Object} obj The scope object
9267          */
9268          handleStartAnimateOut: function (type, args, obj) { },
9269  
9270          /**
9271          * The default onTween handler for the out-animation.
9272          * @method handleTweenAnimateOut
9273          * @param {String} type The CustomEvent type
9274          * @param {Object[]} args The CustomEvent arguments
9275          * @param {Object} obj The scope object
9276          */
9277          handleTweenAnimateOut: function (type, args, obj) { },
9278  
9279          /**
9280          * The default onComplete handler for the out-animation.
9281          * @method handleCompleteAnimateOut
9282          * @param {String} type The CustomEvent type
9283          * @param {Object[]} args The CustomEvent arguments
9284          * @param {Object} obj The scope object
9285          */
9286          handleCompleteAnimateOut: function (type, args, obj) { },
9287          
9288          /**
9289          * Returns a string representation of the object.
9290          * @method toString
9291          * @return {String} The string representation of the ContainerEffect
9292          */
9293          toString: function () {
9294              var output = "ContainerEffect";
9295              if (this.overlay) {
9296                  output += " [" + this.overlay.toString() + "]";
9297              }
9298              return output;
9299          }
9300      };
9301  
9302      YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
9303  
9304  })();
9305  YAHOO.register("container", YAHOO.widget.Module, {version: "2.9.0", build: "2800"});
9306  
9307  }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event", "yui2-skin-sam-container"], "supersedes": ["yui2-containercore"], "optional": ["yui2-animation", "yui2-dragdrop", "yui2-connection"]});


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