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