/* ********** BellSouth Intranet Navigation Script **********
 * 
 * This script provides functionality for generating and controlling static, dropdown, 
 * or flyout menus for BellSouth intranet sites.
 * 
 * Navigation items (the links in the menus) are added to an array either in the 
 * (x)html document, in blsMenusItems.js, or another custom file. The items are 
 * instances of BlsNavItem.
 * 
 * The HTML generated for each set of navigational items is in the form of an unordered
 * list (<ul>). The appearance attributes for each list and the items they contain are
 * specified in the blsMenus.css stylesheet.
 * 
 * Updates:
 * 01.20.05, Chuck Bradley: Addition of Windows-Explorer-style navigation
 *
 */


/* global variables */
var blsMenus = new Array(); // array that will contain all blsMenu objects
var blsVisibleMenus = new Array(); // array of blsMenu objects corresponding to visible menus
var timer = null; // timer to delay removal of menus after mouseout
var xtimer = null; // timer to control scrolling of extended menus
var navItemCounter = 0; // counter for auto-assignation of keys to BlsNavItem objects
var blsNav = new BlsNavItem(); // instantiation of top-level menu (headers)
var xMenuKey = false; // id of extended menu
var menuType = 'top'; // default menu style. Alternate styles are specified in call to makeBlsMenus()
var blsMenuDelay = 500; // delay after mousing out of a menu before menu disappears (in milliseconds)
var blsItemDelay = 200; // delay after mousing out of an item before item "deactivates" (in milliseconds)
var overBlsItem = false; // default state
var openExplorerItems; // container for storing expanded items in Explorer-style navigation



/* BlsNavItem:
 * An instance of this object exists for each navigational item,
 * including the menu headers and the items in each menu.
 * The instances that correspond to items that spawn menus have
 * a populated menuItems array as well as a pointer to the
 * BlsMenu instance corresponding to the menu. The parentMenu
 * attribute is a reference to the BlsMenu whose menuItems array
 * contains this BlsNavItem.
 */
function BlsNavItem(text,url,target,separator,label) {
	this.text = (text) ? text : false; // displayed text
	this.url = (url) ? normalizeUrl(url) : false; // linked url
	this.target = (target) ? target : false; // targeted window for link
	this.separator = (separator) ? separator : false; // show separator line after item?
	this.label = (label) ? label : false; // display item as menuLabel?
	this.key = "blsNavItem" + navItemCounter; // auto-assigned key
	this.menu = false; // reference to BlsMenu whose corresponding div is spawned by this item
	this.menuItems = false; // array of BlsNavItems in above menu
	this.parentMenu = false; // BlsMenu object whose menu array contains this item
	navItemCounter++;
}

/* BlsMenu:
 * An instance of this object exists for each menu that will be
 * available to the document. The spawner attribute is a reference
 * to the BlsNavItem that corresponds to the navigational item
 * that spawns the corresponding menu. The menuItems array is a
 * pointer to the same array within the spawner object.
 */
function BlsMenu(spawner) {
	this.spawner = (spawner) ? spawner : false; // BlsNavItem that spawns this menu
	this.key = this.spawner ? spawner.key : false; // the menu key matches that of its spawner
	this.menuItems = spawner.menuItems; // the array of BlsNavItems that appear in this menu
	this.grandspawner = spawner.parentMenu.spawner; // The spawner of the spawner's parent menu
	if (this.spawner) this.spawner.menu = this; // assignment of this BlsMenu as its spawner's offspring
}



/* Object preparation: */

/* add the default set of menus ('blsNav') to the blsMenus array */
function buildBlsMenus() {
	addToBlsMenus(blsNav);
}

/* recursively add the supplied blsMenu and each of its child blsMenu 
   instances to the blsMenus array */
function addToBlsMenus(blsni) {
	var menu = new BlsMenu(blsni);
	blsMenus.push(menu);
	for (var i=0; i<blsni.menuItems.length; i++) {
		var itm = blsni.menuItems[i];
		itm.parentMenu = menu;
		if (itm.menuItems) addToBlsMenus(itm);
	}
}







/* HTML Generation */

/* calls functions to compile menu item arrays and
 * generate HTML for menus and visible navigation
 */
function makeBlsMenus(mt) {
	if(mt) menuType = mt.toLowerCase();
	if(menuType == 'top' || menuType == 'flyout' || menuType == 'expanded' || menuType == 'explorer') {
		buildBlsMenus();
		if (menuType == 'expanded') generateExpandedBlsMenus();
		else if (menuType == 'explorer') {
			var msg = (makeBlsMenus.arguments.length > 1) ? makeBlsMenus.arguments[1] : 'Explore:';
			generateBlsExplorer(msg);
		} else {
			generateBlsNavHeaders();
			generateBlsMenus();
		}
	} else alert('Error: "' + mt + '" is not an appropriate menutype. [201]');
}


/* generates HTML code for navigation headers */
function generateBlsNavHeaders() {
	var str = '';
	str += '<div id="NavWrapper"><ul';
	if (menuType == "top") str += ' id="TopMenuBar"';
	str += '>';
	for (var i = 0; i< blsNav.menuItems.length; i++) {
		var itm = blsNav.menuItems[i];
		str += '<li';
		if (itm.url || itm.menuItems) {
			if(itm.separator || i==0) {
				str += ' class="';
				if(itm.separator) str += 'blsSep';
		 		if(i==0) str += ' firstItem';
				str += '"';
			}
			str += '><a href="';
			if (itm.url) str += itm.url;
			else str += '#';
			str += '"';
			if (itm.target) str += ' target="' + itm.target + '"';
			str += ' onmouseover="overBlsHeaderItem(';
			if (itm.menuItems) str += '\'' + itm.key + '\'';
			str += ');';
			if (showStatus) str += ' window.status=\'' + itm.text + '\'; return true;';
			if (itm.menuItems || showStatus) {
				str += '" onmouseout="';
				if (itm.menuItems) str += 'outBlsHeader(this)';
				else str += 'window.status=\'\'';
				if (showStatus) str += '; return true;';
			}
			str += '"';
			str += ' id="' + itm.key + 'A"';
			str += ' class="';
			if (itm.menuItems) str += 'blsMenusHeaderParent';
			else str += 'blsMenusHeaderLink';
			str += '">';
		} else { // no url or items:
			str += ' class="menuLabel';
			if (!i) str += ' firstLabel';
			str += '"><strong>';
		}
		str += itm.text;
		if (itm.menuItems) str += '&nbsp;&nbsp;';
		if (itm.url || itm.menuItems) str += '</a>';
		else str += '</strong>';
		str += '</li>\n';
	}
	str += '</ul></div>';
	document.write(str);
}


/* generates HTML code for floating menu divs, assigns it to a
 * global variable, writes it to the document, and calls the
 * function to apply the mouse handling event methods to each div
 */
function generateBlsMenus() {
	for (var i = 1; i < blsMenus.length; i++) {
		var divName = blsMenus[i].key;
		var itms = blsMenus[i].menuItems;
		var divWidth = 70; // minimum menu width
		var preStr = '<div class="menuDiv" id="' + divName + '"';
		var str = '<ul class="blsMenuList">';
		for ( j = 0 ; j < itms.length ; j++ ) {
			var itemNumber = i + "_" + j;
			var itm = itms[j];
			var itemid = itm.key + 'A';
			str += '<li id="' + itm.key + 'R" class="blsMenuItem';
			if(itm.separator) str += ' blsMenuItemSep';
			str += '">';
			if(itm.menuItems || itm.url) {
				str += '<a href="';
				if(itm.url) {
					str += itm.url + '"';
					if (itm.target) str += ' target="' + itm.target + '"';
				} else str += '#"';
				str += ' onmouseover="overBlsMenuItem(\'' + itm.key + '\',\'' + itm.parentMenu.key + '\',\'' + itm.text + '\'';
				if(itm.menuItems) str += ',1';
				str += ')';
				if(showStatus) str += '; return true;';
				str += '" onmouseout="outBlsMenuItem()';
				if(showStatus) str += '; window.status=\'\'; return true;';
				str += '" class="blsMenuLink';
				if(itm.label) str += ' menuLabel';
				if(itm.menuItems) str += ' blsMenuParent';
				else str += ' blsMenuChild';
				str += '" id="' + itemid + '">';
			} else str += '<div class="menuLabel">';
			str += itm.text;
			if(itm.menuItems) str += '&nbsp;&nbsp;&nbsp;';
			if(itm.menuItems || itm.url) str += '</a>';
			else str += '</div>';
			str += '</li>';
			divWidth = calculateMenuWidth(itm,divWidth);
		}
		str += '</ul></div>';
		preStr += ' style="width: ' + divWidth + 'px">';
		str = preStr + str;
		document.write(str);
		addMenuMethods(divName);
	}
	var str = '';
	str += '<div class="menuExtender" id="TopExtender"><a href="JavaScript:void shiftMenu(0)" onmouseover="shiftMenu(0); return true;" onmouseout="holdMenu(); return true;">&nbsp;</a></div>';
	str += '<div class="menuExtender" id="BottomExtender"><a href="JavaScript:void shiftMenu(1)" onmouseover="shiftMenu(1); return true;" onmouseout="holdMenu(); return true;">&nbsp;</a></div>';
	document.write(str);
	addMenuMethods("TopExtender");
	addMenuMethods("BottomExtender");
}



/* adds the mouse event handler methods to specified div element */
function addMenuMethods(divName) {
	var thisDiv = document.getElementById(divName);
	thisDiv.onmouseover = overBlsMenu;
	thisDiv.onmouseout = outBlsMenu;
}

/* calculates an approximate width for a menu based upon the number of characters 
   in the menu's items. Since proportional fonts are not all the same width, the 
   value is only an approximation and extra width is added just in case. */
function calculateMenuWidth(itm,provisionalWidth) {
	var i = Math.round(itm.text.length * 5.5) + 30;
	if (itm.menuItems) i += 20;
	return (i>provisionalWidth) ? i : provisionalWidth;
}



/* generates HTML code for expanded left nav */
function generateExpandedBlsMenus() {
	var str = '';
	str += '<div id="NavWrapper" class="expandedBlsMenu">';
	str += generateNestedLists(blsNav.menuItems);
	str += '</div>';
	document.write(str);
}

/* generates unordered list HTML for each menu object */
function generateNestedLists(menuItems) {
	var str = '';
	str += '<ul>';
	for (var i = 0; i< menuItems.length; i++) {
		var itm = menuItems[i];
		str += '<li';
		if(itm.separator) str += ' class="blsSep"';
		str += '>';
		if (itm.url) {
			str += '<a href="';
			str += itm.url
			str += '"';
			if(itm.target) str += ' target="' + itm.target + '"';
			if(itm.label) str += ' class="menuLabel"';
			str += '>';
		} else str += '<div class="menuLabel">';
		str += itm.text;
		if (itm.url) str += '</a>';
		else str += '</div>';
		if (itm.menuItems) {
			str += generateNestedLists(itm.menuItems);
		}
		str += '</li>';
	}
	str += '</ul>';
	return str;
}




/* Mouse Event Handlers */

/* mouseover handler for header items that don't spawn menus */
function overBlsHeaderItem(key) {
	if (timer) clearTimeout(timer);
	if(key) {
		if(!blsVisibleMenus.length || menuType == "top") displayBlsMenu(key);
		else timer = setTimeout("displayBlsMenu('" + key + "')",blsItemDelay);
	} else if(blsVisibleMenus.length) {
		if (menuType == "top") removeAllBlsMenus();
		else timer = setTimeout("removeAllBlsMenus()",blsItemDelay);
	}
}

/* mouseout handler for header items */
function outBlsHeader(a) {
	if(menuType == "flyout") toggleParentStatus(a, 'off');
	clearTimeout(timer);
	timer = setTimeout("removeAllBlsMenus()",blsItemDelay);
}

/* mouseover handler for menu item anchors */
function overBlsMenuItem(key,parentMenuKey,text,isParent) {
	overBlsItem = true;
	clearTimeout(timer);
	if (showStatus) window.status = text;
	var parentMenu = getBlsMenu(parentMenuKey);
	toggleParentStatus((parentMenu.spawner.key + 'A'), 'on'); // make sure parent menu's spawner is highlighted
	var siblings = parentMenu.menuItems;
	for (var i = 0; i< parentMenu.menuItems.length; i++) { // loop through siblings and deselect others
		if (parentMenu.menuItems[i].key != key) toggleParentStatus((parentMenu.menuItems[i].key + 'A'), 'off');
	}
	var pRank = getBlsMenuRank(parentMenu); // are there any menus visible, from here down?
	if(blsVisibleMenus.length > pRank && getActiveMenu().key != key) { // if so...
		if(isParent) timer = setTimeout("displayBlsMenu('" + key + "')",blsItemDelay); // if this is a parent displayBlsMenu...
		else timer = setTimeout("removeActiveMenu()",blsItemDelay); // if not, removeActiveMenu
	} else if(isParent) displayBlsMenu(key);
}

/* mouseout handler for non-menu-spawing menu item anchors */
function outBlsMenuItem() {
	overBlsItem = false;
}


/* mouseover handling method added to menu div elements
 * maintains layer visibility by cancelling the deactivation timer */
function overBlsMenu() {
	if (!overBlsItem) clearTimeout(timer);
}

/* mouseout handling method added to menu div elements
 * restarts deactivation timer */
function outBlsMenu() {
	clearTimeout(timer);
	timer = setTimeout("removeAllBlsMenus()",blsMenuDelay);
}






/* Menu Functions */

/* display div with id matching key and handles removing others
 * (changing item appearance, etc.) 
 */
function displayBlsMenu(key) {
	clearTimeout(timer); // cancel deactivation clock
	var menu = getBlsMenu(key); // get corresponding BlsMenu object
	var rank = getBlsMenuRank(menu); // find it with the blsVisibleMenus array
	var menuDiv = document.getElementById(key); // get corresponding HTML div element
	if (!rank) { // if it's not already visible... 
		var isSub = (menu.grandspawner.text) ? true : false;
		if(!isSub) removeAllBlsMenus(); // if it's a top-level menu, remove all the visible menus
		else removeBlsMenu(getBlsMenuRank(menu.grandspawner.menu) + 1); // if submenu, remove all menus below parent
		var whichAnchor = document.getElementById(key + "A"); // get spawning anchor element
		toggleParentStatus(whichAnchor,'on'); // change its style
		// determine its position:
		var divTop = findy(whichAnchor);
		var divLeft = findx(whichAnchor);
		// adjust for its width and/or height:
		if(menuType == 'flyout' || isSub) {
			divLeft += getWidth(whichAnchor);
			divTop -= 1;
		} else divTop += getHeight(whichAnchor);
		if(menuType == 'flyout' && !isSub) divTop -= 1;
		ChangeElement(menuDiv, "display", "block"); // make div visible
		// compare the height of the menu to that of the window:
		var divHeight = menuDiv.offsetHeight;
		var winHeight = getWindowHeight();
		if (divTop + divHeight > winHeight) { // if the bottom of the menu falls below the window...
			if(divHeight > winHeight) { // if the menu is taller than the window...
				showMenuExtender ("Bottom", key, divLeft); // display the menu extender arrows
				divTop = 0;
			} else divTop = winHeight - divHeight; // otherwise, shift it up to compensate
		}
		ChangeElement(menuDiv, "top", divTop + "px"); // set top position
		ChangeElement(menuDiv, "left", divLeft + "px"); // set left position
		blsVisibleMenus.push(menu); // add to blsVisibleMenus array
	}
	// if the div is already visibile, but not active, move to it:
	if (rank && rank != blsVisibleMenus.length) removeBlsMenu(rank+1);
	if (showStatus) window.status = menu.spawner.text; // display status text:
}


/* return last item in blsVisibleMenus */
function getActiveMenu() {
	if (blsVisibleMenus.length) return blsVisibleMenus[blsVisibleMenus.length-1];
	else return false;
}

/* return blsMenu object with matching key */
function getBlsMenu(key) {
	for (var i=0; i<blsMenus.length; i++) {
		if (blsMenus[i].key == key) return blsMenus[i];
	}
	return false;
}

/* return index+1 of menu within blsVisibleMenus */
function getBlsMenuRank(menu) {
	for (var i=blsVisibleMenus.length; i>0; i--) {
		if(blsVisibleMenus[i-1] == menu) return i;
	}
	return false;
}

/* remove all visible menus */
function removeAllBlsMenus() {
	hideMenuExtensions();
	removeBlsMenu(1);
}

/* remove only the topmost visible menu */
function removeActiveMenu() {
	removeBlsMenu(blsVisibleMenus.length)
}


/* remove blsMenu objects from blsVisibleMenus array, 
 * beginning with given rank, hide corresponding menus,
 * and deactivate their spawning items */
function removeBlsMenu(rank) {
	while (blsVisibleMenus.length >= rank) {
		var menu = blsVisibleMenus.pop();
		if(xMenuKey && (menu.key == xMenuKey)) hideMenuExtensions();
		ChangeElement(menu.key, "display", "none");
		toggleParentStatus(menu.key + "A",'off');
	}
}


/* change className of parent element */
function toggleParentStatus(e,setting) {
	var el = (typeof(e) == "string") ? document.getElementById(e) : e;
	if(el==null) return false;
	if (el.className.indexOf('HeaderParent') > -1) {
		if (el.className.indexOf('activeBlsMenusHeaderParent') > -1 && setting != 'on')
			el.className=el.className.replace(new RegExp("activeBlsMenusHeaderParent\\b"), "blsMenusHeaderParent");
		else if (el.className.indexOf('blsMenusHeaderParent') > -1 && setting != 'off')
			el.className=el.className.replace(new RegExp("blsMenusHeaderParent\\b"), "activeBlsMenusHeaderParent");
	} else if (el.className.indexOf('MenuParent') > -1) {
		if (el.className.indexOf('blsMenuParent') > -1 && setting != 'off')
			el.className=el.className.replace(new RegExp("blsMenuParent\\b"), "activeBlsMenuParent");
		else if (el.className.indexOf('activeBlsMenuParent') > -1 && setting != 'on')
			el.className=el.className.replace(new RegExp("activeBlsMenuParent\\b"), "blsMenuParent");
	} else return false;
	return true;
}

/* display the menu extenders at the bottom or top of the menu */
function showMenuExtender (end, key, divLeft) {
	var exDivName = end + 'Extender';
	var exDiv = document.getElementById(exDivName);
	if(exDiv.style.display == "block") return;
	var mExtLeft = divLeft + 2;
	var mExtWidth = document.getElementById(key).offsetWidth - 4;
	var mExtTop = (end == "Bottom") ? getWindowHeight() - 14 : 0;
	ChangeElement(exDiv, "display", "block");
	ChangeElement(exDiv, "width", mExtWidth + "px");
	ChangeElement(exDiv, "top", mExtTop + "px");
	ChangeElement(exDiv, "left", mExtLeft + "px");
	xMenuKey = key;
}

function holdMenu() {
	clearTimeout(xtimer);
	window.status = "";
}

function hideMenuExtender(end) {
	var exDivName = end + 'Extender';
	ChangeElement(exDivName, "display", "none");
	window.status = "";
}

function hideMenuExtensions() {
	xMenuKey = false;
	hideMenuExtender("Top");
	hideMenuExtender("Bottom");
}

function shiftMenu(up) {
	clearTimeout(xtimer);
	window.status = "Display more menu items...";
  var menu = getActiveMenu();
	if (!menu) return;
	var div = document.getElementById(menu.key);
	var divTop = findy(div);
	var direction = (up) ? 1 : -1;
  var tFunction = (up) ? 'shiftMenu(true)' : 'shiftMenu(false)';
  var divHeight = div.offsetHeight;
	var winHeight = getWindowHeight();
  if (up && (winHeight > divTop + divHeight)) hideMenuExtender("Bottom");
	else if (!up && divTop >= 0) hideMenuExtender("Top");
	else {
		var divTop = divTop - (8 * direction);
		ChangeElement(div, "top", divTop + "px");
		if (divTop < 0) showMenuExtender ('Top', menu.key, findx(div));
		else hideMenuExtender("Top");
		if(divHeight > winHeight - divTop) showMenuExtender ("Bottom", menu.key, findx(div));
		else hideMenuExtender("Bottom");
  	xtimer = setTimeout(tFunction,30);
  }
}



/* Explorer-style navigation: */

function generateBlsExplorer(msg) {
	var str = '';
	navItemCounter = 0;
	str += '<div id="ExplorerTitle">' + msg + '</div>';
	str += '<div id="ExplorerWrapper">';
	str += generateExplorerLists(blsNav.menuItems);
	str += '</div>';
	document.write(str);
	blsPreExplorer();
}

function generateExplorerLists(menuItems) {
	var str = '';
	str += '<ul id="XL_';
	str += navItemCounter;
	str += '"';
	if(navItemCounter) {
		str += ' class="collapsed">';
	} else str += '>';
	navItemCounter++;
	for (var i = 0; i< menuItems.length; i++) {
		var itm = menuItems[i];
		str += '<li id="';
		str += itm.key;
		str += '"';
		if(i == menuItems.length - 1) str += ' class="last"';
		str += '>';
		if (itm.url) {
			str += '<a href="';
			str += itm.url
			str += '"';
			if(itm.target) str += ' target="' + itm.target + '"';
			if(itm.label) str += ' class="menuLabel"';
			str += '>';
		} else if(itm.label) str += '<span class="menuLabel">';
		str += itm.text;
		if (itm.url) str += '</a>';
		else if(itm.label) str += '</span>';
		if (itm.menuItems) {
			str += '<a href="#" onclick="return blsExplore(this);" class="blsExpIcon"><img src="';
			str += blsxpath;
			str += 'images/explorer_plus.gif" /></a>';
			str += generateExplorerLists(itm.menuItems);
		}
		str += '</li>';
	}
	str += '</ul>';
	return str;
}


function blsExplore(node) {
	var list = getFirstChildByTag(node.parentNode,"UL");
	if (!list) {
		alert("Error: The item does not contain a sub-items to be explored. [401]");
		return false;
	}
	var icon = node.childNodes[0];
	if(!list.className || list.className == "collapsed") {
		list.className = 'xpanded';
		icon.src = blsxpath + 'images/explorer_minus.gif';
		updateItemState(list.id,1);
	} else if(list.className == "xpanded") {
		list.className = 'collapsed';
		icon.src = blsxpath + 'images/explorer_plus.gif';
		updateItemState(list.id,0);
	}
	return false;
}


function getFirstChildByTag(parent,tag) {
	var children = parent.childNodes;
	for(var i=0; i<children.length; i++) {
		var child = children[i];
		if( child.nodeType == 1 && child.nodeName == tag.toUpperCase() ) return child;
	}
	return false;
}


function getFirstChildByClass(parent,className) {
	var children = parent.childNodes;
	for(var i=0; i<children.length; i++) {
		var child = children[i];
		if( child.nodeType == 1 && child.className == className ) return child;
	}
	return false;
}

function blsPreExplorer() {
	if(getExplorerCookie()) {
		openExplorerItems = getExplorerCookie().split('&');
		for(var i=0; i<openExplorerItems.length; i++) {
			var node = getFirstChildByClass(document.getElementById(openExplorerItems[i]).parentNode,'blsExpIcon');
			if(node) blsExplore(node);
		}
	} else openExplorerItems = new Array();
}

function updateItemState(id,state) {
	var update = false;
	var idx = -1;
	for(var i=0; i<openExplorerItems.length; i++) {
		if(openExplorerItems[i] == id) idx = i;
	}
	if(idx > -1 && !state) {
		openExplorerItems.splice(idx,1);
		update = true;
	}
	if(idx < 0 && state) {
		openExplorerItems.push(id);
		update = true;
	}
	if(update) setExplorerCookie(openExplorerItemsToString())
}

function openExplorerItemsToString() {
	var str = '';
	for (var i=0; i<openExplorerItems.length; i++) {
		if(i) str += '&';
		str += openExplorerItems[i];
	}
	return str;
}

// Cookie Handling

function setExplorerCookie(value) {
	var name = "blsExplorerCookie";
	var hours = 1; // expiration time
  var date = new Date();
  date.setTime(date.getTime()+(hours*60*60*1000));
  expires = "; expires="+date.toGMTString();
	var cookieStr = name+"="+value+expires+";path=/";
	document.cookie = cookieStr;
}

function getExplorerCookie() {
	var name = "blsExplorerCookie";
	name += "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(name) == 0) return c.substring(name.length,c.length);
	}
  return false;
}












/* Utility Functions: */

function ChangeElement(e, propertyName, value) {
	var el = (typeof(e) == "string") ? document.getElementById(e) : e;
	if(el==null) return false;
	eval("el.style." + propertyName + " = value");
}

function getHeight (el) {
	return el.offsetHeight;
}

function getWidth (el) {
	return el.offsetWidth;
}

function findy (el) {
	if (el.offsetParent) return el.offsetTop + findy(el.offsetParent);
	else return el.offsetTop;
}

function findx (el) {
	if (el.offsetParent) return el.offsetLeft + findx(el.offsetParent);
	else return el.offsetLeft;
}

function getWindowHeight() {
	var windowHeight=0;
	if (typeof(window.innerHeight)=='number') windowHeight=window.innerHeight;
	else if (document.documentElement && document.documentElement.clientHeight)
		windowHeight = document.documentElement.clientHeight;
	else if (document.body && document.body.clientHeight)
		windowHeight=document.body.clientHeight;
	return windowHeight;
}

function normalizeUrl(url) {
	if (url == '#') return url;
	var firstOne = url.substr(0,1).toLowerCase();
	var firstFour = '';
	if(url.length > 3) firstFour = url.substr(0,4).toLowerCase();
	if ((firstOne == '/') || (firstFour == 'http') || (firstFour == 'java') || (firstFour == 'mail')) return url;
	return site_root + url;
}




/* Array methods:
 * Intenet Explorer 5.0 does not support the following methods
 * of the Array object. These should not have any effect on
 * modern browsers.
 */

var undefined;
function isUndefined(property) {
	return (typeof(property) == 'undefined');
}

// Array.pop() - Remove the last element of an array and return it
if (isUndefined(Array.prototype.pop) == true) {
	Array.prototype.pop = function() {
		var lastItem = undefined;
		if ( this.length > 0 ) {
			lastItem = this[this.length - 1];
			this.length--;
		}
		return lastItem;
	};
}

// Array.push() - Add an element to the end of an array
if (isUndefined(Array.prototype.push) == true) {
	Array.prototype.push = function() {
		var currentLength = this.length;
		for (var i = 0; i < arguments.length; i++) { this[currentLength + i] = arguments[i]; }
		return this.length;
	};
}

// Array.shift() - Remove the first element of an array and return it
if (isUndefined(Array.prototype.shift) == true) {
	Array.prototype.shift = function() {
		var firstItem = this[0];
		for (var i = 0; i < this.length - 1; i++) { this[i] = this[i + 1]; }
		this.length--;
		return firstItem;
	};
}

// Array.unshift - Add an element to the beginning of an array
if (isUndefined(Array.prototype.unshift) == true) {
	Array.prototype.unshift = function(the_item) {
		for (loop = this.length-1 ; loop >= 0; loop--) { this[loop+1] = this[loop]; }
		this[0] = the_item;
		return this.length;
	};
}

// Array.splice - Remove a range of elements from an array
if (isUndefined(Array.prototype.splice) == true) {
	Array.prototype.splice = function (index, range) {
		var temp = new Array();
		var response = new Array();
		var loop = 0;
		for (loop = 0; loop < index; loop++) { temp[temp.length] = this[loop]; }
		for (loop = 2; loop < arguments.length; loop++) { temp[temp.length] = arguments[loop]; }
		for (loop = index + range; loop < this.length; loop++) { temp[temp.length] = this[loop]; }
		for (loop = 0; loop < range; loop++) { response[loop] = this[index + loop]; }
		this.length = 0;
		for (loop = 0; loop < temp.length; loop++) { this[this.length] = temp[loop]; }
		return response;
	};
}



