/******************************************************************************
module:			dynamicLay.js
version:		1.0.0

purpose:		dynamically repositioned layer-object with additional attributes
				and methods for DHTML-usage; cross-browser compatible	

history:		date		    author				change
    			2001-10-25     	Oliver Hilscher    	module written
													comments added
				2001-10-30		Oliver Hilscher		functions added
*******************************************************************************/



/*******************************************************************************
function:		dynamicLay()
version:		1.0.0

purpose:		object constructor; defines attributes and methods and creates
				layer and layer-functions in HTML-document
				
input param:	essential: window-object, layer-ID, HTML-content, left, top,
							width, height, visibility, z-Index
				optional: align, valign, content-align, content-width

history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
													comments added
******************************************************************************/
function dynamicLay()
{
	/* essential attributes */
	this.win = arguments[0];			// defines the correct layer-window-object: within a frameset Netscape browsers tend to refer to the parent-window-object instead
	this.id = arguments[1];				// layer-ID
	this.html = arguments[2];			// layer-HTML-content	
	this.left = arguments[3];			// layer-left-position
	this.top = arguments[4];			// layer-top-position
	this.width = arguments[5];			// layer-width
	this.height = arguments[6];			// layer-height
	this.visibility = arguments[7];		// initial layer-visibility
	this.zindex = arguments[8];			// initial layer-zIndex
	
	/* arguments 9-12 are optional, depending on the desired layer functions */
	if(arguments[9])
		this.align = arguments[9];			// horizontal alignment; options: left, center, right
	if(arguments[10])
		this.valign = arguments[10];		// vertical alignment; options: top, middle, bottom
	if(arguments[11])
		this.contentAlign = arguments[11];	// horizontal alignment of the body-content; options: contentLeft, contentCenter, contentRight
	if(arguments[12])
		this.contentWidth = arguments[12];	// width of the body-content
	
	/* inline CSS-commands */		
	this.css = "position:absolute; left:"+this.left+"; top:"+this.top+"; width:"+this.width+"; z-index:"+this.zindex+"; visibility:"+this.visibility;
	this.styIn = (!this.win.document.layers ? "style=\"" + this.css + "\"" : ""); // Netscape 4 verträgt sich nicht mit document.write generierten Inline-Syle-Angaben
	
	/* outline CSS-commands for NS4 */
	this.styHead = "<style type=\"text/css\">\n<!--\n";
	this.styContent = "#" + this.id + " { "+this.css+" }\n";
	this.styFoot = "//-->\n</style>";
	
	/* layer-HTML-code with Style-Sheet-commands */
	this.htmlHead = "<span id=\"" + this.id + "\" " + this.styIn + ">\n";
	this.htmlContent = this.html+"\n";
	this.htmlFoot = "</span>";
	
	/* methods for generating layer-object and required functions */
	this.writeLay = writeLay;							// writes layer-HTML-code
	this.writeLay();
	this.createFunctionAni = createFunctionAni;			// writes function animateLayerID()
	this.createFunctionRepos = createFunctionRepos;		// writes function repositionLayerID()
				
	/* defines the layer's layer- and style-object for later usage and sets clip area for MSIE */
	this.layerObj = (this.win.document.getElementById ? this.win.document.getElementById(this.id) : this.win.document.all ? this.win.document.all[this.id] : this.win.document.layers[this.id]);
	this.styleObj = (this.win.document.getElementById ? this.layerObj.style : this.win.document.all ? this.layerObj.style : this.layerObj);
	this.styleObj.clip = (navigator.userAgent.indexOf("MSIE")!=-1 ? "rect(" + 0 + "px " + (this.width+2) + "px " + (this.height+2) + "px " + 0 + "px)" : ""); // MSIE clip values have to be set manually at start-up
	
	/* essential methods */
	this.getWinWidth = getWinWidth;			// returns inner window width
	this.getWinHeight = getWinHeight;		// returns inner window height
	this.getXScroll = getXScroll;			// returns current horizontal scroll-position
	this.getYScroll = getYScroll;			// returns current vertical scroll-position
	this.setXScroll = setXScroll;			// sets horizontal scroll-position
	this.setYScroll = setYScroll;			// sets vertical scroll-position
	this.getXpos = getXpos;					// returns layer's current left-position
	this.getYpos = getYpos;					// returns layer's current top-position
	this.setXpos = setXpos;					// sets layer to new left-position
	this.setYpos = setYpos;					// sets layer to new top-position
	this.getMouseX = getMouseX;				// returns current mouse x-position
	this.getMouseY = getMouseY;				// returns current mouse y-position
	this.off = off;							// turns layer-visibility off
	this.on = on;							// turns layer-visibility on
	this.setZ = setZ;						// defines layer's new z-Index
	this.clip = clip;						// returns and sets clip top-position
	this.ani = ani;							// controls animated dynamic re-positioning of the layer
	this.rePos = rePos;						// controls simple dynamic re-positioning of the layer
		
	/* attributes used with simple re-positioning */
	this.startWidth = this.getWinWidth();		// initial inner window-width
	this.startHeight = this.getWinHeight();		// initial inner window-height
	this.startXScroll = this.getXScroll()-1;	// initial horizontal scroll-position
	this.startYScroll = this.getYScroll()-1;	// initial vertical scroll-position
												// ! the scroll-positions are deliberately set to -1 for automatic re-positioing on first load
	
	/* attributes and methods used with animated re-positioning */
	this.baseY = this.getWinHeight()/2;		// defines an initial top-position of the layer needed for calculating the dynamic y-movement; here: middle of the window
	this.baseX = 0;							// defines an initial left-position of the layer needed for calculating the dynamic x-movement
											// ! important: the proposed left-position is "0", as NS4 displays permanent horizontal scrollbars, if the layer's right border exceeds the window-width
	this.targetX = targetX;					// defines fixed horizontal target-position, depending on desired layer-alignment
	this.dynMoveX = dynMoveX;				// calculates the dynamic movement towards the targetX-position
	this.targetY = targetY;					// defines fixed vertical target-position, depending on desired layer-alignment
	this.dynMoveY = dynMoveY;				// calculates the dynamic movement towards the targetY-position
	
	/* attributes and methods for drag & drop feature */
	this.drag = "inactive";					// drag is activated on mousedown only
	this.activeX = this.left;				// initial drag x-position = layer left-position
	this.activeY = this.top;				// initial drag y-position = layer top-position
	this.layerObj.parent = this;			// mousedown event is captured on the layer-object, whereas methods and attributes form part of the object itself
	this.win.root = this;					// NS4: mousemove and mouseup are captured on the window-object, whereas methods and attributes form part of the object itself
	this.win.document.root = this;			// MSIE: mousemove and mouseup are captured on the window-document-object, whereas methods and attributes form part of the object itself
	this.initDrag = initDrag;				// method for capturing events in NS4 and MSIE
}


/******************************************************************************
method:			writeLay()
version:		1.0.0

description:	creates layer object in HTMl-document with corresponding
				Style-Sheet-commands
				
returns:			layer-HTML-Code

history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
													comments added
******************************************************************************/
function writeLay()
{
	if(this.win.document.layers)		// NS4 requires outline style-commands
	{
		output1 = this.styHead + this.styContent + this.styFoot;
		this.win.document.write(output1);
	}
	output2 = this.htmlHead + this.htmlContent + this.htmlFoot;
	this.win.document.write(output2);
}


/******************************************************************************
method:			createFunctionAni()
version:		1.0.0

description:	creates JavaScript function with timeout to control animated
				dynamic repositioning of the layer
				
returns:		function animateLayerID()

history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
													comments added
******************************************************************************/
function createFunctionAni()
{
	output = "<script language=\"javascript\" type=\"text/javascript\">\n";
	output += "function animate" + this.id + "()\n{\n\t";
	output += "if(" + this.id + ")\n\t{\n\t\t";
	output += this.id + ".ani();\n\t\t";
	output += "setTimeout(\"animate" + this.id + "()\",20);\n\t}\n";
	output += "}\n</script>\n";
	this.win.document.write(output);
}


/******************************************************************************
method:			createFunctionRepos()
version:		1.0.0

description:	creates JavaScript function with timeout to control simple
				dynamic repositioning of the layer
				
returns:		function repositionLayerID()

history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
													comments added
******************************************************************************/
function createFunctionRepos()
{
	output = "<script language=\"javascript\" type=\"text/javascript\">\n";
	output += "function reposition" + this.id + "()\n{\n\t";
	output += "if(" + this.id + ")\n\t{\n\t\t";
	output += "if(" + this.id + ".startWidth  != " + this.id + ".getWinWidth()  || " + this.id + ".startHeight  != " + this.id + ".getWinHeight()  || " + this.id + ".startYScroll  != " + this.id + ".getYScroll() || " + this.id + ".startXScroll != " + this.id + ".getXScroll())\n\t\t{\n\t\t\t";
	output += this.id + ".rePos();\n\t\t\t";
	output += this.id + ".startWidth = " + this.id + ".getWinWidth();\n\t\t\t";
	output += this.id + ".startHeight = " + this.id + ".getWinHeight();\n\t\t\t";
	output += this.id + ".startXScroll = " + this.id + ".getXScroll();\n\t\t\t";
	output += this.id + ".startYScroll = " + this.id + ".getYScroll();\n\t\t";
	output += "}\n\t\t";
	output += "setTimeout(\"reposition" + this.id + "()\",500);\n\t}\n";
	output += "}\n</script>\n";
	this.win.document.write(output);
}


/******************************************************************************
methods:		basic functions
version:		1.0.0

description:	functions for handling window-size, scroll-position,
				layer-position, visibility and z-Index

input param:	value (for setXScroll(), setYScroll(), setXpos(), setYpos(),
						setZ())

output return:	value (for getWinWidth(), getWinHeight(), getXScroll(),
						getYScroll(), getXpos(), getYpos())
				
history:		date			author				change
				2001-10-25  	Oliver Hilscher    	functions written
******************************************************************************/
function getWinWidth() { return parseInt((navigator.userAgent.indexOf("MSIE")!=-1 ? this.win.document.body.offsetWidth : this.win.innerWidth)); }
function getWinHeight() { return parseInt((navigator.userAgent.indexOf("MSIE")!=-1 ? this.win.document.body.offsetHeight : this.win.innerHeight)); }
function getXScroll() { return parseInt((navigator.userAgent.indexOf("MSIE")!=-1 ? this.win.document.body.scrollLeft : this.win.pageXOffset)); }
function getYScroll() { return parseInt((navigator.userAgent.indexOf("MSIE")!=-1 ? this.win.document.body.scrollTop : this.win.pageYOffset)); }
function setXScroll(value) { (navigator.userAgent.indexOf("MSIE")!=-1 ? this.win.document.body.scrollLeft = value : this.win.pageXOffset = value); }
function setYScroll(value) { (navigator.userAgent.indexOf("MSIE")!=-1 ? this.win.document.body.scrollTop = value : this.win.pageYOffset = value); }
function getXpos() { return parseInt(this.styleObj.left); }
function getYpos() { return parseInt(this.styleObj.top); }
function setXpos(value) { this.styleObj.left = value; }
function setYpos(value) { this.styleObj.top = value; }
function getMouseX(e) { return (this.win.document.layers ? e.layerX : this.win.document.all ? this.win.event.offsetX : this.win.document.getElementById ? e.pageX - parseInt(this.styleObj.left) : false); }
function getMouseY(e) { return (this.win.document.layers ? e.layerY : this.win.document.all ? this.win.event.offsetY : this.win.document.getElementById ? e.pageY - parseInt(this.styleObj.top) : false); }
function off() { this.styleObj.visibility = "hidden"; }
function on() { this.styleObj.visibility = "visible"; }
function setZ(value) { this.styleObj.zIndex = value; }


/******************************************************************************
methods:		clip()
version:		1.0.0

description:	functions for reading and changing values of clip area

input param:	top, right, bottom, left

output return:	value
				
history:		date			author				change
				2001-11-07  	Oliver Hilscher    	function improved
******************************************************************************/
function clip(top,right,bottom,left)
{
	if(this.win.document.layers)
	{
		if(top && right && bottom && left)
		{
			this.styleObj.clip.top = top;
			this.styleObj.clip.right = right;
			this.styleObj.clip.bottom = bottom;
			this.styleObj.clip.left = left;
		}
		return this.styleObj.clip.left + ", " + this.styleObj.clip.right + ", " + this.styleObj.clip.bottom + ", " + this.styleObj.clip.left;
	}
	else
	{
		if(top && right && bottom && left)
			this.styleObj.clip = "rect(" + top + "px " + right + "px " + bottom + "px " + left + "px)";
		this.clipVal = this.styleObj.clip.split("rect(")[1].split(")")[0].split("px");
		return this.clipVal[0] + ", " + this.clipVal[1] + ", " + this.clipVal[2] + ", " + this.clipVal[3];
	}
}


/******************************************************************************
methods:		targetX(), targetY()
version:		1.0.0

description:	functions to determine the layer's fixed target-position for
				animated repositioning depending on the layer's desired
				alignment, either in relation to the horizontal alignment of
				the content area or absolute				
				
output return:	value

history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
													comments added
******************************************************************************/
function targetX()
{
	if(this.align == "left")
	{
		if(this.getWinWidth()<800)
			return 0;
		else
		{
			if(this.contentAlign == "contentCenter")
				return (this.getWinWidth() - this.contentWidth)/2 - 5;
			else if(this.contentAlign == "contentRight")
				return this.getWinWidth() - this.contentWidth - 10;
			else
				return 0;
		}
	}
	else if(this.align == "center")
	{
		if(this.getWinWidth()<800)
			return (this.getWinWidth()/2) - (this.width/2);
		else
		{
			if(this.contentAlign == "contentLeft")
				return (this.contentWidth/2) - (this.width/2);
			else if(this.contentAlign == "contentRight")
				return (this.getWinWidth() - this.contentWidth) + ((this.contentWidth/2) - (this.width/2));
			else
				return (this.getWinWidth()/2) - (this.width/2) - 6;
		}
	}
	else if(this.align == "right")
	{
		if(this.getWinWidth()<800)
			return this.getWinWidth() - this.width - 18;
		else
		{
			if(this.contentAlign == "contentLeft")
				return this.contentWidth - this.width - 2;
			else if(this.contentAlign == "contentCenter")
				return this.getWinWidth() - ((this.getWinWidth() - this.contentWidth)/2) - this.width - 10;
			else
				return this.getWinWidth() - this.width - 19;
		}
	}
	else
		return this.left;
}

function targetY()
{
	if(this.valign == "top")
		return 0;
	else if(this.valign == "middle")
		return (this.getWinHeight()/2) - (this.height/2);
	else if(this.valign == "bottom")
	{
		if(this.getWinWidth()<800)
			return this.getWinHeight() - this.height-19;

		else
			return this.getWinHeight() - this.height-3;
		// ! important: additional decrease by 19px and 3px respectively, as MSIE allows infinite vertical scrolling, if layer-bottom exceeds window-height
	}
	else
		return this.top;
}


/******************************************************************************
methods:		dynMoveX(), dynMoveY()
version:		1.0.0

description:	functions to calculate smooth movement effect for animated
				repositioning		
				
output return:	value

history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
******************************************************************************/
function dynMoveY() { return ((this.getYScroll() + this.targetY()) - this.baseY)/8; }
function dynMoveX() { return ((this.getXScroll() + this.targetX()) - this.baseX)/8; }


/******************************************************************************
method:			ani()
version:		1.0.0

requires:		control function with timeout in layer's window-object;
				cf. createFunctionAni()

description:	sets layer dynamically to target-position in decreasing steps
				when controlled by timeout
				
history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
******************************************************************************/
function ani()
{
	this.baseY += this.dynMoveY();
	this.baseX += this.dynMoveX();
	this.setYpos(this.baseY);
	this.setXpos(this.baseX);
}


/******************************************************************************
method:			rePos()
version:		1.0.0

requires:		control function with timeout in layer's window-object;
				cf. createFunctionRepos()

description:	sets layer to new x/y-position with a delay of 500ms depending
				on the layer's desired alignment, either in relation to the
				horizontal alignment of	the content area or absolute;
				needs control function with timeout to determine changes of
				window-size and scroll-positions
				
history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
******************************************************************************/
function rePos()
{		
	if(this.align == "left")
	{
		if(this.getWinWidth()<800)
			this.setXpos(0);			
		else
		{
			if(this.contentAlign == "contentCenter")
				this.setXpos((this.getWinWidth() - this.contentWidth)/2 - 5);
			else if(this.contentAlign == "contentRight")
				this.setXpos(this.getWinWidth() - this.contentWidth - 10);
			else
				this.setXpos(0);
		}
	}
	else if(this.align == "center")
	{
		if(this.getWinWidth()<800)
			this.setXpos((this.getWinWidth()/2) - (this.width/2));
		else
		{
			if(this.contentAlign == "contentLeft")
				this.setXpos((this.contentWidth/2) - (this.width/2));
			else if(this.contentAlign == "contentRight")
				this.setXpos((this.getWinWidth() - this.contentWidth) + ((this.contentWidth/2) - (this.width/2)));
			else
				this.setXpos((this.getWinWidth()/2) - (this.width/2) - 6);
		}
	}
	else if(this.align == "right")
	{
		if(this.getWinWidth()<800)
			this.setXpos(this.getWinWidth() - this.width - 18);
		else
		{
			if(this.contentAlign == "contentLeft")
				this.setXpos(this.contentWidth - this.width - 2);
			else if(this.contentAlign == "contentCenter")
				this.setXpos(this.getWinWidth() - ((this.getWinWidth() - this.contentWidth)/2) - this.width - 10);
			else
				this.setXpos(this.getWinWidth() - this.width - 19);
		}
	}
	else
		this.setXpos(this.left);
	
	if(this.valign == "top")
		this.setYpos(0);
	else if(this.valign == "middle")
		this.setYpos((this.getWinHeight()/2) - (this.height/2));
	else if(this.valign=="bottom")
	{
		if(this.getWinWidth()<800)
			this.setYpos(this.getWinHeight() - this.height - 19);
		else
			this.setYpos(this.getWinHeight() - this.height - 3);
	}
	else
		this.setYpos(this.top);
	
	this.setXpos(this.getXpos()+this.getXScroll());
	this.setYpos(this.getYpos()+this.getYScroll());
}


/******************************************************************************
method:			initDrag()
version:		1.0.0

description:	captures events mousedown, mousemove and mouseup
				
history:		date			author				change
				2001-10-30  	Oliver Hilscher    	function written
******************************************************************************/
function initDrag()
{
	if(this.win.document.layers)				// event capturing for NS4
	{
		this.layerObj.captureEvents(Event.MOUSEDOWN);
		this.layerObj.onmousedown = mDown;
		this.win.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP);
		this.win.onmousemove = mMove;			// NS4 captures events on window-object
		this.win.onmouseup = mUp;
	}
	else if(this.win.document.all)				// event capturing for MSIE
	{
		this.layerObj.onmousedown = mDown;
		this.win.document.onmousemove = mMove;	// MSIE captures events on window-document-object
		this.win.document.onmouseup = mUp;
	}	
	else if(this.win.document.getElementById)	// event capturing for Netscape 6 with eventListeners
	{
		this.layerObj.addEventListener("mousedown",mDown,false);
		this.win.addEventListener("mouseup",mUp,true);
		this.win.document.addEventListener("mousemove",mMove,true);
	}
}


/******************************************************************************
method:			mDown(e)
version:		1.0.0

description:	function for mousedown-event to activate drag and store	mouse
				coordinates at onmousedown-event

history:		date			author				change
				2001-10-30  	Oliver Hilscher    	function written
******************************************************************************/
function mDown(e)
{
	/* mousedown is captured on the layer-object, but all methods and attributes
	are part of the object which lies above the layer-object in the object
	hierarchy */
	this.parent.drag = "active";
	this.parent.setZ(this.parent.win.activeZindex++);
	this.parent.activeX = this.parent.getMouseX(e);
	this.parent.activeY = this.parent.getMouseY(e);
}


/******************************************************************************
method:			mMove(e)
version:		1.0.0

description:	function for mousemove-event to move layer along the path of
				the mousemove
				
history:		date			author				change
				2001-10-30  	Oliver Hilscher    	function written
******************************************************************************/
function mMove(e)
{
	/* mousemove is captured on the window- or document-object, but all methods
	and attributes are part of the object which lies higher in the object
	hierarchy */
	if(this.root.drag == "inactive")
		return true;
	else if(this.root.drag == "active")
	{
		if(this.root.win.document.layers)
		{
			this.root.layerObj.pageX = e.pageX - this.root.activeX;
			this.root.layerObj.pageY = e.pageY - this.root.activeY;
		}
		else if(this.root.win.document.all)
		{
			this.root.styleObj.left = this.root.win.event.clientX - this.root.activeX + this.root.getXScroll();
			this.root.styleObj.top = this.root.win.event.clientY - this.root.activeY + this.root.getYScroll();
		}
		else if(this.root.win.document.getElementById)
		{
			this.root.styleObj.left = e.pageX - this.root.activeX;
			this.root.styleObj.top = e.pageY - this.root.activeY;
		}
		return false;
	}
}


/******************************************************************************
method:			mUp(e)
version:		1.0.0

description:	function for mouseup-event to deactivate drag
				
history:		date			author				change
				2001-10-30  	Oliver Hilscher    	function written
******************************************************************************/
function mUp(e)
{
	/* mouseup is captured on the window-object, but all methods and attributes
	are part of the object which lies above the layer-object in the object
	hierarchy */
	this.root.drag = "inactive";
}


/******************************************************************************
function:		ns4Reload()
version:		1.0.0

purpose:		Netscape 4 resize fix to keep layers positioned correctly

description:	reloads page in NS4 browsers after resize
				
history:		date			author				change
				2001-10-25  	Oliver Hilscher    	function written
													comments added
******************************************************************************/
function ns4Reload(value)
{
	if (value == true) with (navigator)
	{
		if ((appName == "Netscape") && (parseInt(appVersion) == 4))
		{
			docWidth = innerWidth;
			docHeight = innerHeight;
			onresize = ns4Reload;
		}
	}
  	else if (innerWidth != docWidth || innerHeight != docHeight)
		location.reload();
}
ns4Reload(true);

