/* 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/* 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') {		buildBlsMenus();		if (menuType == 'expanded') generateExpandedBlsMenus();		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);  }}/* 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;	};}