Bug 16241 - Move staff client CSS out of language directory
[koha.git] / koha-tmpl / intranet-tmpl / lib / yui / container / container_core-debug.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.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     * ContainerEffect encapsulates animation transitions that are executed when 
4755     * an Overlay is shown or hidden.
4756     * @namespace YAHOO.widget
4757     * @class ContainerEffect
4758     * @constructor
4759     * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation 
4760     * should be associated with
4761     * @param {Object} attrIn The object literal representing the animation 
4762     * arguments to be used for the animate-in transition. The arguments for 
4763     * this literal are: attributes(object, see YAHOO.util.Anim for description), 
4764     * duration(Number), and method(i.e. Easing.easeIn).
4765     * @param {Object} attrOut The object literal representing the animation 
4766     * arguments to be used for the animate-out transition. The arguments for  
4767     * this literal are: attributes(object, see YAHOO.util.Anim for description), 
4768     * duration(Number), and method(i.e. Easing.easeIn).
4769     * @param {HTMLElement} targetElement Optional. The target element that  
4770     * should be animated during the transition. Defaults to overlay.element.
4771     * @param {class} Optional. The animation class to instantiate. Defaults to 
4772     * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4773     */
4774     YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
4775
4776         if (!animClass) {
4777             animClass = YAHOO.util.Anim;
4778         }
4779
4780         /**
4781         * The overlay to animate
4782         * @property overlay
4783         * @type YAHOO.widget.Overlay
4784         */
4785         this.overlay = overlay;
4786     
4787         /**
4788         * The animation attributes to use when transitioning into view
4789         * @property attrIn
4790         * @type Object
4791         */
4792         this.attrIn = attrIn;
4793     
4794         /**
4795         * The animation attributes to use when transitioning out of view
4796         * @property attrOut
4797         * @type Object
4798         */
4799         this.attrOut = attrOut;
4800     
4801         /**
4802         * The target element to be animated
4803         * @property targetElement
4804         * @type HTMLElement
4805         */
4806         this.targetElement = targetElement || overlay.element;
4807     
4808         /**
4809         * The animation class to use for animating the overlay
4810         * @property animClass
4811         * @type class
4812         */
4813         this.animClass = animClass;
4814     
4815     };
4816
4817
4818     var Dom = YAHOO.util.Dom,
4819         CustomEvent = YAHOO.util.CustomEvent,
4820         ContainerEffect = YAHOO.widget.ContainerEffect;
4821
4822
4823     /**
4824     * A pre-configured ContainerEffect instance that can be used for fading 
4825     * an overlay in and out.
4826     * @method FADE
4827     * @static
4828     * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4829     * @param {Number} dur The duration of the animation
4830     * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4831     */
4832     ContainerEffect.FADE = function (overlay, dur) {
4833
4834         var Easing = YAHOO.util.Easing,
4835             fin = {
4836                 attributes: {opacity:{from:0, to:1}},
4837                 duration: dur,
4838                 method: Easing.easeIn
4839             },
4840             fout = {
4841                 attributes: {opacity:{to:0}},
4842                 duration: dur,
4843                 method: Easing.easeOut
4844             },
4845             fade = new ContainerEffect(overlay, fin, fout, overlay.element);
4846
4847         fade.handleUnderlayStart = function() {
4848             var underlay = this.overlay.underlay;
4849             if (underlay && YAHOO.env.ua.ie) {
4850                 var hasFilters = (underlay.filters && underlay.filters.length > 0);
4851                 if(hasFilters) {
4852                     Dom.addClass(overlay.element, "yui-effect-fade");
4853                 }
4854             }
4855         };
4856
4857         fade.handleUnderlayComplete = function() {
4858             var underlay = this.overlay.underlay;
4859             if (underlay && YAHOO.env.ua.ie) {
4860                 Dom.removeClass(overlay.element, "yui-effect-fade");
4861             }
4862         };
4863
4864         fade.handleStartAnimateIn = function (type, args, obj) {
4865             Dom.addClass(obj.overlay.element, "hide-select");
4866
4867             if (!obj.overlay.underlay) {
4868                 obj.overlay.cfg.refireEvent("underlay");
4869             }
4870
4871             obj.handleUnderlayStart();
4872
4873             obj.overlay._setDomVisibility(true);
4874             Dom.setStyle(obj.overlay.element, "opacity", 0);
4875         };
4876
4877         fade.handleCompleteAnimateIn = function (type,args,obj) {
4878             Dom.removeClass(obj.overlay.element, "hide-select");
4879
4880             if (obj.overlay.element.style.filter) {
4881                 obj.overlay.element.style.filter = null;
4882             }
4883
4884             obj.handleUnderlayComplete();
4885
4886             obj.overlay.cfg.refireEvent("iframe");
4887             obj.animateInCompleteEvent.fire();
4888         };
4889
4890         fade.handleStartAnimateOut = function (type, args, obj) {
4891             Dom.addClass(obj.overlay.element, "hide-select");
4892             obj.handleUnderlayStart();
4893         };
4894
4895         fade.handleCompleteAnimateOut =  function (type, args, obj) {
4896             Dom.removeClass(obj.overlay.element, "hide-select");
4897             if (obj.overlay.element.style.filter) {
4898                 obj.overlay.element.style.filter = null;
4899             }
4900             obj.overlay._setDomVisibility(false);
4901             Dom.setStyle(obj.overlay.element, "opacity", 1);
4902
4903             obj.handleUnderlayComplete();
4904
4905             obj.overlay.cfg.refireEvent("iframe");
4906             obj.animateOutCompleteEvent.fire();
4907         };
4908
4909         fade.init();
4910         return fade;
4911     };
4912     
4913     
4914     /**
4915     * A pre-configured ContainerEffect instance that can be used for sliding an 
4916     * overlay in and out.
4917     * @method SLIDE
4918     * @static
4919     * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4920     * @param {Number} dur The duration of the animation
4921     * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4922     */
4923     ContainerEffect.SLIDE = function (overlay, dur) {
4924         var Easing = YAHOO.util.Easing,
4925
4926             x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
4927             y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
4928             clientWidth = Dom.getClientWidth(),
4929             offsetWidth = overlay.element.offsetWidth,
4930
4931             sin =  { 
4932                 attributes: { points: { to: [x, y] } },
4933                 duration: dur,
4934                 method: Easing.easeIn 
4935             },
4936
4937             sout = {
4938                 attributes: { points: { to: [(clientWidth + 25), y] } },
4939                 duration: dur,
4940                 method: Easing.easeOut 
4941             },
4942
4943             slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
4944
4945         slide.handleStartAnimateIn = function (type,args,obj) {
4946             obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
4947             obj.overlay.element.style.top  = y + "px";
4948         };
4949
4950         slide.handleTweenAnimateIn = function (type, args, obj) {
4951         
4952             var pos = Dom.getXY(obj.overlay.element),
4953                 currentX = pos[0],
4954                 currentY = pos[1];
4955         
4956             if (Dom.getStyle(obj.overlay.element, "visibility") == 
4957                 "hidden" && currentX < x) {
4958
4959                 obj.overlay._setDomVisibility(true);
4960
4961             }
4962         
4963             obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
4964             obj.overlay.cfg.refireEvent("iframe");
4965         };
4966         
4967         slide.handleCompleteAnimateIn = function (type, args, obj) {
4968             obj.overlay.cfg.setProperty("xy", [x, y], true);
4969             obj.startX = x;
4970             obj.startY = y;
4971             obj.overlay.cfg.refireEvent("iframe");
4972             obj.animateInCompleteEvent.fire();
4973         };
4974         
4975         slide.handleStartAnimateOut = function (type, args, obj) {
4976     
4977             var vw = Dom.getViewportWidth(),
4978                 pos = Dom.getXY(obj.overlay.element),
4979                 yso = pos[1];
4980     
4981             obj.animOut.attributes.points.to = [(vw + 25), yso];
4982         };
4983         
4984         slide.handleTweenAnimateOut = function (type, args, obj) {
4985     
4986             var pos = Dom.getXY(obj.overlay.element),
4987                 xto = pos[0],
4988                 yto = pos[1];
4989         
4990             obj.overlay.cfg.setProperty("xy", [xto, yto], true);
4991             obj.overlay.cfg.refireEvent("iframe");
4992         };
4993         
4994         slide.handleCompleteAnimateOut = function (type, args, obj) {
4995             obj.overlay._setDomVisibility(false);
4996
4997             obj.overlay.cfg.setProperty("xy", [x, y]);
4998             obj.animateOutCompleteEvent.fire();
4999         };
5000
5001         slide.init();
5002         return slide;
5003     };
5004
5005     ContainerEffect.prototype = {
5006
5007         /**
5008         * Initializes the animation classes and events.
5009         * @method init
5010         */
5011         init: function () {
5012
5013             this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
5014             this.beforeAnimateInEvent.signature = CustomEvent.LIST;
5015             
5016             this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
5017             this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
5018         
5019             this.animateInCompleteEvent = this.createEvent("animateInComplete");
5020             this.animateInCompleteEvent.signature = CustomEvent.LIST;
5021         
5022             this.animateOutCompleteEvent = 
5023                 this.createEvent("animateOutComplete");
5024             this.animateOutCompleteEvent.signature = CustomEvent.LIST;
5025         
5026             this.animIn = new this.animClass(this.targetElement, 
5027                 this.attrIn.attributes, this.attrIn.duration, 
5028                 this.attrIn.method);
5029
5030             this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
5031             this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
5032
5033             this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn, 
5034                 this);
5035         
5036             this.animOut = new this.animClass(this.targetElement, 
5037                 this.attrOut.attributes, this.attrOut.duration, 
5038                 this.attrOut.method);
5039
5040             this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
5041             this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
5042             this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, 
5043                 this);
5044
5045         },
5046         
5047         /**
5048         * Triggers the in-animation.
5049         * @method animateIn
5050         */
5051         animateIn: function () {
5052             this.beforeAnimateInEvent.fire();
5053             this.animIn.animate();
5054         },
5055
5056         /**
5057         * Triggers the out-animation.
5058         * @method animateOut
5059         */
5060         animateOut: function () {
5061             this.beforeAnimateOutEvent.fire();
5062             this.animOut.animate();
5063         },
5064
5065         /**
5066         * The default onStart handler for the in-animation.
5067         * @method handleStartAnimateIn
5068         * @param {String} type The CustomEvent type
5069         * @param {Object[]} args The CustomEvent arguments
5070         * @param {Object} obj The scope object
5071         */
5072         handleStartAnimateIn: function (type, args, obj) { },
5073
5074         /**
5075         * The default onTween handler for the in-animation.
5076         * @method handleTweenAnimateIn
5077         * @param {String} type The CustomEvent type
5078         * @param {Object[]} args The CustomEvent arguments
5079         * @param {Object} obj The scope object
5080         */
5081         handleTweenAnimateIn: function (type, args, obj) { },
5082
5083         /**
5084         * The default onComplete handler for the in-animation.
5085         * @method handleCompleteAnimateIn
5086         * @param {String} type The CustomEvent type
5087         * @param {Object[]} args The CustomEvent arguments
5088         * @param {Object} obj The scope object
5089         */
5090         handleCompleteAnimateIn: function (type, args, obj) { },
5091
5092         /**
5093         * The default onStart handler for the out-animation.
5094         * @method handleStartAnimateOut
5095         * @param {String} type The CustomEvent type
5096         * @param {Object[]} args The CustomEvent arguments
5097         * @param {Object} obj The scope object
5098         */
5099         handleStartAnimateOut: function (type, args, obj) { },
5100
5101         /**
5102         * The default onTween handler for the out-animation.
5103         * @method handleTweenAnimateOut
5104         * @param {String} type The CustomEvent type
5105         * @param {Object[]} args The CustomEvent arguments
5106         * @param {Object} obj The scope object
5107         */
5108         handleTweenAnimateOut: function (type, args, obj) { },
5109
5110         /**
5111         * The default onComplete handler for the out-animation.
5112         * @method handleCompleteAnimateOut
5113         * @param {String} type The CustomEvent type
5114         * @param {Object[]} args The CustomEvent arguments
5115         * @param {Object} obj The scope object
5116         */
5117         handleCompleteAnimateOut: function (type, args, obj) { },
5118         
5119         /**
5120         * Returns a string representation of the object.
5121         * @method toString
5122         * @return {String} The string representation of the ContainerEffect
5123         */
5124         toString: function () {
5125             var output = "ContainerEffect";
5126             if (this.overlay) {
5127                 output += " [" + this.overlay.toString() + "]";
5128             }
5129             return output;
5130         }
5131     };
5132
5133     YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
5134
5135 })();
5136 YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.8.0r4", build: "2449"});