[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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