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