[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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