PageSourceSearch

http://www.accountsupport.com/generalAppC/javascripts/yui/container/container.js

js accountsupport.com collected 2026-10-03 22:10:26 UTC 320,751 bytes, 9,064 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.