[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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

   1  YUI.add('yui2-containercore', function(Y) {
   2      var YAHOO    = Y.YUI2;
   3      /*
   4  Copyright (c) 2011, Yahoo! Inc. All rights reserved.
   5  Code licensed under the BSD License:
   6  http://developer.yahoo.com/yui/license.html
   7  version: 2.9.0
   8  */
   9  (function () {
  10  
  11      /**
  12      * Config is a utility used within an Object to allow the implementer to
  13      * maintain a list of local configuration properties and listen for changes 
  14      * to those properties dynamically using CustomEvent. The initial values are 
  15      * also maintained so that the configuration can be reset at any given point 
  16      * to its initial state.
  17      * @namespace YAHOO.util
  18      * @class Config
  19      * @constructor
  20      * @param {Object} owner The owner Object to which this Config Object belongs
  21      */
  22      YAHOO.util.Config = function (owner) {
  23  
  24          if (owner) {
  25              this.init(owner);
  26          }
  27  
  28          if (!owner) {  YAHOO.log("No owner specified for Config object", "error", "Config"); }
  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              YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
 157              var property = this.config[key];
 158          
 159              if (property && property.event) {
 160                  property.event.fire(value);
 161              } 
 162          },
 163          
 164          /**
 165          * Adds a property to the Config Object's private config hash.
 166          * @method addProperty
 167          * @param {String} key The configuration property's name
 168          * @param {Object} propertyObject The Object containing all of this 
 169          * property's arguments
 170          */
 171          addProperty: function ( key, propertyObject ) {
 172              key = key.toLowerCase();
 173              YAHOO.log("Added property: " + key, "info", "Config");
 174          
 175              this.config[key] = propertyObject;
 176          
 177              propertyObject.event = this.createEvent(key, { scope: this.owner });
 178              propertyObject.event.signature = CustomEvent.LIST;
 179              
 180              
 181              propertyObject.key = key;
 182          
 183              if (propertyObject.handler) {
 184                  propertyObject.event.subscribe(propertyObject.handler, 
 185                      this.owner);
 186              }
 187          
 188              this.setProperty(key, propertyObject.value, true);
 189              
 190              if (! propertyObject.suppressEvent) {
 191                  this.queueProperty(key, propertyObject.value);
 192              }
 193              
 194          },
 195          
 196          /**
 197          * Returns a key-value configuration map of the values currently set in  
 198          * the Config Object.
 199          * @method getConfig
 200          * @return {Object} The current config, represented in a key-value map
 201          */
 202          getConfig: function () {
 203          
 204              var cfg = {},
 205                  currCfg = this.config,
 206                  prop,
 207                  property;
 208                  
 209              for (prop in currCfg) {
 210                  if (Lang.hasOwnProperty(currCfg, prop)) {
 211                      property = currCfg[prop];
 212                      if (property && property.event) {
 213                          cfg[prop] = property.value;
 214                      }
 215                  }
 216              }
 217  
 218              return cfg;
 219          },
 220          
 221          /**
 222          * Returns the value of specified property.
 223          * @method getProperty
 224          * @param {String} key The name of the property
 225          * @return {Object}  The value of the specified property
 226          */
 227          getProperty: function (key) {
 228              var property = this.config[key.toLowerCase()];
 229              if (property && property.event) {
 230                  return property.value;
 231              } else {
 232                  return undefined;
 233              }
 234          },
 235          
 236          /**
 237          * Resets the specified property's value to its initial value.
 238          * @method resetProperty
 239          * @param {String} key The name of the property
 240          * @return {Boolean} True is the property was reset, false if not
 241          */
 242          resetProperty: function (key) {
 243              key = key.toLowerCase();
 244  
 245              var property = this.config[key];
 246  
 247              if (property && property.event) {
 248                  if (key in this.initialConfig) {
 249                      this.setProperty(key, this.initialConfig[key]);
 250                      return true;
 251                  }
 252              } else {
 253                  return false;
 254              }
 255          },
 256          
 257          /**
 258          * Sets the value of a property. If the silent property is passed as 
 259          * true, the property's event will not be fired.
 260          * @method setProperty
 261          * @param {String} key The name of the property
 262          * @param {String} value The value to set the property to
 263          * @param {Boolean} silent Whether the value should be set silently, 
 264          * without firing the property event.
 265          * @return {Boolean} True, if the set was successful, false if it failed.
 266          */
 267          setProperty: function (key, value, silent) {
 268          
 269              var property;
 270          
 271              key = key.toLowerCase();
 272              YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
 273          
 274              if (this.queueInProgress && ! silent) {
 275                  // Currently running through a queue... 
 276                  this.queueProperty(key,value);
 277                  return true;
 278      
 279              } else {
 280                  property = this.config[key];
 281                  if (property && property.event) {
 282                      if (property.validator && !property.validator(value)) {
 283                          return false;
 284                      } else {
 285                          property.value = value;
 286                          if (! silent) {
 287                              this.fireEvent(key, value);
 288                              this.configChangedEvent.fire([key, value]);
 289                          }
 290                          return true;
 291                      }
 292                  } else {
 293                      return false;
 294                  }
 295              }
 296          },
 297          
 298          /**
 299          * Sets the value of a property and queues its event to execute. If the 
 300          * event is already scheduled to execute, it is
 301          * moved from its current position to the end of the queue.
 302          * @method queueProperty
 303          * @param {String} key The name of the property
 304          * @param {String} value The value to set the property to
 305          * @return {Boolean}  true, if the set was successful, false if 
 306          * it failed.
 307          */ 
 308          queueProperty: function (key, value) {
 309          
 310              key = key.toLowerCase();
 311              YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
 312          
 313              var property = this.config[key],
 314                  foundDuplicate = false,
 315                  iLen,
 316                  queueItem,
 317                  queueItemKey,
 318                  queueItemValue,
 319                  sLen,
 320                  supercedesCheck,
 321                  qLen,
 322                  queueItemCheck,
 323                  queueItemCheckKey,
 324                  queueItemCheckValue,
 325                  i,
 326                  s,
 327                  q;
 328                                  
 329              if (property && property.event) {
 330      
 331                  if (!Lang.isUndefined(value) && property.validator && 
 332                      !property.validator(value)) { // validator
 333                      return false;
 334                  } else {
 335          
 336                      if (!Lang.isUndefined(value)) {
 337                          property.value = value;
 338                      } else {
 339                          value = property.value;
 340                      }
 341          
 342                      foundDuplicate = false;
 343                      iLen = this.eventQueue.length;
 344          
 345                      for (i = 0; i < iLen; i++) {
 346                          queueItem = this.eventQueue[i];
 347          
 348                          if (queueItem) {
 349                              queueItemKey = queueItem[0];
 350                              queueItemValue = queueItem[1];
 351  
 352                              if (queueItemKey == key) {
 353      
 354                                  /*
 355                                      found a dupe... push to end of queue, null 
 356                                      current item, and break
 357                                  */
 358      
 359                                  this.eventQueue[i] = null;
 360      
 361                                  this.eventQueue.push(
 362                                      [key, (!Lang.isUndefined(value) ? 
 363                                      value : queueItemValue)]);
 364      
 365                                  foundDuplicate = true;
 366                                  break;
 367                              }
 368                          }
 369                      }
 370                      
 371                      // this is a refire, or a new property in the queue
 372      
 373                      if (! foundDuplicate && !Lang.isUndefined(value)) { 
 374                          this.eventQueue.push([key, value]);
 375                      }
 376                  }
 377          
 378                  if (property.supercedes) {
 379  
 380                      sLen = property.supercedes.length;
 381  
 382                      for (s = 0; s < sLen; s++) {
 383  
 384                          supercedesCheck = property.supercedes[s];
 385                          qLen = this.eventQueue.length;
 386  
 387                          for (q = 0; q < qLen; q++) {
 388                              queueItemCheck = this.eventQueue[q];
 389  
 390                              if (queueItemCheck) {
 391                                  queueItemCheckKey = queueItemCheck[0];
 392                                  queueItemCheckValue = queueItemCheck[1];
 393  
 394                                  if (queueItemCheckKey == 
 395                                      supercedesCheck.toLowerCase() ) {
 396  
 397                                      this.eventQueue.push([queueItemCheckKey, 
 398                                          queueItemCheckValue]);
 399  
 400                                      this.eventQueue[q] = null;
 401                                      break;
 402  
 403                                  }
 404                              }
 405                          }
 406                      }
 407                  }
 408  
 409                  YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
 410  
 411                  return true;
 412              } else {
 413                  return false;
 414              }
 415          },
 416          
 417          /**
 418          * Fires the event for a property using the property's current value.
 419          * @method refireEvent
 420          * @param {String} key The name of the property
 421          */
 422          refireEvent: function (key) {
 423      
 424              key = key.toLowerCase();
 425          
 426              var property = this.config[key];
 427      
 428              if (property && property.event && 
 429      
 430                  !Lang.isUndefined(property.value)) {
 431      
 432                  if (this.queueInProgress) {
 433      
 434                      this.queueProperty(key);
 435      
 436                  } else {
 437      
 438                      this.fireEvent(key, property.value);
 439      
 440                  }
 441      
 442              }
 443          },
 444          
 445          /**
 446          * Applies a key-value Object literal to the configuration, replacing  
 447          * any existing values, and queueing the property events.
 448          * Although the values will be set, fireQueue() must be called for their 
 449          * associated events to execute.
 450          * @method applyConfig
 451          * @param {Object} userConfig The configuration Object literal
 452          * @param {Boolean} init  When set to true, the initialConfig will 
 453          * be set to the userConfig passed in, so that calling a reset will 
 454          * reset the properties to the passed values.
 455          */
 456          applyConfig: function (userConfig, init) {
 457          
 458              var sKey,
 459                  oConfig;
 460  
 461              if (init) {
 462                  oConfig = {};
 463                  for (sKey in userConfig) {
 464                      if (Lang.hasOwnProperty(userConfig, sKey)) {
 465                          oConfig[sKey.toLowerCase()] = userConfig[sKey];
 466                      }
 467                  }
 468                  this.initialConfig = oConfig;
 469              }
 470  
 471              for (sKey in userConfig) {
 472                  if (Lang.hasOwnProperty(userConfig, sKey)) {
 473                      this.queueProperty(sKey, userConfig[sKey]);
 474                  }
 475              }
 476          },
 477          
 478          /**
 479          * Refires the events for all configuration properties using their 
 480          * current values.
 481          * @method refresh
 482          */
 483          refresh: function () {
 484  
 485              var prop;
 486  
 487              for (prop in this.config) {
 488                  if (Lang.hasOwnProperty(this.config, prop)) {
 489                      this.refireEvent(prop);
 490                  }
 491              }
 492          },
 493          
 494          /**
 495          * Fires the normalized list of queued property change events
 496          * @method fireQueue
 497          */
 498          fireQueue: function () {
 499          
 500              var i, 
 501                  queueItem,
 502                  key,
 503                  value,
 504                  property;
 505          
 506              this.queueInProgress = true;
 507              for (i = 0;i < this.eventQueue.length; i++) {
 508                  queueItem = this.eventQueue[i];
 509                  if (queueItem) {
 510          
 511                      key = queueItem[0];
 512                      value = queueItem[1];
 513                      property = this.config[key];
 514  
 515                      property.value = value;
 516  
 517                      // Clear out queue entry, to avoid it being 
 518                      // re-added to the queue by any queueProperty/supercedes
 519                      // calls which are invoked during fireEvent
 520                      this.eventQueue[i] = null;
 521  
 522                      this.fireEvent(key,value);
 523                  }
 524              }
 525              
 526              this.queueInProgress = false;
 527              this.eventQueue = [];
 528          },
 529          
 530          /**
 531          * Subscribes an external handler to the change event for any 
 532          * given property. 
 533          * @method subscribeToConfigEvent
 534          * @param {String} key The property name
 535          * @param {Function} handler The handler function to use subscribe to 
 536          * the property's event
 537          * @param {Object} obj The Object to use for scoping the event handler 
 538          * (see CustomEvent documentation)
 539          * @param {Boolean} overrideContext Optional. If true, will override
 540          * "this" within the handler to map to the scope Object passed into the
 541          * method.
 542          * @return {Boolean} True, if the subscription was successful, 
 543          * otherwise false.
 544          */ 
 545          subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
 546      
 547              var property = this.config[key.toLowerCase()];
 548      
 549              if (property && property.event) {
 550                  if (!Config.alreadySubscribed(property.event, handler, obj)) {
 551                      property.event.subscribe(handler, obj, overrideContext);
 552                  }
 553                  return true;
 554              } else {
 555                  return false;
 556              }
 557      
 558          },
 559          
 560          /**
 561          * Unsubscribes an external handler from the change event for any 
 562          * given property. 
 563          * @method unsubscribeFromConfigEvent
 564          * @param {String} key The property name
 565          * @param {Function} handler The handler function to use subscribe to 
 566          * the property's event
 567          * @param {Object} obj The Object to use for scoping the event 
 568          * handler (see CustomEvent documentation)
 569          * @return {Boolean} True, if the unsubscription was successful, 
 570          * otherwise false.
 571          */
 572          unsubscribeFromConfigEvent: function (key, handler, obj) {
 573              var property = this.config[key.toLowerCase()];
 574              if (property && property.event) {
 575                  return property.event.unsubscribe(handler, obj);
 576              } else {
 577                  return false;
 578              }
 579          },
 580          
 581          /**
 582          * Returns a string representation of the Config object
 583          * @method toString
 584          * @return {String} The Config object in string format.
 585          */
 586          toString: function () {
 587              var output = "Config";
 588              if (this.owner) {
 589                  output += " [" + this.owner.toString() + "]";
 590              }
 591              return output;
 592          },
 593          
 594          /**
 595          * Returns a string representation of the Config object's current 
 596          * CustomEvent queue
 597          * @method outputEventQueue
 598          * @return {String} The string list of CustomEvents currently queued 
 599          * for execution
 600          */
 601          outputEventQueue: function () {
 602  
 603              var output = "",
 604                  queueItem,
 605                  q,
 606                  nQueue = this.eventQueue.length;
 607                
 608              for (q = 0; q < nQueue; q++) {
 609                  queueItem = this.eventQueue[q];
 610                  if (queueItem) {
 611                      output += queueItem[0] + "=" + queueItem[1] + ", ";
 612                  }
 613              }
 614              return output;
 615          },
 616  
 617          /**
 618          * Sets all properties to null, unsubscribes all listeners from each 
 619          * property's change event and all listeners from the configChangedEvent.
 620          * @method destroy
 621          */
 622          destroy: function () {
 623  
 624              var oConfig = this.config,
 625                  sProperty,
 626                  oProperty;
 627  
 628  
 629              for (sProperty in oConfig) {
 630              
 631                  if (Lang.hasOwnProperty(oConfig, sProperty)) {
 632  
 633                      oProperty = oConfig[sProperty];
 634  
 635                      oProperty.event.unsubscribeAll();
 636                      oProperty.event = null;
 637  
 638                  }
 639              
 640              }
 641              
 642              this.configChangedEvent.unsubscribeAll();
 643              
 644              this.configChangedEvent = null;
 645              this.owner = null;
 646              this.config = null;
 647              this.initialConfig = null;
 648              this.eventQueue = null;
 649          
 650          }
 651  
 652      };
 653      
 654      
 655      
 656      /**
 657      * Checks to determine if a particular function/Object pair are already 
 658      * subscribed to the specified CustomEvent
 659      * @method YAHOO.util.Config.alreadySubscribed
 660      * @static
 661      * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check 
 662      * the subscriptions
 663      * @param {Function} fn The function to look for in the subscribers list
 664      * @param {Object} obj The execution scope Object for the subscription
 665      * @return {Boolean} true, if the function/Object pair is already subscribed 
 666      * to the CustomEvent passed in
 667      */
 668      Config.alreadySubscribed = function (evt, fn, obj) {
 669      
 670          var nSubscribers = evt.subscribers.length,
 671              subsc,
 672              i;
 673  
 674          if (nSubscribers > 0) {
 675              i = nSubscribers - 1;
 676              do {
 677                  subsc = evt.subscribers[i];
 678                  if (subsc && subsc.obj == obj && subsc.fn == fn) {
 679                      return true;
 680                  }
 681              }
 682              while (i--);
 683          }
 684  
 685          return false;
 686  
 687      };
 688  
 689      YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
 690  
 691  }());
 692  (function () {
 693  
 694      /**
 695      * The Container family of components is designed to enable developers to 
 696      * create different kinds of content-containing modules on the web. Module 
 697      * and Overlay are the most basic containers, and they can be used directly 
 698      * or extended to build custom containers. Also part of the Container family 
 699      * are four UI controls that extend Module and Overlay: Tooltip, Panel, 
 700      * Dialog, and SimpleDialog.
 701      * @module container
 702      * @title Container
 703      * @requires yahoo, dom, event 
 704      * @optional dragdrop, animation, button
 705      */
 706      
 707      /**
 708      * Module is a JavaScript representation of the Standard Module Format. 
 709      * Standard Module Format is a simple standard for markup containers where 
 710      * child nodes representing the header, body, and footer of the content are 
 711      * denoted using the CSS classes "hd", "bd", and "ft" respectively. 
 712      * Module is the base class for all other classes in the YUI 
 713      * Container package.
 714      * @namespace YAHOO.widget
 715      * @class Module
 716      * @constructor
 717      * @param {String} el The element ID representing the Module <em>OR</em>
 718      * @param {HTMLElement} el The element representing the Module
 719      * @param {Object} userConfig The configuration Object literal containing 
 720      * the configuration that should be set for this module. See configuration 
 721      * documentation for more details.
 722      */
 723      YAHOO.widget.Module = function (el, userConfig) {
 724          if (el) {
 725              this.init(el, userConfig);
 726          } else {
 727              YAHOO.log("No element or element ID specified" + 
 728                  " for Module instantiation", "error");
 729          }
 730      };
 731  
 732      var Dom = YAHOO.util.Dom,
 733          Config = YAHOO.util.Config,
 734          Event = YAHOO.util.Event,
 735          CustomEvent = YAHOO.util.CustomEvent,
 736          Module = YAHOO.widget.Module,
 737          UA = YAHOO.env.ua,
 738  
 739          m_oModuleTemplate,
 740          m_oHeaderTemplate,
 741          m_oBodyTemplate,
 742          m_oFooterTemplate,
 743  
 744          /**
 745          * Constant representing the name of the Module's events
 746          * @property EVENT_TYPES
 747          * @private
 748          * @final
 749          * @type Object
 750          */
 751          EVENT_TYPES = {
 752              "BEFORE_INIT": "beforeInit",
 753              "INIT": "init",
 754              "APPEND": "append",
 755              "BEFORE_RENDER": "beforeRender",
 756              "RENDER": "render",
 757              "CHANGE_HEADER": "changeHeader",
 758              "CHANGE_BODY": "changeBody",
 759              "CHANGE_FOOTER": "changeFooter",
 760              "CHANGE_CONTENT": "changeContent",
 761              "DESTROY": "destroy",
 762              "BEFORE_SHOW": "beforeShow",
 763              "SHOW": "show",
 764              "BEFORE_HIDE": "beforeHide",
 765              "HIDE": "hide"
 766          },
 767              
 768          /**
 769          * Constant representing the Module's configuration properties
 770          * @property DEFAULT_CONFIG
 771          * @private
 772          * @final
 773          * @type Object
 774          */
 775          DEFAULT_CONFIG = {
 776          
 777              "VISIBLE": { 
 778                  key: "visible", 
 779                  value: true, 
 780                  validator: YAHOO.lang.isBoolean 
 781              },
 782  
 783              "EFFECT": {
 784                  key: "effect",
 785                  suppressEvent: true,
 786                  supercedes: ["visible"]
 787              },
 788  
 789              "MONITOR_RESIZE": {
 790                  key: "monitorresize",
 791                  value: true
 792              },
 793  
 794              "APPEND_TO_DOCUMENT_BODY": {
 795                  key: "appendtodocumentbody",
 796                  value: false
 797              }
 798          };
 799  
 800      /**
 801      * Constant representing the prefix path to use for non-secure images
 802      * @property YAHOO.widget.Module.IMG_ROOT
 803      * @static
 804      * @final
 805      * @type String
 806      */
 807      Module.IMG_ROOT = null;
 808      
 809      /**
 810      * Constant representing the prefix path to use for securely served images
 811      * @property YAHOO.widget.Module.IMG_ROOT_SSL
 812      * @static
 813      * @final
 814      * @type String
 815      */
 816      Module.IMG_ROOT_SSL = null;
 817      
 818      /**
 819      * Constant for the default CSS class name that represents a Module
 820      * @property YAHOO.widget.Module.CSS_MODULE
 821      * @static
 822      * @final
 823      * @type String
 824      */
 825      Module.CSS_MODULE = "yui-module";
 826      
 827      /**
 828      * 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.
 829      * @property YAHOO.widget.Module.CSS_HEADER
 830      * @static
 831      * @final
 832      * @type String
 833      */
 834      Module.CSS_HEADER = "hd";
 835  
 836      /**
 837      * 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.
 838      * @property YAHOO.widget.Module.CSS_BODY
 839      * @static
 840      * @final
 841      * @type String
 842      */
 843      Module.CSS_BODY = "bd";
 844      
 845      /**
 846      * 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.
 847      * @property YAHOO.widget.Module.CSS_FOOTER
 848      * @static
 849      * @final
 850      * @type String
 851      */
 852      Module.CSS_FOOTER = "ft";
 853      
 854      /**
 855      * Constant representing the url for the "src" attribute of the iframe 
 856      * used to monitor changes to the browser's base font size
 857      * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
 858      * @static
 859      * @final
 860      * @type String
 861      */
 862      Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
 863  
 864      /**
 865      * Constant representing the buffer amount (in pixels) to use when positioning
 866      * the text resize monitor offscreen. The resize monitor is positioned
 867      * offscreen by an amount eqaul to its offsetHeight + the buffer value.
 868      * 
 869      * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
 870      * @static
 871      * @type Number
 872      */
 873      // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
 874      Module.RESIZE_MONITOR_BUFFER = 1;
 875  
 876      /**
 877      * Singleton CustomEvent fired when the font size is changed in the browser.
 878      * Opera's "zoom" functionality currently does not support text 
 879      * size detection.
 880      * @event YAHOO.widget.Module.textResizeEvent
 881      */
 882      Module.textResizeEvent = new CustomEvent("textResize");
 883  
 884      /**
 885       * Helper utility method, which forces a document level 
 886       * redraw for Opera, which can help remove repaint
 887       * irregularities after applying DOM changes.
 888       *
 889       * @method YAHOO.widget.Module.forceDocumentRedraw
 890       * @static
 891       */
 892      Module.forceDocumentRedraw = function() {
 893          var docEl = document.documentElement;
 894          if (docEl) {
 895              docEl.className += " ";
 896              docEl.className = YAHOO.lang.trim(docEl.className);
 897          }
 898      };
 899  
 900      function createModuleTemplate() {
 901  
 902          if (!m_oModuleTemplate) {
 903              m_oModuleTemplate = document.createElement("div");
 904              
 905              m_oModuleTemplate.innerHTML = ("<div class=\"" + 
 906                  Module.CSS_HEADER + "\"></div>" + "<div class=\"" + 
 907                  Module.CSS_BODY + "\"></div><div class=\"" + 
 908                  Module.CSS_FOOTER + "\"></div>");
 909  
 910              m_oHeaderTemplate = m_oModuleTemplate.firstChild;
 911              m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
 912              m_oFooterTemplate = m_oBodyTemplate.nextSibling;
 913          }
 914  
 915          return m_oModuleTemplate;
 916      }
 917  
 918      function createHeader() {
 919          if (!m_oHeaderTemplate) {
 920              createModuleTemplate();
 921          }
 922          return (m_oHeaderTemplate.cloneNode(false));
 923      }
 924  
 925      function createBody() {
 926          if (!m_oBodyTemplate) {
 927              createModuleTemplate();
 928          }
 929          return (m_oBodyTemplate.cloneNode(false));
 930      }
 931  
 932      function createFooter() {
 933          if (!m_oFooterTemplate) {
 934              createModuleTemplate();
 935          }
 936          return (m_oFooterTemplate.cloneNode(false));
 937      }
 938  
 939      Module.prototype = {
 940  
 941          /**
 942          * The class's constructor function
 943          * @property contructor
 944          * @type Function
 945          */
 946          constructor: Module,
 947          
 948          /**
 949          * The main module element that contains the header, body, and footer
 950          * @property element
 951          * @type HTMLElement
 952          */
 953          element: null,
 954  
 955          /**
 956          * The header element, denoted with CSS class "hd"
 957          * @property header
 958          * @type HTMLElement
 959          */
 960          header: null,
 961  
 962          /**
 963          * The body element, denoted with CSS class "bd"
 964          * @property body
 965          * @type HTMLElement
 966          */
 967          body: null,
 968  
 969          /**
 970          * The footer element, denoted with CSS class "ft"
 971          * @property footer
 972          * @type HTMLElement
 973          */
 974          footer: null,
 975  
 976          /**
 977          * The id of the element
 978          * @property id
 979          * @type String
 980          */
 981          id: null,
 982  
 983          /**
 984          * A string representing the root path for all images created by
 985          * a Module instance.
 986          * @deprecated It is recommend that any images for a Module be applied
 987          * via CSS using the "background-image" property.
 988          * @property imageRoot
 989          * @type String
 990          */
 991          imageRoot: Module.IMG_ROOT,
 992  
 993          /**
 994          * Initializes the custom events for Module which are fired 
 995          * automatically at appropriate times by the Module class.
 996          * @method initEvents
 997          */
 998          initEvents: function () {
 999  
1000              var SIGNATURE = CustomEvent.LIST;
1001  
1002              /**
1003              * CustomEvent fired prior to class initalization.
1004              * @event beforeInitEvent
1005              * @param {class} classRef class reference of the initializing 
1006              * class, such as this.beforeInitEvent.fire(Module)
1007              */
1008              this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1009              this.beforeInitEvent.signature = SIGNATURE;
1010  
1011              /**
1012              * CustomEvent fired after class initalization.
1013              * @event initEvent
1014              * @param {class} classRef class reference of the initializing 
1015              * class, such as this.beforeInitEvent.fire(Module)
1016              */  
1017              this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1018              this.initEvent.signature = SIGNATURE;
1019  
1020              /**
1021              * CustomEvent fired when the Module is appended to the DOM
1022              * @event appendEvent
1023              */
1024              this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1025              this.appendEvent.signature = SIGNATURE;
1026  
1027              /**
1028              * CustomEvent fired before the Module is rendered
1029              * @event beforeRenderEvent
1030              */
1031              this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1032              this.beforeRenderEvent.signature = SIGNATURE;
1033          
1034              /**
1035              * CustomEvent fired after the Module is rendered
1036              * @event renderEvent
1037              */
1038              this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1039              this.renderEvent.signature = SIGNATURE;
1040          
1041              /**
1042              * CustomEvent fired when the header content of the Module 
1043              * is modified
1044              * @event changeHeaderEvent
1045              * @param {String/HTMLElement} content String/element representing 
1046              * the new header content
1047              */
1048              this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1049              this.changeHeaderEvent.signature = SIGNATURE;
1050              
1051              /**
1052              * CustomEvent fired when the body content of the Module is modified
1053              * @event changeBodyEvent
1054              * @param {String/HTMLElement} content String/element representing 
1055              * the new body content
1056              */  
1057              this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1058              this.changeBodyEvent.signature = SIGNATURE;
1059              
1060              /**
1061              * CustomEvent fired when the footer content of the Module 
1062              * is modified
1063              * @event changeFooterEvent
1064              * @param {String/HTMLElement} content String/element representing 
1065              * the new footer content
1066              */
1067              this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1068              this.changeFooterEvent.signature = SIGNATURE;
1069          
1070              /**
1071              * CustomEvent fired when the content of the Module is modified
1072              * @event changeContentEvent
1073              */
1074              this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1075              this.changeContentEvent.signature = SIGNATURE;
1076  
1077              /**
1078              * CustomEvent fired when the Module is destroyed
1079              * @event destroyEvent
1080              */
1081              this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
1082              this.destroyEvent.signature = SIGNATURE;
1083  
1084              /**
1085              * CustomEvent fired before the Module is shown
1086              * @event beforeShowEvent
1087              */
1088              this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1089              this.beforeShowEvent.signature = SIGNATURE;
1090  
1091              /**
1092              * CustomEvent fired after the Module is shown
1093              * @event showEvent
1094              */
1095              this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1096              this.showEvent.signature = SIGNATURE;
1097  
1098              /**
1099              * CustomEvent fired before the Module is hidden
1100              * @event beforeHideEvent
1101              */
1102              this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1103              this.beforeHideEvent.signature = SIGNATURE;
1104  
1105              /**
1106              * CustomEvent fired after the Module is hidden
1107              * @event hideEvent
1108              */
1109              this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1110              this.hideEvent.signature = SIGNATURE;
1111          }, 
1112  
1113          /**
1114          * String identifying whether the current platform is windows or mac. This property
1115          * currently only identifies these 2 platforms, and returns false otherwise. 
1116          * @property platform
1117          * @deprecated Use YAHOO.env.ua
1118          * @type {String|Boolean}
1119          */
1120          platform: function () {
1121              var ua = navigator.userAgent.toLowerCase();
1122  
1123              if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1124                  return "windows";
1125              } else if (ua.indexOf("macintosh") != -1) {
1126                  return "mac";
1127              } else {
1128                  return false;
1129              }
1130          }(),
1131          
1132          /**
1133          * String representing the user-agent of the browser
1134          * @deprecated Use YAHOO.env.ua
1135          * @property browser
1136          * @type {String|Boolean}
1137          */
1138          browser: function () {
1139              var ua = navigator.userAgent.toLowerCase();
1140              /*
1141                   Check Opera first in case of spoof and check Safari before
1142                   Gecko since Safari's user agent string includes "like Gecko"
1143              */
1144              if (ua.indexOf('opera') != -1) { 
1145                  return 'opera';
1146              } else if (ua.indexOf('msie 7') != -1) {
1147                  return 'ie7';
1148              } else if (ua.indexOf('msie') != -1) {
1149                  return 'ie';
1150              } else if (ua.indexOf('safari') != -1) { 
1151                  return 'safari';
1152              } else if (ua.indexOf('gecko') != -1) {
1153                  return 'gecko';
1154              } else {
1155                  return false;
1156              }
1157          }(),
1158          
1159          /**
1160          * Boolean representing whether or not the current browsing context is 
1161          * secure (https)
1162          * @property isSecure
1163          * @type Boolean
1164          */
1165          isSecure: function () {
1166              if (window.location.href.toLowerCase().indexOf("https") === 0) {
1167                  return true;
1168              } else {
1169                  return false;
1170              }
1171          }(),
1172          
1173          /**
1174          * Initializes the custom events for Module which are fired 
1175          * automatically at appropriate times by the Module class.
1176          */
1177          initDefaultConfig: function () {
1178              // Add properties //
1179              /**
1180              * Specifies whether the Module is visible on the page.
1181              * @config visible
1182              * @type Boolean
1183              * @default true
1184              */
1185              this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1186                  handler: this.configVisible, 
1187                  value: DEFAULT_CONFIG.VISIBLE.value, 
1188                  validator: DEFAULT_CONFIG.VISIBLE.validator
1189              });
1190  
1191              /**
1192              * <p>
1193              * Object or array of objects representing the ContainerEffect 
1194              * classes that are active for animating the container.
1195              * </p>
1196              * <p>
1197              * <strong>NOTE:</strong> Although this configuration 
1198              * property is introduced at the Module level, an out of the box
1199              * implementation is not shipped for the Module class so setting
1200              * the proroperty on the Module class has no effect. The Overlay 
1201              * class is the first class to provide out of the box ContainerEffect 
1202              * support.
1203              * </p>
1204              * @config effect
1205              * @type Object
1206              * @default null
1207              */
1208              this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1209                  handler: this.configEffect,
1210                  suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent, 
1211                  supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1212              });
1213  
1214              /**
1215              * Specifies whether to create a special proxy iframe to monitor 
1216              * for user font resizing in the document
1217              * @config monitorresize
1218              * @type Boolean
1219              * @default true
1220              */
1221              this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1222                  handler: this.configMonitorResize,
1223                  value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1224              });
1225  
1226              /**
1227              * Specifies if the module should be rendered as the first child 
1228              * of document.body or appended as the last child when render is called
1229              * with document.body as the "appendToNode".
1230              * <p>
1231              * Appending to the body while the DOM is still being constructed can 
1232              * lead to Operation Aborted errors in IE hence this flag is set to 
1233              * false by default.
1234              * </p>
1235              * 
1236              * @config appendtodocumentbody
1237              * @type Boolean
1238              * @default false
1239              */
1240              this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1241                  value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1242              });
1243          },
1244  
1245          /**
1246          * The Module class's initialization method, which is executed for
1247          * Module and all of its subclasses. This method is automatically 
1248          * called by the constructor, and  sets up all DOM references for 
1249          * pre-existing markup, and creates required markup if it is not 
1250          * already present.
1251          * <p>
1252          * If the element passed in does not have an id, one will be generated
1253          * for it.
1254          * </p>
1255          * @method init
1256          * @param {String} el The element ID representing the Module <em>OR</em>
1257          * @param {HTMLElement} el The element representing the Module
1258          * @param {Object} userConfig The configuration Object literal 
1259          * containing the configuration that should be set for this module. 
1260          * See configuration documentation for more details.
1261          */
1262          init: function (el, userConfig) {
1263  
1264              var elId, child;
1265  
1266              this.initEvents();
1267              this.beforeInitEvent.fire(Module);
1268  
1269              /**
1270              * The Module's Config object used for monitoring 
1271              * configuration properties.
1272              * @property cfg
1273              * @type YAHOO.util.Config
1274              */
1275              this.cfg = new Config(this);
1276  
1277              if (this.isSecure) {
1278                  this.imageRoot = Module.IMG_ROOT_SSL;
1279              }
1280  
1281              if (typeof el == "string") {
1282                  elId = el;
1283                  el = document.getElementById(el);
1284                  if (! el) {
1285                      el = (createModuleTemplate()).cloneNode(false);
1286                      el.id = elId;
1287                  }
1288              }
1289  
1290              this.id = Dom.generateId(el);
1291              this.element = el;
1292  
1293              child = this.element.firstChild;
1294  
1295              if (child) {
1296                  var fndHd = false, fndBd = false, fndFt = false;
1297                  do {
1298                      // We're looking for elements
1299                      if (1 == child.nodeType) {
1300                          if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1301                              this.header = child;
1302                              fndHd = true;
1303                          } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1304                              this.body = child;
1305                              fndBd = true;
1306                          } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1307                              this.footer = child;
1308                              fndFt = true;
1309                          }
1310                      }
1311                  } while ((child = child.nextSibling));
1312              }
1313  
1314              this.initDefaultConfig();
1315  
1316              Dom.addClass(this.element, Module.CSS_MODULE);
1317  
1318              if (userConfig) {
1319                  this.cfg.applyConfig(userConfig, true);
1320              }
1321  
1322              /*
1323                  Subscribe to the fireQueue() method of Config so that any 
1324                  queued configuration changes are excecuted upon render of 
1325                  the Module
1326              */ 
1327  
1328              if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1329                  this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1330              }
1331  
1332              this.initEvent.fire(Module);
1333          },
1334  
1335          /**
1336          * Initialize an empty IFRAME that is placed out of the visible area 
1337          * that can be used to detect text resize.
1338          * @method initResizeMonitor
1339          */
1340          initResizeMonitor: function () {
1341  
1342              var isGeckoWin = (UA.gecko && this.platform == "windows");
1343              if (isGeckoWin) {
1344                  // Help prevent spinning loading icon which 
1345                  // started with FireFox 2.0.0.8/Win
1346                  var self = this;
1347                  setTimeout(function(){self._initResizeMonitor();}, 0);
1348              } else {
1349                  this._initResizeMonitor();
1350              }
1351          },
1352  
1353          /**
1354           * Create and initialize the text resize monitoring iframe.
1355           * 
1356           * @protected
1357           * @method _initResizeMonitor
1358           */
1359          _initResizeMonitor : function() {
1360  
1361              var oDoc, 
1362                  oIFrame, 
1363                  sHTML;
1364  
1365              function fireTextResize() {
1366                  Module.textResizeEvent.fire();
1367              }
1368  
1369              if (!UA.opera) {
1370                  oIFrame = Dom.get("_yuiResizeMonitor");
1371  
1372                  var supportsCWResize = this._supportsCWResize();
1373  
1374                  if (!oIFrame) {
1375                      oIFrame = document.createElement("iframe");
1376  
1377                      if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1378                          oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1379                      }
1380  
1381                      if (!supportsCWResize) {
1382                          // Can't monitor on contentWindow, so fire from inside iframe
1383                          sHTML = ["<html><head><script ",
1384                                   "type=\"text/javascript\">",
1385                                   "window.onresize=function(){window.parent.",
1386                                   "YAHOO.widget.Module.textResizeEvent.",
1387                                   "fire();};<",
1388                                   "\/script></head>",
1389                                   "<body></body></html>"].join('');
1390  
1391                          oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1392                      }
1393  
1394                      oIFrame.id = "_yuiResizeMonitor";
1395                      oIFrame.title = "Text Resize Monitor";
1396                      oIFrame.tabIndex = -1;
1397                      oIFrame.setAttribute("role", "presentation");
1398  
1399                      /*
1400                          Need to set "position" property before inserting the 
1401                          iframe into the document or Safari's status bar will 
1402                          forever indicate the iframe is loading 
1403                          (See YUILibrary bug #1723064)
1404                      */
1405                      oIFrame.style.position = "absolute";
1406                      oIFrame.style.visibility = "hidden";
1407  
1408                      var db = document.body,
1409                          fc = db.firstChild;
1410                      if (fc) {
1411                          db.insertBefore(oIFrame, fc);
1412                      } else {
1413                          db.appendChild(oIFrame);
1414                      }
1415  
1416                      // Setting the background color fixes an issue with IE6/IE7, where
1417                      // elements in the DOM, with -ve margin-top which positioned them 
1418                      // offscreen (so they would be overlapped by the iframe and its -ve top
1419                      // setting), would have their -ve margin-top ignored, when the iframe 
1420                      // was added.
1421                      oIFrame.style.backgroundColor = "transparent";
1422  
1423                      oIFrame.style.borderWidth = "0";
1424                      oIFrame.style.width = "2em";
1425                      oIFrame.style.height = "2em";
1426                      oIFrame.style.left = "0";
1427                      oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1428                      oIFrame.style.visibility = "visible";
1429  
1430                      /*
1431                         Don't open/close the document for Gecko like we used to, since it
1432                         leads to duplicate cookies. (See YUILibrary bug #1721755)
1433                      */
1434                      if (UA.webkit) {
1435                          oDoc = oIFrame.contentWindow.document;
1436                          oDoc.open();
1437                          oDoc.close();
1438                      }
1439                  }
1440  
1441                  if (oIFrame && oIFrame.contentWindow) {
1442                      Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1443  
1444                      if (!Module.textResizeInitialized) {
1445                          if (supportsCWResize) {
1446                              if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1447                                  /*
1448                                       This will fail in IE if document.domain has 
1449                                       changed, so we must change the listener to 
1450                                       use the oIFrame element instead
1451                                  */
1452                                  Event.on(oIFrame, "resize", fireTextResize);
1453                              }
1454                          }
1455                          Module.textResizeInitialized = true;
1456                      }
1457                      this.resizeMonitor = oIFrame;
1458                  }
1459              }
1460          },
1461  
1462          /**
1463           * Text resize monitor helper method.
1464           * Determines if the browser supports resize events on iframe content windows.
1465           * 
1466           * @private
1467           * @method _supportsCWResize
1468           */
1469          _supportsCWResize : function() {
1470              /*
1471                  Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1472                  Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1473  
1474                  We don't want to start sniffing for patch versions, so fire textResize the same
1475                  way on all FF2 flavors
1476               */
1477              var bSupported = true;
1478              if (UA.gecko && UA.gecko <= 1.8) {
1479                  bSupported = false;
1480              }
1481              return bSupported;
1482          },
1483  
1484          /**
1485          * Event handler fired when the resize monitor element is resized.
1486          * @method onDomResize
1487          * @param {DOMEvent} e The DOM resize event
1488          * @param {Object} obj The scope object passed to the handler
1489          */
1490          onDomResize: function (e, obj) {
1491  
1492              var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1493  
1494              this.resizeMonitor.style.top = nTop + "px";
1495              this.resizeMonitor.style.left = "0";
1496          },
1497  
1498          /**
1499          * Sets the Module's header content to the markup specified, or appends 
1500          * the passed element to the header. 
1501          * 
1502          * If no header is present, one will 
1503          * be automatically created. An empty string can be passed to the method
1504          * to clear the contents of the header.
1505          * 
1506          * @method setHeader
1507          * @param {HTML} headerContent The markup used to set the header content.
1508          * As a convenience, non HTMLElement objects can also be passed into 
1509          * the method, and will be treated as strings, with the header innerHTML
1510          * set to their default toString implementations. 
1511          * 
1512          * <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>
1513          * 
1514          * <em>OR</em>
1515          * @param {HTMLElement} headerContent The HTMLElement to append to 
1516          * <em>OR</em>
1517          * @param {DocumentFragment} headerContent The document fragment 
1518          * containing elements which are to be added to the header
1519          */
1520          setHeader: function (headerContent) {
1521              var oHeader = this.header || (this.header = createHeader());
1522  
1523              if (headerContent.nodeName) {
1524                  oHeader.innerHTML = "";
1525                  oHeader.appendChild(headerContent);
1526              } else {
1527                  oHeader.innerHTML = headerContent;
1528              }
1529  
1530              if (this._rendered) {
1531                  this._renderHeader();
1532              }
1533  
1534              this.changeHeaderEvent.fire(headerContent);
1535              this.changeContentEvent.fire();
1536  
1537          },
1538  
1539          /**
1540          * Appends the passed element to the header. If no header is present, 
1541          * one will be automatically created.
1542          * @method appendToHeader
1543          * @param {HTMLElement | DocumentFragment} element The element to 
1544          * append to the header. In the case of a document fragment, the
1545          * children of the fragment will be appended to the header.
1546          */
1547          appendToHeader: function (element) {
1548              var oHeader = this.header || (this.header = createHeader());
1549  
1550              oHeader.appendChild(element);
1551  
1552              this.changeHeaderEvent.fire(element);
1553              this.changeContentEvent.fire();
1554  
1555          },
1556  
1557          /**
1558          * Sets the Module's body content to the HTML specified. 
1559          * 
1560          * If no body is present, one will be automatically created. 
1561          * 
1562          * An empty string can be passed to the method to clear the contents of the body.
1563          * @method setBody
1564          * @param {HTML} bodyContent The HTML used to set the body content 
1565          * As a convenience, non HTMLElement objects can also be passed into 
1566          * the method, and will be treated as strings, with the body innerHTML
1567          * set to their default toString implementations.
1568          * 
1569          * <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>
1570          * 
1571          * <em>OR</em>
1572          * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1573          * child of the body element.
1574          * <em>OR</em>
1575          * @param {DocumentFragment} bodyContent The document fragment 
1576          * containing elements which are to be added to the body
1577          */
1578          setBody: function (bodyContent) {
1579              var oBody = this.body || (this.body = createBody());
1580  
1581              if (bodyContent.nodeName) {
1582                  oBody.innerHTML = "";
1583                  oBody.appendChild(bodyContent);
1584              } else {
1585                  oBody.innerHTML = bodyContent;
1586              }
1587  
1588              if (this._rendered) {
1589                  this._renderBody();
1590              }
1591  
1592              this.changeBodyEvent.fire(bodyContent);
1593              this.changeContentEvent.fire();
1594          },
1595  
1596          /**
1597          * Appends the passed element to the body. If no body is present, one 
1598          * will be automatically created.
1599          * @method appendToBody
1600          * @param {HTMLElement | DocumentFragment} element The element to 
1601          * append to the body. In the case of a document fragment, the
1602          * children of the fragment will be appended to the body.
1603          * 
1604          */
1605          appendToBody: function (element) {
1606              var oBody = this.body || (this.body = createBody());
1607          
1608              oBody.appendChild(element);
1609  
1610              this.changeBodyEvent.fire(element);
1611              this.changeContentEvent.fire();
1612  
1613          },
1614  
1615          /**
1616          * Sets the Module's footer content to the HTML specified, or appends 
1617          * the passed element to the footer. If no footer is present, one will 
1618          * be automatically created. An empty string can be passed to the method
1619          * to clear the contents of the footer.
1620          * @method setFooter
1621          * @param {HTML} footerContent The HTML used to set the footer 
1622          * As a convenience, non HTMLElement objects can also be passed into 
1623          * the method, and will be treated as strings, with the footer innerHTML
1624          * set to their default toString implementations.
1625          * 
1626          * <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>
1627          * 
1628          * <em>OR</em>
1629          * @param {HTMLElement} footerContent The HTMLElement to append to 
1630          * the footer
1631          * <em>OR</em>
1632          * @param {DocumentFragment} footerContent The document fragment containing 
1633          * elements which are to be added to the footer
1634          */
1635          setFooter: function (footerContent) {
1636  
1637              var oFooter = this.footer || (this.footer = createFooter());
1638  
1639              if (footerContent.nodeName) {
1640                  oFooter.innerHTML = "";
1641                  oFooter.appendChild(footerContent);
1642              } else {
1643                  oFooter.innerHTML = footerContent;
1644              }
1645  
1646              if (this._rendered) {
1647                  this._renderFooter();
1648              }
1649  
1650              this.changeFooterEvent.fire(footerContent);
1651              this.changeContentEvent.fire();
1652          },
1653  
1654          /**
1655          * Appends the passed element to the footer. If no footer is present, 
1656          * one will be automatically created.
1657          * @method appendToFooter
1658          * @param {HTMLElement | DocumentFragment} element The element to 
1659          * append to the footer. In the case of a document fragment, the
1660          * children of the fragment will be appended to the footer
1661          */
1662          appendToFooter: function (element) {
1663  
1664              var oFooter = this.footer || (this.footer = createFooter());
1665  
1666              oFooter.appendChild(element);
1667  
1668              this.changeFooterEvent.fire(element);
1669              this.changeContentEvent.fire();
1670  
1671          },
1672  
1673          /**
1674          * Renders the Module by inserting the elements that are not already 
1675          * in the main Module into their correct places. Optionally appends 
1676          * the Module to the specified node prior to the render's execution. 
1677          * <p>
1678          * For Modules without existing markup, the appendToNode argument 
1679          * is REQUIRED. If this argument is ommitted and the current element is 
1680          * not present in the document, the function will return false, 
1681          * indicating that the render was a failure.
1682          * </p>
1683          * <p>
1684          * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1685          * then the module is rendered as the first child of the body element, 
1686          * and not appended to it, to avoid Operation Aborted errors in IE when 
1687          * rendering the module before window's load event is fired. You can 
1688          * use the appendtodocumentbody configuration property to change this 
1689          * to append to document.body if required.
1690          * </p>
1691          * @method render
1692          * @param {String} appendToNode The element id to which the Module 
1693          * should be appended to prior to rendering <em>OR</em>
1694          * @param {HTMLElement} appendToNode The element to which the Module 
1695          * should be appended to prior to rendering
1696          * @param {HTMLElement} moduleElement OPTIONAL. The element that 
1697          * represents the actual Standard Module container.
1698          * @return {Boolean} Success or failure of the render
1699          */
1700          render: function (appendToNode, moduleElement) {
1701  
1702              var me = this;
1703  
1704              function appendTo(parentNode) {
1705                  if (typeof parentNode == "string") {
1706                      parentNode = document.getElementById(parentNode);
1707                  }
1708  
1709                  if (parentNode) {
1710                      me._addToParent(parentNode, me.element);
1711                      me.appendEvent.fire();
1712                  }
1713              }
1714  
1715              this.beforeRenderEvent.fire();
1716  
1717              if (! moduleElement) {
1718                  moduleElement = this.element;
1719              }
1720  
1721              if (appendToNode) {
1722                  appendTo(appendToNode);
1723              } else { 
1724                  // No node was passed in. If the element is not already in the Dom, this fails
1725                  if (! Dom.inDocument(this.element)) {
1726                      YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
1727                      return false;
1728                  }
1729              }
1730  
1731              this._renderHeader(moduleElement);
1732              this._renderBody(moduleElement);
1733              this._renderFooter(moduleElement);
1734  
1735              this._rendered = true;
1736  
1737              this.renderEvent.fire();
1738              return true;
1739          },
1740  
1741          /**
1742           * Renders the currently set header into it's proper position under the 
1743           * module element. If the module element is not provided, "this.element" 
1744           * is used.
1745           * 
1746           * @method _renderHeader
1747           * @protected
1748           * @param {HTMLElement} moduleElement Optional. A reference to the module element
1749           */
1750          _renderHeader: function(moduleElement){
1751              moduleElement = moduleElement || this.element;
1752  
1753              // Need to get everything into the DOM if it isn't already
1754              if (this.header && !Dom.inDocument(this.header)) {
1755                  // There is a header, but it's not in the DOM yet. Need to add it.
1756                  var firstChild = moduleElement.firstChild;
1757                  if (firstChild) {
1758                      moduleElement.insertBefore(this.header, firstChild);
1759                  } else {
1760                      moduleElement.appendChild(this.header);
1761                  }
1762              }
1763          },
1764  
1765          /**
1766           * Renders the currently set body into it's proper position under the 
1767           * module element. If the module element is not provided, "this.element" 
1768           * is used.
1769           * 
1770           * @method _renderBody
1771           * @protected
1772           * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1773           */
1774          _renderBody: function(moduleElement){
1775              moduleElement = moduleElement || this.element;
1776  
1777              if (this.body && !Dom.inDocument(this.body)) {
1778                  // There is a body, but it's not in the DOM yet. Need to add it.
1779                  if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1780                      moduleElement.insertBefore(this.body, this.footer);
1781                  } else {
1782                      moduleElement.appendChild(this.body);
1783                  }
1784              }
1785          },
1786  
1787          /**
1788           * Renders the currently set footer into it's proper position under the 
1789           * module element. If the module element is not provided, "this.element" 
1790           * is used.
1791           * 
1792           * @method _renderFooter
1793           * @protected
1794           * @param {HTMLElement} moduleElement Optional. A reference to the module element
1795           */
1796          _renderFooter: function(moduleElement){
1797              moduleElement = moduleElement || this.element;
1798  
1799              if (this.footer && !Dom.inDocument(this.footer)) {
1800                  // There is a footer, but it's not in the DOM yet. Need to add it.
1801                  moduleElement.appendChild(this.footer);
1802              }
1803          },
1804  
1805          /**
1806          * Removes the Module element from the DOM, sets all child elements to null, and purges the bounding element of event listeners.
1807          * @method destroy
1808          * @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. 
1809          * 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.
1810          */
1811          destroy: function (shallowPurge) {
1812  
1813              var parent,
1814                  purgeChildren = !(shallowPurge);
1815  
1816              if (this.element) {
1817                  Event.purgeElement(this.element, purgeChildren);
1818                  parent = this.element.parentNode;
1819              }
1820  
1821              if (parent) {
1822                  parent.removeChild(this.element);
1823              }
1824          
1825              this.element = null;
1826              this.header = null;
1827              this.body = null;
1828              this.footer = null;
1829  
1830              Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1831  
1832              this.cfg.destroy();
1833              this.cfg = null;
1834  
1835              this.destroyEvent.fire();
1836          },
1837  
1838          /**
1839          * Shows the Module element by setting the visible configuration 
1840          * property to true. Also fires two events: beforeShowEvent prior to 
1841          * the visibility change, and showEvent after.
1842          * @method show
1843          */
1844          show: function () {
1845              this.cfg.setProperty("visible", true);
1846          },
1847  
1848          /**
1849          * Hides the Module element by setting the visible configuration 
1850          * property to false. Also fires two events: beforeHideEvent prior to 
1851          * the visibility change, and hideEvent after.
1852          * @method hide
1853          */
1854          hide: function () {
1855              this.cfg.setProperty("visible", false);
1856          },
1857          
1858          // BUILT-IN EVENT HANDLERS FOR MODULE //
1859          /**
1860          * Default event handler for changing the visibility property of a 
1861          * Module. By default, this is achieved by switching the "display" style 
1862          * between "block" and "none".
1863          * This method is responsible for firing showEvent and hideEvent.
1864          * @param {String} type The CustomEvent type (usually the property name)
1865          * @param {Object[]} args The CustomEvent arguments. For configuration 
1866          * handlers, args[0] will equal the newly applied value for the property.
1867          * @param {Object} obj The scope object. For configuration handlers, 
1868          * this will usually equal the owner.
1869          * @method configVisible
1870          */
1871          configVisible: function (type, args, obj) {
1872              var visible = args[0];
1873              if (visible) {
1874                  if(this.beforeShowEvent.fire()) {
1875                      Dom.setStyle(this.element, "display", "block");
1876                      this.showEvent.fire();
1877                  }
1878              } else {
1879                  if (this.beforeHideEvent.fire()) {
1880                      Dom.setStyle(this.element, "display", "none");
1881                      this.hideEvent.fire();
1882                  }
1883              }
1884          },
1885  
1886          /**
1887          * Default event handler for the "effect" configuration property
1888          * @param {String} type The CustomEvent type (usually the property name)
1889          * @param {Object[]} args The CustomEvent arguments. For configuration 
1890          * handlers, args[0] will equal the newly applied value for the property.
1891          * @param {Object} obj The scope object. For configuration handlers, 
1892          * this will usually equal the owner.
1893          * @method configEffect
1894          */
1895          configEffect: function (type, args, obj) {
1896              this._cachedEffects = (this.cacheEffects) ? this._createEffects(args[0]) : null;
1897          },
1898  
1899          /**
1900           * If true, ContainerEffects (and Anim instances) are cached when "effect" is set, and reused. 
1901           * If false, new instances are created each time the container is hidden or shown, as was the 
1902           * behavior prior to 2.9.0. 
1903           *
1904           * @property cacheEffects
1905           * @since 2.9.0
1906           * @default true
1907           * @type boolean
1908           */
1909          cacheEffects : true,
1910  
1911          /**
1912           * Creates an array of ContainerEffect instances from the provided configs
1913           * 
1914           * @method _createEffects
1915           * @param {Array|Object} effectCfg An effect configuration or array of effect configurations
1916           * @return {Array} An array of ContainerEffect instances.
1917           * @protected
1918           */
1919          _createEffects: function(effectCfg) {
1920              var effectInstances = null,
1921                  n, 
1922                  i,
1923                  eff;
1924  
1925              if (effectCfg) {
1926                  if (effectCfg instanceof Array) {
1927                      effectInstances = [];
1928                      n = effectCfg.length;
1929                      for (i = 0; i < n; i++) {
1930                          eff = effectCfg[i];
1931                          if (eff.effect) {
1932                              effectInstances[effectInstances.length] = eff.effect(this, eff.duration);
1933                          }
1934                      }
1935                  } else if (effectCfg.effect) {
1936                      effectInstances = [effectCfg.effect(this, effectCfg.duration)];
1937                  }
1938              }
1939  
1940              return effectInstances;
1941          },
1942  
1943          /**
1944          * Default event handler for the "monitorresize" configuration property
1945          * @param {String} type The CustomEvent type (usually the property name)
1946          * @param {Object[]} args The CustomEvent arguments. For configuration 
1947          * handlers, args[0] will equal the newly applied value for the property.
1948          * @param {Object} obj The scope object. For configuration handlers, 
1949          * this will usually equal the owner.
1950          * @method configMonitorResize
1951          */
1952          configMonitorResize: function (type, args, obj) {
1953              var monitor = args[0];
1954              if (monitor) {
1955                  this.initResizeMonitor();
1956              } else {
1957                  Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1958                  this.resizeMonitor = null;
1959              }
1960          },
1961  
1962          /**
1963           * This method is a protected helper, used when constructing the DOM structure for the module 
1964           * to account for situations which may cause Operation Aborted errors in IE. It should not 
1965           * be used for general DOM construction.
1966           * <p>
1967           * If the parentNode is not document.body, the element is appended as the last element.
1968           * </p>
1969           * <p>
1970           * If the parentNode is document.body the element is added as the first child to help
1971           * prevent Operation Aborted errors in IE.
1972           * </p>
1973           *
1974           * @param {parentNode} The HTML element to which the element will be added
1975           * @param {element} The HTML element to be added to parentNode's children
1976           * @method _addToParent
1977           * @protected
1978           */
1979          _addToParent: function(parentNode, element) {
1980              if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1981                  parentNode.insertBefore(element, parentNode.firstChild);
1982              } else {
1983                  parentNode.appendChild(element);
1984              }
1985          },
1986  
1987          /**
1988          * Returns a String representation of the Object.
1989          * @method toString
1990          * @return {String} The string representation of the Module
1991          */
1992          toString: function () {
1993              return "Module " + this.id;
1994          }
1995      };
1996  
1997      YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1998  
1999  }());
2000  (function () {
2001  
2002      /**
2003      * Overlay is a Module that is absolutely positioned above the page flow. It 
2004      * has convenience methods for positioning and sizing, as well as options for 
2005      * controlling zIndex and constraining the Overlay's position to the current 
2006      * visible viewport. Overlay also contains a dynamicly generated IFRAME which 
2007      * is placed beneath it for Internet Explorer 6 and 5.x so that it will be 
2008      * properly rendered above SELECT elements.
2009      * @namespace YAHOO.widget
2010      * @class Overlay
2011      * @extends YAHOO.widget.Module
2012      * @param {String} el The element ID representing the Overlay <em>OR</em>
2013      * @param {HTMLElement} el The element representing the Overlay
2014      * @param {Object} userConfig The configuration object literal containing 
2015      * the configuration that should be set for this Overlay. See configuration 
2016      * documentation for more details.
2017      * @constructor
2018      */
2019      YAHOO.widget.Overlay = function (el, userConfig) {
2020          YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
2021      };
2022  
2023      var Lang = YAHOO.lang,
2024          CustomEvent = YAHOO.util.CustomEvent,
2025          Module = YAHOO.widget.Module,
2026          Event = YAHOO.util.Event,
2027          Dom = YAHOO.util.Dom,
2028          Config = YAHOO.util.Config,
2029          UA = YAHOO.env.ua,
2030          Overlay = YAHOO.widget.Overlay,
2031  
2032          _SUBSCRIBE = "subscribe",
2033          _UNSUBSCRIBE = "unsubscribe",
2034          _CONTAINED = "contained",
2035  
2036          m_oIFrameTemplate,
2037  
2038          /**
2039          * Constant representing the name of the Overlay's events
2040          * @property EVENT_TYPES
2041          * @private
2042          * @final
2043          * @type Object
2044          */
2045          EVENT_TYPES = {
2046              "BEFORE_MOVE": "beforeMove",
2047              "MOVE": "move"
2048          },
2049  
2050          /**
2051          * Constant representing the Overlay's configuration properties
2052          * @property DEFAULT_CONFIG
2053          * @private
2054          * @final
2055          * @type Object
2056          */
2057          DEFAULT_CONFIG = {
2058  
2059              "X": { 
2060                  key: "x", 
2061                  validator: Lang.isNumber, 
2062                  suppressEvent: true, 
2063                  supercedes: ["iframe"]
2064              },
2065  
2066              "Y": { 
2067                  key: "y", 
2068                  validator: Lang.isNumber, 
2069                  suppressEvent: true, 
2070                  supercedes: ["iframe"]
2071              },
2072  
2073              "XY": { 
2074                  key: "xy", 
2075                  suppressEvent: true, 
2076                  supercedes: ["iframe"] 
2077              },
2078  
2079              "CONTEXT": { 
2080                  key: "context", 
2081                  suppressEvent: true, 
2082                  supercedes: ["iframe"] 
2083              },
2084  
2085              "FIXED_CENTER": { 
2086                  key: "fixedcenter", 
2087                  value: false, 
2088                  supercedes: ["iframe", "visible"] 
2089              },
2090  
2091              "WIDTH": { 
2092                  key: "width",
2093                  suppressEvent: true,
2094                  supercedes: ["context", "fixedcenter", "iframe"]
2095              }, 
2096  
2097              "HEIGHT": { 
2098                  key: "height", 
2099                  suppressEvent: true, 
2100                  supercedes: ["context", "fixedcenter", "iframe"] 
2101              },
2102  
2103              "AUTO_FILL_HEIGHT" : {
2104                  key: "autofillheight",
2105                  supercedes: ["height"],
2106                  value:"body"
2107              },
2108  
2109              "ZINDEX": { 
2110                  key: "zindex", 
2111                  value: null 
2112              },
2113  
2114              "CONSTRAIN_TO_VIEWPORT": { 
2115                  key: "constraintoviewport", 
2116                  value: false, 
2117                  validator: Lang.isBoolean, 
2118                  supercedes: ["iframe", "x", "y", "xy"]
2119              }, 
2120  
2121              "IFRAME": { 
2122                  key: "iframe", 
2123                  value: (UA.ie == 6 ? true : false), 
2124                  validator: Lang.isBoolean, 
2125                  supercedes: ["zindex"] 
2126              },
2127  
2128              "PREVENT_CONTEXT_OVERLAP": {
2129                  key: "preventcontextoverlap",
2130                  value: false,
2131                  validator: Lang.isBoolean,  
2132                  supercedes: ["constraintoviewport"]
2133              }
2134  
2135          };
2136  
2137      /**
2138      * The URL that will be placed in the iframe
2139      * @property YAHOO.widget.Overlay.IFRAME_SRC
2140      * @static
2141      * @final
2142      * @type String
2143      */
2144      Overlay.IFRAME_SRC = "javascript:false;";
2145  
2146      /**
2147      * Number representing how much the iframe shim should be offset from each 
2148      * side of an Overlay instance, in pixels.
2149      * @property YAHOO.widget.Overlay.IFRAME_SRC
2150      * @default 3
2151      * @static
2152      * @final
2153      * @type Number
2154      */
2155      Overlay.IFRAME_OFFSET = 3;
2156  
2157      /**
2158      * Number representing the minimum distance an Overlay instance should be 
2159      * positioned relative to the boundaries of the browser's viewport, in pixels.
2160      * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2161      * @default 10
2162      * @static
2163      * @final
2164      * @type Number
2165      */
2166      Overlay.VIEWPORT_OFFSET = 10;
2167  
2168      /**
2169      * Constant representing the top left corner of an element, used for 
2170      * configuring the context element alignment
2171      * @property YAHOO.widget.Overlay.TOP_LEFT
2172      * @static
2173      * @final
2174      * @type String
2175      */
2176      Overlay.TOP_LEFT = "tl";
2177  
2178      /**
2179      * Constant representing the top right corner of an element, used for 
2180      * configuring the context element alignment
2181      * @property YAHOO.widget.Overlay.TOP_RIGHT
2182      * @static
2183      * @final
2184      * @type String
2185      */
2186      Overlay.TOP_RIGHT = "tr";
2187  
2188      /**
2189      * Constant representing the top bottom left corner of an element, used for 
2190      * configuring the context element alignment
2191      * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2192      * @static
2193      * @final
2194      * @type String
2195      */
2196      Overlay.BOTTOM_LEFT = "bl";
2197  
2198      /**
2199      * Constant representing the bottom right corner of an element, used for 
2200      * configuring the context element alignment
2201      * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2202      * @static
2203      * @final
2204      * @type String
2205      */
2206      Overlay.BOTTOM_RIGHT = "br";
2207  
2208      Overlay.PREVENT_OVERLAP_X = {
2209          "tltr": true,
2210          "blbr": true,
2211          "brbl": true,
2212          "trtl": true
2213      };
2214              
2215      Overlay.PREVENT_OVERLAP_Y = {
2216          "trbr": true,
2217          "tlbl": true,
2218          "bltl": true,
2219          "brtr": true
2220      };
2221  
2222      /**
2223      * Constant representing the default CSS class used for an Overlay
2224      * @property YAHOO.widget.Overlay.CSS_OVERLAY
2225      * @static
2226      * @final
2227      * @type String
2228      */
2229      Overlay.CSS_OVERLAY = "yui-overlay";
2230  
2231      /**
2232      * Constant representing the default hidden CSS class used for an Overlay. This class is 
2233      * applied to the overlay's outer DIV whenever it's hidden.
2234      *
2235      * @property YAHOO.widget.Overlay.CSS_HIDDEN
2236      * @static
2237      * @final
2238      * @type String
2239      */
2240      Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2241  
2242      /**
2243      * Constant representing the default CSS class used for an Overlay iframe shim.
2244      * 
2245      * @property YAHOO.widget.Overlay.CSS_IFRAME
2246      * @static
2247      * @final
2248      * @type String
2249      */
2250      Overlay.CSS_IFRAME = "yui-overlay-iframe";
2251  
2252      /**
2253       * Constant representing the names of the standard module elements
2254       * used in the overlay.
2255       * @property YAHOO.widget.Overlay.STD_MOD_RE
2256       * @static
2257       * @final
2258       * @type RegExp
2259       */
2260      Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2261  
2262      /**
2263      * A singleton CustomEvent used for reacting to the DOM event for 
2264      * window scroll
2265      * @event YAHOO.widget.Overlay.windowScrollEvent
2266      */
2267      Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2268  
2269      /**
2270      * A singleton CustomEvent used for reacting to the DOM event for
2271      * window resize
2272      * @event YAHOO.widget.Overlay.windowResizeEvent
2273      */
2274      Overlay.windowResizeEvent = new CustomEvent("windowResize");
2275  
2276      /**
2277      * The DOM event handler used to fire the CustomEvent for window scroll
2278      * @method YAHOO.widget.Overlay.windowScrollHandler
2279      * @static
2280      * @param {DOMEvent} e The DOM scroll event
2281      */
2282      Overlay.windowScrollHandler = function (e) {
2283          var t = Event.getTarget(e);
2284  
2285          // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2286          // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2287          // - IE doesn't recognize scroll registered on the document.
2288          //
2289          // Also, when document view is scrolled, IE doesn't provide a target, 
2290          // rest of the browsers set target to window.document, apart from opera 
2291          // which sets target to window.
2292          if (!t || t === window || t === window.document) {
2293              if (UA.ie) {
2294  
2295                  if (! window.scrollEnd) {
2296                      window.scrollEnd = -1;
2297                  }
2298  
2299                  clearTimeout(window.scrollEnd);
2300          
2301                  window.scrollEnd = setTimeout(function () { 
2302                      Overlay.windowScrollEvent.fire(); 
2303                  }, 1);
2304          
2305              } else {
2306                  Overlay.windowScrollEvent.fire();
2307              }
2308          }
2309      };
2310  
2311      /**
2312      * The DOM event handler used to fire the CustomEvent for window resize
2313      * @method YAHOO.widget.Overlay.windowResizeHandler
2314      * @static
2315      * @param {DOMEvent} e The DOM resize event
2316      */
2317      Overlay.windowResizeHandler = function (e) {
2318  
2319          if (UA.ie) {
2320              if (! window.resizeEnd) {
2321                  window.resizeEnd = -1;
2322              }
2323  
2324              clearTimeout(window.resizeEnd);
2325  
2326              window.resizeEnd = setTimeout(function () {
2327                  Overlay.windowResizeEvent.fire(); 
2328              }, 100);
2329          } else {
2330              Overlay.windowResizeEvent.fire();
2331          }
2332      };
2333  
2334      /**
2335      * A boolean that indicated whether the window resize and scroll events have 
2336      * already been subscribed to.
2337      * @property YAHOO.widget.Overlay._initialized
2338      * @private
2339      * @type Boolean
2340      */
2341      Overlay._initialized = null;
2342  
2343      if (Overlay._initialized === null) {
2344          Event.on(window, "scroll", Overlay.windowScrollHandler);
2345          Event.on(window, "resize", Overlay.windowResizeHandler);
2346          Overlay._initialized = true;
2347      }
2348  
2349      /**
2350       * Internal map of special event types, which are provided
2351       * by the instance. It maps the event type to the custom event 
2352       * instance. Contains entries for the "windowScroll", "windowResize" and
2353       * "textResize" static container events.
2354       *
2355       * @property YAHOO.widget.Overlay._TRIGGER_MAP
2356       * @type Object
2357       * @static
2358       * @private
2359       */
2360      Overlay._TRIGGER_MAP = {
2361          "windowScroll" : Overlay.windowScrollEvent,
2362          "windowResize" : Overlay.windowResizeEvent,
2363          "textResize"   : Module.textResizeEvent
2364      };
2365  
2366      YAHOO.extend(Overlay, Module, {
2367  
2368          /**
2369           * <p>
2370           * Array of default event types which will trigger
2371           * context alignment for the Overlay class.
2372           * </p>
2373           * <p>The array is empty by default for Overlay,
2374           * but maybe populated in future releases, so classes extending
2375           * Overlay which need to define their own set of CONTEXT_TRIGGERS
2376           * should concatenate their super class's prototype.CONTEXT_TRIGGERS 
2377           * value with their own array of values.
2378           * </p>
2379           * <p>
2380           * E.g.:
2381           * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2382           * </p>
2383           * 
2384           * @property CONTEXT_TRIGGERS
2385           * @type Array
2386           * @final
2387           */
2388          CONTEXT_TRIGGERS : [],
2389  
2390          /**
2391          * The Overlay initialization method, which is executed for Overlay and  
2392          * all of its subclasses. This method is automatically called by the 
2393          * constructor, and  sets up all DOM references for pre-existing markup, 
2394          * and creates required markup if it is not already present.
2395          * @method init
2396          * @param {String} el The element ID representing the Overlay <em>OR</em>
2397          * @param {HTMLElement} el The element representing the Overlay
2398          * @param {Object} userConfig The configuration object literal 
2399          * containing the configuration that should be set for this Overlay. 
2400          * See configuration documentation for more details.
2401          */
2402          init: function (el, userConfig) {
2403  
2404              /*
2405                   Note that we don't pass the user config in here yet because we
2406                   only want it executed once, at the lowest subclass level
2407              */
2408  
2409              Overlay.superclass.init.call(this, el/*, userConfig*/);
2410  
2411              this.beforeInitEvent.fire(Overlay);
2412  
2413              Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2414  
2415              if (userConfig) {
2416                  this.cfg.applyConfig(userConfig, true);
2417              }
2418  
2419              if (this.platform == "mac" && UA.gecko) {
2420  
2421                  if (! Config.alreadySubscribed(this.showEvent,
2422                      this.showMacGeckoScrollbars, this)) {
2423  
2424                      this.showEvent.subscribe(this.showMacGeckoScrollbars, 
2425                          this, true);
2426  
2427                  }
2428  
2429                  if (! Config.alreadySubscribed(this.hideEvent, 
2430                      this.hideMacGeckoScrollbars, this)) {
2431  
2432                      this.hideEvent.subscribe(this.hideMacGeckoScrollbars, 
2433                          this, true);
2434  
2435                  }
2436              }
2437  
2438              this.initEvent.fire(Overlay);
2439          },
2440          
2441          /**
2442          * Initializes the custom events for Overlay which are fired  
2443          * automatically at appropriate times by the Overlay class.
2444          * @method initEvents
2445          */
2446          initEvents: function () {
2447  
2448              Overlay.superclass.initEvents.call(this);
2449  
2450              var SIGNATURE = CustomEvent.LIST;
2451  
2452              /**
2453              * CustomEvent fired before the Overlay is moved.
2454              * @event beforeMoveEvent
2455              * @param {Number} x x coordinate
2456              * @param {Number} y y coordinate
2457              */
2458              this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2459              this.beforeMoveEvent.signature = SIGNATURE;
2460  
2461              /**
2462              * CustomEvent fired after the Overlay is moved.
2463              * @event moveEvent
2464              * @param {Number} x x coordinate
2465              * @param {Number} y y coordinate
2466              */
2467              this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2468              this.moveEvent.signature = SIGNATURE;
2469  
2470          },
2471          
2472          /**
2473          * Initializes the class's configurable properties which can be changed 
2474          * using the Overlay's Config object (cfg).
2475          * @method initDefaultConfig
2476          */
2477          initDefaultConfig: function () {
2478      
2479              Overlay.superclass.initDefaultConfig.call(this);
2480  
2481              var cfg = this.cfg;
2482  
2483              // Add overlay config properties //
2484              
2485              /**
2486              * The absolute x-coordinate position of the Overlay
2487              * @config x
2488              * @type Number
2489              * @default null
2490              */
2491              cfg.addProperty(DEFAULT_CONFIG.X.key, { 
2492      
2493                  handler: this.configX, 
2494                  validator: DEFAULT_CONFIG.X.validator, 
2495                  suppressEvent: DEFAULT_CONFIG.X.suppressEvent, 
2496                  supercedes: DEFAULT_CONFIG.X.supercedes
2497      
2498              });
2499  
2500              /**
2501              * The absolute y-coordinate position of the Overlay
2502              * @config y
2503              * @type Number
2504              * @default null
2505              */
2506              cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2507  
2508                  handler: this.configY, 
2509                  validator: DEFAULT_CONFIG.Y.validator, 
2510                  suppressEvent: DEFAULT_CONFIG.Y.suppressEvent, 
2511                  supercedes: DEFAULT_CONFIG.Y.supercedes
2512  
2513              });
2514  
2515              /**
2516              * An array with the absolute x and y positions of the Overlay
2517              * @config xy
2518              * @type Number[]
2519              * @default null
2520              */
2521              cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2522                  handler: this.configXY, 
2523                  suppressEvent: DEFAULT_CONFIG.XY.suppressEvent, 
2524                  supercedes: DEFAULT_CONFIG.XY.supercedes
2525              });
2526  
2527              /**
2528              * <p>
2529              * The array of context arguments for context-sensitive positioning. 
2530              * </p>
2531              *
2532              * <p>
2533              * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2534              * the 5 array elements described in detail below:
2535              * </p>
2536              *
2537              * <dl>
2538              * <dt>contextElementOrId &#60;String|HTMLElement&#62;</dt>
2539              * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2540              * <dt>overlayCorner &#60;String&#62;</dt>
2541              * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the 
2542              * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are: 
2543              * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2544              * <dt>contextCorner &#60;String&#62;</dt>
2545              * <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>
2546              * <dt>arrayOfTriggerEvents (optional) &#60;Array[String|CustomEvent]&#62;</dt>
2547              * <dd>
2548              * <p>
2549              * 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> 
2550              * 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. 
2551              * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2552              * </p>
2553              * <p>
2554              * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2555              * 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).
2556              * </p>
2557              * </dd>
2558              * <dt>xyOffset &#60;Number[]&#62;</dt>
2559              * <dd>
2560              * 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.
2561              * 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. 
2562              * </dd>
2563              * </dl>
2564              *
2565              * <p>
2566              * For example, setting this property to <code>["img1", "tl", "bl"]</code> will 
2567              * align the Overlay's top left corner to the bottom left corner of the
2568              * context element with id "img1".
2569              * </p>
2570              * <p>
2571              * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will 
2572              * align the Overlay's top left corner to the bottom left corner of the
2573              * 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).
2574              * </p>
2575              * <p>
2576              * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2577              * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2578              * </p>
2579              *
2580              * @config context
2581              * @type Array
2582              * @default null
2583              */
2584              cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2585                  handler: this.configContext, 
2586                  suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent, 
2587                  supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2588              });
2589  
2590              /**
2591              * Determines whether or not the Overlay should be anchored 
2592              * to the center of the viewport.
2593              * 
2594              * <p>This property can be set to:</p>
2595              * 
2596              * <dl>
2597              * <dt>true</dt>
2598              * <dd>
2599              * To enable fixed center positioning
2600              * <p>
2601              * When enabled, the overlay will 
2602              * be positioned in the center of viewport when initially displayed, and 
2603              * will remain in the center of the viewport whenever the window is 
2604              * scrolled or resized.
2605              * </p>
2606              * <p>
2607              * If the overlay is too big for the viewport, 
2608              * it's top left corner will be aligned with the top left corner of the viewport.
2609              * </p>
2610              * </dd>
2611              * <dt>false</dt>
2612              * <dd>
2613              * To disable fixed center positioning.
2614              * <p>In this case the overlay can still be 
2615              * centered as a one-off operation, by invoking the <code>center()</code> method,
2616              * however it will not remain centered when the window is scrolled/resized.
2617              * </dd>
2618              * <dt>"contained"<dt>
2619              * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2620              * <p>However, unlike setting the property to <code>true</code>, 
2621              * when the property is set to <code>"contained"</code>, if the overlay is 
2622              * too big for the viewport, it will not get automatically centered when the 
2623              * user scrolls or resizes the window (until the window is large enough to contain the 
2624              * overlay). This is useful in cases where the Overlay has both header and footer 
2625              * UI controls which the user may need to access.
2626              * </p>
2627              * </dd>
2628              * </dl>
2629              *
2630              * @config fixedcenter
2631              * @type Boolean | String
2632              * @default false
2633              */
2634              cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2635                  handler: this.configFixedCenter,
2636                  value: DEFAULT_CONFIG.FIXED_CENTER.value, 
2637                  validator: DEFAULT_CONFIG.FIXED_CENTER.validator, 
2638                  supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2639              });
2640      
2641              /**
2642              * CSS width of the Overlay.
2643              * @config width
2644              * @type String
2645              * @default null
2646              */
2647              cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2648                  handler: this.configWidth, 
2649                  suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent, 
2650                  supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2651              });
2652  
2653              /**
2654              * CSS height of the Overlay.
2655              * @config height
2656              * @type String
2657              * @default null
2658              */
2659              cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2660                  handler: this.configHeight, 
2661                  suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent, 
2662                  supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2663              });
2664  
2665              /**
2666              * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2667              * Supported values are "header", "body", "footer".
2668              *
2669              * @config autofillheight
2670              * @type String
2671              * @default null
2672              */
2673              cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2674                  handler: this.configAutoFillHeight, 
2675                  value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2676                  validator : this._validateAutoFill,
2677                  supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2678              });
2679  
2680              /**
2681              * CSS z-index of the Overlay.
2682              * @config zIndex
2683              * @type Number
2684              * @default null
2685              */
2686              cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2687                  handler: this.configzIndex,
2688                  value: DEFAULT_CONFIG.ZINDEX.value
2689              });
2690  
2691              /**
2692              * True if the Overlay should be prevented from being positioned 
2693              * out of the viewport.
2694              * @config constraintoviewport
2695              * @type Boolean
2696              * @default false
2697              */
2698              cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2699  
2700                  handler: this.configConstrainToViewport, 
2701                  value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value, 
2702                  validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator, 
2703                  supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2704  
2705              });
2706  
2707              /**
2708              * @config iframe
2709              * @description Boolean indicating whether or not the Overlay should 
2710              * have an IFRAME shim; used to prevent SELECT elements from 
2711              * poking through an Overlay instance in IE6.  When set to "true", 
2712              * the iframe shim is created when the Overlay instance is intially
2713              * made visible.
2714              * @type Boolean
2715              * @default true for IE6 and below, false for all other browsers.
2716              */
2717              cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2718  
2719                  handler: this.configIframe, 
2720                  value: DEFAULT_CONFIG.IFRAME.value, 
2721                  validator: DEFAULT_CONFIG.IFRAME.validator, 
2722                  supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2723  
2724              });
2725  
2726              /**
2727              * @config preventcontextoverlap
2728              * @description Boolean indicating whether or not the Overlay should overlap its 
2729              * context element (defined using the "context" configuration property) when the 
2730              * "constraintoviewport" configuration property is set to "true".
2731              * @type Boolean
2732              * @default false
2733              */
2734              cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2735                  value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value, 
2736                  validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator, 
2737                  supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2738              });
2739          },
2740  
2741          /**
2742          * Moves the Overlay to the specified position. This function is  
2743          * identical to calling this.cfg.setProperty("xy", [x,y]);
2744          * @method moveTo
2745          * @param {Number} x The Overlay's new x position
2746          * @param {Number} y The Overlay's new y position
2747          */
2748          moveTo: function (x, y) {
2749              this.cfg.setProperty("xy", [x, y]);
2750          },
2751  
2752          /**
2753          * Adds a CSS class ("hide-scrollbars") and removes a CSS class 
2754          * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X 
2755          * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2756          * @method hideMacGeckoScrollbars
2757          */
2758          hideMacGeckoScrollbars: function () {
2759              Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2760          },
2761  
2762          /**
2763          * Adds a CSS class ("show-scrollbars") and removes a CSS class 
2764          * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X 
2765          * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2766          * @method showMacGeckoScrollbars
2767          */
2768          showMacGeckoScrollbars: function () {
2769              Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2770          },
2771  
2772          /**
2773           * Internal implementation to set the visibility of the overlay in the DOM.
2774           *
2775           * @method _setDomVisibility
2776           * @param {boolean} visible Whether to show or hide the Overlay's outer element
2777           * @protected
2778           */
2779          _setDomVisibility : function(show) {
2780              Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2781              var hiddenClass = Overlay.CSS_HIDDEN;
2782  
2783              if (show) {
2784                  Dom.removeClass(this.element, hiddenClass);
2785              } else {
2786                  Dom.addClass(this.element, hiddenClass);
2787              }
2788          },
2789  
2790          // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2791          /**
2792          * The default event handler fired when the "visible" property is 
2793          * changed.  This method is responsible for firing showEvent
2794          * and hideEvent.
2795          * @method configVisible
2796          * @param {String} type The CustomEvent type (usually the property name)
2797          * @param {Object[]} args The CustomEvent arguments. For configuration
2798          * handlers, args[0] will equal the newly applied value for the property.
2799          * @param {Object} obj The scope object. For configuration handlers, 
2800          * this will usually equal the owner.
2801          */
2802          configVisible: function (type, args, obj) {
2803  
2804              var visible = args[0],
2805                  currentVis = Dom.getStyle(this.element, "visibility"),
2806                  effects = this._cachedEffects || this._createEffects(this.cfg.getProperty("effect")),
2807                  isMacGecko = (this.platform == "mac" && UA.gecko),
2808                  alreadySubscribed = Config.alreadySubscribed,
2809                  ei, e, j, k, h,
2810                  nEffectInstances;
2811  
2812              if (currentVis == "inherit") {
2813                  e = this.element.parentNode;
2814  
2815                  while (e.nodeType != 9 && e.nodeType != 11) {
2816                      currentVis = Dom.getStyle(e, "visibility");
2817  
2818                      if (currentVis != "inherit") {
2819                          break;
2820                      }
2821  
2822                      e = e.parentNode;
2823                  }
2824  
2825                  if (currentVis == "inherit") {
2826                      currentVis = "visible";
2827                  }
2828              }
2829  
2830              if (visible) { // Show
2831  
2832                  if (isMacGecko) {
2833                      this.showMacGeckoScrollbars();
2834                  }
2835  
2836                  if (effects) { // Animate in
2837                      if (visible) { // Animate in if not showing
2838  
2839                           // Fading out is a bit of a hack, but didn't want to risk doing 
2840                           // something broader (e.g a generic this._animatingOut) for 2.9.0
2841  
2842                          if (currentVis != "visible" || currentVis === "" || this._fadingOut) {
2843                              if (this.beforeShowEvent.fire()) {
2844  
2845                                  nEffectInstances = effects.length;
2846  
2847                                  for (j = 0; j < nEffectInstances; j++) {
2848                                      ei = effects[j];
2849                                      if (j === 0 && !alreadySubscribed(ei.animateInCompleteEvent, this.showEvent.fire, this.showEvent)) {
2850                                          ei.animateInCompleteEvent.subscribe(this.showEvent.fire, this.showEvent, true);
2851                                      }
2852                                      ei.animateIn();
2853                                  }
2854                              }
2855                          }
2856                      }
2857                  } else { // Show
2858                      if (currentVis != "visible" || currentVis === "") {
2859                          if (this.beforeShowEvent.fire()) {
2860                              this._setDomVisibility(true);
2861                              this.cfg.refireEvent("iframe");
2862                              this.showEvent.fire();
2863                          }
2864                      } else {
2865                          this._setDomVisibility(true);
2866                      }
2867                  }
2868              } else { // Hide
2869  
2870                  if (isMacGecko) {
2871                      this.hideMacGeckoScrollbars();
2872                  }
2873  
2874                  if (effects) { // Animate out if showing
2875                      if (currentVis == "visible" || this._fadingIn) {
2876                          if (this.beforeHideEvent.fire()) {
2877                              nEffectInstances = effects.length;
2878                              for (k = 0; k < nEffectInstances; k++) {
2879                                  h = effects[k];
2880          
2881                                  if (k === 0 && !alreadySubscribed(h.animateOutCompleteEvent, this.hideEvent.fire, this.hideEvent)) {
2882                                      h.animateOutCompleteEvent.subscribe(this.hideEvent.fire, this.hideEvent, true);
2883                                  }
2884                                  h.animateOut();
2885                              }
2886                          }
2887  
2888                      } else if (currentVis === "") {
2889                          this._setDomVisibility(false);
2890                      }
2891  
2892                  } else { // Simple hide
2893  
2894                      if (currentVis == "visible" || currentVis === "") {
2895                          if (this.beforeHideEvent.fire()) {
2896                              this._setDomVisibility(false);
2897                              this.hideEvent.fire();
2898                          }
2899                      } else {
2900                          this._setDomVisibility(false);
2901                      }
2902                  }
2903              }
2904          },
2905  
2906          /**
2907          * Fixed center event handler used for centering on scroll/resize, but only if 
2908          * the overlay is visible and, if "fixedcenter" is set to "contained", only if 
2909          * the overlay fits within the viewport.
2910          *
2911          * @method doCenterOnDOMEvent
2912          */
2913          doCenterOnDOMEvent: function () {
2914              var cfg = this.cfg,
2915                  fc = cfg.getProperty("fixedcenter");
2916  
2917              if (cfg.getProperty("visible")) {
2918                  if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2919                      this.center();
2920                  }
2921              }
2922          },
2923  
2924          /**
2925           * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET) 
2926           * will fit entirely inside the viewport, in both dimensions - width and height.
2927           * 
2928           * @method fitsInViewport
2929           * @return boolean true if the Overlay will fit, false if not
2930           */
2931          fitsInViewport : function() {
2932              var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2933                  element = this.element,
2934                  elementWidth = element.offsetWidth,
2935                  elementHeight = element.offsetHeight,
2936                  viewportWidth = Dom.getViewportWidth(),
2937                  viewportHeight = Dom.getViewportHeight();
2938  
2939              return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2940          },
2941  
2942          /**
2943          * The default event handler fired when the "fixedcenter" property 
2944          * is changed.
2945          * @method configFixedCenter
2946          * @param {String} type The CustomEvent type (usually the property name)
2947          * @param {Object[]} args The CustomEvent arguments. For configuration 
2948          * handlers, args[0] will equal the newly applied value for the property.
2949          * @param {Object} obj The scope object. For configuration handlers, 
2950          * this will usually equal the owner.
2951          */
2952          configFixedCenter: function (type, args, obj) {
2953  
2954              var val = args[0],
2955                  alreadySubscribed = Config.alreadySubscribed,
2956                  windowResizeEvent = Overlay.windowResizeEvent,
2957                  windowScrollEvent = Overlay.windowScrollEvent;
2958  
2959              if (val) {
2960                  this.center();
2961  
2962                  if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2963                      this.beforeShowEvent.subscribe(this.center);
2964                  }
2965  
2966                  if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2967                      windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2968                  }
2969  
2970                  if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2971                      windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2972                  }
2973  
2974              } else {
2975                  this.beforeShowEvent.unsubscribe(this.center);
2976  
2977                  windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2978                  windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2979              }
2980          },
2981  
2982          /**
2983          * The default event handler fired when the "height" property is changed.
2984          * @method configHeight
2985          * @param {String} type The CustomEvent type (usually the property name)
2986          * @param {Object[]} args The CustomEvent arguments. For configuration 
2987          * handlers, args[0] will equal the newly applied value for the property.
2988          * @param {Object} obj The scope object. For configuration handlers, 
2989          * this will usually equal the owner.
2990          */
2991          configHeight: function (type, args, obj) {
2992  
2993              var height = args[0],
2994                  el = this.element;
2995  
2996              Dom.setStyle(el, "height", height);
2997              this.cfg.refireEvent("iframe");
2998          },
2999  
3000          /**
3001           * The default event handler fired when the "autofillheight" property is changed.
3002           * @method configAutoFillHeight
3003           *
3004           * @param {String} type The CustomEvent type (usually the property name)
3005           * @param {Object[]} args The CustomEvent arguments. For configuration 
3006           * handlers, args[0] will equal the newly applied value for the property.
3007           * @param {Object} obj The scope object. For configuration handlers, 
3008           * this will usually equal the owner.
3009           */
3010          configAutoFillHeight: function (type, args, obj) {
3011              var fillEl = args[0],
3012                  cfg = this.cfg,
3013                  autoFillHeight = "autofillheight",
3014                  height = "height",
3015                  currEl = cfg.getProperty(autoFillHeight),
3016                  autoFill = this._autoFillOnHeightChange;
3017  
3018              cfg.unsubscribeFromConfigEvent(height, autoFill);
3019              Module.textResizeEvent.unsubscribe(autoFill);
3020              this.changeContentEvent.unsubscribe(autoFill);
3021  
3022              if (currEl && fillEl !== currEl && this[currEl]) {
3023                  Dom.setStyle(this[currEl], height, "");
3024              }
3025  
3026              if (fillEl) {
3027                  fillEl = Lang.trim(fillEl.toLowerCase());
3028  
3029                  cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
3030                  Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
3031                  this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
3032  
3033                  cfg.setProperty(autoFillHeight, fillEl, true);
3034              }
3035          },
3036  
3037          /**
3038          * The default event handler fired when the "width" property is changed.
3039          * @method configWidth
3040          * @param {String} type The CustomEvent type (usually the property name)
3041          * @param {Object[]} args The CustomEvent arguments. For configuration 
3042          * handlers, args[0] will equal the newly applied value for the property.
3043          * @param {Object} obj The scope object. For configuration handlers, 
3044          * this will usually equal the owner.
3045          */
3046          configWidth: function (type, args, obj) {
3047  
3048              var width = args[0],
3049                  el = this.element;
3050  
3051              Dom.setStyle(el, "width", width);
3052              this.cfg.refireEvent("iframe");
3053          },
3054  
3055          /**
3056          * The default event handler fired when the "zIndex" property is changed.
3057          * @method configzIndex
3058          * @param {String} type The CustomEvent type (usually the property name)
3059          * @param {Object[]} args The CustomEvent arguments. For configuration 
3060          * handlers, args[0] will equal the newly applied value for the property.
3061          * @param {Object} obj The scope object. For configuration handlers, 
3062          * this will usually equal the owner.
3063          */
3064          configzIndex: function (type, args, obj) {
3065  
3066              var zIndex = args[0],
3067                  el = this.element;
3068  
3069              if (! zIndex) {
3070                  zIndex = Dom.getStyle(el, "zIndex");
3071                  if (! zIndex || isNaN(zIndex)) {
3072                      zIndex = 0;
3073                  }
3074              }
3075  
3076              if (this.iframe || this.cfg.getProperty("iframe") === true) {
3077                  if (zIndex <= 0) {
3078                      zIndex = 1;
3079                  }
3080              }
3081  
3082              Dom.setStyle(el, "zIndex", zIndex);
3083              this.cfg.setProperty("zIndex", zIndex, true);
3084  
3085              if (this.iframe) {
3086                  this.stackIframe();
3087              }
3088          },
3089  
3090          /**
3091          * The default event handler fired when the "xy" property is changed.
3092          * @method configXY
3093          * @param {String} type The CustomEvent type (usually the property name)
3094          * @param {Object[]} args The CustomEvent arguments. For configuration 
3095          * handlers, args[0] will equal the newly applied value for the property.
3096          * @param {Object} obj The scope object. For configuration handlers, 
3097          * this will usually equal the owner.
3098          */
3099          configXY: function (type, args, obj) {
3100  
3101              var pos = args[0],
3102                  x = pos[0],
3103                  y = pos[1];
3104  
3105              this.cfg.setProperty("x", x);
3106              this.cfg.setProperty("y", y);
3107  
3108              this.beforeMoveEvent.fire([x, y]);
3109  
3110              x = this.cfg.getProperty("x");
3111              y = this.cfg.getProperty("y");
3112  
3113              YAHOO.log(("xy: " + [x, y]), "iframe");
3114  
3115              this.cfg.refireEvent("iframe");
3116              this.moveEvent.fire([x, y]);
3117          },
3118  
3119          /**
3120          * The default event handler fired when the "x" property is changed.
3121          * @method configX
3122          * @param {String} type The CustomEvent type (usually the property name)
3123          * @param {Object[]} args The CustomEvent arguments. For configuration 
3124          * handlers, args[0] will equal the newly applied value for the property.
3125          * @param {Object} obj The scope object. For configuration handlers, 
3126          * this will usually equal the owner.
3127          */
3128          configX: function (type, args, obj) {
3129  
3130              var x = args[0],
3131                  y = this.cfg.getProperty("y");
3132  
3133              this.cfg.setProperty("x", x, true);
3134              this.cfg.setProperty("y", y, true);
3135  
3136              this.beforeMoveEvent.fire([x, y]);
3137  
3138              x = this.cfg.getProperty("x");
3139              y = this.cfg.getProperty("y");
3140  
3141              Dom.setX(this.element, x, true);
3142  
3143              this.cfg.setProperty("xy", [x, y], true);
3144  
3145              this.cfg.refireEvent("iframe");
3146              this.moveEvent.fire([x, y]);
3147          },
3148  
3149          /**
3150          * The default event handler fired when the "y" property is changed.
3151          * @method configY
3152          * @param {String} type The CustomEvent type (usually the property name)
3153          * @param {Object[]} args The CustomEvent arguments. For configuration 
3154          * handlers, args[0] will equal the newly applied value for the property.
3155          * @param {Object} obj The scope object. For configuration handlers, 
3156          * this will usually equal the owner.
3157          */
3158          configY: function (type, args, obj) {
3159  
3160              var x = this.cfg.getProperty("x"),
3161                  y = args[0];
3162  
3163              this.cfg.setProperty("x", x, true);
3164              this.cfg.setProperty("y", y, true);
3165  
3166              this.beforeMoveEvent.fire([x, y]);
3167  
3168              x = this.cfg.getProperty("x");
3169              y = this.cfg.getProperty("y");
3170  
3171              Dom.setY(this.element, y, true);
3172  
3173              this.cfg.setProperty("xy", [x, y], true);
3174  
3175              this.cfg.refireEvent("iframe");
3176              this.moveEvent.fire([x, y]);
3177          },
3178          
3179          /**
3180          * Shows the iframe shim, if it has been enabled.
3181          * @method showIframe
3182          */
3183          showIframe: function () {
3184  
3185              var oIFrame = this.iframe,
3186                  oParentNode;
3187  
3188              if (oIFrame) {
3189                  oParentNode = this.element.parentNode;
3190  
3191                  if (oParentNode != oIFrame.parentNode) {
3192                      this._addToParent(oParentNode, oIFrame);
3193                  }
3194                  oIFrame.style.display = "block";
3195              }
3196          },
3197  
3198          /**
3199          * Hides the iframe shim, if it has been enabled.
3200          * @method hideIframe
3201          */
3202          hideIframe: function () {
3203              if (this.iframe) {
3204                  this.iframe.style.display = "none";
3205              }
3206          },
3207  
3208          /**
3209          * Syncronizes the size and position of iframe shim to that of its 
3210          * corresponding Overlay instance.
3211          * @method syncIframe
3212          */
3213          syncIframe: function () {
3214  
3215              var oIFrame = this.iframe,
3216                  oElement = this.element,
3217                  nOffset = Overlay.IFRAME_OFFSET,
3218                  nDimensionOffset = (nOffset * 2),
3219                  aXY;
3220  
3221              if (oIFrame) {
3222                  // Size <iframe>
3223                  oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3224                  oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3225  
3226                  // Position <iframe>
3227                  aXY = this.cfg.getProperty("xy");
3228  
3229                  if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3230                      this.syncPosition();
3231                      aXY = this.cfg.getProperty("xy");
3232                  }
3233                  Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3234              }
3235          },
3236  
3237          /**
3238           * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3239           * the Overlay element. The zindex of the iframe is set to be one less 
3240           * than the Overlay element's zindex.
3241           * 
3242           * <p>NOTE: This method will not bump up the zindex of the Overlay element
3243           * to ensure that the iframe shim has a non-negative zindex.
3244           * If you require the iframe zindex to be 0 or higher, the zindex of 
3245           * the Overlay element should be set to a value greater than 0, before 
3246           * this method is called.
3247           * </p>
3248           * @method stackIframe
3249           */
3250          stackIframe: function () {
3251              if (this.iframe) {
3252                  var overlayZ = Dom.getStyle(this.element, "zIndex");
3253                  if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3254                      Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3255                  }
3256              }
3257          },
3258  
3259          /**
3260          * The default event handler fired when the "iframe" property is changed.
3261          * @method configIframe
3262          * @param {String} type The CustomEvent type (usually the property name)
3263          * @param {Object[]} args The CustomEvent arguments. For configuration 
3264          * handlers, args[0] will equal the newly applied value for the property.
3265          * @param {Object} obj The scope object. For configuration handlers, 
3266          * this will usually equal the owner.
3267          */
3268          configIframe: function (type, args, obj) {
3269  
3270              var bIFrame = args[0];
3271  
3272              function createIFrame() {
3273  
3274                  var oIFrame = this.iframe,
3275                      oElement = this.element,
3276                      oParent;
3277  
3278                  if (!oIFrame) {
3279                      if (!m_oIFrameTemplate) {
3280                          m_oIFrameTemplate = document.createElement("iframe");
3281  
3282                          if (this.isSecure) {
3283                              m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3284                          }
3285  
3286                          /*
3287                              Set the opacity of the <iframe> to 0 so that it 
3288                              doesn't modify the opacity of any transparent 
3289                              elements that may be on top of it (like a shadow).
3290                          */
3291                          if (UA.ie) {
3292                              m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3293                              /*
3294                                   Need to set the "frameBorder" property to 0 
3295                                   supress the default <iframe> border in IE.  
3296                                   Setting the CSS "border" property alone 
3297                                   doesn't supress it.
3298                              */
3299                              m_oIFrameTemplate.frameBorder = 0;
3300                          }
3301                          else {
3302                              m_oIFrameTemplate.style.opacity = "0";
3303                          }
3304  
3305                          m_oIFrameTemplate.style.position = "absolute";
3306                          m_oIFrameTemplate.style.border = "none";
3307                          m_oIFrameTemplate.style.margin = "0";
3308                          m_oIFrameTemplate.style.padding = "0";
3309                          m_oIFrameTemplate.style.display = "none";
3310                          m_oIFrameTemplate.tabIndex = -1;
3311                          m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3312                      }
3313  
3314                      oIFrame = m_oIFrameTemplate.cloneNode(false);
3315                      oIFrame.id = this.id + "_f";
3316                      oParent = oElement.parentNode;
3317  
3318                      var parentNode = oParent || document.body;
3319  
3320                      this._addToParent(parentNode, oIFrame);
3321                      this.iframe = oIFrame;
3322                  }
3323  
3324                  /*
3325                       Show the <iframe> before positioning it since the "setXY" 
3326                       method of DOM requires the element be in the document 
3327                       and visible.
3328                  */
3329                  this.showIframe();
3330  
3331                  /*
3332                       Syncronize the size and position of the <iframe> to that 
3333                       of the Overlay.
3334                  */
3335                  this.syncIframe();
3336                  this.stackIframe();
3337  
3338                  // Add event listeners to update the <iframe> when necessary
3339                  if (!this._hasIframeEventListeners) {
3340                      this.showEvent.subscribe(this.showIframe);
3341                      this.hideEvent.subscribe(this.hideIframe);
3342                      this.changeContentEvent.subscribe(this.syncIframe);
3343  
3344                      this._hasIframeEventListeners = true;
3345                  }
3346              }
3347  
3348              function onBeforeShow() {
3349                  createIFrame.call(this);
3350                  this.beforeShowEvent.unsubscribe(onBeforeShow);
3351                  this._iframeDeferred = false;
3352              }
3353  
3354              if (bIFrame) { // <iframe> shim is enabled
3355  
3356                  if (this.cfg.getProperty("visible")) {
3357                      createIFrame.call(this);
3358                  } else {
3359                      if (!this._iframeDeferred) {
3360                          this.beforeShowEvent.subscribe(onBeforeShow);
3361                          this._iframeDeferred = true;
3362                      }
3363                  }
3364  
3365              } else {    // <iframe> shim is disabled
3366                  this.hideIframe();
3367  
3368                  if (this._hasIframeEventListeners) {
3369                      this.showEvent.unsubscribe(this.showIframe);
3370                      this.hideEvent.unsubscribe(this.hideIframe);
3371                      this.changeContentEvent.unsubscribe(this.syncIframe);
3372  
3373                      this._hasIframeEventListeners = false;
3374                  }
3375              }
3376          },
3377  
3378          /**
3379           * Set's the container's XY value from DOM if not already set.
3380           * 
3381           * Differs from syncPosition, in that the XY value is only sync'd with DOM if 
3382           * not already set. The method also refire's the XY config property event, so any
3383           * beforeMove, Move event listeners are invoked.
3384           * 
3385           * @method _primeXYFromDOM
3386           * @protected
3387           */
3388          _primeXYFromDOM : function() {
3389              if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3390                  // Set CFG XY based on DOM XY
3391                  this.syncPosition();
3392                  // Account for XY being set silently in syncPosition (no moveTo fired/called)
3393                  this.cfg.refireEvent("xy");
3394                  this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3395              }
3396          },
3397  
3398          /**
3399          * The default event handler fired when the "constraintoviewport" 
3400          * property is changed.
3401          * @method configConstrainToViewport
3402          * @param {String} type The CustomEvent type (usually the property name)
3403          * @param {Object[]} args The CustomEvent arguments. For configuration 
3404          * handlers, args[0] will equal the newly applied value for 
3405          * the property.
3406          * @param {Object} obj The scope object. For configuration handlers, 
3407          * this will usually equal the owner.
3408          */
3409          configConstrainToViewport: function (type, args, obj) {
3410              var val = args[0];
3411  
3412              if (val) {
3413                  if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3414                      this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3415                  }
3416                  if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3417                      this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3418                  }
3419              } else {
3420                  this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3421                  this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3422              }
3423          },
3424  
3425           /**
3426          * The default event handler fired when the "context" property
3427          * is changed.
3428          *
3429          * @method configContext
3430          * @param {String} type The CustomEvent type (usually the property name)
3431          * @param {Object[]} args The CustomEvent arguments. For configuration 
3432          * handlers, args[0] will equal the newly applied value for the property.
3433          * @param {Object} obj The scope object. For configuration handlers, 
3434          * this will usually equal the owner.
3435          */
3436          configContext: function (type, args, obj) {
3437  
3438              var contextArgs = args[0],
3439                  contextEl,
3440                  elementMagnetCorner,
3441                  contextMagnetCorner,
3442                  triggers,
3443                  offset,
3444                  defTriggers = this.CONTEXT_TRIGGERS;
3445  
3446              if (contextArgs) {
3447  
3448                  contextEl = contextArgs[0];
3449                  elementMagnetCorner = contextArgs[1];
3450                  contextMagnetCorner = contextArgs[2];
3451                  triggers = contextArgs[3];
3452                  offset = contextArgs[4];
3453  
3454                  if (defTriggers && defTriggers.length > 0) {
3455                      triggers = (triggers || []).concat(defTriggers);
3456                  }
3457  
3458                  if (contextEl) {
3459                      if (typeof contextEl == "string") {
3460                          this.cfg.setProperty("context", [
3461                                  document.getElementById(contextEl), 
3462                                  elementMagnetCorner,
3463                                  contextMagnetCorner,
3464                                  triggers,
3465                                  offset],
3466                                  true);
3467                      }
3468  
3469                      if (elementMagnetCorner && contextMagnetCorner) {
3470                          this.align(elementMagnetCorner, contextMagnetCorner, offset);
3471                      }
3472  
3473                      if (this._contextTriggers) {
3474                          // Unsubscribe Old Set
3475                          this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3476                      }
3477  
3478                      if (triggers) {
3479                          // Subscribe New Set
3480                          this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3481                          this._contextTriggers = triggers;
3482                      }
3483                  }
3484              }
3485          },
3486  
3487          /**
3488           * Custom Event handler for context alignment triggers. Invokes the align method
3489           * 
3490           * @method _alignOnTrigger
3491           * @protected
3492           * 
3493           * @param {String} type The event type (not used by the default implementation)
3494           * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3495           */
3496          _alignOnTrigger: function(type, args) {
3497              this.align();
3498          },
3499  
3500          /**
3501           * Helper method to locate the custom event instance for the event name string
3502           * passed in. As a convenience measure, any custom events passed in are returned.
3503           *
3504           * @method _findTriggerCE
3505           * @private
3506           *
3507           * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a 
3508           * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3509           */
3510          _findTriggerCE : function(t) {
3511              var tce = null;
3512              if (t instanceof CustomEvent) {
3513                  tce = t;
3514              } else if (Overlay._TRIGGER_MAP[t]) {
3515                  tce = Overlay._TRIGGER_MAP[t];
3516              }
3517              return tce;
3518          },
3519  
3520          /**
3521           * Utility method that subscribes or unsubscribes the given 
3522           * function from the list of trigger events provided.
3523           *
3524           * @method _processTriggers
3525           * @protected 
3526           *
3527           * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings 
3528           * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be 
3529           * subscribed/unsubscribed respectively.
3530           *
3531           * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3532           * we are subscribing or unsubscribing trigger listeners
3533           * 
3534           * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3535           * Context is always set to the overlay instance, and no additional object argument 
3536           * get passed to the subscribed function.
3537           */
3538          _processTriggers : function(triggers, mode, fn) {
3539              var t, tce;
3540  
3541              for (var i = 0, l = triggers.length; i < l; ++i) {
3542                  t = triggers[i];
3543                  tce = this._findTriggerCE(t);
3544                  if (tce) {
3545                      tce[mode](fn, this, true);
3546                  } else {
3547                      this[mode](t, fn);
3548                  }
3549              }
3550          },
3551  
3552          // END BUILT-IN PROPERTY EVENT HANDLERS //
3553          /**
3554          * Aligns the Overlay to its context element using the specified corner 
3555          * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, 
3556          * and BOTTOM_RIGHT.
3557          * @method align
3558          * @param {String} elementAlign  The String representing the corner of 
3559          * the Overlay that should be aligned to the context element
3560          * @param {String} contextAlign  The corner of the context element 
3561          * that the elementAlign corner should stick to.
3562          * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3563          * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the 
3564          * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3565          */
3566          align: function (elementAlign, contextAlign, xyOffset) {
3567  
3568              var contextArgs = this.cfg.getProperty("context"),
3569                  me = this,
3570                  context,
3571                  element,
3572                  contextRegion;
3573  
3574              function doAlign(v, h) {
3575  
3576                  var alignX = null, alignY = null;
3577  
3578                  switch (elementAlign) {
3579      
3580                      case Overlay.TOP_LEFT:
3581                          alignX = h;
3582                          alignY = v;
3583                          break;
3584          
3585                      case Overlay.TOP_RIGHT:
3586                          alignX = h - element.offsetWidth;
3587                          alignY = v;
3588                          break;
3589          
3590                      case Overlay.BOTTOM_LEFT:
3591                          alignX = h;
3592                          alignY = v - element.offsetHeight;
3593                          break;
3594          
3595                      case Overlay.BOTTOM_RIGHT:
3596                          alignX = h - element.offsetWidth; 
3597                          alignY = v - element.offsetHeight;
3598                          break;
3599                  }
3600  
3601                  if (alignX !== null && alignY !== null) {
3602                      if (xyOffset) {
3603                          alignX += xyOffset[0];
3604                          alignY += xyOffset[1];
3605                      }
3606                      me.moveTo(alignX, alignY);
3607                  }
3608              }
3609  
3610              if (contextArgs) {
3611                  context = contextArgs[0];
3612                  element = this.element;
3613                  me = this;
3614  
3615                  if (! elementAlign) {
3616                      elementAlign = contextArgs[1];
3617                  }
3618  
3619                  if (! contextAlign) {
3620                      contextAlign = contextArgs[2];
3621                  }
3622  
3623                  if (!xyOffset && contextArgs[4]) {
3624                      xyOffset = contextArgs[4];
3625                  }
3626  
3627                  if (element && context) {
3628                      contextRegion = Dom.getRegion(context);
3629  
3630                      switch (contextAlign) {
3631      
3632                          case Overlay.TOP_LEFT:
3633                              doAlign(contextRegion.top, contextRegion.left);
3634                              break;
3635          
3636                          case Overlay.TOP_RIGHT:
3637                              doAlign(contextRegion.top, contextRegion.right);
3638                              break;
3639          
3640                          case Overlay.BOTTOM_LEFT:
3641                              doAlign(contextRegion.bottom, contextRegion.left);
3642                              break;
3643          
3644                          case Overlay.BOTTOM_RIGHT:
3645                              doAlign(contextRegion.bottom, contextRegion.right);
3646                              break;
3647                      }
3648                  }
3649              }
3650          },
3651  
3652          /**
3653          * The default event handler executed when the moveEvent is fired, if the 
3654          * "constraintoviewport" is set to true.
3655          * @method enforceConstraints
3656          * @param {String} type The CustomEvent type (usually the property name)
3657          * @param {Object[]} args The CustomEvent arguments. For configuration 
3658          * handlers, args[0] will equal the newly applied value for the property.
3659          * @param {Object} obj The scope object. For configuration handlers, 
3660          * this will usually equal the owner.
3661          */
3662          enforceConstraints: function (type, args, obj) {
3663              var pos = args[0];
3664  
3665              var cXY = this.getConstrainedXY(pos[0], pos[1]);
3666              this.cfg.setProperty("x", cXY[0], true);
3667              this.cfg.setProperty("y", cXY[1], true);
3668              this.cfg.setProperty("xy", cXY, true);
3669          },
3670  
3671          /**
3672           * Shared implementation method for getConstrainedX and getConstrainedY.
3673           * 
3674           * <p>
3675           * Given a coordinate value, returns the calculated coordinate required to 
3676           * position the Overlay if it is to be constrained to the viewport, based on the 
3677           * current element size, viewport dimensions, scroll values and preventoverlap 
3678           * settings
3679           * </p>
3680           *
3681           * @method _getConstrainedPos
3682           * @protected
3683           * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3684           * @param {Number} The coordinate value which needs to be constrained
3685           * @return {Number} The constrained coordinate value
3686           */
3687          _getConstrainedPos: function(pos, val) {
3688  
3689              var overlayEl = this.element,
3690  
3691                  buffer = Overlay.VIEWPORT_OFFSET,
3692  
3693                  x = (pos == "x"),
3694  
3695                  overlaySize      = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3696                  viewportSize     = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3697                  docScroll        = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3698                  overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3699  
3700                  context = this.cfg.getProperty("context"),
3701  
3702                  bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3703                  bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3704  
3705                  minConstraint = docScroll + buffer,
3706                  maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3707  
3708                  constrainedVal = val;
3709  
3710              if (val < minConstraint || val > maxConstraint) {
3711                  if (bPreventContextOverlap) {
3712                      constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3713                  } else {
3714                      if (bOverlayFitsInViewport) {
3715                          if (val < minConstraint) {
3716                              constrainedVal = minConstraint;
3717                          } else if (val > maxConstraint) {
3718                              constrainedVal = maxConstraint;
3719                          }
3720                      } else {
3721                          constrainedVal = minConstraint;
3722                      }
3723                  }
3724              }
3725  
3726              return constrainedVal;
3727          },
3728  
3729          /**
3730           * Helper method, used to position the Overlap to prevent overlap with the 
3731           * context element (used when preventcontextoverlap is enabled)
3732           *
3733           * @method _preventOverlap
3734           * @protected
3735           * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3736           * @param {HTMLElement} contextEl The context element
3737           * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3738           * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3739           * @param {Object} docScroll  The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3740           *
3741           * @return {Number} The new coordinate value which was set to prevent overlap
3742           */
3743          _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3744              
3745              var x = (pos == "x"),
3746  
3747                  buffer = Overlay.VIEWPORT_OFFSET,
3748  
3749                  overlay = this,
3750  
3751                  contextElPos   = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3752                  contextElSize  = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3753  
3754                  minRegionSize = contextElPos - buffer,
3755                  maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3756  
3757                  bFlipped = false,
3758  
3759                  flip = function () {
3760                      var flippedVal;
3761  
3762                      if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3763                          flippedVal = (contextElPos - overlaySize);
3764                      } else {
3765                          flippedVal = (contextElPos + contextElSize);
3766                      }
3767  
3768                      overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3769  
3770                      return flippedVal;
3771                  },
3772  
3773                  setPosition = function () {
3774  
3775                      var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3776                          position;
3777  
3778                      if (overlaySize > displayRegionSize) {
3779                          if (bFlipped) {
3780                              /*
3781                                   All possible positions and values have been 
3782                                   tried, but none were successful, so fall back 
3783                                   to the original size and position.
3784                              */
3785                              flip();
3786                          } else {
3787                              flip();
3788                              bFlipped = true;
3789                              position = setPosition();
3790                          }
3791                      }
3792  
3793                      return position;
3794                  };
3795  
3796              setPosition();
3797  
3798              return this.cfg.getProperty(pos);
3799          },
3800  
3801          /**
3802           * Given x coordinate value, returns the calculated x coordinate required to 
3803           * position the Overlay if it is to be constrained to the viewport, based on the 
3804           * current element size, viewport dimensions and scroll values.
3805           *
3806           * @param {Number} x The X coordinate value to be constrained
3807           * @return {Number} The constrained x coordinate
3808           */        
3809          getConstrainedX: function (x) {
3810              return this._getConstrainedPos("x", x);
3811          },
3812  
3813          /**
3814           * Given y coordinate value, returns the calculated y coordinate required to 
3815           * position the Overlay if it is to be constrained to the viewport, based on the 
3816           * current element size, viewport dimensions and scroll values.
3817           *
3818           * @param {Number} y The Y coordinate value to be constrained
3819           * @return {Number} The constrained y coordinate
3820           */        
3821          getConstrainedY : function (y) {
3822              return this._getConstrainedPos("y", y);
3823          },
3824  
3825          /**
3826           * Given x, y coordinate values, returns the calculated coordinates required to 
3827           * position the Overlay if it is to be constrained to the viewport, based on the 
3828           * current element size, viewport dimensions and scroll values.
3829           *
3830           * @param {Number} x The X coordinate value to be constrained
3831           * @param {Number} y The Y coordinate value to be constrained
3832           * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3833           */
3834          getConstrainedXY: function(x, y) {
3835              return [this.getConstrainedX(x), this.getConstrainedY(y)];
3836          },
3837  
3838          /**
3839          * Centers the container in the viewport.
3840          * @method center
3841          */
3842          center: function () {
3843  
3844              var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3845                  elementWidth = this.element.offsetWidth,
3846                  elementHeight = this.element.offsetHeight,
3847                  viewPortWidth = Dom.getViewportWidth(),
3848                  viewPortHeight = Dom.getViewportHeight(),
3849                  x,
3850                  y;
3851  
3852              if (elementWidth < viewPortWidth) {
3853                  x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3854              } else {
3855                  x = nViewportOffset + Dom.getDocumentScrollLeft();
3856              }
3857  
3858              if (elementHeight < viewPortHeight) {
3859                  y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3860              } else {
3861                  y = nViewportOffset + Dom.getDocumentScrollTop();
3862              }
3863  
3864              this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3865              this.cfg.refireEvent("iframe");
3866  
3867              if (UA.webkit) {
3868                  this.forceContainerRedraw();
3869              }
3870          },
3871  
3872          /**
3873          * Synchronizes the Panel's "xy", "x", and "y" properties with the 
3874          * Panel's position in the DOM. This is primarily used to update  
3875          * position information during drag & drop.
3876          * @method syncPosition
3877          */
3878          syncPosition: function () {
3879  
3880              var pos = Dom.getXY(this.element);
3881  
3882              this.cfg.setProperty("x", pos[0], true);
3883              this.cfg.setProperty("y", pos[1], true);
3884              this.cfg.setProperty("xy", pos, true);
3885  
3886          },
3887  
3888          /**
3889          * Event handler fired when the resize monitor element is resized.
3890          * @method onDomResize
3891          * @param {DOMEvent} e The resize DOM event
3892          * @param {Object} obj The scope object
3893          */
3894          onDomResize: function (e, obj) {
3895  
3896              var me = this;
3897  
3898              Overlay.superclass.onDomResize.call(this, e, obj);
3899  
3900              setTimeout(function () {
3901                  me.syncPosition();
3902                  me.cfg.refireEvent("iframe");
3903                  me.cfg.refireEvent("context");
3904              }, 0);
3905          },
3906  
3907          /**
3908           * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3909           *
3910           * @method _getComputedHeight
3911           * @private
3912           * @param {HTMLElement} el The element for which the content height needs to be determined
3913           * @return {Number} The content box height of the given element, or null if it could not be determined.
3914           */
3915          _getComputedHeight : (function() {
3916  
3917              if (document.defaultView && document.defaultView.getComputedStyle) {
3918                  return function(el) {
3919                      var height = null;
3920                      if (el.ownerDocument && el.ownerDocument.defaultView) {
3921                          var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3922                          if (computed) {
3923                              height = parseInt(computed.height, 10);
3924                          }
3925                      }
3926                      return (Lang.isNumber(height)) ? height : null;
3927                  };
3928              } else {
3929                  return function(el) {
3930                      var height = null;
3931                      if (el.style.pixelHeight) {
3932                          height = el.style.pixelHeight;
3933                      }
3934                      return (Lang.isNumber(height)) ? height : null;
3935                  };
3936              }
3937          })(),
3938  
3939          /**
3940           * autofillheight validator. Verifies that the autofill value is either null 
3941           * or one of the strings : "body", "header" or "footer".
3942           *
3943           * @method _validateAutoFillHeight
3944           * @protected
3945           * @param {String} val
3946           * @return true, if valid, false otherwise
3947           */
3948          _validateAutoFillHeight : function(val) {
3949              return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3950          },
3951  
3952          /**
3953           * The default custom event handler executed when the overlay's height is changed, 
3954           * if the autofillheight property has been set.
3955           *
3956           * @method _autoFillOnHeightChange
3957           * @protected
3958           * @param {String} type The event type
3959           * @param {Array} args The array of arguments passed to event subscribers
3960           * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3961           * out the containers height
3962           */
3963          _autoFillOnHeightChange : function(type, args, el) {
3964              var height = this.cfg.getProperty("height");
3965              if ((height && height !== "auto") || (height === 0)) {
3966                  this.fillHeight(el);
3967              }
3968          },
3969  
3970          /**
3971           * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3972           * otherwise returns the offsetHeight
3973           * @method _getPreciseHeight
3974           * @private
3975           * @param {HTMLElement} el
3976           * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3977           */
3978          _getPreciseHeight : function(el) {
3979              var height = el.offsetHeight;
3980  
3981              if (el.getBoundingClientRect) {
3982                  var rect = el.getBoundingClientRect();
3983                  height = rect.bottom - rect.top;
3984              }
3985  
3986              return height;
3987          },
3988  
3989          /**
3990           * <p>
3991           * Sets the height on the provided header, body or footer element to 
3992           * fill out the height of the container. It determines the height of the 
3993           * containers content box, based on it's configured height value, and 
3994           * sets the height of the autofillheight element to fill out any 
3995           * space remaining after the other standard module element heights 
3996           * have been accounted for.
3997           * </p>
3998           * <p><strong>NOTE:</strong> This method is not designed to work if an explicit 
3999           * height has not been set on the container, since for an "auto" height container, 
4000           * the heights of the header/body/footer will drive the height of the container.</p>
4001           *
4002           * @method fillHeight
4003           * @param {HTMLElement} el The element which should be resized to fill out the height
4004           * of the container element.
4005           */
4006          fillHeight : function(el) {
4007              if (el) {
4008                  var container = this.innerElement || this.element,
4009                      containerEls = [this.header, this.body, this.footer],
4010                      containerEl,
4011                      total = 0,
4012                      filled = 0,
4013                      remaining = 0,
4014                      validEl = false;
4015  
4016                  for (var i = 0, l = containerEls.length; i < l; i++) {
4017                      containerEl = containerEls[i];
4018                      if (containerEl) {
4019                          if (el !== containerEl) {
4020                              filled += this._getPreciseHeight(containerEl);
4021                          } else {
4022                              validEl = true;
4023                          }
4024                      }
4025                  }
4026  
4027                  if (validEl) {
4028  
4029                      if (UA.ie || UA.opera) {
4030                          // Need to set height to 0, to allow height to be reduced
4031                          Dom.setStyle(el, 'height', 0 + 'px');
4032                      }
4033  
4034                      total = this._getComputedHeight(container);
4035  
4036                      // Fallback, if we can't get computed value for content height
4037                      if (total === null) {
4038                          Dom.addClass(container, "yui-override-padding");
4039                          total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4040                          Dom.removeClass(container, "yui-override-padding");
4041                      }
4042      
4043                      remaining = Math.max(total - filled, 0);
4044      
4045                      Dom.setStyle(el, "height", remaining + "px");
4046      
4047                      // Re-adjust height if required, to account for el padding and border
4048                      if (el.offsetHeight != remaining) {
4049                          remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4050                      }
4051                      Dom.setStyle(el, "height", remaining + "px");
4052                  }
4053              }
4054          },
4055  
4056          /**
4057          * Places the Overlay on top of all other instances of 
4058          * YAHOO.widget.Overlay.
4059          * @method bringToTop
4060          */
4061          bringToTop: function () {
4062  
4063              var aOverlays = [],
4064                  oElement = this.element;
4065  
4066              function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4067  
4068                  var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4069                      sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4070  
4071                      nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4072                      nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4073  
4074                  if (nZIndex1 > nZIndex2) {
4075                      return -1;
4076                  } else if (nZIndex1 < nZIndex2) {
4077                      return 1;
4078                  } else {
4079                      return 0;
4080                  }
4081              }
4082  
4083              function isOverlayElement(p_oElement) {
4084  
4085                  var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4086                      Panel = YAHOO.widget.Panel;
4087  
4088                  if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4089                      if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4090                          aOverlays[aOverlays.length] = p_oElement.parentNode;
4091                      } else {
4092                          aOverlays[aOverlays.length] = p_oElement;
4093                      }
4094                  }
4095              }
4096  
4097              Dom.getElementsBy(isOverlayElement, "div", document.body);
4098  
4099              aOverlays.sort(compareZIndexDesc);
4100  
4101              var oTopOverlay = aOverlays[0],
4102                  nTopZIndex;
4103  
4104              if (oTopOverlay) {
4105                  nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4106  
4107                  if (!isNaN(nTopZIndex)) {
4108                      var bRequiresBump = false;
4109  
4110                      if (oTopOverlay != oElement) {
4111                          bRequiresBump = true;
4112                      } else if (aOverlays.length > 1) {
4113                          var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4114                          // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4115                          if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4116                              bRequiresBump = true;
4117                          }
4118                      }
4119                      if (bRequiresBump) {
4120                          this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4121                      }
4122                  }
4123              }
4124          },
4125  
4126          /**
4127          * Removes the Overlay element from the DOM and sets all child 
4128          * elements to null.
4129          * @method destroy
4130          * @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. 
4131          * 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.
4132          */
4133          destroy: function (shallowPurge) {
4134  
4135              if (this.iframe) {
4136                  this.iframe.parentNode.removeChild(this.iframe);
4137              }
4138  
4139              this.iframe = null;
4140  
4141              Overlay.windowResizeEvent.unsubscribe(
4142                  this.doCenterOnDOMEvent, this);
4143      
4144              Overlay.windowScrollEvent.unsubscribe(
4145                  this.doCenterOnDOMEvent, this);
4146  
4147              Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4148  
4149              if (this._contextTriggers) {
4150                  // Unsubscribe context triggers - to cover context triggers which listen for global
4151                  // events such as windowResize and windowScroll. Easier just to unsubscribe all
4152                  this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4153              }
4154  
4155              Overlay.superclass.destroy.call(this, shallowPurge);
4156          },
4157  
4158          /**
4159           * Can be used to force the container to repaint/redraw it's contents.
4160           * <p>
4161           * By default applies and then removes a 1px bottom margin through the 
4162           * application/removal of a "yui-force-redraw" class.
4163           * </p>
4164           * <p>
4165           * It is currently used by Overlay to force a repaint for webkit 
4166           * browsers, when centering.
4167           * </p>
4168           * @method forceContainerRedraw
4169           */
4170          forceContainerRedraw : function() {
4171              var c = this;
4172              Dom.addClass(c.element, "yui-force-redraw");
4173              setTimeout(function() {
4174                  Dom.removeClass(c.element, "yui-force-redraw");
4175              }, 0);
4176          },
4177  
4178          /**
4179          * Returns a String representation of the object.
4180          * @method toString
4181          * @return {String} The string representation of the Overlay.
4182          */
4183          toString: function () {
4184              return "Overlay " + this.id;
4185          }
4186  
4187      });
4188  }());
4189  (function () {
4190  
4191      /**
4192      * OverlayManager is used for maintaining the focus status of 
4193      * multiple Overlays.
4194      * @namespace YAHOO.widget
4195      * @namespace YAHOO.widget
4196      * @class OverlayManager
4197      * @constructor
4198      * @param {Array} overlays Optional. A collection of Overlays to register 
4199      * with the manager.
4200      * @param {Object} userConfig  The object literal representing the user 
4201      * configuration of the OverlayManager
4202      */
4203      YAHOO.widget.OverlayManager = function (userConfig) {
4204          this.init(userConfig);
4205      };
4206  
4207      var Overlay = YAHOO.widget.Overlay,
4208          Event = YAHOO.util.Event,
4209          Dom = YAHOO.util.Dom,
4210          Config = YAHOO.util.Config,
4211          CustomEvent = YAHOO.util.CustomEvent,
4212          OverlayManager = YAHOO.widget.OverlayManager;
4213  
4214      /**
4215      * The CSS class representing a focused Overlay
4216      * @property OverlayManager.CSS_FOCUSED
4217      * @static
4218      * @final
4219      * @type String
4220      */
4221      OverlayManager.CSS_FOCUSED = "focused";
4222  
4223      OverlayManager.prototype = {
4224  
4225          /**
4226          * The class's constructor function
4227          * @property contructor
4228          * @type Function
4229          */
4230          constructor: OverlayManager,
4231  
4232          /**
4233          * The array of Overlays that are currently registered
4234          * @property overlays
4235          * @type YAHOO.widget.Overlay[]
4236          */
4237          overlays: null,
4238  
4239          /**
4240          * Initializes the default configuration of the OverlayManager
4241          * @method initDefaultConfig
4242          */
4243          initDefaultConfig: function () {
4244              /**
4245              * The collection of registered Overlays in use by 
4246              * the OverlayManager
4247              * @config overlays
4248              * @type YAHOO.widget.Overlay[]
4249              * @default null
4250              */
4251              this.cfg.addProperty("overlays", { suppressEvent: true } );
4252  
4253              /**
4254              * The default DOM event that should be used to focus an Overlay
4255              * @config focusevent
4256              * @type String
4257              * @default "mousedown"
4258              */
4259              this.cfg.addProperty("focusevent", { value: "mousedown" } );
4260          },
4261  
4262          /**
4263          * Initializes the OverlayManager
4264          * @method init
4265          * @param {Overlay[]} overlays Optional. A collection of Overlays to 
4266          * register with the manager.
4267          * @param {Object} userConfig  The object literal representing the user 
4268          * configuration of the OverlayManager
4269          */
4270          init: function (userConfig) {
4271  
4272              /**
4273              * The OverlayManager's Config object used for monitoring 
4274              * configuration properties.
4275              * @property cfg
4276              * @type Config
4277              */
4278              this.cfg = new Config(this);
4279  
4280              this.initDefaultConfig();
4281  
4282              if (userConfig) {
4283                  this.cfg.applyConfig(userConfig, true);
4284              }
4285              this.cfg.fireQueue();
4286  
4287              /**
4288              * The currently activated Overlay
4289              * @property activeOverlay
4290              * @private
4291              * @type YAHOO.widget.Overlay
4292              */
4293              var activeOverlay = null;
4294  
4295              /**
4296              * Returns the currently focused Overlay
4297              * @method getActive
4298              * @return {Overlay} The currently focused Overlay
4299              */
4300              this.getActive = function () {
4301                  return activeOverlay;
4302              };
4303  
4304              /**
4305              * Focuses the specified Overlay
4306              * @method focus
4307              * @param {Overlay} overlay The Overlay to focus
4308              * @param {String} overlay The id of the Overlay to focus
4309              */
4310              this.focus = function (overlay) {
4311                  var o = this.find(overlay);
4312                  if (o) {
4313                      o.focus();
4314                  }
4315              };
4316  
4317              /**
4318              * Removes the specified Overlay from the manager
4319              * @method remove
4320              * @param {Overlay} overlay The Overlay to remove
4321              * @param {String} overlay The id of the Overlay to remove
4322              */
4323              this.remove = function (overlay) {
4324  
4325                  var o = this.find(overlay), 
4326                          originalZ;
4327  
4328                  if (o) {
4329                      if (activeOverlay == o) {
4330                          activeOverlay = null;
4331                      }
4332  
4333                      var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4334  
4335                      if (!bDestroyed) {
4336                          // Set it's zindex so that it's sorted to the end.
4337                          originalZ = Dom.getStyle(o.element, "zIndex");
4338                          o.cfg.setProperty("zIndex", -1000, true);
4339                      }
4340  
4341                      this.overlays.sort(this.compareZIndexDesc);
4342                      this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4343  
4344                      o.hideEvent.unsubscribe(o.blur);
4345                      o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4346                      o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4347                      o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4348  
4349                      if (!bDestroyed) {
4350                          Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4351                          o.cfg.setProperty("zIndex", originalZ, true);
4352                          o.cfg.setProperty("manager", null);
4353                      }
4354  
4355                      /* _managed Flag for custom or existing. Don't want to remove existing */
4356                      if (o.focusEvent._managed) { o.focusEvent = null; }
4357                      if (o.blurEvent._managed) { o.blurEvent = null; }
4358  
4359                      if (o.focus._managed) { o.focus = null; }
4360                      if (o.blur._managed) { o.blur = null; }
4361                  }
4362              };
4363  
4364              /**
4365              * Removes focus from all registered Overlays in the manager
4366              * @method blurAll
4367              */
4368              this.blurAll = function () {
4369  
4370                  var nOverlays = this.overlays.length,
4371                      i;
4372  
4373                  if (nOverlays > 0) {
4374                      i = nOverlays - 1;
4375                      do {
4376                          this.overlays[i].blur();
4377                      }
4378                      while(i--);
4379                  }
4380              };
4381  
4382              /**
4383               * Updates the state of the OverlayManager and overlay, as a result of the overlay
4384               * being blurred.
4385               * 
4386               * @method _manageBlur
4387               * @param {Overlay} overlay The overlay instance which got blurred.
4388               * @protected
4389               */
4390              this._manageBlur = function (overlay) {
4391                  var changed = false;
4392                  if (activeOverlay == overlay) {
4393                      Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4394                      activeOverlay = null;
4395                      changed = true;
4396                  }
4397                  return changed;
4398              };
4399  
4400              /**
4401               * Updates the state of the OverlayManager and overlay, as a result of the overlay 
4402               * receiving focus.
4403               *
4404               * @method _manageFocus
4405               * @param {Overlay} overlay The overlay instance which got focus.
4406               * @protected
4407               */
4408              this._manageFocus = function(overlay) {
4409                  var changed = false;
4410                  if (activeOverlay != overlay) {
4411                      if (activeOverlay) {
4412                          activeOverlay.blur();
4413                      }
4414                      activeOverlay = overlay;
4415                      this.bringToTop(activeOverlay);
4416                      Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4417                      changed = true;
4418                  }
4419                  return changed;
4420              };
4421  
4422              var overlays = this.cfg.getProperty("overlays");
4423  
4424              if (! this.overlays) {
4425                  this.overlays = [];
4426              }
4427  
4428              if (overlays) {
4429                  this.register(overlays);
4430                  this.overlays.sort(this.compareZIndexDesc);
4431              }
4432          },
4433  
4434          /**
4435          * @method _onOverlayElementFocus
4436          * @description Event handler for the DOM event that is used to focus 
4437          * the Overlay instance as specified by the "focusevent" 
4438          * configuration property.
4439          * @private
4440          * @param {Event} p_oEvent Object representing the DOM event 
4441          * object passed back by the event utility (Event).
4442          */
4443          _onOverlayElementFocus: function (p_oEvent) {
4444  
4445              var oTarget = Event.getTarget(p_oEvent),
4446                  oClose = this.close;
4447  
4448              if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4449                  this.blur();
4450              } else {
4451                  this.focus();
4452              }
4453          },
4454  
4455          /**
4456          * @method _onOverlayDestroy
4457          * @description "destroy" event handler for the Overlay.
4458          * @private
4459          * @param {String} p_sType String representing the name of the event  
4460          * that was fired.
4461          * @param {Array} p_aArgs Array of arguments sent when the event 
4462          * was fired.
4463          * @param {Overlay} p_oOverlay Object representing the overlay that 
4464          * fired the event.
4465          */
4466          _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4467              this.remove(p_oOverlay);
4468          },
4469  
4470          /**
4471          * @method _onOverlayFocusHandler
4472          *
4473          * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4474          *
4475          * @private
4476          * @param {String} p_sType String representing the name of the event  
4477          * that was fired.
4478          * @param {Array} p_aArgs Array of arguments sent when the event 
4479          * was fired.
4480          * @param {Overlay} p_oOverlay Object representing the overlay that 
4481          * fired the event.
4482          */
4483          _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4484              this._manageFocus(p_oOverlay);
4485          },
4486  
4487          /**
4488          * @method _onOverlayBlurHandler
4489          * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4490          *
4491          * @private
4492          * @param {String} p_sType String representing the name of the event  
4493          * that was fired.
4494          * @param {Array} p_aArgs Array of arguments sent when the event 
4495          * was fired.
4496          * @param {Overlay} p_oOverlay Object representing the overlay that 
4497          * fired the event.
4498          */
4499          _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4500              this._manageBlur(p_oOverlay);
4501          },
4502  
4503          /**
4504           * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4505           * monitor focus state.
4506           * 
4507           * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe 
4508           * to the existing focusEvent, however if a focusEvent or focus method does not exist
4509           * on the instance, the _bindFocus method will add them, and the focus method will 
4510           * update the OverlayManager's state directly.
4511           * 
4512           * @method _bindFocus
4513           * @param {Overlay} overlay The overlay for which focus needs to be managed
4514           * @protected
4515           */
4516          _bindFocus : function(overlay) {
4517              var mgr = this;
4518  
4519              if (!overlay.focusEvent) {
4520                  overlay.focusEvent = overlay.createEvent("focus");
4521                  overlay.focusEvent.signature = CustomEvent.LIST;
4522                  overlay.focusEvent._managed = true;
4523              } else {
4524                  overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4525              }
4526  
4527              if (!overlay.focus) {
4528                  Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4529                  overlay.focus = function () {
4530                      if (mgr._manageFocus(this)) {
4531                          // For Panel/Dialog
4532                          if (this.cfg.getProperty("visible") && this.focusFirst) {
4533                              this.focusFirst();
4534                          }
4535                          this.focusEvent.fire();
4536                      }
4537                  };
4538                  overlay.focus._managed = true;
4539              }
4540          },
4541  
4542          /**
4543           * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4544           * monitor blur state.
4545           *
4546           * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe 
4547           * to the existing blurEvent, however if a blurEvent or blur method does not exist
4548           * on the instance, the _bindBlur method will add them, and the blur method 
4549           * update the OverlayManager's state directly.
4550           *
4551           * @method _bindBlur
4552           * @param {Overlay} overlay The overlay for which blur needs to be managed
4553           * @protected
4554           */
4555          _bindBlur : function(overlay) {
4556              var mgr = this;
4557  
4558              if (!overlay.blurEvent) {
4559                  overlay.blurEvent = overlay.createEvent("blur");
4560                  overlay.blurEvent.signature = CustomEvent.LIST;
4561                  overlay.focusEvent._managed = true;
4562              } else {
4563                  overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4564              }
4565  
4566              if (!overlay.blur) {
4567                  overlay.blur = function () {
4568                      if (mgr._manageBlur(this)) {
4569                          this.blurEvent.fire();
4570                      }
4571                  };
4572                  overlay.blur._managed = true;
4573              }
4574  
4575              overlay.hideEvent.subscribe(overlay.blur);
4576          },
4577  
4578          /**
4579           * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4580           * to be removed for the OverlayManager when destroyed.
4581           * 
4582           * @method _bindDestroy
4583           * @param {Overlay} overlay The overlay instance being managed
4584           * @protected
4585           */
4586          _bindDestroy : function(overlay) {
4587              var mgr = this;
4588              overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4589          },
4590  
4591          /**
4592           * Ensures the zIndex configuration property on the managed overlay based instance
4593           * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4594           *
4595           * @method _syncZIndex
4596           * @param {Overlay} overlay The overlay instance being managed
4597           * @protected
4598           */
4599          _syncZIndex : function(overlay) {
4600              var zIndex = Dom.getStyle(overlay.element, "zIndex");
4601              if (!isNaN(zIndex)) {
4602                  overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4603              } else {
4604                  overlay.cfg.setProperty("zIndex", 0);
4605              }
4606          },
4607  
4608          /**
4609          * Registers an Overlay or an array of Overlays with the manager. Upon 
4610          * registration, the Overlay receives functions for focus and blur, 
4611          * along with CustomEvents for each.
4612          *
4613          * @method register
4614          * @param {Overlay} overlay  An Overlay to register with the manager.
4615          * @param {Overlay[]} overlay  An array of Overlays to register with 
4616          * the manager.
4617          * @return {boolean} true if any Overlays are registered.
4618          */
4619          register: function (overlay) {
4620  
4621              var registered = false,
4622                  i,
4623                  n;
4624  
4625              if (overlay instanceof Overlay) {
4626  
4627                  overlay.cfg.addProperty("manager", { value: this } );
4628  
4629                  this._bindFocus(overlay);
4630                  this._bindBlur(overlay);
4631                  this._bindDestroy(overlay);
4632                  this._syncZIndex(overlay);
4633  
4634                  this.overlays.push(overlay);
4635                  this.bringToTop(overlay);
4636  
4637                  registered = true;
4638  
4639              } else if (overlay instanceof Array) {
4640  
4641                  for (i = 0, n = overlay.length; i < n; i++) {
4642                      registered = this.register(overlay[i]) || registered;
4643                  }
4644  
4645              }
4646  
4647              return registered;
4648          },
4649  
4650          /**
4651          * Places the specified Overlay instance on top of all other 
4652          * Overlay instances.
4653          * @method bringToTop
4654          * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an 
4655          * Overlay instance.
4656          * @param {String} p_oOverlay String representing the id of an 
4657          * Overlay instance.
4658          */        
4659          bringToTop: function (p_oOverlay) {
4660  
4661              var oOverlay = this.find(p_oOverlay),
4662                  nTopZIndex,
4663                  oTopOverlay,
4664                  aOverlays;
4665  
4666              if (oOverlay) {
4667  
4668                  aOverlays = this.overlays;
4669                  aOverlays.sort(this.compareZIndexDesc);
4670  
4671                  oTopOverlay = aOverlays[0];
4672  
4673                  if (oTopOverlay) {
4674                      nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4675  
4676                      if (!isNaN(nTopZIndex)) {
4677  
4678                          var bRequiresBump = false;
4679  
4680                          if (oTopOverlay !== oOverlay) {
4681                              bRequiresBump = true;
4682                          } else if (aOverlays.length > 1) {
4683                              var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4684                              // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4685                              if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4686                                  bRequiresBump = true;
4687                              }
4688                          }
4689  
4690                          if (bRequiresBump) {
4691                              oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4692                          }
4693                      }
4694                      aOverlays.sort(this.compareZIndexDesc);
4695                  }
4696              }
4697          },
4698  
4699          /**
4700          * Attempts to locate an Overlay by instance or ID.
4701          * @method find
4702          * @param {Overlay} overlay  An Overlay to locate within the manager
4703          * @param {String} overlay  An Overlay id to locate within the manager
4704          * @return {Overlay} The requested Overlay, if found, or null if it 
4705          * cannot be located.
4706          */
4707          find: function (overlay) {
4708  
4709              var isInstance = overlay instanceof Overlay,
4710                  overlays = this.overlays,
4711                  n = overlays.length,
4712                  found = null,
4713                  o,
4714                  i;
4715  
4716              if (isInstance || typeof overlay == "string") {
4717                  for (i = n-1; i >= 0; i--) {
4718                      o = overlays[i];
4719                      if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4720                          found = o;
4721                          break;
4722                      }
4723                  }
4724              }
4725  
4726              return found;
4727          },
4728  
4729          /**
4730          * Used for sorting the manager's Overlays by z-index.
4731          * @method compareZIndexDesc
4732          * @private
4733          * @return {Number} 0, 1, or -1, depending on where the Overlay should 
4734          * fall in the stacking order.
4735          */
4736          compareZIndexDesc: function (o1, o2) {
4737  
4738              var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4739                  zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4740  
4741              if (zIndex1 === null && zIndex2 === null) {
4742                  return 0;
4743              } else if (zIndex1 === null){
4744                  return 1;
4745              } else if (zIndex2 === null) {
4746                  return -1;
4747              } else if (zIndex1 > zIndex2) {
4748                  return -1;
4749              } else if (zIndex1 < zIndex2) {
4750                  return 1;
4751              } else {
4752                  return 0;
4753              }
4754          },
4755  
4756          /**
4757          * Shows all Overlays in the manager.
4758          * @method showAll
4759          */
4760          showAll: function () {
4761              var overlays = this.overlays,
4762                  n = overlays.length,
4763                  i;
4764  
4765              for (i = n - 1; i >= 0; i--) {
4766                  overlays[i].show();
4767              }
4768          },
4769  
4770          /**
4771          * Hides all Overlays in the manager.
4772          * @method hideAll
4773          */
4774          hideAll: function () {
4775              var overlays = this.overlays,
4776                  n = overlays.length,
4777                  i;
4778  
4779              for (i = n - 1; i >= 0; i--) {
4780                  overlays[i].hide();
4781              }
4782          },
4783  
4784          /**
4785          * Returns a string representation of the object.
4786          * @method toString
4787          * @return {String} The string representation of the OverlayManager
4788          */
4789          toString: function () {
4790              return "OverlayManager";
4791          }
4792      };
4793  }());
4794  (function () {
4795  
4796      /**
4797      * ContainerEffect encapsulates animation transitions that are executed when 
4798      * an Overlay is shown or hidden.
4799      * @namespace YAHOO.widget
4800      * @class ContainerEffect
4801      * @constructor
4802      * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation 
4803      * should be associated with
4804      * @param {Object} attrIn The object literal representing the animation 
4805      * arguments to be used for the animate-in transition. The arguments for 
4806      * this literal are: attributes(object, see YAHOO.util.Anim for description), 
4807      * duration(Number), and method(i.e. Easing.easeIn).
4808      * @param {Object} attrOut The object literal representing the animation 
4809      * arguments to be used for the animate-out transition. The arguments for  
4810      * this literal are: attributes(object, see YAHOO.util.Anim for description), 
4811      * duration(Number), and method(i.e. Easing.easeIn).
4812      * @param {HTMLElement} targetElement Optional. The target element that  
4813      * should be animated during the transition. Defaults to overlay.element.
4814      * @param {class} Optional. The animation class to instantiate. Defaults to 
4815      * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4816      */
4817      YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
4818  
4819          if (!animClass) {
4820              animClass = YAHOO.util.Anim;
4821          }
4822  
4823          /**
4824          * The overlay to animate
4825          * @property overlay
4826          * @type YAHOO.widget.Overlay
4827          */
4828          this.overlay = overlay;
4829      
4830          /**
4831          * The animation attributes to use when transitioning into view
4832          * @property attrIn
4833          * @type Object
4834          */
4835          this.attrIn = attrIn;
4836      
4837          /**
4838          * The animation attributes to use when transitioning out of view
4839          * @property attrOut
4840          * @type Object
4841          */
4842          this.attrOut = attrOut;
4843      
4844          /**
4845          * The target element to be animated
4846          * @property targetElement
4847          * @type HTMLElement
4848          */
4849          this.targetElement = targetElement || overlay.element;
4850      
4851          /**
4852          * The animation class to use for animating the overlay
4853          * @property animClass
4854          * @type class
4855          */
4856          this.animClass = animClass;
4857      };
4858  
4859      var Dom = YAHOO.util.Dom,
4860          CustomEvent = YAHOO.util.CustomEvent,
4861          ContainerEffect = YAHOO.widget.ContainerEffect;
4862  
4863      /**
4864      * A pre-configured ContainerEffect instance that can be used for fading 
4865      * an overlay in and out.
4866      * @method FADE
4867      * @static
4868      * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4869      * @param {Number} dur The duration of the animation
4870      * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4871      */
4872      ContainerEffect.FADE = function (overlay, dur) {
4873  
4874          var Easing = YAHOO.util.Easing,
4875              fin = {
4876                  attributes: {opacity:{from:0, to:1}},
4877                  duration: dur,
4878                  method: Easing.easeIn
4879              },
4880              fout = {
4881                  attributes: {opacity:{to:0}},
4882                  duration: dur,
4883                  method: Easing.easeOut
4884              },
4885              fade = new ContainerEffect(overlay, fin, fout, overlay.element);
4886  
4887          fade.handleUnderlayStart = function() {
4888              var underlay = this.overlay.underlay;
4889              if (underlay && YAHOO.env.ua.ie) {
4890                  var hasFilters = (underlay.filters && underlay.filters.length > 0);
4891                  if(hasFilters) {
4892                      Dom.addClass(overlay.element, "yui-effect-fade");
4893                  }
4894              }
4895          };
4896  
4897          fade.handleUnderlayComplete = function() {
4898              var underlay = this.overlay.underlay;
4899              if (underlay && YAHOO.env.ua.ie) {
4900                  Dom.removeClass(overlay.element, "yui-effect-fade");
4901              }
4902          };
4903  
4904          fade.handleStartAnimateIn = function (type, args, obj) {
4905              obj.overlay._fadingIn = true;
4906  
4907              Dom.addClass(obj.overlay.element, "hide-select");
4908  
4909              if (!obj.overlay.underlay) {
4910                  obj.overlay.cfg.refireEvent("underlay");
4911              }
4912  
4913              obj.handleUnderlayStart();
4914  
4915              obj.overlay._setDomVisibility(true);
4916              Dom.setStyle(obj.overlay.element, "opacity", 0);
4917          };
4918  
4919          fade.handleCompleteAnimateIn = function (type,args,obj) {
4920              obj.overlay._fadingIn = false;
4921              
4922              Dom.removeClass(obj.overlay.element, "hide-select");
4923  
4924              if (obj.overlay.element.style.filter) {
4925                  obj.overlay.element.style.filter = null;
4926              }
4927  
4928              obj.handleUnderlayComplete();
4929  
4930              obj.overlay.cfg.refireEvent("iframe");
4931              obj.animateInCompleteEvent.fire();
4932          };
4933  
4934          fade.handleStartAnimateOut = function (type, args, obj) {
4935              obj.overlay._fadingOut = true;
4936              Dom.addClass(obj.overlay.element, "hide-select");
4937              obj.handleUnderlayStart();
4938          };
4939  
4940          fade.handleCompleteAnimateOut =  function (type, args, obj) {
4941              obj.overlay._fadingOut = false;
4942              Dom.removeClass(obj.overlay.element, "hide-select");
4943  
4944              if (obj.overlay.element.style.filter) {
4945                  obj.overlay.element.style.filter = null;
4946              }
4947              obj.overlay._setDomVisibility(false);
4948              Dom.setStyle(obj.overlay.element, "opacity", 1);
4949  
4950              obj.handleUnderlayComplete();
4951  
4952              obj.overlay.cfg.refireEvent("iframe");
4953              obj.animateOutCompleteEvent.fire();
4954          };
4955  
4956          fade.init();
4957          return fade;
4958      };
4959      
4960      
4961      /**
4962      * A pre-configured ContainerEffect instance that can be used for sliding an 
4963      * overlay in and out.
4964      * @method SLIDE
4965      * @static
4966      * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4967      * @param {Number} dur The duration of the animation
4968      * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4969      */
4970      ContainerEffect.SLIDE = function (overlay, dur) {
4971          var Easing = YAHOO.util.Easing,
4972  
4973              x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
4974              y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
4975              clientWidth = Dom.getClientWidth(),
4976              offsetWidth = overlay.element.offsetWidth,
4977  
4978              sin =  { 
4979                  attributes: { points: { to: [x, y] } },
4980                  duration: dur,
4981                  method: Easing.easeIn 
4982              },
4983  
4984              sout = {
4985                  attributes: { points: { to: [(clientWidth + 25), y] } },
4986                  duration: dur,
4987                  method: Easing.easeOut 
4988              },
4989  
4990              slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
4991  
4992          slide.handleStartAnimateIn = function (type,args,obj) {
4993              obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
4994              obj.overlay.element.style.top  = y + "px";
4995          };
4996  
4997          slide.handleTweenAnimateIn = function (type, args, obj) {
4998          
4999              var pos = Dom.getXY(obj.overlay.element),
5000                  currentX = pos[0],
5001                  currentY = pos[1];
5002          
5003              if (Dom.getStyle(obj.overlay.element, "visibility") == 
5004                  "hidden" && currentX < x) {
5005  
5006                  obj.overlay._setDomVisibility(true);
5007  
5008              }
5009          
5010              obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
5011              obj.overlay.cfg.refireEvent("iframe");
5012          };
5013          
5014          slide.handleCompleteAnimateIn = function (type, args, obj) {
5015              obj.overlay.cfg.setProperty("xy", [x, y], true);
5016              obj.startX = x;
5017              obj.startY = y;
5018              obj.overlay.cfg.refireEvent("iframe");
5019              obj.animateInCompleteEvent.fire();
5020          };
5021  
5022          slide.handleStartAnimateOut = function (type, args, obj) {
5023      
5024              var vw = Dom.getViewportWidth(),
5025                  pos = Dom.getXY(obj.overlay.element),
5026                  yso = pos[1];
5027      
5028              obj.animOut.attributes.points.to = [(vw + 25), yso];
5029          };
5030          
5031          slide.handleTweenAnimateOut = function (type, args, obj) {
5032      
5033              var pos = Dom.getXY(obj.overlay.element),
5034                  xto = pos[0],
5035                  yto = pos[1];
5036          
5037              obj.overlay.cfg.setProperty("xy", [xto, yto], true);
5038              obj.overlay.cfg.refireEvent("iframe");
5039          };
5040          
5041          slide.handleCompleteAnimateOut = function (type, args, obj) {
5042              obj.overlay._setDomVisibility(false);
5043  
5044              obj.overlay.cfg.setProperty("xy", [x, y]);
5045              obj.animateOutCompleteEvent.fire();
5046          };
5047  
5048          slide.init();
5049          return slide;
5050      };
5051  
5052      ContainerEffect.prototype = {
5053  
5054          /**
5055          * Initializes the animation classes and events.
5056          * @method init
5057          */
5058          init: function () {
5059  
5060              this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
5061              this.beforeAnimateInEvent.signature = CustomEvent.LIST;
5062              
5063              this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
5064              this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
5065          
5066              this.animateInCompleteEvent = this.createEvent("animateInComplete");
5067              this.animateInCompleteEvent.signature = CustomEvent.LIST;
5068          
5069              this.animateOutCompleteEvent = this.createEvent("animateOutComplete");
5070              this.animateOutCompleteEvent.signature = CustomEvent.LIST;
5071  
5072              this.animIn = new this.animClass(
5073                  this.targetElement, 
5074                  this.attrIn.attributes, 
5075                  this.attrIn.duration, 
5076                  this.attrIn.method);
5077  
5078              this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
5079              this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
5080              this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);
5081          
5082              this.animOut = new this.animClass(
5083                  this.targetElement, 
5084                  this.attrOut.attributes, 
5085                  this.attrOut.duration, 
5086                  this.attrOut.method);
5087  
5088              this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
5089              this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
5090              this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, this);
5091  
5092          },
5093  
5094          /**
5095          * Triggers the in-animation.
5096          * @method animateIn
5097          */
5098          animateIn: function () {
5099              this._stopAnims(this.lastFrameOnStop);
5100              this.beforeAnimateInEvent.fire();
5101              this.animIn.animate();
5102          },
5103  
5104          /**
5105          * Triggers the out-animation.
5106          * @method animateOut
5107          */
5108          animateOut: function () {
5109              this._stopAnims(this.lastFrameOnStop);
5110              this.beforeAnimateOutEvent.fire();
5111              this.animOut.animate();
5112          },
5113          
5114          /**
5115           * Flag to define whether Anim should jump to the last frame,
5116           * when animateIn or animateOut is stopped.
5117           *
5118           * @property lastFrameOnStop
5119           * @default true
5120           * @type boolean
5121           */
5122          lastFrameOnStop : true,
5123  
5124          /**
5125           * Stops both animIn and animOut instances, if in progress.
5126           *
5127           * @method _stopAnims
5128           * @param {boolean} finish If true, animation will jump to final frame.
5129           * @protected
5130           */
5131          _stopAnims : function(finish) {
5132              if (this.animOut && this.animOut.isAnimated()) {
5133                  this.animOut.stop(finish);
5134              }
5135  
5136              if (this.animIn && this.animIn.isAnimated()) {
5137                  this.animIn.stop(finish);
5138              }
5139          },
5140  
5141          /**
5142          * The default onStart handler for the in-animation.
5143          * @method handleStartAnimateIn
5144          * @param {String} type The CustomEvent type
5145          * @param {Object[]} args The CustomEvent arguments
5146          * @param {Object} obj The scope object
5147          */
5148          handleStartAnimateIn: function (type, args, obj) { },
5149  
5150          /**
5151          * The default onTween handler for the in-animation.
5152          * @method handleTweenAnimateIn
5153          * @param {String} type The CustomEvent type
5154          * @param {Object[]} args The CustomEvent arguments
5155          * @param {Object} obj The scope object
5156          */
5157          handleTweenAnimateIn: function (type, args, obj) { },
5158  
5159          /**
5160          * The default onComplete handler for the in-animation.
5161          * @method handleCompleteAnimateIn
5162          * @param {String} type The CustomEvent type
5163          * @param {Object[]} args The CustomEvent arguments
5164          * @param {Object} obj The scope object
5165          */
5166          handleCompleteAnimateIn: function (type, args, obj) { },
5167  
5168          /**
5169          * The default onStart handler for the out-animation.
5170          * @method handleStartAnimateOut
5171          * @param {String} type The CustomEvent type
5172          * @param {Object[]} args The CustomEvent arguments
5173          * @param {Object} obj The scope object
5174          */
5175          handleStartAnimateOut: function (type, args, obj) { },
5176  
5177          /**
5178          * The default onTween handler for the out-animation.
5179          * @method handleTweenAnimateOut
5180          * @param {String} type The CustomEvent type
5181          * @param {Object[]} args The CustomEvent arguments
5182          * @param {Object} obj The scope object
5183          */
5184          handleTweenAnimateOut: function (type, args, obj) { },
5185  
5186          /**
5187          * The default onComplete handler for the out-animation.
5188          * @method handleCompleteAnimateOut
5189          * @param {String} type The CustomEvent type
5190          * @param {Object[]} args The CustomEvent arguments
5191          * @param {Object} obj The scope object
5192          */
5193          handleCompleteAnimateOut: function (type, args, obj) { },
5194          
5195          /**
5196          * Returns a string representation of the object.
5197          * @method toString
5198          * @return {String} The string representation of the ContainerEffect
5199          */
5200          toString: function () {
5201              var output = "ContainerEffect";
5202              if (this.overlay) {
5203                  output += " [" + this.overlay.toString() + "]";
5204              }
5205              return output;
5206          }
5207      };
5208  
5209      YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
5210  
5211  })();
5212  YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.9.0", build: "2800"});
5213  
5214  }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event"]});


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