// library to do popup layers V3.0
// by Thomas M. Farrell, tfarrell@skepsis.com
// Free for use or modification by anyone, please leave this notice in the code
// and include comments to show what you did to it.

// This library requires the use of sniff.js to function. Load sniff.js first.


// *******************
// **               **
// **  Main Object  **
// **   REQUIRED    **
// **               **
// *******************


// The following function makes a layer object containing related values 
// and methods.
function layerObject(theID) {
	this.layerID = theID; // string - ID of layer from DIV tag
	this.theAbstract = makeAbstract(this.layerID); // abstract reference used by other methods.
	this.content = layerObjectContent; // method to replace layer content
	this.show = showLayerObject; // method to show layer
	this.hide = hideLayerObject; // method to hide layer
	this.reposition = positionLayerObject; // method to reposition layer
	this.getPosition = getLayerObjectPosition; // method returns [x,y] for layer
	this.offsetVertical = offsetObjectVertical; // method to offset vertically
	this.offsetHorizontal = offsetObjectHorizontal; // method to offset horizontally
	this.resize = resizeObject; // method to resize layer
	this.makeScrollable = makeLayerObjectScrollable; // method prepares layer for scrolling
	this.getClip = getLayerObjectClip; // method returns [t,r,b,l] clip from layer
	this.setClip = setLayerObjectClip; // method takes [t,r,b,l] clip for layer
	this.scroll = scrollLayerClip; // method scrolls layer
	this.scrollingLayerHeight = 0; // DO NOT MODIFY
	this.startScrolling = startScrollingLayer; // starts layer scrolling
	this.stopScrolling = stopScrollingLayer; // stops layer scrolling
	this.scrollingLayerLocation = null; // DO NOT MODIFY
	this.scrollingLayerInterval = null; // DO NOT MODIFY
	this.scrollingLayerLength = null; // DO NOT MODIFY
	this.scrollingIsInfinite = true; // determines if scrollability has an end point
	this.hasMouse = mouseInLayer; // method determines if mouse over layer
	} // end function


// ***********************
// **                   **
// **  Primary methods  **
// **     REQUIRED      **
// **   DO NOT REMOVE   **
// **                   **
// ***********************


//the following is used by the layerObject function to change content in 
//a layer. 
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function layerObjectContent(newContent) {
	if(is_nav4) {
		layerContentHandle = makeContentAbstract(this.layerID);
		layerContentHandle.write(newContent);
		layerContentHandle.close();
		} //end if
	else if (is_nav6up) {
	// MODIFY HERE
		var rng = document.createRange();
		var el = document.getElementById(elementid);
		rng.setStartBefore(el);
		var htmlFrag = rng.createContextualFragment(newContent);
		while (el.hasChildNodes()) {
			el.removeChild(el.lastChild);
			} // end while
		el.appendChild(htmlFrag);
		} //end else if
	else {
		layerContentHandle = makeContentAbstract(this.layerID);
		layerContentHandle.innerHTML = newContent;
		} //end else
	} //end function

//the following is used by the layerObject function to show a layer. 
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function showLayerObject() {
	this.theAbstract.visibility = "visible";
	} //end function

//the following is used by the layerObject function to hide a layer. 
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function hideLayerObject() {
	this.theAbstract.visibility = "hidden";
	} //end function

//the following is used by the layerObject function to reposition a layer. 
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function positionLayerObject(newPosition) {
	this.theAbstract.top = newPosition[1] + px;
	this.theAbstract.left = newPosition[0] + px;
	} //end function

//the following is used by the layerObject function to determine the position 
//of a layer. 
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function getLayerObjectPosition() {
	var tempArray = [parseInt(this.theAbstract.left),parseInt(this.theAbstract.top)];
	return tempArray;
	} //end function

//the following is used by the layerObject function to offset a layer 
//vertically.
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function offsetObjectVertical(theOffset) {
	var temp = this.getPosition();
	this.reposition([temp[0],temp[1]+theOffset]);
	} //end function

//the following is used by the layerObject function to offset a layer 
//horizontally. 
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function offsetObjectHorizontal(theOffset) {
	var temp = this.getPosition();
	this.reposition([temp[0]+theOffset,temp[1]]);
	} //end function

//the following is used by the layerObject function to resize a layer. 
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function resizeObject(newSize) {
	// newSize is an array of [w,h]
	this.theAbstract.width = newSize[0];
	this.theAbstract.height = newSize[1];
	} //end function


// ************************
// **                    **
// **  Abstraction code  **
// **      REQUIRED      **
// **    DO NOT REMOVE   **
// **                    **
// ************************


//this sets up some browser-specific code so we can abstract the layers.
var doc = "";
var sty = "";
var htm = "";
var px = 0;
if(is_nav4) {
	doc = "document";
	sty = "";
	htm = ".document";
	px = 0;
	}//end if
else if(is_ie4up) {
	doc = "document.all";
	sty = ".style";
	htm = "";
	px = 0;
	} //end else if
else if (is_nav6up) {
	doc = "document";
	sty = "style";
	htm = ".document";
	px = "px";
	}//end if

//the following function sets up the abstract reference to a particular layer.
//YOU SHOULD HAVE NO NEED TO CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function makeAbstract(layerName) {
	var foo = null;
	if (!is_nav6up) {
		foo = eval(doc + '["' + layerName + '"]' + sty);
		} //end if
	else {
		foo = document.getElementById(layerName).style;
		} //end else
	return foo;
	} //end function

// The following function sets up an abstract reference to the *content* of 
// a layer.
// DO NOT CALL THIS FUNCTION. IT GETS USED BY THE LAYER OBJECT METHODS.
function makeContentAbstract(layerName) {
	var foo = null;
	foo = eval(doc + '["' + layerName + '"]' + htm);
	return foo;
	} //end function


// *****************
// **             **
// **  Centering  **
// **             **
// *****************


//the following function returns the width of the browser window. In order for 
//the function to work, you have to place the following code into the HTML of the
//base page (not in a layer):
//
//  <table id="determinewidth" name="determinewidth" width=100% border=0 cellpadding=0
//  cellspacing=0><tr><td>&nbsp;</td></tr></table>
//
function getBrowserWidth() {
	var totalWidth = null;
	if (is_ie4up) {
		totalWidth = determinewidth.clientWidth;
		} //end if
	else if (is_nav4up) {
		totalWidth = window.innerWidth;
		} //end if
	return totalWidth;
	} //end function

//the following function is used when you have a page that you're laying out with absolute
//layers and you want the content to center in the browser window regardless of the browser
//window size. You have to prepare the page to run getBrowserWidth() (see comments on that
//function above) and you have to build an array of the abstract layers, which is passed
//as the first parameter. The second parameter is the width, in pixels, of the content area
//to be centered.
function centerContent(arrayOfLayers, contentWidth) {
	var theOffset = (getBrowserWidth() - contentWidth) / 2;
	for (var x=0; x<arrayOfLayers.length; x++) {
		arrayOfLayers[x].offsetHorizontal(theOffset);
		} //end for loop
	} //end function


// ********************************
// **                            **
// ** Multiple layer collections **
// **                            **
// ********************************


// The following creates a collection of layers with associated data
// and methods.
function layerCollection(thePrefix,theSuffix,theMax) {
	this.prefix = thePrefix;
	this.suffix = theSuffix;
	this.max = theMax;
	this.layers = [];
	if (thePrefix!=null) {
		this.layers = returnAllLayers(thePrefix,theSuffix,theMax);
		} //end if
	this.previousButton = new layerObject(thePrefix + "Pr" + theSuffix);
	this.nextButton = new layerObject(thePrefix + "Ne" + theSuffix);
	this.collect = addToCollection;
	this.previous = collectionGoPrevious;
	this.next = collectionGoNext;
	this.current = 0;
	this.manageControls = manageCollectionControls;
	this.startPaging = startPagingCollection;
	this.show = showCollection;
	this.hide = hideCollection;
	this.showOnly = oneLayer;
	} //end function

//the following function shows all layers in the collection
function showCollection() {
	for (var x=0; x<this.layers.length; x++) {
		this.layers[x].show();
		} //end for loop
	} //end function

//the following function hides all layers in the collection
function hideCollection() {
	for (var x=0; x<this.layers.length; x++) {
		this.layers[x].hide();
		} //end for loop
	} //end function

function addToCollection(incomingLayerObject) {
	this.layers[this.layers.length] = incomingLayerObject;
	} //end function

function collectionGoPrevious() {
	if (this.current>0) {
		this.current -= 1;
		this.showOnly(this.current);
		} //end if
	this.manageControls();
	} //end function

function collectionGoNext() {
	if (this.current<this.max) {
		this.current += 1;
		this.showOnly(this.current);
		} //end if
	this.manageControls();
	} //end function

function manageCollectionControls() {
	if (this.current==0) {
		this.previousButton.hide();
		} //end if
	else {
		this.previousButton.show();
		} //end else
	if (this.current==this.max) {
		this.nextButton.hide();
		} //end if
	else {
		this.nextButton.show();
		} //end else
	} //end function

function startPagingCollection() {
	oneLayerSelect(this.layers,this.current);
	this.manageControls();
	} //end function

//the following function takes a general name for a set of layers and the number of the largest
//and puts them all in an array and returns it. Note: they must be numbered starting at zero!
//the prefix is what comes before the number on all of the layers. 
//the suffix is what comes after the number on all of the layers.
function returnAllLayers(prefix,suffix,maxNumber) {
	var tempLayers = [];
	for (var x=0; x<=maxNumber; x++) {
		tempLayers[x] = new layerObject(prefix + x + suffix);
		} //end for loop
	return tempLayers;
	} //end function

//the following function makes only the numbered layer visible of the array.
function oneLayer(theNumber) {
	if (this.layers[theNumber]!=null) {
		this.hide();
		this.layers[theNumber].show();
		} //end if
	} //end function


// ****************
// **            **
// **  Clipping  **
// **            **
// ****************


// The following function returns an array with the four clip values for a layer, in 
// the order [top, right, bottom, left] .
//
// As usual, Netscape and IE couldn't agree on any standard way of dealing with this,
// so this function contains browser-specific code.
//
// DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function getLayerObjectClip() {
	var theLayer = this.theAbstract;
	var top = null;
	var right = null;
	var bottom = null;
	var left = null;
	if (is_nav4) {
		top = this.theAbstract.clip.top;
		right = this.theAbstract.clip.right;
		bottom = this.theAbstract.clip.bottom;
		left = this.theAbstract.clip.left;
		} //end else if
	else if (is_ie4up || is_nav6up) {
		var parsedClip = this.theAbstract.clip.split("rect(")[1].split(")")[0].split("px");
		top = Number(parsedClip[0]);
		right = Number(parsedClip[1]);
		bottom = Number(parsedClip[2]);
		left = Number(parsedClip[3]);
		} //end else if
	if (top!=null) {
		var tempArray = [top,right,bottom,left];
		return tempArray;
		} //end if
	else {
		return null;
		} //end else
	} //end function

// The following function sets the four clip values for a layer.
// The first parameter is the layer object for the layer to be clipped.
// The second parameter is an array of four integers in the order 
// [top, right, bottom, left] .
//
// As usual, Netscape and IE couldn't agree on any standard way of dealing with this,
// so this function contains browser-specific code.
//
// DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function setLayerObjectClip(clipArray) {
	var theLayer = this.theAbstract;
	if (is_nav4) {
		theLayer.clip.top = clipArray[0];
		theLayer.clip.right = clipArray[1];
		theLayer.clip.bottom = clipArray[2];
		theLayer.clip.left = clipArray[3];
		} //end if
	else if (is_ie4up || is_nav6up) {
		theLayer.clip = "rect(" + clipArray[0] + "px " + clipArray[1] + "px " + clipArray[2] + "px " + clipArray[3] + "px)";
		} //end else if
	} //end function


// *****************
// **             **
// **  Scrolling  **
// **             **
// *****************


// The following function initializes a layer to be a scrollable unit
// to fit within the specified height.
//
// DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function makeLayerObjectScrollable(clipHeight) {
	var layerClip = this.getClip();
	// The following line grabs the original clip length of the layer in case 
	// you want to prevent infinite scrolling.
	this.scrollingLayerLength = layerClip[2];
	layerClip[2] = clipHeight;
	this.setClip(layerClip);
	this.scrollingLayerLocation = this.getPosition();
	this.scrollingLayerHeight = clipHeight;
	scrollingLayer = new layerObject(this.layerID);
	this.show();
	} //end function

//the following function scrolls the scrollable layer by the specified increment.
//DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
function scrollLayerClip(increment) {
	if (this.scrollingLayerHeight!=0) {
		var layerClip = this.getClip();
		var doIt = false;
		// If infinite scrolling is allowed, just make sure not to run off the top.
		if (this.scrollingIsInfinite) {
			if ( ((layerClip[0]+increment)>=0) && ((layerClip[2]+increment)>0) ) {
				doIt = true;
				} //end if
			} //end if
		// however, if infinite scrolling is not allowed, make sure not to run
		// off the top or the bottom.
		else {
			if ( ((layerClip[0]+increment)>=0) && ((layerClip[2]+increment)>0) && ((layerClip[2]+increment)<=this.scrollingLayerLength) ) {
				doIt = true;
				} //end if
			} //end else
		if (doIt) {
			layerClip[0] += increment;
			layerClip[2] += increment;
			this.setClip(layerClip);
			this.reposition([this.scrollingLayerLocation[0],this.scrollingLayerLocation[1]-layerClip[0]]);
			} //end if
		} //end if
	} //end function

function startScrollingLayer(increment,delay) {
	if (scrollingLayer!=null) {
		scrollingLayer.stopScrolling();
		} //end if
	scrollingLayer = this;
	var theAction = "scrollingLayer.scroll(" + increment + ")";
	this.scrollingLayerInterval = setInterval(theAction,delay);
	} //end function

function stopScrollingLayer() {
	if (this.scrollingLayerInterval!=null) {
		clearInterval(this.scrollingLayerInterval);
		this.scrollingLayerInterval = null;
		} //end if
	} //end function

// The following global variable is not intended to be modified by the programmer.
var scrollingLayer = null;


// **************************
// **                      **
// **  Compatibility Test  **
// **                      **
// **************************


// These functions test the browser to determine if it's compatible with 
// Dynamic HTML.
//
// This actualy provides no layer functionality whatsoever, but it's
// useful if you want to test whether or not the browser will be able
// to use the layer code.

//the following function does nothing if the browser passes the compatibility test, 
//goes to the page at location failpage if it doesn't.
function testCompatibility(failpage) {
	if (!compatible()) {
		location.href=failpage;
		} //end if
	} //end function

//the following function returns true if the browser is Netscape or IE version 4 or higher,
//false if it's not one of those browsers or not a high enough version.
function compatible() {
	if ( (is_nav || is_ie) && (is_major>=4) ) {
		return true; 
		}
	return false;
	} //end function


// *************
// **         **
// **  Mouse  **
// **         **
// *************


// INSTRUCTIONS:
// Call loadMouse() from the onLoad handler of the body tag of the document.
// mouseX will reflect the X value of the mouse's location,
// mouseY will reflect the Y value of the mouse's location.
// Both will be null until the mouse enters the page.

// Global variables:
var mouseX = null;
var mouseY = null;

function getLocation(foo) {
	if (is_nav6up) {
		mouseX = foo.clientX;
		mouseY = foo.clientY;
		} //end if
	else if (is_nav4up) {
		mouseX = foo.pageX;
		mouseY = foo.pageY;
		} //end else if
	else if (is_ie4up) {
		mouseX = window.event.x;
		mouseY = window.event.y;
		} //end else if
	if (is_ie5 || is_ie5_5) {
		mouseX = mouseX + document.body.scrollLeft;
		mouseY = mouseY + document.body.scrollTop;
		} //end if
	} // end function

function loadMouse() {
	if (is_nav4) {
		captureEvents(Event.MOUSEMOVE);
		onmousemove = getLocation;
		} //end if
	else if (is_ie4up) {
		document.onmousemove = getLocation;
		} //end else if
	else if (is_nav6up) {
		document.body.addEventListener("mousemove",getLocation,false);
		} //end else if
	} //end function

// The following is a method of the layerObject function.
// DO NOT CALL THIS FUNCTION. USE THE LAYER OBJECT INSTEAD.
// Its purpose is to determine if the mouse is over the layer.
// Note that this does not determine if the layer is actually visible.
function mouseInLayer() {
	var theClip = this.getClip();
	var thePosition = this.getPosition();
	var top = thePosition[1] + theClip[0];
	var right = thePosition[0] + theClip[1];
	var bottom = thePosition[1] + theClip[2];
	var left = thePosition[0] + theClip[3];
	var result = (mouseY >= top) && (mouseY <= bottom) && (mouseX >= left) && (mouseX <= right);
	return result;
	} //end function

