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