/****************************************************************************************************************************************

	Purpose: this file contains all JS for menus (not DMB menus!)
	
	History:
		File modified on 12/06/2005
		File modified on 06/22/2006 - BUG FIX for v2.2.4 - changed line #260 to search className instead of doing an exact match

****************************************************************************************************************************************/

// global var to store all IDs of menus that need to be setup after page loads
var setupMenuIds = new Array();

// function stores menu IDs in an array, and adds onload event to body to call setupDropMenus if not already added
function setupDropMenu(menuId) {
	setupMenuIds[setupMenuIds.length] = menuId;
}

// Purpose of function is to fix class names for IE only, as it doesn't support hover on LI tags :(
function setupDropMenus() {
	var i, menuDiv, parentUL, li, lis, uls, ul, previousSib, nextSib, menuShim, lastChild;

	// bail if there are no menus to setup
	if (!setupMenuIds) return;
	
	// loop thru each menu ID
	for(i=0;i<setupMenuIds.length;i++) {

		// grab ref. to menuDiv
		menuDiv = document.getElementById(setupMenuIds[i]);

		// IE doesn't support the hover pseudo class for LI tags...this fixes that (sorta)
		if (isIE) {
			// get all LI tags inside the menu DIV
			lis = menuDiv.getElementsByTagName('li');

			for (i=0; i<lis.length; i++) {
				li = lis[i];
	           
				lastChild = getLastChildElement(li);
				
				// If the LI has another menu level
	            if(lastChild.tagName=="UL" || lastChild.tagName == 'IFRAME'){
	            	
					/***************************************************************************
						The code below is preventing an IE bug that causes the border of the 
						menu that appears on mouseover to not appear until the 2nd mouseover.
						
						Don't mess with this!
					***************************************************************************/
					li.onmouseover=function() {
	            		/* display the inner menu */
	            		this.className+=" over";

	            		// grab reference to submenu <ul />
						var subMenu = this.lastChild.nodeName == 'UL' ? this.lastChild : this.lastChild.previousSibling;
					
						// add/resize iframe shim
						if(subMenu) {
							ieShim(subMenu);
						}
	            	}
	            	li.onmouseout=function() {
	            		/* hide the inner menu */
	            		this.className = this.className.replace("over","");
	                }
	            }
			}
		}
		

		// menu needs to be visibile (but with no display) so offset properties of it and submenus can be grabbed
		menuDiv.style.visibility = 'hidden';
		menuDiv.style.display = 'block';

		// setup scrolling on main top level menu
		setupScrollMenu(menuDiv.id);
		

		// grab all UL tags inside menu
		uls = menuDiv.getElementsByTagName('ul');
		
		// loop thru menus, and turn display on (but keep visibility hidden)...this allows the setupScrollMenu() function to obtain offset properties
		for(i=0;i<uls.length;i++) {
			// shorten var
			ul = uls[i];

			ul.style.visibility = 'hidden';
			ul.style.display = 'block';
		}

		// loop thru them
		for(i=0;i<uls.length;i++) {
			// shorten var
			ul = uls[i];
			
			/**********************************
				Add arrow images
			**********************************/
			// grab element right before this ul
			previousSib = getPreviousElement(ul);
			if (previousSib) {
				// if the element before this ul is an <a />, then we are on a submenu
				if (previousSib.nodeName == 'A') {
					// add class name to show the arrow bg image to indicate there is a sub
					previousSib.className += ' right_arrow';
				}
				
				// setup scrolling on submenu
				setupScrollMenu(ul);
			}
		}
		
		// loop thru menus, and turn display on (but keep visibility hidden)...this allows the setupScrollMenu() function to obtain offset properties
		for(i=uls.length;i>0;i--) {
			// shorten var
			ul = uls[i-1];

			ul.style.visibility = '';
			ul.style.display = '';
		}
		

		
		menuDiv.style.visibility = '';
		menuDiv.style.display = '';
		
	}	
}



/********************************************************************************
	This function is used to add an iFrame shim behind any element.
	Most of the work is done by ieShimDelayed. This just sets up the delay
********************************************************************************/
var shimElements = new Array();
function ieShim(elem){
	// if elem is an ID, grab ref. to it's corresponding element
	if (typeof(elem)=='string') elem = document.getElementById(elem);
	
	// add element to the shimElements array, which is used by ieShimDelayed()
	shimElements[shimElements.length] = elem;
	
	// call ieShimDelayed with a timeout, so IE has long enough to calculate all the offsetWidth properties
	//ieShimDelayed();
	setTimeout("ieShimDelayed()",0);
}

/**************************************************************************************************************

	Purpose of function is to add an absolutely positioned iFrame as a sibling of node "elem", size it to 
	match "elem" and position it directly behind "elem". This is used so "elem" can appear above form elements.
	
	Parameters: None
	
	This function should not be called directly - use isShim() instead, which will setup a delayed call to
	this function.
	
**************************************************************************************************************/
function ieShimDelayed() {
	var shim, nextSib, elem;

	// loop thru elements waiting to be shimmed (setup via a call to ieShim)
	while(elem = shimElements.shift()){
		// cleanup
		shim = '';
		
		// if an id string is passed, grab ref. to that element
		if (typeof(elem) == 'string') elem = document.getElementById(elem);
	
		// if no reference to element, or if not IE, bail
		if (!elem || !isIE) continue;
	
		// iFrame is added as the next sibling of elem, so we need to grab it and see if it's already an iFrame
		nextSib = getNextElement(elem);

		// if next sibling found, see if it is an iframe
		if (nextSib) {
			// if an iframe, store in new var
			if (nextSib.nodeName == 'IFRAME') {
				shim = nextSib;
			}
		}
		
		// if shim doesn't exist, create it
		if (!shim) {
			shim = document.createElement('iframe');
			// add new iframe to DOM, right after the DIV for the menu
			if (nextSib) {
				shim = elem.parentNode.insertBefore(shim, nextSib);
			} else {
				shim = elem.parentNode.appendChild(shim);
			}
			
			// CSS uses this to turn the display on and off for the iframe
			shim.className = 'iframe_shim';
		}
		
		if (shim) {
			// for some reason, the shims where off on the filter menus (on the data grid)...this accounts for that
			var leftDiff = 0;
			if (elem.id.indexOf('filter_modes')!=-1) leftDiff = 6;
			
			// in order for the shim to be behind the menu (elem), the elem must have a zindex of at least 2
			elem.style.zIndex = elem.style.zIndex <= 1 ? 2 : elem.style.zIndex;

			// size and position shim, then display it....make sure the zIndex is one less than the div above it
			shim.style.width 	= elem.offsetWidth;
			shim.style.height 	= elem.offsetHeight;
			//shim.style.border	="black solid 5px";
			shim.style.position = 'absolute';
			shim.style.left 	= elem.offsetLeft ? (elem.offsetLeft-leftDiff)+'px' : elem.style.left;
			shim.style.top 		= elem.offsetTop ? elem.offsetTop+'px' : elem.style.top;
			shim.style.zIndex 	= elem.style.zIndex - 1;
			//shim.style.display = 'none';
		}
	}
}

// global var that will be used to store references to divs that need to be hidden when document is clicked on
var hideMenuRefs = new Array;

// global var for the ID to be set to the result of setTimeout("hideMenus()");
var menuHide = false;

// this function is called via a window.setTimeout() call, and will hide all open menus IF the menuHide var is true
function hideMenusAuto() {
	if (menuHide) hideMenus();
}



/*************************************************************************************************************************

	Purpose of function is to show a popup menu div, along with it's iframe shim (for IE to cover select inputs)
	
	Parameters:
		menuId			(str) id of menu to show
		event
		positionElem	ref. to OR id of an element to position menu below, lining up with it's left edge (optional)
	
*************************************************************************************************************************/

function showMenu(menuId,event,positionElem) {
	// cancel bubble, so the window.onclick won't fire and hide this menu
	if (event) event.cancelBubble = true;
	// grab ref to menu div
	var menu = document.getElementById(menuId);
	if (menu) {

		// position menu if positionElem was passed
		if (positionElem) {
			// store the positioning element in the menu, so setupScrollMenu can grab it if needed
			menu.positionElem = positionElem;
		}

		// need to setup the menu when it's shown, so we can account for any changes in scroll or window size
		setupMenuIds.length=0;
		setupMenuIds[0] = menu.id;
		if (menu.className.indexOf('dropdown') != -1) setupDropMenus();
		
		// setup iframe shim for IE to cover form fields
		if (isIE) {
			ieShim(menu);
			// CSS works perfect inside ieShim if we don't turn 'display' on for the iframe,
			// so we need to turn it on here, just for the top level menu
			var shimRef = menu.nextSibling;
			//if (shimRef.nodeName=='IFRAME') shimRef.style.display='block';
		}
		
		// store ref. to menu div in hideMenus array so the hideMenus function can hide them as needed
		hideMenuRefs[hideMenuRefs.length] = menu;
		
		// setup menu, if not already done
		if (!menu.setup) {
			menu.onmouseout 	= function() { menuHide = true; setTimeout('hideMenusAuto()',1000);};
			menu.onmouseover 	= function() { menuHide = false;};
			menu.setup 			= true;
		}
		
		// display menu
		menu.style.display="block";
		if (isIE && shimRef) shimRef.style.display='block';
	}
}







/**************************************************************************************************
	Purpose of function is to setup menu to scroll if needed
	
	This does the following:
	Sets up scroll links at the top and bottom of the menu (<ul /> tag)
	Scrolls all the way to the top
	Hides all elements past the cutoff specified by the "maxitems" prop. on the <ul /> tag
**************************************************************************************************/
function setupScrollMenu(menu) {
	// ref. to the menu to setup
	if (typeof(menu) == 'string') var menu = document.getElementById(menu);
	var contentDiv = document.getElementById('content');
	// all menu items (<li /> tags)
	var menuChildren = menu.childNodes;
	var menuItems = new Array();
	for(var i=0;menuChildren[i];i++){
		if (menuChildren[i].nodeName == 'LI') menuItems[menuItems.length] = menuChildren[i];
	}

	// loop below will grab the top position of the main menu, and store it as a "mainMenuTop" property of this menu
	var upParent=menu;
	
	while(upParent.parentNode) {
		if (upParent.nodeName == 'UL' && upParent.parentNode.nodeName != 'LI') {
			menu.mainMenuTop = upParent.offsetTop;
			break;
		} else {
			upParent = upParent.parentNode;
		}
	}
	
	// set initial height of menu to the top of the bounding element
	var parentMenuCoords = getCoordinates(menu.parentNode.parentNode);
	menu.style.top = '-'+(parentMenuCoords.yTop-contentDiv.scrollTop-contentDiv.offsetTop)+'px';

	// set maximum height available for menu, which will be the height of the contentDiv, minus a little extra to be safe
	var maxHeight		= contentDiv.offsetHeight - 5;
	if (!menu.itemHeight) {
		menu.itemHeight = menuItems[1] ? menuItems[1].offsetHeight : menuItems[0].offsetHeight
	}

	// calculate max. # of visible items to obtain maxHeight
	maxItems = Math.floor(maxHeight / menu.itemHeight);

	// adjust maxItems to account for scrollbutton that will be adding
	maxItems = maxItems - 2;

	// store maxItems in menu for use by scroll functions
	menu.maxItems = maxItems;
	
	// Look for special scroll bars (<li /> with scroll_how="up" or scroll_how="down" attributes).
	// If not found, add them
	if (!menuItems[0].getAttribute('scroll_how')) {
		var scrollUpLI 			= document.createElement('li');		// create an <li /> tag to contain the <a />
		var scrollUpA			= document.createElement('a');		// create an <a /> tag to trigger scrolling
		scrollUpA.innerHTML 	= '&nbsp;';
		scrollUpA.onmouseover 	= function() { scrollOn(this);};
		scrollUpA.onmouseout 	= scrollOff;
		scrollUpA.setAttribute('href','#');
		scrollUpLI.className	= "scroll_up"
		scrollUpLI.setAttribute('scroll_how','up');
		scrollUpLI.appendChild(scrollUpA);
		
		// add <li /> to the top	 of the <ul /> menu
		scrollUpLI = menu.insertBefore(scrollUpLI,menu.firstChild);

		var scrollDownLI 		= document.createElement('li');
		var scrollDownA			= document.createElement('a');
		scrollDownA.innerHTML 	= '&nbsp;';
		scrollDownA.onmouseover = function() { scrollOn(this);};
		scrollDownA.onmouseout	= scrollOff;
		scrollDownA.setAttribute('href','#');
		scrollDownLI.className	= "scroll_down";
		scrollDownLI.setAttribute('scroll_how','down');
		scrollDownLI.appendChild(scrollDownA);

		// add <li /> to the bottom of the <ul /> menu
		scrollDownLI = menu.appendChild(scrollDownLI);

		// hide the scroll down button if not needed
		if (maxItems > menuItems.length) scrollDownLI.style.visibility = 'hidden';
		
	} else {
		// scroll up button should initially be hidden
		menuItems[0].style.visibility = 'hidden';
		
		// get rid of the scroll buttons from menuItems array
		menuItems.shift();
		menuItems.pop();
	}


	
	// If scrolling is not needed
	if (maxItems > menuItems.length) {
		// position menu if positionElem was passed
		if (menu.positionElem) {
			
			// grab new coordinates for menu relative to the first "relative" parent, and position it
			var coordinates = getCoordinates(menu.positionElem,1);
			// Opera seems to be off by an extra 9 pixels in both directions...this sets the postion of the menu, and fixes for opera if needed
			menu.style.top 	= isOpera ? (coordinates.yBottom-9) + 'px' 	: coordinates.yBottom + 'px';
			menu.style.left = isOpera ? (coordinates.xLeft-9) + 'px'	: coordinates.xLeft + 'px';
		}

		// Menu needs to be positioned inline with it's parent menu item that triggered it...
		// ONLY for submenus
		// grab x y coordinates of this menu's parent, which should be where the mouse is when this menu appears
		var parentMenuCoords = getCoordinates(menu.parentNode,1);

		// position menu so it's top is inline with the list item that triggered it (as long as it is a submenu)
		if (!menu.positionElem) menu.style.top 	= parentMenuCoords.yTop-menu.mainMenuTop;

		// the menu may be off the screen...if so, this pushes it up as needed
		menuCoordinates	= getCoordinates(menu);
	
		if (menuCoordinates.yBottom-contentDiv.scrollTop > contentDiv.offsetHeight) {
			//menu.style.top = (menu.offsetTop - (menuCoordinates.yBottom - contentDiv.offsetHeight)-5)+'px';
			menu.style.top = (menu.offsetTop - (menuCoordinates.yBottom - contentDiv.offsetHeight - contentDiv.scrollTop)-5)+'px';
			
			//var parentMenuCoords = getCoordinates(menu.parentNode.parentNode);
			//menu.style.top = '-'+(parentMenuCoords.yTop-contentDiv.scrollTop-contentDiv.offsetTop)+'px';
			
		}
		
		// rest of stuff below sets up the scroll...no need, so bail out
		return;
	}

	
	
	// preload m/o over scroll images
	var scrollUpMo 		= new Image(13,12);
	scrollUpMo.src 		= 'images/cart/scroll_up_mo.gif';
	var scrollDownMo 	= new Image(13,12);
	scrollDownMo.src 	= 'images/cart/scroll_down_mo.gif';

	// loop thru all menu items, hiding those that are passed the "maxitems" limit
	// stopping at the one right before the bottom scroll buttom
	var menuItemsLength = menuItems.length;
	for(var i=0, menuItem; (menuItem = menuItems[i]) && i<menuItemsLength;i++){
		if (i<maxItems) {
			menuItem.style.display = 'block';
		} else {
			menuItem.style.display = 'none';
		}
	}

	menu.topMenuItem = 0;
}


/*var topMenuItem;*/
var scrollState;
var scrollInterval;



function scrollOn(btn){
	// grab menu ID
	var menu = btn.parentNode.parentNode;

	// pull the scroll_how attribute (s/be up OR down)
	var how = btn.parentNode.getAttribute('scroll_how');
	
	// turn scrolling on
	scrollState = 'on';
	
	// scroll once so we aren't waiting for the delay
	var skip=1;
	scrollMenu(menu,how,skip);

	// give menu an id if it doesn't have one
	if (!menu.id) {
		var d = new Date();
		menu.id = d.getMilliseconds();
	}
	scrollInterval = setInterval("scrollMenu('"+menu.id+"','"+how+"',"+skip+")",50);
}

function scrollOff(){
	scrollState = 'off';
	clearInterval(scrollInterval);
}

function scrollMenu(menu,how,skip) {

	// set some vars
	var i, loopCount=0;

	// bail when scroll is shut off
	if (scrollState == 'off') return;

	// ref. to the menu to scroll
	if (typeof(menu)=='string') menu = document.getElementById(menu);
	

	var menuItems = new Array();
	var menuChildNodes = menu.childNodes;
	for(i=0;i<menuChildNodes.length;i++){
		if (menuChildNodes[i].nodeName == 'LI') menuItems[menuItems.length] = menuChildNodes[i];
	}

	// grab scroll buttons and remove them from menuItems
	var scrollUpBtn 	= menuItems.shift();
	var scrollDownBtn 	= menuItems.pop();

	// skip is used to speed things up
	if (!skip) skip = 1;
	

	// set number of items we can have and still have the correct menu height
	maxItems = menu.maxItems;
	if (maxItems > menuItems.length) return;
	
	// An IE bug causes the border from the parent menu to show thru on the submenu during scrolling only
	// To fix this, we need to hide the parentmenu before we change the display on the items being scrolled,
	// and then turn it right back on again...code below grabs reference to parentMenu, and the scroll sections below use it to perform this hack
	if (isIE) {
		var parentMenu;
		if (menu.parentNode.parentNode.nodeName == 'UL') {
			var parentMenu = menu.parentNode.parentNode;
		}
	}	
	
	if (how == 'down') {
		var bottomItem = menuItems[menuItems.length-1];
		while(loopCount++ < skip){
			if (bottomItem.display != 'none' && menuItems[menu.topMenuItem+maxItems]) {
				
				// IE hack to keep border of parent from bleeding thru
				if (parentMenu) parentMenu.style.visibility='hidden';
				
				menuItems[menu.topMenuItem+maxItems].style.display = 'block';
				menuItems[menu.topMenuItem].style.display = 'none';

				// IE hack to keep border of parent from bleeding thru
				if (parentMenu) parentMenu.style.visibility='visible';

				//topMenuItem = topMenuItem < menuItems.length ? topMenuItem + 1 : menuItems.length-1;
				menu.topMenuItem++
				
				// show the scroll up button
				scrollUpBtn.style.visibility='visible';
			} else {
				scrollOff();

				// hide the scroll button...not needed now
				scrollDownBtn.style.visibility='hidden';
				
				break;
			}
		}
	} else if (how == 'up') {
		while(loopCount++ < skip){
			//if (menuItems[0].style.display != 'block' && menuItems[menu.topMenuItem+maxItems]) {
			if (menuItems[0].style.display != 'block') {
				
				// IE hack to keep border of parent from bleeding thru
				if (parentMenu) parentMenu.style.visibility='hidden';

				menuItems[menu.topMenuItem+maxItems-1].style.display = 'none';
				menuItems[menu.topMenuItem-1].style.display = 'block';
				
				// IE hack to keep border of parent from bleeding thru
				if (parentMenu) parentMenu.style.visibility='visible';

				// IE has another problem that mysteriously cause the 2nd to last menu item to be invisible
				// This fixes that by upping it's z-index
				prb = menuItems[menu.topMenuItem+maxItems-2];
				if (prb) prb.style.zIndex++;
				
				menu.topMenuItem--;


				// show the scroll down button
				scrollDownBtn.style.visibility='visible';

			} else {
				scrollOff();
				
				// hide the scroll button...not needed now
				scrollUpBtn.style.visibility='hidden';

				break
			}
		}
	}
}

		
		
		
		
		
		
		
		
		
		

// Purpose of function is to hide all open popup div menus
function hideMenus() {
	// define some vars
	var divRef,shimRef,shims,x;

	// loop thru each menu that needs to be hidden, pulling it from the list at the same time
	while (divRef = hideMenuRefs.pop()) {
		// hide the div....
		divRef.style.display = 'none';
		if (isIE) {
			// see if there is an IE iframe shim...if so, hide that 2
			shimRef = divRef.nextSibling;
			if (shimRef.nodeName=='IFRAME') {
				shimRef.style.display = 'none';
			}
		}
	}
}







/********************************************************
	Function below needs to GO!
********************************************************/

// function shows the developer menu seen when right clicking on a field name in the control panel
function show_field_menu(x,y,field_def_rn,field_help_rn,table,field_name) {

	// grab iframe reference...will be used to assist div in covering over select inputs
	var IfrRef = document.getElementById('DivShim2');

	right_clicked_field = true;
	field_menu = document.getElementById("field_context_menu");
	content_div = document.getElementById("content");

	// grab the anchor tag that is in the context menu
	field_def_anchor = document.getElementById("field_def_link");
	field_help_anchor = document.getElementById("field_help_link");

	// change the href in the link in the context menu, that takes you to the field def record for this field
	if (field_def_rn != "") {
		field_def_anchor.href = "index.php?edit_records=1&table=Field_Definition&selected_record_number=" + field_def_rn;
		field_def_anchor.innerHTML = "Edit Field Definition";
	} else {
		field_def_anchor.href = "index.php?add_new_item=1&table=Field_Definition&Table_Name=" + table + "&Field_Name=" + field_name;
		field_def_anchor.innerHTML = "Create Field Definition";
	}
	// change the href in the link in the context menu, that takes you to the field def record for this field
	if (field_help_rn != "") {
		field_help_anchor.href = "index.php?edit_records=1&table=Field_Help&selected_record_number=" + field_help_rn;
		field_help_anchor.innerHTML = "Edit Field Help";
	} else {
		field_help_anchor.href = "index.php?add_new_item=1&table=Field_Help&Table_Name=" + table + "&Field_Name=" + field_name;
		field_help_anchor.innerHTML = "Create Field Help";
	}

	// make field_context_menu appear
	field_menu.style.display = "block";
	// make it move to mouse position
	field_menu.style.left = x + content_div.scrollLeft - 0;
	//field_menu.style.top = y + content_div.scrollTop - 30;
	field_menu.style.top = y - 30;

	field_menu.style.display = "block";

	// set position of iframe right behind the div, so it will cover up select inputs
	IfrRef.style.width = field_menu.offsetWidth;
	IfrRef.style.height = field_menu.offsetHeight;
	IfrRef.style.top = field_menu.style.top;
	IfrRef.style.left = field_menu.style.left;
	IfrRef.style.zIndex = field_menu.style.zIndex - 1;
	IfrRef.style.display = "block";

}

