# Yahoo! UI Library

### Container

Yahoo! UI Library > container > Overlay.js (source view)

    /*
    Copyright (c) 2006, Yahoo! Inc. All rights reserved.
    Code licensed under the BSD License:
    http://developer.yahoo.net/yui/license.txt
    Version 0.12
    */

    /**
    * Overlay is a Module that is absolutely positioned above the page flow. It has convenience methods for positioning and sizing, as well as options for controlling zIndex and constraining the Overlay's position to the current visible viewport. Overlay also contains a dynamicly generated IFRAME which is placed beneath it for Internet Explorer 6 and 5.x so that it will be properly rendered above SELECT elements.
    * @namespace YAHOO.widget
    * @class Overlay
    * @extends YAHOO.widget.Module
    * @param {String}	el	The element ID representing the Overlay <em>OR</em>
    * @param {HTMLElement}	el	The element representing the Overlay
    * @param {Object}	userConfig	The configuration object literal containing 10/23/2006the configuration that should be set for this Overlay. See configuration documentation for more details.
    * @constructor
    */
    YAHOO.widget.Overlay = function(el, userConfig) {
    	YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
    };

    YAHOO.extend(YAHOO.widget.Overlay, YAHOO.widget.Module);

    /**
    * The URL that will be placed in the iframe
    * @property YAHOO.widget.Overlay.IFRAME_SRC
    * @static
    * @final
    * @type String
    */
    YAHOO.widget.Overlay.IFRAME_SRC = "javascript:false;"

    /**
    * Constant representing the top left corner of an element, used for configuring the context element alignment
    * @property YAHOO.widget.Overlay.TOP_LEFT
    * @static
    * @final
    * @type String
    */
    YAHOO.widget.Overlay.TOP_LEFT = "tl";

    /**
    * Constant representing the top right corner of an element, used for configuring the context element alignment
    * @property YAHOO.widget.Overlay.TOP_RIGHT
    * @static
    * @final
    * @type String
    */
    YAHOO.widget.Overlay.TOP_RIGHT = "tr";

    /**
    * Constant representing the top bottom left corner of an element, used for configuring the context element alignment
    * @property YAHOO.widget.Overlay.BOTTOM_LEFT
    * @static
    * @final
    * @type String
    */
    YAHOO.widget.Overlay.BOTTOM_LEFT = "bl";

    /**
    * Constant representing the bottom right corner of an element, used for configuring the context element alignment
    * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
    * @static
    * @final
    * @type String
    */
    YAHOO.widget.Overlay.BOTTOM_RIGHT = "br";

    /**
    * Constant representing the default CSS class used for an Overlay
    * @property YAHOO.widget.Overlay.CSS_OVERLAY
    * @static
    * @final
    * @type String
    */
    YAHOO.widget.Overlay.CSS_OVERLAY = "overlay";

    /**
    * The Overlay initialization method, which is executed for Overlay and all of its subclasses. This method is automatically called by the constructor, and  sets up all DOM references for pre-existing markup, and creates required markup if it is not already present.
    * @method init
    * @param {String}	el	The element ID representing the Overlay <em>OR</em>
    * @param {HTMLElement}	el	The element representing the Overlay
    * @param {Object}	userConfig	The configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details.
    */
    YAHOO.widget.Overlay.prototype.init = function(el, userConfig) {
    	YAHOO.widget.Overlay.superclass.init.call(this, el/*, userConfig*/);  // Note that we don't pass the user config in here yet because we only want it executed once, at the lowest subclass level

    	this.beforeInitEvent.fire(YAHOO.widget.Overlay);

    	YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Overlay.CSS_OVERLAY);

    	if (userConfig) {
    		this.cfg.applyConfig(userConfig, true);
    	}

    	if (this.platform == "mac" && this.browser == "gecko") {
    		if (! YAHOO.util.Config.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)) {
    			this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true);
    		}
    		if (! YAHOO.util.Config.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)) {
    			this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true);
    		}
    	}

    	this.initEvent.fire(YAHOO.widget.Overlay);
    };

    /**
    * Initializes the custom events for Overlay which are fired automatically at appropriate times by the Overlay class.
    * @method initEvents
    */
    YAHOO.widget.Overlay.prototype.initEvents = function() {
    	YAHOO.widget.Overlay.superclass.initEvents.call(this);

    	/**
    	* CustomEvent fired before the Overlay is moved.
    	* @event beforeMoveEvent
    	* @param {Number} x	x coordinate
    	* @param {Number} y	y coordinate
    	*/
    	this.beforeMoveEvent = new YAHOO.util.CustomEvent("beforeMove", this);

    	/**
    	* CustomEvent fired after the Overlay is moved.
    	* @event moveEvent
    	* @param {Number} x	x coordinate
    	* @param {Number} y	y coordinate
    	*/
    	this.moveEvent = new YAHOO.util.CustomEvent("move", this);
    };

    /**
    * Initializes the class's configurable properties which can be changed using the Overlay's Config object (cfg).
    * @method initDefaultConfig
    */
    YAHOO.widget.Overlay.prototype.initDefaultConfig = function() {
    	YAHOO.widget.Overlay.superclass.initDefaultConfig.call(this);

    	// Add overlay config properties //

    	/**
    	* The absolute x-coordinate position of the Overlay
    	* @config x
    	* @type Number
    	* @default null
    	*/
    	this.cfg.addProperty("x", { handler:this.configX, validator:this.cfg.checkNumber, suppressEvent:true, supercedes:["iframe"] } );

    	/**
    	* The absolute y-coordinate position of the Overlay
    	* @config y
    	* @type Number
    	* @default null
    	*/
    	this.cfg.addProperty("y", { handler:this.configY, validator:this.cfg.checkNumber, suppressEvent:true, supercedes:["iframe"] } );

    	/**
    	* An array with the absolute x and y positions of the Overlay
    	* @config xy
    	* @type Number[]
    	* @default null
    	*/
    	this.cfg.addProperty("xy",{ handler:this.configXY, suppressEvent:true, supercedes:["iframe"] } );

    	/**
    	* The array of context arguments for context-sensitive positioning. The format is: [id or element, element corner, context corner]. For example, setting this property to ["img1", "tl", "bl"] would align the Overlay's top left corner to the context element's bottom left corner.
    	* @config context
    	* @type Array
    	* @default null
    	*/
    	this.cfg.addProperty("context",	{ handler:this.configContext, suppressEvent:true, supercedes:["iframe"] } );

    	/**
    	* True if the Overlay should be anchored to the center of the viewport.
    	* @config fixedcenter
    	* @type Boolean
    	* @default false
    	*/
    	this.cfg.addProperty("fixedcenter", { value:false, handler:this.configFixedCenter, validator:this.cfg.checkBoolean, supercedes:["iframe","visible"] } );

    	/**
    	* CSS width of the Overlay.
    	* @config width
    	* @type String
    	* @default null
    	*/
    	this.cfg.addProperty("width", { handler:this.configWidth, suppressEvent:true, supercedes:["iframe"] } );

    	/**
    	* CSS height of the Overlay.
    	* @config height
    	* @type String
    	* @default null
    	*/
    	this.cfg.addProperty("height", { handler:this.configHeight, suppressEvent:true, supercedes:["iframe"] } );

    	/**
    	* CSS z-index of the Overlay.
    	* @config zIndex
    	* @type Number
    	* @default null
    	*/
    	this.cfg.addProperty("zIndex", { value:null, handler:this.configzIndex } );

    	/**
    	* True if the Overlay should be prevented from being positioned out of the viewport.
    	* @config constraintoviewport
    	* @type Boolean
    	* @default false
    	*/
    	this.cfg.addProperty("constraintoviewport", { value:false, handler:this.configConstrainToViewport, validator:this.cfg.checkBoolean, supercedes:["iframe","x","y","xy"] } );

    	/**
    	* True if the Overlay should have an IFRAME shim (for correcting the select z-index bug in IE6 and below).
    	* @config iframe
    	* @type Boolean
    	* @default true for IE6 and below, false for all others
    	*/
    	this.cfg.addProperty("iframe", { value:(this.browser == "ie" ? true : false), handler:this.configIframe, validator:this.cfg.checkBoolean, supercedes:["zIndex"] } );
    };

    /**
    * Moves the Overlay to the specified position. This function is identical to calling this.cfg.setProperty("xy", [x,y]);
    * @method moveTo
    * @param {Number}	x	The Overlay's new x position
    * @param {Number}	y	The Overlay's new y position
    */
    YAHOO.widget.Overlay.prototype.moveTo = function(x, y) {
    	this.cfg.setProperty("xy",[x,y]);
    };

    /**
    * Adds a special CSS class to the Overlay when Mac/Gecko is in use, to work around a Gecko bug where
    * scrollbars cannot be hidden. See https://bugzilla.mozilla.org/show_bug.cgi?id=187435
    * @method hideMacGeckoScrollbars
    */
    YAHOO.widget.Overlay.prototype.hideMacGeckoScrollbars = function() {
    	YAHOO.util.Dom.removeClass(this.element, "show-scrollbars");
    	YAHOO.util.Dom.addClass(this.element, "hide-scrollbars");
    };

    /**
    * Removes a special CSS class from the Overlay when Mac/Gecko is in use, to work around a Gecko bug where
    * scrollbars cannot be hidden. See https://bugzilla.mozilla.org/show_bug.cgi?id=187435
    * @method showMacGeckoScrollbars
    */
    YAHOO.widget.Overlay.prototype.showMacGeckoScrollbars = function() {
    	YAHOO.util.Dom.removeClass(this.element, "hide-scrollbars");
    	YAHOO.util.Dom.addClass(this.element, "show-scrollbars");
    };

    // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //

    /**
    * The default event handler fired when the "visible" property is changed. This method is responsible for firing showEvent and hideEvent.
    * @method configVisible
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configVisible = function(type, args, obj) {
    	var visible = args[0];

    	var currentVis = YAHOO.util.Dom.getStyle(this.element, "visibility");

    	if (currentVis == "inherit") {
    		var e = this.element.parentNode;
    		while (e.nodeType != 9 && e.nodeType != 11) {
    			currentVis = YAHOO.util.Dom.getStyle(e, "visibility");
    			if (currentVis != "inherit") { break; }
    			e = e.parentNode;
    		}
    		if (currentVis == "inherit") {
    			currentVis = "visible";
    		}
    	}

    	var effect = this.cfg.getProperty("effect");

    	var effectInstances = [];
    	if (effect) {
    		if (effect instanceof Array) {
    			for (var i=0;i<effect.length;i++) {
    				var eff = effect[i];
    				effectInstances[effectInstances.length] = eff.effect(this, eff.duration);
    			}
    		} else {
    			effectInstances[effectInstances.length] = effect.effect(this, effect.duration);
    		}
    	}

    	var isMacGecko = (this.platform == "mac" && this.browser == "gecko");

    	if (visible) { // Show
    		if (isMacGecko) {
    			this.showMacGeckoScrollbars();
    		}

    		if (effect) { // Animate in
    			if (visible) { // Animate in if not showing
    				if (currentVis != "visible" || currentVis === "") {
    					this.beforeShowEvent.fire();
    					for (var j=0;j<effectInstances.length;j++) {
    						var ei = effectInstances[j];
    						if (j === 0 && ! YAHOO.util.Config.alreadySubscribed(ei.animateInCompleteEvent,this.showEvent.fire,this.showEvent)) {
    							ei.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true); // Delegate showEvent until end of animateInComplete
    						}
    						ei.animateIn();
    					}
    				}
    			}
    		} else { // Show
    			if (currentVis != "visible" || currentVis === "") {
    				this.beforeShowEvent.fire();
    				YAHOO.util.Dom.setStyle(this.element, "visibility", "visible");
    				this.cfg.refireEvent("iframe");
    				this.showEvent.fire();
    			}
    		}

    	} else { // Hide
    		if (isMacGecko) {
    			this.hideMacGeckoScrollbars();
    		}

    		if (effect) { // Animate out if showing
    			if (currentVis == "visible") {
    				this.beforeHideEvent.fire();
    				for (var k=0;k<effectInstances.length;k++) {
    					var h = effectInstances[k];
    					if (k === 0 && ! YAHOO.util.Config.alreadySubscribed(h.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)) {
    						h.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true); // Delegate hideEvent until end of animateOutComplete
    					}
    					h.animateOut();
    				}
    			} else if (currentVis === "") {
    				YAHOO.util.Dom.setStyle(this.element, "visibility", "hidden");
    			}
    		} else { // Simple hide
    			if (currentVis == "visible" || currentVis === "") {
    				this.beforeHideEvent.fire();
    				YAHOO.util.Dom.setStyle(this.element, "visibility", "hidden");
    				this.cfg.refireEvent("iframe");
    				this.hideEvent.fire();
    			}
    		}
    	}
    };

    /**
    * Center event handler used for centering on scroll/resize, but only if the Overlay is visible
    * @method doCenterOnDOMEvent
    */
    YAHOO.widget.Overlay.prototype.doCenterOnDOMEvent = function() {
    	if (this.cfg.getProperty("visible")) {
    		this.center();
    	}
    };

    /**
    * The default event handler fired when the "fixedcenter" property is changed.
    * @method configFixedCenter
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configFixedCenter = function(type, args, obj) {
    	var val = args[0];

    	if (val) {
    		this.center();

    		if (! YAHOO.util.Config.alreadySubscribed(this.beforeShowEvent, this.center, this)) {
    			this.beforeShowEvent.subscribe(this.center, this, true);
    		}

    		if (! YAHOO.util.Config.alreadySubscribed(YAHOO.widget.Overlay.windowResizeEvent, this.doCenterOnDOMEvent, this)) {
    			YAHOO.widget.Overlay.windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
    		}

    		if (! YAHOO.util.Config.alreadySubscribed(YAHOO.widget.Overlay.windowScrollEvent, this.doCenterOnDOMEvent, this)) {
    			YAHOO.widget.Overlay.windowScrollEvent.subscribe( this.doCenterOnDOMEvent, this, true);
    		}
    	} else {
    		YAHOO.widget.Overlay.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
    		YAHOO.widget.Overlay.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
    	}
    };

    /**
    * The default event handler fired when the "height" property is changed.
    * @method configHeight
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configHeight = function(type, args, obj) {
    	var height = args[0];
    	var el = this.element;
    	YAHOO.util.Dom.setStyle(el, "height", height);
    	this.cfg.refireEvent("iframe");
    };

    /**
    * The default event handler fired when the "width" property is changed.
    * @method configWidth
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configWidth = function(type, args, obj) {
    	var width = args[0];
    	var el = this.element;
    	YAHOO.util.Dom.setStyle(el, "width", width);
    	this.cfg.refireEvent("iframe");
    };

    /**
    * The default event handler fired when the "zIndex" property is changed.
    * @method configzIndex
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configzIndex = function(type, args, obj) {
    	var zIndex = args[0];

    	var el = this.element;

    	if (! zIndex) {
    		zIndex = YAHOO.util.Dom.getStyle(el, "zIndex");
    		if (! zIndex || isNaN(zIndex)) {
    			zIndex = 0;
    		}
    	}

    	if (this.iframe) {
    		if (zIndex <= 0) {
    			zIndex = 1;
    		}
    		YAHOO.util.Dom.setStyle(this.iframe, "zIndex", (zIndex-1));
    	}

    	YAHOO.util.Dom.setStyle(el, "zIndex", zIndex);
    	this.cfg.setProperty("zIndex", zIndex, true);
    };

    /**
    * The default event handler fired when the "xy" property is changed.
    * @method configXY
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configXY = function(type, args, obj) {
    	var pos = args[0];
    	var x = pos[0];
    	var y = pos[1];

    	this.cfg.setProperty("x", x);
    	this.cfg.setProperty("y", y);

    	this.beforeMoveEvent.fire([x,y]);

    	x = this.cfg.getProperty("x");
    	y = this.cfg.getProperty("y");

    	this.cfg.refireEvent("iframe");
    	this.moveEvent.fire([x,y]);
    };

    /**
    * The default event handler fired when the "x" property is changed.
    * @method configX
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configX = function(type, args, obj) {
    	var x = args[0];
    	var y = this.cfg.getProperty("y");

    	this.cfg.setProperty("x", x, true);
    	this.cfg.setProperty("y", y, true);

    	this.beforeMoveEvent.fire([x,y]);

    	x = this.cfg.getProperty("x");
    	y = this.cfg.getProperty("y");

    	YAHOO.util.Dom.setX(this.element, x, true);

    	this.cfg.setProperty("xy", [x, y], true);

    	this.cfg.refireEvent("iframe");
    	this.moveEvent.fire([x, y]);
    };

    /**
    * The default event handler fired when the "y" property is changed.
    * @method configY
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configY = function(type, args, obj) {
    	var x = this.cfg.getProperty("x");
    	var y = args[0];

    	this.cfg.setProperty("x", x, true);
    	this.cfg.setProperty("y", y, true);

    	this.beforeMoveEvent.fire([x,y]);

    	x = this.cfg.getProperty("x");
    	y = this.cfg.getProperty("y");

    	YAHOO.util.Dom.setY(this.element, y, true);

    	this.cfg.setProperty("xy", [x, y], true);

    	this.cfg.refireEvent("iframe");
    	this.moveEvent.fire([x, y]);
    };

    /**
    * Shows the iframe shim, if it has been enabled
    * @method showIframe
    */
    YAHOO.widget.Overlay.prototype.showIframe = function() {
    	if (this.iframe) {
    		this.iframe.style.display = "block";
    	}
    };

    /**
    * Hides the iframe shim, if it has been enabled
    * @method hideIframe
    */
    YAHOO.widget.Overlay.prototype.hideIframe = function() {
    	if (this.iframe) {
    		this.iframe.style.display = "none";
    	}
    };

    /**
    * The default event handler fired when the "iframe" property is changed.
    * @method configIframe
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configIframe = function(type, args, obj) {

    	var val = args[0];

    	if (val) { // IFRAME shim is enabled

    		if (! YAHOO.util.Config.alreadySubscribed(this.showEvent, this.showIframe, this)) {
    			this.showEvent.subscribe(this.showIframe, this, true);
    		}
    		if (! YAHOO.util.Config.alreadySubscribed(this.hideEvent, this.hideIframe, this)) {
    			this.hideEvent.subscribe(this.hideIframe, this, true);
    		}

    		var x = this.cfg.getProperty("x");
    		var y = this.cfg.getProperty("y");

    		if (! x || ! y) {
    			this.syncPosition();
    			x = this.cfg.getProperty("x");
    			y = this.cfg.getProperty("y");
    		}

    		if (! isNaN(x) && ! isNaN(y)) {
    			if (! this.iframe) {
    				this.iframe = document.createElement("iframe");
    				if (this.isSecure) {
    					this.iframe.src = this.imageRoot + YAHOO.widget.Overlay.IFRAME_SRC;
    				}

    				var parent = this.element.parentNode;
    				if (parent) {
    					parent.appendChild(this.iframe);
    				} else {
    					document.body.appendChild(this.iframe);
    				}

    				YAHOO.util.Dom.setStyle(this.iframe, "position", "absolute");
    				YAHOO.util.Dom.setStyle(this.iframe, "border", "none");
    				YAHOO.util.Dom.setStyle(this.iframe, "margin", "0");
    				YAHOO.util.Dom.setStyle(this.iframe, "padding", "0");
    				YAHOO.util.Dom.setStyle(this.iframe, "opacity", "0");
    				if (this.cfg.getProperty("visible")) {
    					this.showIframe();
    				} else {
    					this.hideIframe();
    				}
    			}

    			var iframeDisplay = YAHOO.util.Dom.getStyle(this.iframe, "display");

    			if (iframeDisplay == "none") {
    				this.iframe.style.display = "block";
    			}

    			YAHOO.util.Dom.setXY(this.iframe, [x,y]);

    			var width = this.element.clientWidth;
    			var height = this.element.clientHeight;

    			YAHOO.util.Dom.setStyle(this.iframe, "width", (width+2) + "px");
    			YAHOO.util.Dom.setStyle(this.iframe, "height", (height+2) + "px");

    			if (iframeDisplay == "none") {
    				this.iframe.style.display = "none";
    			}
    		}
    	} else {
    		if (this.iframe) {
    			this.iframe.style.display = "none";
    		}
    		this.showEvent.unsubscribe(this.showIframe, this);
    		this.hideEvent.unsubscribe(this.hideIframe, this);
    	}
    };

    /**
    * The default event handler fired when the "constraintoviewport" property is changed.
    * @method configConstrainToViewport
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configConstrainToViewport = function(type, args, obj) {
    	var val = args[0];
    	if (val) {
    		if (! YAHOO.util.Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
    			this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
    		}
    	} else {
    		this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
    	}
    };

    /**
    * The default event handler fired when the "context" property is changed.
    * @method configContext
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.configContext = function(type, args, obj) {
    	var contextArgs = args[0];

    	if (contextArgs) {
    		var contextEl = contextArgs[0];
    		var elementMagnetCorner = contextArgs[1];
    		var contextMagnetCorner = contextArgs[2];

    		if (contextEl) {
    			if (typeof contextEl == "string") {
    				this.cfg.setProperty("context", [document.getElementById(contextEl),elementMagnetCorner,contextMagnetCorner], true);
    			}

    			if (elementMagnetCorner && contextMagnetCorner) {
    				this.align(elementMagnetCorner, contextMagnetCorner);
    			}
    		}
    	}
    };

    // END BUILT-IN PROPERTY EVENT HANDLERS //

    /**
    * Aligns the Overlay to its context element using the specified corner points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, and BOTTOM_RIGHT.
    * @method align
    * @param {String} elementAlign		The String representing the corner of the Overlay that should be aligned to the context element
    * @param {String} contextAlign		The corner of the context element that the elementAlign corner should stick to.
    */
    YAHOO.widget.Overlay.prototype.align = function(elementAlign, contextAlign) {
    	var contextArgs = this.cfg.getProperty("context");
    	if (contextArgs) {
    		var context = contextArgs[0];

    		var element = this.element;
    		var me = this;

    		if (! elementAlign) {
    			elementAlign = contextArgs[1];
    		}

    		if (! contextAlign) {
    			contextAlign = contextArgs[2];
    		}

    		if (element && context) {
    			var elementRegion = YAHOO.util.Dom.getRegion(element);
    			var contextRegion = YAHOO.util.Dom.getRegion(context);

    			var doAlign = function(v,h) {
    				switch (elementAlign) {
    					case YAHOO.widget.Overlay.TOP_LEFT:
    						me.moveTo(h,v);
    						break;
    					case YAHOO.widget.Overlay.TOP_RIGHT:
    						me.moveTo(h-element.offsetWidth,v);
    						break;
    					case YAHOO.widget.Overlay.BOTTOM_LEFT:
    						me.moveTo(h,v-element.offsetHeight);
    						break;
    					case YAHOO.widget.Overlay.BOTTOM_RIGHT:
    						me.moveTo(h-element.offsetWidth,v-element.offsetHeight);
    						break;
    				}
    			};

    			switch (contextAlign) {
    				case YAHOO.widget.Overlay.TOP_LEFT:
    					doAlign(contextRegion.top, contextRegion.left);
    					break;
    				case YAHOO.widget.Overlay.TOP_RIGHT:
    					doAlign(contextRegion.top, contextRegion.right);
    					break;
    				case YAHOO.widget.Overlay.BOTTOM_LEFT:
    					doAlign(contextRegion.bottom, contextRegion.left);
    					break;
    				case YAHOO.widget.Overlay.BOTTOM_RIGHT:
    					doAlign(contextRegion.bottom, contextRegion.right);
    					break;
    			}
    		}
    	}
    };

    /**
    * The default event handler executed when the moveEvent is fired, if the "constraintoviewport" is set to true.
    * @method enforceConstraints
    * @param {String} type	The CustomEvent type (usually the property name)
    * @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
    * @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
    */
    YAHOO.widget.Overlay.prototype.enforceConstraints = function(type, args, obj) {
    	var pos = args[0];

    	var x = pos[0];
    	var y = pos[1];

    	var offsetHeight = this.element.offsetHeight;
    	var offsetWidth = this.element.offsetWidth;

    	var viewPortWidth = YAHOO.util.Dom.getViewportWidth();
    	var viewPortHeight = YAHOO.util.Dom.getViewportHeight();

    	var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
    	var scrollY = document.documentElement.scrollTop || document.body.scrollTop;

    	var topConstraint = scrollY + 10;
    	var leftConstraint = scrollX + 10;
    	var bottomConstraint = scrollY + viewPortHeight - offsetHeight - 10;
    	var rightConstraint = scrollX + viewPortWidth - offsetWidth - 10;

    	if (x < leftConstraint) {
    		x = leftConstraint;
    	} else if (x > rightConstraint) {
    		x = rightConstraint;
    	}

    	if (y < topConstraint) {
    		y = topConstraint;
    	} else if (y > bottomConstraint) {
    		y = bottomConstraint;
    	}

    	this.cfg.setProperty("x", x, true);
    	this.cfg.setProperty("y", y, true);
    	this.cfg.setProperty("xy", [x,y], true);
    };

    /**
    * Centers the container in the viewport.
    * @method center
    */
    YAHOO.widget.Overlay.prototype.center = function() {
    	var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
    	var scrollY = document.documentElement.scrollTop || document.body.scrollTop;

    	var viewPortWidth = YAHOO.util.Dom.getClientWidth();
    	var viewPortHeight = YAHOO.util.Dom.getClientHeight();

    	var elementWidth = this.element.offsetWidth;
    	var elementHeight = this.element.offsetHeight;

    	var x = (viewPortWidth / 2) - (elementWidth / 2) + scrollX;
    	var y = (viewPortHeight / 2) - (elementHeight / 2) + scrollY;

    	this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);

    	this.cfg.refireEvent("iframe");
    };

    /**
    * Synchronizes the Panel's "xy", "x", and "y" properties with the Panel's position in the DOM. This is primarily used to update position information during drag & drop.
    * @method syncPosition
    */
    YAHOO.widget.Overlay.prototype.syncPosition = function() {
    	var pos = YAHOO.util.Dom.getXY(this.element);
    	this.cfg.setProperty("x", pos[0], true);
    	this.cfg.setProperty("y", pos[1], true);
    	this.cfg.setProperty("xy", pos, true);
    };

    /**
    * Event handler fired when the resize monitor element is resized.
    * @method onDomResize
    * @param {DOMEvent} e	The resize DOM event
    * @param {Object} obj	The scope object
    */
    YAHOO.widget.Overlay.prototype.onDomResize = function(e, obj) {
    	YAHOO.widget.Overlay.superclass.onDomResize.call(this, e, obj);
    	var me = this;
    	setTimeout(function() {
    		me.syncPosition();
    		me.cfg.refireEvent("iframe");
    		me.cfg.refireEvent("context");
    	}, 0);
    };

    /**
    * Removes the Overlay element from the DOM and sets all child elements to null.
    * @method destroy
    */
    YAHOO.widget.Overlay.prototype.destroy = function() {
    	if (this.iframe) {
    		this.iframe.parentNode.removeChild(this.iframe);
    	}

    	this.iframe = null;

    	YAHOO.widget.Overlay.superclass.destroy.call(this);
    };

    /**
    * Returns a String representation of the object.
    * @method toString
    * @return {String} The string representation of the Overlay.
    */
    YAHOO.widget.Overlay.prototype.toString = function() {
    	return "Overlay " + this.id;
    };

    /**
    * A singleton CustomEvent used for reacting to the DOM event for window scroll
    * @event YAHOO.widget.Overlay.windowScrollEvent
    */
    YAHOO.widget.Overlay.windowScrollEvent = new YAHOO.util.CustomEvent("windowScroll");

    /**
    * A singleton CustomEvent used for reacting to the DOM event for window resize
    * @event YAHOO.widget.Overlay.windowResizeEvent
    */
    YAHOO.widget.Overlay.windowResizeEvent = new YAHOO.util.CustomEvent("windowResize");

    /**
    * The DOM event handler used to fire the CustomEvent for window scroll
    * @method YAHOO.widget.Overlay.windowScrollHandler
    * @static
    * @param {DOMEvent} e The DOM scroll event
    */
    YAHOO.widget.Overlay.windowScrollHandler = function(e) {
    	if (YAHOO.widget.Module.prototype.browser == "ie" || YAHOO.widget.Module.prototype.browser == "ie7") {
    		if (! window.scrollEnd) {
    			window.scrollEnd = -1;
    		}
    		clearTimeout(window.scrollEnd);
    		window.scrollEnd = setTimeout(function() { YAHOO.widget.Overlay.windowScrollEvent.fire(); }, 1);
    	} else {
    		YAHOO.widget.Overlay.windowScrollEvent.fire();
    	}
    };

    /**
    * The DOM event handler used to fire the CustomEvent for window resize
    * @method YAHOO.widget.Overlay.windowResizeHandler
    * @static
    * @param {DOMEvent} e The DOM resize event
    */
    YAHOO.widget.Overlay.windowResizeHandler = function(e) {
    	if (YAHOO.widget.Module.prototype.browser == "ie" || YAHOO.widget.Module.prototype.browser == "ie7") {
    		if (! window.resizeEnd) {
    			window.resizeEnd = -1;
    		}
    		clearTimeout(window.resizeEnd);
    		window.resizeEnd = setTimeout(function() { YAHOO.widget.Overlay.windowResizeEvent.fire(); }, 100);
    	} else {
    		YAHOO.widget.Overlay.windowResizeEvent.fire();
    	}
    };

    /**
    * A boolean that indicated whether the window resize and scroll events have already been subscribed to.
    * @property YAHOO.widget.Overlay._initialized
    * @private
    * @type Boolean
    */
    YAHOO.widget.Overlay._initialized = null;

    if (YAHOO.widget.Overlay._initialized === null) {
    	YAHOO.util.Event.addListener(window, "scroll", YAHOO.widget.Overlay.windowScrollHandler);
    	YAHOO.util.Event.addListener(window, "resize", YAHOO.widget.Overlay.windowResizeHandler);

    	YAHOO.widget.Overlay._initialized = true;
    }

Copyright © 2006 Yahoo! Inc. All rights reserved.