PageSourceSearch

https://www.aulaformacion.org/campus/lib/yui/container/container_core.js

js aulaformacion.org collected 2026-10-04 13:25:19 UTC 177,356 bytes, 5,049 lines download raw bytes

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

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.