/*
 * Confidential and Proprietary for Oracle Corporation
 *
 * This computer program contains valuable, confidential, and
 * proprietary information.  Disclosure, use, or reproduction
 * without the written authorization of Oracle is prohibited.
 * This unpublished work by Oracle is protected by the laws
 * of the United States and other countries.  If publication
 * of this computer program should occur, the following notice
 * shall apply:
 *
 * Copyright (c) 2003-2006 Stellent, Inc.
 * All rights reserved.
 * Copyright (c) 2008-2009 Oracle Corp.
 * All rights reserved.
 *
 * $Id: common.js 72266 2009-04-02 18:43:27Z dlew $
 */

///////////////////////////////////////////////////////
// Template: COMMON_JS
// Class: javascript:common
// Location: resources/layouts/common.js
///////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////
// WARNING: This file is generated by a Content Server template 
// and is then published to the weblayout directory. Any 
// changes made to the weblayout copy will be automatically 
// overwritten by the Content Server.
//////////////////////////////////////////////////////////////
//
// YOU SHOULD NEVER EVER MODIFY THIS FILE!
// =======================================
//
// If you wish to modify a layout, you should place all your code
//   in the function 'initCustomNodes' in the 'nav.js' file for
//   that specific layout.
//
// If you are writing a component, you should override the include
//   'custom_finish_layout_init' with the 'super' tag, and modify
//   the 'navBuilder' object there to modify the layout.
//
// If there is a method in this file that you wish to modify, then
//   you should write the new function in a seperate 'js' file.
//   Use a component to modify 'std_js_bootstrap_vars' and load
//   the 'js' file at the end of the include.
//
//////////////////////////////////////////////////////////////

/* Declare global variables for core XML document, root element, and associated
   node map object. */
var coreNav = null;

/* Create a navBuilder object for any page-specific menus */
var pageNav = null;

/* Create an object that links a tree node's information to a counter. */
var displayNodes = new Object();
var displayNodeCounter = 1;

var its = new sniffer();

/* Load the XML nav stuff from the commonNav.js */
function loadNavshell()
{
	if (coreNav == null)
	{
		coreNav = new navBuilder();
	}
	
	/* Verify that XML is loaded before firing the navigation routines. */
	if (coreNav.xmlRoot)
	{
		generateNavigation(coreNav);
	}
	else
	{
		setTimeout("loadNavshell()", 100);
	}
}

/////////////////////////////////////////////////////////////////
//  XML/HTML DOM Utility functions
/////////////////////////////////////////////////////////////////

/* return the frame window based on ID */
function frameWindow(id)
{
	var elt = document.getElementById(id);
	if (elt)  // IE 5.5, NN7 7+, Moz 1.1+
	{
		if (elt.contentWindow)
		{
			return elt.contentWindow;
		}
	}
	else // IE 5.0
	{
		return window.frames[id];
	}
}

/* This function is called by the page's onload function. */
function createXMLFromString (string)
{
	var xmlDoc = null;

	if (its.ie && its.win)
	{
		// The better XML parser for IE 6 and up is the ActiveXObject.
		// If this object can not load due to security settings, or
		// if the user is using IE 5 (which has a lot of bugs in its
		// XML parser, default to the JavaScript one.
		if (its.major >= 6)
		{
			try
			{
				xmlDoc = new ActiveXObject('Msxml2.DOMDocument');
				xmlDoc.async = true;
				xmlDoc.loadXML(string);
			}
			catch (e)
			{
			}
		}
		
		if (xmlDoc == null)
		{
			xmlDoc = new jsXMLDocument();
			xmlDoc.loadXML(string);
		}
	}

	else if (its.mozilla || (its.nn && its.major > 6))
	{
		var xmlParser = new DOMParser();
		xmlDoc = xmlParser.parseFromString(string, 'text/xml');
	}

	else // no native XML parser
	{
		xmlDoc = new jsXMLDocument();
		xmlDoc.loadXML(string);
	}

	return xmlDoc;
}

/* Note: the "parentPath" argument is not to be used when calling the funciton
   from another function it is only used when the function recursively calls
   itself. */
function walkXMLTree(parentElement, openingHtmlFunction, coreHtmlFunction, closingHtmlFunction, parentPath)
{
	/* Create a variable containing all children of the passed-in element. */
	var childList = parentElement.childNodes;

	/* Call the function that generates the opening html code for a collection
	   (the generated code will typically be an opening <div> tag that will act
	   as a container for the collection).*/
	openingHtmlFunction(parentElement, parentPath);

	/* Loop through the children of the passed-in element. For each child, run
	   the core html function, and if that child has children of its own,
	   recursively call the walkXMLTree function.  Note: since the
	   standards-based browsers don't ignore whitespace, the nodeType value of
	   each node must be checked. */
	for (var i=0; i<childList.length; i++)
	{
		var childNode = childList[i];

		if (parentPath)
		{
			var nodePath = parentPath + "." + i;
		}
		else
		{
			var nodePath = i.toString();
		}

		if (childNode.nodeType == 1)
		{
			coreHtmlFunction(childNode, nodePath);

			if (childNode.tagName == "collection")
			{
				walkXMLTree(childNode, openingHtmlFunction, coreHtmlFunction, closingHtmlFunction, nodePath);
			}
		}
	}

	/* Call the function that generates the closing html code for a collection (the
	   generated code will typically be a closing </div> tag for the collection
	   container).*/
	closingHtmlFunction(parentElement);
}

/* This function had to be used to find the next element-type node in a
   collection of children since the standards-based browsers interpret
   whitespace as additional text nodes in the hierarchy. */
function nextSiblingElement(element)
{
	var foundSiblingElement = false;
	var testNode = element.nextSibling;
	while (testNode != null)
	{
		if (testNode.nodeType == 1)
		{
			foundSiblingElement = true;
			break
		}
		testNode = testNode.nextSibling;
	}
	if (foundSiblingElement) { return testNode }
	else { return null }
}

/* This function had to be used to find the previous element-type node in a
   collection of children since the standards-based browsers interpret
   whitespace as additional text nodes in the hierarchy. */
function previousSiblingElement(element)
{
	var foundSiblingElement = false;
	var testNode = element.previousSibling;
	while (testNode != null)
	{
		if (testNode.nodeType == 1)
		{
			foundSiblingElement = true;
			break
		}
		testNode = testNode.previousSibling;
	}
	if (foundSiblingElement) { return testNode }
	else { return null }
}

/* make a iterable map of the XML nodes */
function mapXMLTree(element, nodeMapObject)
{
	if (nodeMapObject[element.getAttribute("id")])
	{
		var parentPath = nodeMapObject[element.getAttribute("id")].location;
	}
	else
	{
		var parentPath = null;
	}

	var childList = element.childNodes;

	for (var i=0; i<childList.length; i++)
	{
		var childNode = childList[i];

		if (childNode.nodeType == 1)
		{
			if (parentPath)
			{
				var nodePath = parentPath + "." + i;
			}
			else
			{
				/* Had to use toString() function here to prevent mixing number
				   and string types in array. */
				var nodePath = i.toString();
			}

			var nodeID = childNode.getAttribute("id");
			nodeMapObject[nodeID] = new nodePointer(nodePath);

			if (childNode.hasChildNodes())
			{
				mapXMLTree(childNode, nodeMapObject);
			}
		}
	}
}

/* object for the XML tree */
function nodePointer(nodePath)
{
	this.location = nodePath;
}

/* get a debug dump of the attributes in a node */
function DEBUG_displayNode(attStr, node)
{
	for (var i=0; i < node.attributes.length; i++)
		attStr = attStr + node.attributes[i].name + " = " + node.attributes[i].value + "\n";
	alert(attStr);
}

/* This is a debug function that dumps a node map listing into a new browser
   window. */
function DEBUG_displayNodeMap(nodeMapObject)
{
	var pointerStringArray = new Array();
	var i = 0;

	for (var nodePointer in nodeMapObject)
	{
		pointerStringArray[i] = nodeMapObject[nodePointer].location + " : " + nodePointer;
		i++;
	}
	pointerStringArray.sort();

	var testString = "<font size='2'>";
	testString += pointerStringArray.join("<br>");
	testString += "</font>"

	window.open("javascript:document.write(\"" + testString + "\");document.close();","testWindow");
}



/////////////////////////////////////////////////////////////////
//  Script for generating action popups.
/////////////////////////////////////////////////////////////////

var currentPopup;
var currentPopupRow;
var currentParentId;
var timeoutId;
var actionImage;
var actionImageOver;
var currentParentImage;

function initActionImages()
{
	currentParentImage = document.getElementById(currentParentId);
	
	if (typeof actionImage == "undefined")
	{
		actionImage = new Image();
		actionImageOver = new Image();
	}
	
	if (currentParentImage.src.indexOf("ActionsIcon") != -1 && actionImage.src != currentParentImage.src)
	{
		actionImage.src = httpSkinRoot + "ActionsIcon.gif";
		actionImageOver.src = httpSkinRoot + "ActionsIcon_over.gif";
	}
	
	if (currentParentImage.src.indexOf("targetedQS") != -1 && actionImage.src != currentParentImage.src)
	{
		actionImage.src = httpSkinRoot + "targetedQS.gif";
		actionImageOver.src = httpSkinRoot + "targetedQS_over.gif";
	}  
	
	// Use include 'custom_action_image_init_code' to insert custom image definition code
	// into this hook function.
	if (typeof customActionImageInit != "undefined")
	customActionImageInit();
}

/* 
 'id' is the id property of the popup menu's top-level container element
 'parentId' is the id of icon image element whose onclick event displays the popup
 'event' is the window's current event object (should always be set as event)
 'parameterString' is an optional comma-delimited string of display 
	parameters in the form: 'name1=value1,name2=value2';

 the following optional display parameters are available:

 'position' - allowable values: 'horizontal' (default), 'vertical', or 'overlay'
 'closeMode' - allowable values: 'auto' (default) or 'manual' 
*/
function showPopup(id, parentId, event, parameterString)
{
	// Define parameter object and default values for all optional parameters
	var parameters = new Object();
	parameters.position = "horizontal";
	parameters.closeMode = "auto";
   
	// Set parameter values based upon contents of optional parameterString argument
	if (parameterString)
	{
		var parameterArray = parameterString.split(",");     
		for (var i=0; i<parameterArray.length; i++)
			parameters[parameterArray[i].split("=")[0]] = parameterArray[i].split("=")[1];
	}
  
	closePopups();
  
	currentParentId = parentId;  
	initActionImages();
	var parentImage = document.getElementById(parentId);
	currentPopup = document.getElementById(id);
  
	displayMenu(parentImage, currentPopup, parameters.position)

	//*** change Actions image src if applicable
	if (parentImage.src)
		parentImage.src = actionImageOver.src;

	//*** register the mouseout handlers used to close the popup
	if (parameters.closeMode == "auto")
	{
		if (document.addEventListener)
		{ // DOM Level 2 Event Model
			currentPopup.addEventListener("mouseout", popupMouseOut, true);
			currentPopup.addEventListener("mouseover", popupMouseOver, true);
			parentImage.addEventListener("mouseout", parentMouseOut, true);
		}
		else if (document.attachEvent)
		{ // Older event model
			currentPopup.onmouseout = popupMouseOut;
			currentPopup.onmouseover = popupMouseOver;
			parentImage.onmouseout = parentMouseOut;
		}
	}
}

function popupMouseOut(e)
{
	var curNode;
	var newNode;

	if (typeof(window.event) != 'undefined')
	{
		curNode = this;
		newNode = window.event.toElement;
	}
	else
	{
		curNode = e.currentTarget;
		newNode = e.relatedTarget;
	}

	if (curNode != newNode && !containsNode(curNode, newNode))
		closePopups();
}


function parentMouseOut(e)
{
	var newNode;

	if (typeof(window.event) != 'undefined')
		newNode = window.event.toElement;
	else
		newNode = e.relatedTarget;

	if (newNode != currentPopup && !containsNode(currentPopup, newNode))
		timeoutId = setTimeout("closePopups()", 300);
}

function popupMouseOver(e)
{
	window.clearTimeout(timeoutId);
}

function containsNode(containerNode, testNode)
{
	if (testNode == null)
		return false;
	while (testNode.parentNode)
	{
		testNode = testNode.parentNode;
		if (testNode == containerNode)
			return true;
	}
	return false;
}

function closePopups()
{	
	if (currentPopup != null)
	{
		hideMenu(currentPopup);
	}
	if (currentParentId)
	{
		var parent = document.getElementById(currentParentId);
		parent.src = actionImage.src;
	}
}

// This event handler closes an open popup when the user clicks anywhere on the page
if (document.addEventListener) // DOM Event Model
	document.addEventListener("click", clearPopups, false);
else if (document.attachEvent) // IE 5+ Event Model
	document.attachEvent("onclick", clearPopups);
  
function clearPopups(e)
{
	if (currentPopup != null && currentPopup.style.display == "block")
	{
		if (!e) e = event;
		
		if (e.target != null)
			var targetElmt = e.target;
		else
			var targetElmt = e.srcElement;
		  
		var skipAction = false;
		
		if (targetElmt.onclick != null && targetElmt.onclick.toString().indexOf("showPopup") > -1)
			skipAction = true;
		  
		if (!skipAction)
			closePopups();
	}
}  

function glowPopupRow(obj, glowClass, fadeClass)
{
	fadePopupRow(currentPopupRow, fadeClass);
	currentPopupRow = obj;
	currentPopupRow.className = glowClass;

	var linkObj = obj.getElementsByTagName("A")[0];
	if (linkObj != null)
		linkObj.className = linkObj.className + "_over";
}

function fadePopupRow(obj, fadeClass)
{
	if (obj != null)
	{
		obj.className = fadeClass;

		var linkObj = obj.getElementsByTagName("A")[0];
		if (linkObj != null)
			linkObj.className = linkObj.className.replace(/_over/, "");
	}
}


/////////////////////////////////////////////////////////////////
//  Script for resizing table columns
/////////////////////////////////////////////////////////////////

function resizeColumns_horizontal(leftColId, rightColId, event)
{
	// Get right and left table cell objects to be resized.
	var leftCol = document.getElementById(leftColId);
	var rightCol = document.getElementById(rightColId);

	// Set the starting X-position of the mouse.
	var startPosX = event.clientX;

	// Register the event handlers that will respond to the mousemove events
	// and the mouseup event that follow this mousedown event.
	if (document.addEventListener)
	{ // DOM Level 2 Event Model
		document.addEventListener("mousemove", moveHandler, true);
		document.addEventListener("mouseup", upHandler, true);
	}
	else if (document.attachEvent)
	{ // IE 5+ Event Model
		document.attachEvent("onmousemove", moveHandler);
		document.attachEvent("onmouseup", upHandler);
	}
	else
	{
		/* 
		   IE 4 Event Model
		   In IE 4 we can't use attachEvent(), so assign the event handlers
		   directly after storing any previously assigned handlers so they
		   can be restored.  Note that this also relies on event bubbling.
		   var oldmovehandler = document.onmousemove;
		   var olduphandler = document.onmouseup;
		   document.onmousemove = moveHandler;
		   document.onmouseup = upHandler;
		 */
	}

	// We've handled this event.  Don't let anybody else see it.
	if (event.stopPropagation) event.stopPropagation();   // DOM Level 2
	else event.cancelBubble = true;                       // IE

	// Now prevent any default action.
	if (event.preventDefault) event.preventDefault();     // DOM Level 2
	else event.returnValue = false;                       // IE

	/**
	 * This is the handler that captures mousemove events when an element
	 * is being dragged.  It is responsible for moving the element.
	 **/
	function moveHandler(e)
	{
		if (!e) e = window.event;  // IE event model

		// Set starting widths of table cell objects to be resized.
		var startLeftColWidth, startRightColWidth;
		if ((its.mozilla || its.nn) && its.rv > 1.3)
		{	// Mozilla & Netscape:
			// getComputedStyle() does not always reflects the current style/width.
			// so check the style.width setting first. Calling getComputedStyle only
			// if style.width is not being set.
			startLeftColWidth = parseInt(leftCol.style.width);
			if (isNaN(startLeftColWidth))
			{
				startLeftColWidth = parseInt(document.defaultView.getComputedStyle(leftCol, "").getPropertyValue("width"));
			}
			startRightColWidth = parseInt(rightCol.style.width);
			if (isNaN(startRightColWidth))
			{
				startRightColWidth = parseInt(document.defaultView.getComputedStyle(rightCol, "").getPropertyValue("width"));
			}
		}
		else
		{ 	// IE, Safari
			startLeftColWidth = parseInt(leftCol.offsetWidth);
			startRightColWidth = parseInt(rightCol.offsetWidth);
		}

		/* Calculate the direction we're moving the columns based on the direction of the page. */
		var newLeftColWidth, newRightColWidth;
		if (lcDirection != null && lcDirection == 'rtl')
		{
			newLeftColWidth = startLeftColWidth + (startPosX - e.clientX)
			newRightColWidth = startRightColWidth - (startPosX - e.clientX)
		}
		else
		{
			newLeftColWidth = startLeftColWidth - (startPosX - e.clientX)
			newRightColWidth = startRightColWidth + (startPosX - e.clientX)
		}

		/* Use conditional test to prevent columns from being re-sized smaller
		   than a pre-defined minimum width (10px in this case). */
		if (newLeftColWidth > 10 && newRightColWidth > 10)
		{
			// Resize table cells based upon mouse poistion
			leftCol.style.width = newLeftColWidth + "px";
			rightCol.style.width = newRightColWidth + "px";
			
			// Reset starting mouse position.
			startPosX = e.clientX;
		}

		// And don't let anyone else see this event.
		if (e.stopPropagation) e.stopPropagation();       // DOM Level 2
		else e.cancelBubble = true;                       // IE
	}

	/**
	 * This is the handler that captures the final mouseup event that
	 * occurs at the end of a drag.
	 **/
	function upHandler(e)
	{
		if (!e) e = window.event;  // IE event model

		// Unregister the capturing event handlers.
		if (document.removeEventListener)
		{	// DOM Event Model
			document.removeEventListener("mouseup", upHandler, true);
			document.removeEventListener("mousemove", moveHandler, true);
		}
		else if (document.detachEvent)
		{	// IE 5+ Event Model
			document.detachEvent("onmouseup", upHandler);
			document.detachEvent("onmousemove", moveHandler);

			// deselect any accidentally selected text
			var r = document.selection.createRange();
			r.collapse();
			r.select();
		}
		else
		{	// IE 4 Event Model
			//document.onmouseup = olduphandler;
			//document.onmousemove = oldmovehandler;
		}

		// And don't let the event propagate any further.
		if (e.stopPropagation) e.stopPropagation();       // DOM Level 2
		else e.cancelBubble = true;                       // IE
	}
}


/////////////////////////////////////////////////////////////////
//  Script for showing full titles for DAM search results
/////////////////////////////////////////////////////////////////

function dam_showFullTitle(parentCell, titlePopupId)
{
	var titleSpanOb = parentCell.getElementsByTagName("SPAN")[0];

	if (titleSpanOb.firstChild.nodeValue.indexOf("...") != -1)
	{
		parentCell.style.cursor = "default";
		var titlePopup = document.getElementById(titlePopupId);
		displayMenu(titleSpanOb, titlePopup, "overlay");
	}
}


function dam_hideFullTitle(parentCell, titlePopupId, e)
{
	if (!e) e = window.event;
	var titleSpanOb = parentCell.getElementsByTagName("SPAN")[0];

	if (titleSpanOb.firstChild.nodeValue.indexOf("...") != -1)
	{
		var titlePopup = document.getElementById(titlePopupId);
		hideMenu(titlePopup, e);
	}
}


/////////////////////////////////////////////////////////////////
//  Menu Bar DHTML
/////////////////////////////////////////////////////////////////

g_registeredMenus = new Array();

function registerMenu(menuId)
{
	var foundMenu = false;
	for (var i = 0; i < g_registeredMenus.length; i++)
	{
		if (menuId == g_registeredMenus[i])
		{
			foundMenu = true;
			break;
		}
	}

	if (!foundMenu)
	{
		g_registeredMenus[g_registeredMenus.length] = menuId;
	}
}

function unregisterMenu(menuId)
{
	var index = -1;
	for (var i = 0; i < g_registeredMenus.length; i++)
	{
		if (menuId == g_registeredMenus[i])
		{
			index = i;
			break;
		}
	}
	
	if (index != -1)
	{
		g_registeredMenus.splice(i, 1);
	}
}

function topCollectionItem_mouseover(e, element)
{
	if (element.getElementsByTagName("div").length > 0)
	{
		var childMenu = element.getElementsByTagName("div")[0];
		if (childMenu.style.display == "none")
		{
			resetMenus();
		}
	}
	highlightItem(element);
}


function topCollectionItem_mouseout(e, element)
{
	if (element.getElementsByTagName("div").length > 0)
	{
		var childMenu = element.getElementsByTagName("div")[0];
		if (childMenu.style.display == "none")
		{
			unhighlightItem(element);
		}
	}
}


function topCollectionItem_onclick(e, element, childMenuId, placement)
{
	var childMenu = document.getElementById(childMenuId);
	if (element != null && childMenu != null)
	{
		// DISPLAY MENU
		if (childMenu.style.display == "none")
		{
			resetMenus();	// Hide any open menus
			displayMenu(element, childMenu, placement);
		}

		// HIDE MENU
		else if (childMenu.style.display == "block")
		{
			hideMenu(childMenu);
			highlightItem(element);
			/* Note: had to re-highlight the parent element since the mouse is
			   logically still over this element, and the resetMenus() function
			   loop sets parent elements of ALL child menus (including the
			   target) back to regular style */
		}
	}

	if (its.ie) e.cancelBubble = true;
	else e.stopPropagation();
}


function childCollectionItem_mouseover(e, element, placement)
{
	if (!e) e = window.event;

	highlightItem(element);

	if (element.getElementsByTagName("div").length > 0)
	{
		var childMenu = element.getElementsByTagName("div")[0];

		if (childMenu.style.display == "none")
		{
			displayMenu(element, childMenu, placement);
		}
	}

	if (its.ie) e.cancelBubble = true;
	else e.stopPropagation();	
}


function childCollectionItem_mouseout(e, element)
{
	if (!e) e = window.event;
	
	var newTarget = (typeof e.relatedTarget != "undefined") ? e.relatedTarget : e.toElement;

	if (!containsNode(element, newTarget))
	{
		unhighlightItem(element);

		if (element.getElementsByTagName("div").length > 0)
		{
			var childMenu = element.getElementsByTagName("div")[0];
			
			closeOpenSiblingsOf(childMenu);
			hideMenu(childMenu, e);
			
			/* re-hides any elements that conflict with a parent that's still
			   displayed*/
			resetParentConflicts(childMenu);
		}
	}
}


function childCollectionItem_onclick(e, element, childMenuId, placement)
{
	if (its.ie)
	{
		e.cancelBubble = true;
	}
	else
	{
		e.stopPropagation();
	}
}


function linkItem_mouseover(element)
{
	if (element.className.indexOf("TopLinkItem") != -1)
		resetMenus();

	element.className = element.className + "_over";
	var linkObject = element.getElementsByTagName("A")[0];
	if (linkObject != null)
		linkObject.className = linkObject.className + "_over";
}


function linkItem_mouseout(element)
{
	element.className = element.className.replace(/_over/, "");
	var linkObject = element.getElementsByTagName("A")[0];
	if (linkObject != null)
	{
		linkObject.className = linkObject.className.replace(/_over/, "");
	}
}


function linkItem_onclick(e, element, url, target)
{
	// find the nested 'A' tag, if any
	var children = element.childNodes;
	var subLink = null;
	for (var i=0; i<children.length; i++)
	{
		if (children[i].tagName == "A")
		{
			subLink = children[i];
			url = subLink.href;
			target = subLink.target;
			break;
		}
	}

	// prevent bubble-up
	if (its.ie)
		e.cancelBubble = true;
	else
	{
		// sidestep a bug in mozilla
		if (element.className.indexOf("_over") != -1)
			element.className = element.className.replace(/_over/, "");
		if (subLink != null && subLink.className.indexOf("_over") != -1)
			subLink.className = subLink.className.replace(/_over/, "");
		e.stopPropagation();
	}

	// do nothing if the mouse is over a child 'A' tag
	if (subLink == null || !(itemOnClickEventDoesNothing || theseElementsOverlap(e, subLink)))
	{
		if (target==null || target=="")
			window.location.href = url;
		else
			window.open(url, target);
	}

	resetMenus();
}


function highlightItem(element)
{
	var itemId = element.id;
	var itemTable = document.getElementById(itemId + "_itemTable");
	var labelCell = document.getElementById(itemId + "_labelCell");
	var arrowImg = document.getElementById(itemId + "_arrowImg");

	if (itemTable != null && itemTable.className.indexOf("_over") == -1)
		itemTable.className = itemTable.className + "_over";
	if (labelCell != null && labelCell.className.indexOf("_over") == -1)
		labelCell.className = labelCell.className + "_over";
	if (arrowImg != null && arrowImg.src.indexOf("_over") == -1)
		arrowImg.src = arrowImg.src.replace(/.gif/, "_over.gif");
}


function unhighlightItem(element)
{
	var itemId = element.id;
	var itemTable = document.getElementById(itemId + "_itemTable");
	var labelCell = document.getElementById(itemId + "_labelCell");
	var arrowImg = document.getElementById(itemId + "_arrowImg");

	itemTable.className = itemTable.className.replace(/_over/, "");
	labelCell.className = labelCell.className.replace(/_over/, "");
	arrowImg.src = arrowImg.src.replace(/_over/, "");
}


/* Closes an element's associated child menu as well as all decendents of that
   menu. */
function closeChildMenusOf(element)
{
	var decendentDivs = element.getElementsByTagName("div");

	for (var i=decendentDivs.length-1; i>=0; i--)
	{
		if (decendentDivs[i].id.indexOf("_menu") != -1)
		{
			var childMenu = decendentDivs[i];

			unhighlightItem(childMenu.parentNode);

			hideMenu(childMenu);
			/* re-hides any elements that conflict with a parent that's still
			   displayed*/
			resetParentConflicts(childMenu); 
		}
	}
}


function closeOpenSiblingsOf(element)
{
	var idArray = element.id.split(".");
	if (idArray.length > 1)
	{
		idArray.length = idArray.length - 1;
		var parentId = idArray.join(".");
	}
	else
		parentId = "";

	var i = 0;
	var siblingElement = document.getElementById(parentId + "." + i);
	while (siblingElement != null)
	{
		var siblingMenu = document.getElementById(siblingElement.id + "_menu");
		if (siblingMenu != null)
		{
			if (siblingMenu.style.display == "block" && siblingElement != element)
				closeChildMenusOf(siblingElement);
		}
		i++;
		siblingElement = document.getElementById(parentId + "." + i);
	}
}


function resetMenus(e)
{
	var menuCharCode = 65; // initialize to capital "A"
	var menuId = "menu" + String.fromCharCode(menuCharCode);
	var firstCellId = menuId + "_0";
	var firstCellObject = document.getElementById(firstCellId);
	while (firstCellObject != null)
	{
		resetSpecificMenu(e, menuId);
		
		menuCharCode++;
		menuId = "menu" + String.fromCharCode(menuCharCode);
		firstCellId = menuId + "_0";
		firstCellObject = document.getElementById(firstCellId);
	}
	
	for (var i = 0; i < g_registeredMenus.length; i++)
	{
		menuId = g_registeredMenus[i];
		resetSpecificMenu(e, menuId);
	}
}

function resetSpecificMenu(e, menuId)
{
	var menuItemCount = 0;
	var menuCellId = menuId + "_" + menuItemCount;
	var menuCell = document.getElementById(menuCellId);

	while (menuCell != null)
	{
		var menuContainer = document.getElementById(menuCell.id + "_menu");
		if (menuContainer != null)
		{
			if (menuContainer.style.display == "block")
			{
				closeChildMenusOf(menuCell);
			}
		}

		menuItemCount++;
		
		menuCellId = menuId + "_" + menuItemCount;
		menuCell = document.getElementById(menuCellId);
	}
}


/* This function is called after a menu is hidden. When a menu gets hidden
   using the 'hideMenu' function, elements that conflict with that menu are
   re-displayed. This function loops through the parents of the hidden menu, and
   re-hides any elements that still conflict with visible ancestor menus.
 */
function resetParentConflicts(childMenu)
{
	var idArray = childMenu.id.split(".");
	idArray.length = idArray.length - 1;
	parentId = idArray.join(".") + "_menu";
	parentMenu = document.getElementById(parentId);

	while (parentMenu != null)
	{
		setConflictingElements("hidden", parentMenu);

		idArray = parentId.split(".");
		idArray.length = idArray.length - 1;
		parentId = idArray.join(".") + "_menu";
		parentMenu = document.getElementById(parentId);
	}
}

/* This function takes a parent element and a hidden (display="none"),
   absolutely-positioned DTHML menu container as parameters; it displays the
   menu container adjacent to the parent element, adjusts position to ensure the
   menu remains on-screen, and hides any elements (such as applets or select
   lists) that may create layering conflicts with the menu.  An optional third
   parameter 'placement' can be used to specify if the menu pops up beside the
   parent or under the parent by default; the legal values are ('vertical',
   'horizontal', or 'overlay'); if this parameter is left blank, the menu will
   appear beside the parent by default. */
function displayMenu(parentElement, childMenu, placement)
{
	// Get the browser's window dimensions and current scroll positions
	var windowWidth = document.body.clientWidth;
	var windowHeight = document.body.clientHeight;
	if (document.body.scrollLeft != null)
	{
		var scrollValue_x = document.body.scrollLeft;
		var scrollValue_y = document.body.scrollTop;
	}
	else if (window.pageXOffset != null)
	{
		var scrollValue_x = window.pageXOffset;
		var scrollValue_y = window.pageYOffset;
	}
	else
	{
		var scrollValue_x = 0;
		var scrollValue_y = 0;
	}

	//*** Get the dimensions and positioning values of the parent element
	 var parentData = new dimensionFinder(parentElement);

	childMenu.style.visibility = "hidden";

	//*** Initialize the menu position before rendering
	childMenu.style.top = "0px";
	childMenu.style.left = "0px";

	//*** Render the menu
	childMenu.style.display = "block";

	//*** Get the rendered dimensions of the menu
	var menuWidth = childMenu.offsetWidth;
	var menuHeight = childMenu.offsetHeight;
	var menuTable = childMenu.getElementsByTagName("TABLE")[0];
	if (menuTable != null)
	{
		menuWidth = menuTable.offsetWidth;
		menuHeight = menuTable.offsetHeight;
	}

	// FOR MENUS THAT DISPLAY BELOW OR ABOVE THE PARENT
	if (placement == "vertical" || placement == "overlay" || placement == "north" || placement == "south")
	{
		//*** Move the menu to its final vertical postion
		if (placement != "overlay")
		{
			if (placement != 'north' && (parentData.actualTop + parentData.height + menuHeight <= windowHeight + scrollValue_y))
			{
				// place below parent
				childMenu.style.top = (parentData.relativeTop + parentData.height) + "px";
			}
			else
			{
				if (menuHeight < parentData.actualTop)
				{
					// place above parent
					childMenu.style.top = (parentData.relativeTop - menuHeight) + "px"; 
				}
				else
				{
					// place at top edge of window
					childMenu.style.top = (parentData.relativeTop - parentData.actualTop) + "px"; 
				}
			}
		}
		else // "overlay"
		{
			childMenu.style.top = parentData.relativeTop + "px";
		}

		//*** Move the menu to its final horizontal postion
		if (lcDirection == 'rtl')
		{
			// Thise code adapts the display for ltr or rtl.
			//if (parentData.actualLeft - menuWidth + parentData.width <= windowWidth + scrollValue_x
			if (parentData.actualLeft - menuWidth + parentData.width > scrollValue_x)
			{
				// align with left edge of parent
				childMenu.style.left = (parentData.relativeLeft - menuWidth + parentData.width - 3) + "px";
			}
			else
			{
				if (menuWidth <= windowWidth)
				{
					// align with left edge of window
					childMenu.style.left = (parentData.relativeLeft - parentData.actualLeft + scrollValue_x) + "px";
				}
				else
				{
					// align with right edge of window
					childMenu.style.left = (parentData.relativeLeft - parentData.actualLeft + windowWidth + scrollValue_x - menuWidth - 3) + "px";
				}
			}
		}
		else
		{
			
			if (parentData.actualLeft + menuWidth <= windowWidth + scrollValue_x)
			{
				// align with left edge of parent
				childMenu.style.left = parentData.relativeLeft + "px"; 
			}
			else
			{
				if (menuWidth <= windowWidth)
				{
					// align with right edge of window
					childMenu.style.left = (parentData.relativeLeft - parentData.actualLeft + windowWidth + scrollValue_x - menuWidth - 3) + "px";
				}
				else
				{
					// align with left edge of window
					childMenu.style.left = (parentData.relativeLeft - parentData.actualLeft) + "px"; 
				}
			}
		}
	}

	// FOR MENUS THAT DISPLAY BESIDE THE PARENT
	else if (placement == "horizontal" || placement == "east" || placement == "west" || placement == null)
	{
		// Thise code adapts the display for ltr or rtl. 
		if (lcDirection == 'rtl' && (placement == "horizontal" || placement == "east" || placement == null))
		{
			placement = 'west'
			edgeOfWindow = parentData.relativeLeft + parentData.width;
		}
		else
		{
			edgeOfWindow = parentData.relativeLeft - parentData.actualLeft;
		}
	
		//*** Move the menu to its final horizontal postion
		if (placement != "west" && (parentData.actualLeft + parentData.width + menuWidth <= windowWidth + scrollValue_x))
		{
			// place to right of parent
			childMenu.style.left = (parentData.relativeLeft + parentData.width) + "px";
		}
		else
		{
			if (menuWidth < parentData.actualLeft)
			{
				// place to left of parent
				childMenu.style.left = (parentData.relativeLeft - menuWidth) + "px";
			}
			else
			{
				// align with left edge of window
				childMenu.style.left = edgeOfWindow + "px";
			}
		}

		//*** Move the menu to its final vertical postion
		if (parentData.actualTop + menuHeight <= windowHeight + scrollValue_y)
		{
			// align with top edge of parent
			childMenu.style.top = parentData.relativeTop + "px"; 
		}
		else
		{
			if (menuHeight <= windowHeight)
			{
				// align with bottom edge of window
				childMenu.style.top = (parentData.relativeTop - parentData.actualTop + windowHeight + scrollValue_y - menuHeight - 3) + "px";
			}
			else
			{
				// align with top edge of window
				childMenu.style.top = (parentData.relativeTop - parentData.actualTop + scrollValue_y) + "px";
			}
		}
	}

	//*** Hide conflicting elements that overlap the menu
	setConflictingElements("hidden", childMenu);
	
	childMenu.style.visibility = "visible";
}


/* This function is the logical opposite of the 'displayMenu' function above.
   It takes a currently-displayed popup menu container object as a parameter; it
   hides the menu object and re-displays any conflicting elements that were
   previously hidden when the menu was displayed. */
function hideMenu(childMenu, event)
{
	if (event != null)
	{
		// dont hide a menu if the mouse is over it - IE bug
		if(theseElementsOverlap(childMenu, event))
		{
			return;
		}
	}
	if (childMenu != null)
	{
		setConflictingElements("visible", childMenu);
		childMenu.style.display = "none";
	}
}


/////////////////////////////////////////////////////////////////
//  The XML Navigation Builder Object
/////////////////////////////////////////////////////////////////

var didPrototype = false;

/* declare constructor function used to build XML navigation trees */
function navBuilder(string)
{
	if (string==null)
	{
		string = '<?xml version="1.0" encoding="iso-8859-1"?><navtree id="NAVTREE"></navtree>';
	}

	if (!didPrototype)
	{
		doPrototype();
	}

	// members
	this.menuId = "";
	this.xmlDocument = createXMLFromString(string);
	this.xmlRoot = this.xmlDocument.documentElement;
	this.xmlNodeMap = new Object();
	this.topLevelNodes = new Array();
	this.htmlString = "";
	
	// all functions have the signature (node, nodeLocation)
	this.makeOpeningHtml = new Function();
	this.makeCoreHtml = new Function();
	this.makeClosingHtml = new Function();
	
	// sub navBuilder objects
	this.menuA = null;
	this.menuB = null;
	this.trayA = null;
	
	// a menu which appears by the title to the current page
	this.pageHeadingMenus = null;
	
	// additional page menus, if they exist
	this.additionalMenus = null;
}

function doPrototype()
{
	didPrototype = true;

	/* call the constructor function to force creation of a prototype
	   navBuilder object */
	new navBuilder();

	/* add common methods to prototype object to be inherited by all navBuilder
	   instances */
	navBuilder.prototype.addTopLevelNode = _navBuilder_addTopLevelNode;
	navBuilder.prototype.deleteTopLevelNode = _navBuilder_deleteTopLevelNode;
	navBuilder.prototype.addPrevSiblingNodeTo = _navBuilder_addPrevSiblingNodeTo;
	navBuilder.prototype.addChildNodeTo = _navBuilder_addChildNodeTo;
	navBuilder.prototype.moveItemInto = _navBuilder_moveItemInto;
	navBuilder.prototype.moveItemAbove = _navBuilder_moveItemAbove;
	navBuilder.prototype.setAttributeValue = _navBuilder_setAttributeValue;
	navBuilder.prototype.deleteItem = _navBuilder_deleteItem;
	navBuilder.prototype.deleteChildrenOf = _navBuilder_deleteChildrenOf;
	navBuilder.prototype.getNodeById = _navBuilder_getNodeById;
	navBuilder.prototype.buildHtmlStringFromXml = _navBuilder_buildHtmlStringFromXml;
}


/* Adds a node ID to a list of top-level nodes to display on a menu or tree */
function _navBuilder_addTopLevelNode(xmlNodeId, beforeNodeId)
{
	if (beforeNodeId != null)
	{
		var oldLength = this.topLevelNodes.length;
		var foundIndex = oldLength + 1;
		var i = 0;
		var id = this.topLevelNodes[i++];

		while (i < oldLength && id != beforeNodeId)
			id = this.topLevelNodes[i++];

		if (id == beforeNodeId)
		{
			foundIndex = i-1;
			i = oldLength + 1;
			while (i > foundIndex)
				this.topLevelNodes[i] = this.topLevelNodes[--i]
		}
		
		this.topLevelNodes[foundIndex] = xmlNodeId;
	}
	else
	{
		this.topLevelNodes[this.topLevelNodes.length] = xmlNodeId;
	}
}

/* Removes a node from the array of top-level nodes */
function _navBuilder_deleteTopLevelNode(xmlNodeId)
{
	var newNodes = new Array();
	var length = this.topLevelNodes.length;
	for (var index=0; index<length; index++)
	{
		if(this.topLevelNodes[index] != xmlNodeId)
			newNodes[newNodes.length] = this.topLevelNodes[index];
	}
	
	this.topLevelNodes = newNodes;
}

/*  This function adds a menu item before the existing item referenced by
	siblingId. newNodeName is the tag name of the new element to be created (in
	the current implementation, the only two legal values are "collection" or
	"item").  Subsequent attributes represent the name/value pairs of attributes
	to be added tot the new element (formatted as: "label==Some Name"). At a
	minimum, the attributes "id", "label", and "url" must be included (others
	may be added to address specific needs of a given layout).*/
function _navBuilder_addPrevSiblingNodeTo(siblingId, newNodeName)
{
	var argValues = _navBuilder_addPrevSiblingNodeTo.arguments;
	var argCount = _navBuilder_addPrevSiblingNodeTo.arguments.length;

	var newElement = this.xmlDocument.createElement(newNodeName);

	if (argCount > 2)
	{
		for (i=2; i<argCount; i++)
		{
			var attrName = argValues[i].split("==")[0];
			var attrValue = argValues[i].split("==")[1];
			newElement.setAttribute(attrName, attrValue);
		}
	}

	var siblingElement = this.getNodeById(siblingId);
	if (siblingElement)
	{
		var parentElement = siblingElement.parentNode;
		parentElement.insertBefore(newElement, siblingElement);

		mapXMLTree(parentElement, this.xmlNodeMap);
	}
}

/*  This function adds a menu item as a child of the existing collection item
	referenced by collectionId. newNodeName is the tag name of the new element
	to be created (in the current implementation, the only two legal values are
	"collection" or "item"). Subsequent attributes represent the name/value
	pairs of attributes to be added tot the new element (formatted as:
	"label==Some Name"). At a minimum, the attributes "id", "label", and "url"
	must be included (others may be added to address specific needs of a given
	layout). See the Explorer component for examples of how this function is
	called.  */
function _navBuilder_addChildNodeTo(collectionId, newNodeName)
{
	var argValues = _navBuilder_addChildNodeTo.arguments;
	var argCount = _navBuilder_addChildNodeTo.arguments.length;
	var newElement = this.xmlDocument.createElement(newNodeName);

	// loop through the unspecified arguments that generate the node's attributes.
	if (argCount > 2)
	{
		for (i=2; i<argCount; i++)
		{
			var attrName = argValues[i].split("==")[0];
			var attrValue = argValues[i].split("==")[1];
			newElement.setAttribute(attrName, attrValue);
		}
	}

	// get a pointer to the parent element and establish a node path value for
	// the new node in the xmlNodeMap.
	var parentElement;
	if (collectionId == "NAVTREE")
		parentElement = this.xmlRoot;
	else
		parentElement = this.getNodeById(collectionId);

	if (parentElement)
	{
		// append the new element onto the parent's child list.
		parentElement.appendChild(newElement);

		// Add a nodePointer object to the xmlNodeMap for the new node (since
		// the new element was added to the end of a collection, there's no
		// need to recursively remap all the parent's decendents).
		var nodeId = newElement.getAttribute("id");
		var nodeIndex = (parentElement.childNodes.length-1).toString();
		if (collectionId == "NAVTREE")
			var nodePath = nodeIndex;
		else
			var nodePath = this.xmlNodeMap[collectionId].location + "." + nodeIndex;
		this.xmlNodeMap[nodeId] = new nodePointer(nodePath);
	}
}

/*	This function moves an item to a different parent collection. If the item
	being moved is itself a collection, all of its children are moved with it.
	The first argument (newParentCollectionId) is the ID value of the collection
	that the item is being moved into.  The second argument (nodeID) is the ID
	value of the item being moved. The third argument (clone) is a boolean value
	that determines if the item being moved is removed from its original location
	(false), or copied and moved (true).  */
function _navBuilder_moveItemInto(newParentCollectionId, nodeId, clone)
{
	var newParentElement = this.getNodeById(newParentCollectionId);
	var node = this.getNodeById(nodeId);

	if (newParentElement && node)
	{

		if (clone == true)
		{
			// Creates a duplicate node to move and leaves the existing one.
			var newClone = createClone(node, this);
			newParentElement.appendChild(newClone);
		}
		else
		{
			// Grab a pointer to the original parent node before the node is removed.
			var oldParentElement = node.parentNode;
			// Remove the node from its previous location and move it to the new
			// location.
			newParentElement.appendChild(node);
			// Remap the previous parent node's decendents if previous parent is
			// different from new parent.
			if (oldParentElement != newParentElement)
			{
				mapXMLTree(oldParentElement, this.xmlNodeMap);
			}
		}
		// Remap the new parent node's decentdents.
		mapXMLTree(newParentElement, this.xmlNodeMap);
	}
}

/*  This function moves an item to a different parent collection. If the item
	being moved is itself a collection, all of its children are moved with it.
	The first argument (newParentCollectionId) is the ID value of the
	collection that the item is being moved into.  The second argument (nodeID)
	is the ID value of the item being moved. The third argument (clone) is a
	boolean value that determines if the item being moved is removed from its
	original location (false), or copied and moved (true).  */
function _navBuilder_moveItemAbove(siblingId, nodeId, clone)
{
	var siblingElement = this.getNodeById(siblingId);
	var node = this.getNodeById(nodeId);

	if (siblingElement && node)
	{
		var parentElement = siblingElement.parentNode;

		if (clone == true)
		{
			// Creates a duplicate node to move and leaves the existing one.
			var newClone = createClone(node, this);
			parentElement.insertBefore(newClone, siblingElement);
		}
		else
		{
			// must clone the node, then delete the old one, due to bugs in IE 5.5
			var oldParentElement = node.parentNode;
			var newClone = node.cloneNode(true);
			this.deleteItem(node.getAttribute("id"));
			parentElement.insertBefore(newClone, siblingElement);

			// remap the old parent elements, if the parent has changed
			if (oldParentElement != parentElement)
				mapXMLTree(oldParentElement, this.xmlNodeMap);
		}

		// Remap the new parent node's decentdents.
		mapXMLTree(parentElement, this.xmlNodeMap);
	}
}

/*  This function sets the value of a menu item's attribute. The first argument
	(nodeId) is the ID value of the menu item whose attribute you want to
	change. The second argument (attrName) a the name of the attribute you want
	to set (if no attribute by this name currently exists, a new attribute will
	be created).  The third argument is the value to which the attibute will be
	set. This function will most frequenly be used to change the display label
	(label attribute) for a menu item.  */
function _navBuilder_setAttributeValue(nodeId, attrName, attrValue)
{
	var node = this.getNodeById(nodeId);

	if (node)
	{
		node.setAttribute(attrName, attrValue);
	}
}

/*	Pass in the ID value of an XML node in the core XML tree, and it removes
	that node from the tree.  */
function _navBuilder_deleteItem(nodeId)
{
	var node = this.getNodeById(nodeId);

	if (node)
	{
		// find the node's parent element
		var parentElement = node.parentNode;
		// delete the node from the collection
		parentElement.removeChild(node);

		// delete the node's pointer from the node map, and remap the
		// parent's decendents
		delete this.xmlNodeMap[nodeId];
		
		// Note, future work needs to be done here because if deleting all
		// children for a parent or we know that we are deleting at the end of
		// a list, then this call is unnecessary.
		mapXMLTree(parentElement, this.xmlNodeMap);
	}
}

/*	Pass in the ID value of an XML node in the core XML tree, and it removes
	that children of this node from the tree. The node itself still remains.  */
function _navBuilder_deleteChildrenOf(nodeId)
{
	var node = this.getNodeById(nodeId);
	doDeleteChildrenOf(this, node);
}

/* Recursive deletion of child nodes, and their values from the node map */
function doDeleteChildrenOf(builder, node)
{
	if (builder == null || node == null)
		return;
	
	var childList = node.childNodes;
	for (var i = childList.length-1; i>=0; i--)
	{
		var subNodeId = childList[i].getAttribute("id");
		delete builder.xmlNodeMap[subNodeId];
		
		var subChildList = childList[i].childNodes;
		if (subChildList != null && subChildList.length > 0)
			doDeleteChildrenOf(builder, childList[i]);
		
		node.removeChild(childList[i]);
	}
}

/* get an XML node by its ID */
function _navBuilder_getNodeById(id)
{
	if (this.xmlNodeMap[id])
	{
		/* Split the array element associated with the ID value into an array
		   of separate index numbers. */
		var nodeIndexArray = this.xmlNodeMap[id].location.split(".");

		/* Start with the root element within xml document */
		var node = this.xmlRoot;

		/* Loop through the index array, using the index numbers to navigate
		   down to the requested node in the master XML document. */
		for (var i=0; i<nodeIndexArray.length; i++)
		{
			if (node != null)
				node = node.childNodes[nodeIndexArray[i]];
		}

		return node;
	}
	else if(id == "NAVTREE")
	{
		return this.xmlRoot;
	}
	else
	{
		return null;
	}
}

/*	Note: the "parentLocation" argument should be left blank when parentElement
	is the root of its XML document.  */
function _navBuilder_buildHtmlStringFromXml(node, nodeLocation)
{
	/* Create a variable containing all children of the parent element. */
	var childList = node.childNodes;

	/* Call the function that generates the opening html code for a collection
	   (the generated code will typically be an opening <div> tag that will act
	   as a container for the collection).  */
	this.makeOpeningHtml(node, nodeLocation);

	/* Loop through the children of the passed-in element. For each child, run
	   the core html function, and if that child has children of its own,
	   recursively call the buildHtmlStringFromXml method.  Note: since the
	   standards-based browsers don't ignore whitespace, the nodeType value of
	   each node must be checked.  */
	for (var i=0; i<childList.length; i++)
	{
		var childNode = childList[i];

		var childNodeLocation = i.toString();
		if (nodeLocation)
			childNodeLocation = nodeLocation + "." + i;
		if (childNode.nodeType == 1)
		{
			this.makeCoreHtml(childNode, childNodeLocation);

			if (isCollectionNode(childNode))
			{
				this.buildHtmlStringFromXml(childNode, childNodeLocation);
			}
		}
	}

	/* Call the function that generates the closing html code for a collection
	   (the generated code will typically be a closing </div> tag for the
	   collection container).*/
	this.makeClosingHtml(node, nodeLocation);
}

function isCollectionNode(node)
{
	return (node.tagName == "collection");
}

/*	This function creates a clone of a node, and ensures that it and its
	decendents all have unique ID values.  */
function createClone(node, parentTree)
{
	var newClone = node.cloneNode(true);
	setCloneId(newClone);
	setCloneDecendentIds(newClone);
	return newClone;

	function setCloneId(clone)
	{
		var baseNodeId = clone.getAttribute("id").replace(/_clone[0-9]*/, "");
		var cloneCount = 1;
		var cloneId = baseNodeId + "_clone" + cloneCount;
		var previousClone = parentTree.getNodeById(cloneId);

		while (previousClone != null)
		{
			cloneCount++;
			cloneId = baseNodeId + "_clone" + cloneCount;
			previousClone = parentTree.getNodeById(cloneId);
		}

		clone.setAttribute("id", cloneId);
	}

	function setCloneDecendentIds(parentClone)
	{
		for (var i = 0; i < parentClone.childNodes.length; i++)
		{
			var childClone = parentClone.childNodes[i];
			setCloneId(childClone);
			if (childClone.hasChildNodes()) { setCloneDecendentIds(childClone); }
		}
	}

}


//////////////////////////////////////////////////////////////////////
//  sample HTML-drawing methods for a tree-control view of XML nodes
//////////////////////////////////////////////////////////////////////

/* images and sizes of the nav tree icons. Note - all 'closed' images below must
   have an associated 'open' image for when the icon is clicked */
var tree_control_config;

function initTreeControlConfig()
{
	if (typeof tree_control_config != "undefined")
		return;
	
	tree_control_config = new Array();
	tree_control_config["src_I"] = httpSkinRoot + "tree_I.gif";
	tree_control_config["src_Icon_ColClosed"] = httpSkinRoot + "tree_icon_collection_closed.gif";
	tree_control_config["src_Icon_Item"] = httpSkinRoot + "tree_icon_item.gif";
	tree_control_config["src_L_ColClosed"] = httpSkinRoot + "tree_L_collection_closed.gif";
	tree_control_config["src_T_ColClosed"] = httpSkinRoot + "tree_T_collection_closed.gif";
	tree_control_config["src_L_Item"] = httpSkinRoot + "tree_L_item.gif";
	tree_control_config["src_T_Item"] = httpSkinRoot + "tree_T_item.gif";
	tree_control_config["src_tree_space"] = httpSkinRoot + "tree_space.gif";
	tree_control_config["src_Top_ColClosed"] = httpSkinRoot + "tree_top_collection_closed.gif";
	tree_control_config["src_TopOnly_ColClosed"] = httpSkinRoot + "tree_top_only_collection_closed.gif";
	tree_control_config["src_Top_Item"] = httpSkinRoot + "tree_top_item.gif";
	tree_control_config["src_TopOnly_Item"] = httpSkinRoot + "tree_top_only_item.gif";
	tree_control_config["iconWidth_Col"] = "16";
	tree_control_config["iconHeight_Col"] = "16";
	tree_control_config["iconWidth_Item"] = "16";
	tree_control_config["iconHeight_Item"] = "16";
	tree_control_config["connectorWidth"] = "12";
	tree_control_config["connectorHeight"] = "20";
}

/* generate the core HTML for either a COLLECTION or an ITEM node */
function tree_control_CoreHtml(node, nodeLocation)
{
	initTreeControlConfig();
	var config = tree_control_config;
	/* Declare string variables for markup. */
	var iconImageHtml = "";
	var connectorImageHtml = "";
	var offsetImagesHtml = "";
	var imageCellWidth = 0;
	var labelTextHtml = "";
	var id = nodeLocation;

	// **** COLLECTION ****
	if (node.tagName == "collection")
	{
		/* Define icon image and image attributes for current element. */
		if (node.getAttribute("icon"))
		{
			var iconSrc = httpSkinRoot + node.getAttribute("icon");
		}
		else
		{
			var iconSrc = config["src_Icon_ColClosed"];
		}
		var iconWidth = config["iconWidth_Col"];
		var iconHeight = config["iconHeight_Col"];

		/* This block tests any top-level collections to see if they are the
		   first collection in the listing (e.g. they have no previous sibling
		   in their display group). This is used below to define the unique
		   connector images used for the top collection. */
		var isFirstMenuItem = false;
		if (node.parentNode.tagName == "navtree" && previousSiblingElement(node) == null)
			isFirstMenuItem = true;

		/* Define connector image for the current collection. */
		if (isFirstMenuItem)
		{
			if (nextSiblingElement(node) == null)
			{
				var connectorSrc = config["src_TopOnly_ColClosed"];
			}
			else
			{
				var connectorSrc = config["src_Top_ColClosed"];
			}
		}
		else if (nextSiblingElement(node) != null)
		{
			var connectorSrc = config["src_T_ColClosed"];
		}
		else
		{
			var connectorSrc = config["src_L_ColClosed"];
		}
	}

	// **** ITEM ****
	else
	{
		/* Define icon image and image attributes for current element. */
		if (node.getAttribute("icon"))
		{
			var iconSrc = httpSkinRoot + node.getAttribute("icon");
		}
		else
		{
			var iconSrc = config["src_Icon_Item"];
		}
		var iconWidth = config["iconWidth_Item"];
		var iconHeight = config["iconHeight_Item"];

		/* This block tests any top-level items to see if they are the first
		   item in the listing (e.g. they have no previous sibling in their
		   display group). This is used below to define the unique connector
		   images used for the top item. */
		var isFirstMenuItem = false;
		if (node.parentNode != null &&
			node.parentNode.tagName == "navtree" && previousSiblingElement(node) == null)
		{
			isFirstMenuItem = true;
		}

		/* Define connector image for the current item. */
		var connectorSrc = config["src_L_Item"];
		if (isFirstMenuItem)
		{
			if (nextSiblingElement(node) == null)
				connectorSrc = config["src_TopOnly_Item"];
			else
				connectorSrc = config["src_Top_Item"];
		}
		else if (nextSiblingElement(node) != null)
		{
			connectorSrc = config["src_T_Item"];
		}
	}

	/* Generate the html code for the icon and node-connection point graphics
	   using image property values determined in the block above. */
	iconImageHtml = imageHtml(iconSrc, iconWidth, iconHeight);
	connectorImageHtml = imageHtml(connectorSrc, config["connectorWidth"], config["connectorHeight"]);

	/* Loop upward through the ancestors of the current element to generate
	   html code for the offset image graphics (either dotted lines or spaces in
	   this implementation).  Also keep a count of the number of levels to use
	   in calculating the width of the table cell that will contain the images. */
	var parent = node.parentNode;
	var offsetCount = 0;
	var referenceParent;
	while (parent != null && parent.tagName != "navtree")
	{
		referenceParent = parent;
		if (nextSiblingElement(parent) && referenceParent.tagName != "navtree")
			offsetImagesHtml = imageHtml(config["src_I"], config["connectorWidth"], config["connectorHeight"]) + offsetImagesHtml;
		else
			offsetImagesHtml = imageHtml(config["src_tree_space"], config["connectorWidth"], config["connectorHeight"]) + offsetImagesHtml;
		offsetCount++;
		parent = parent.parentNode;
	}

	/* Calculate the width of the table cell containing the images. First the
	   total width of all offset images is calculated, then the widths of the
	   node point connector and the icon are added. */
	imageCellWidth = (offsetCount * config["connectorWidth"]) + parseInt(config["connectorWidth"]) + parseInt(iconWidth);

	/* Generate target attribute code for the <a> tag (if a target attribute exists in the XML). */
	if (node.getAttribute("target") != null && node.getAttribute("target") != "")
		var linkTarget = ' target="' + node.getAttribute("target") + '"';
	else
		var linkTarget = "";

	/* Generate html code for the node point connector and icon graphics and
	   associated links.  In this implementation, the icon for an "item" will be
	   a link to the url from the item's xml "url" attribute; a "collection"
	   will have both the node point connector and icon contained in a common
	   <span> tag with an href javascript event that calls the function to open the
	   collection folder.  */
	if (node.tagName == "item")
	{
		var nodeImagesHtml = connectorImageHtml + '<a href="' + node.getAttribute("url") + 
			'"' + linkTarget + '>' + iconImageHtml + '</a>';
	}
	else
	{
		var displayNodeId = registerDisplayNode(node.getAttribute("id"), 
			node.getAttribute("collection_service"), window.name);
		var nodeImagesHtml = '<a id="' + node.getAttribute("id") +
			'_link" href="javascript:parent.toggleDisplayNode(\'' + displayNodeId + '\')">' + 
			connectorImageHtml + iconImageHtml + '</a>';
	}

	/* Generate the html code for the label text. A link will be included if
	   the xml data contains a value for the "url" atrribute (either "items"
	   or "collections" may contain a link). */
	if (node.getAttribute("url") != null && node.getAttribute("url") != "")
	{
		/* This branch had to be added because the addition of the mini search
		   page in the tray in the left menu area seemed to confuse the link
		   targeting mechanisms. */
		if (linkTarget == "" || linkTarget == "contentFrame")
		{
			labelTextHtml = '<a href="' + node.getAttribute("url") + '" class="navItemLink"'
				+ linkTarget + '>' + node.getAttribute("label") + '</a>';
		}
		else
		{
			labelTextHtml = '<a href="' + node.getAttribute("url") + '" class="navItemLink"'
				+ linkTarget + '>' + node.getAttribute("label") + '</a>';
		}
	}
	else
	{
		labelTextHtml = node.getAttribute("label");
	}

	/* Append the final html table code for the item to the global html string
	   variable. */
	this.htmlString +=
		'<table id="' + id + '" class="navItemTable" border="0" cellspacing="0" cellpadding="0" summary="">\n' +
		'	<tr>\n' +
		'		<td style="width:' + imageCellWidth.toString() + 'px; text-align:left; white-space:nowrap" nowrap>' + 
					offsetImagesHtml + nodeImagesHtml + '</td>\n' +
		'		<td class="navItemText" nowrap>' + labelTextHtml + '</td>\n' +
		'	</tr>\n' +
		'</table>\n';
}


/* This function is passed as a parameter to the buildHtmlStringFromXml method.
   It generates the opening html code for a single display collection/folder in
   the nav tree.  */
function tree_control_OpeningHtml(node, nodeLocation)
{
	if (node.tagName == "navtree") // root
	{
		this.htmlString +=
			'<table id="navtreeTable" class="trayA_topLevelTable" border="0" cellspacing="0" cellpadding="0" summary="">\n' +
			'	<tr>\n' +
			'		<td style="vertical-align:top;height:100%;width:100%">\n' +
			'			<div id="trayTableMainDiv" style="width:100%;height:100%;padding-left:5px">\n';
	}
	else
	{
		/* Only create the container if it doesn't already exist. */
		if (document.getElementById(node.getAttribute("id")) == null)		
			this.htmlString += '<div id="' + node.getAttribute("id") + '" style="display:none">\n';
	}
}


/* close the HTML code block for a COLLECTION item */
function tree_control_ClosingHtml(node, nodeLocation)
{
	if (document.getElementById(node.getAttribute("id")) == null)
	{
		if (node.tagName == "navtree") // root
		{
			this.htmlString +=
				'  		</div>\n' +
				'  	</td>\n' +
				'  </tr>\n' +
				'</table>\n';
		}
		else
		{
			this.htmlString += '</div>\n';
		}
	}
}

/////////////////////////////////////////////////////////////////
//  Code for dynamicly drawing nodes
/////////////////////////////////////////////////////////////////

function toggleElemDisplay(id)
{
	var elem = document.getElementById(id);
	if (elem)
	{
		if (elem.style.display == 'none')
			elem.style.display='block';
		else
			elem.style.display='none';
	}
}

function toggleElemDisplayInline(id)
{
	var elem = document.getElementById(id);
	if (elem)
	{
		if (elem.style.display == 'none')
			elem.style.display='inline';
		else
			elem.style.display='none';
	}
}
	
/* Utility function that parses an html text string and inserts it into an element
   (replacing any existing contents). */
function insertHtml(text, element)
{
	var range;
	var htmlFragment;

	/* This branch is the pure-W3C DOM approach (should have long-term
	   forward-compatibility) */
	if (document.createRange) 
	{
		range = document.createRange();
		range.selectNodeContents(element);
		range.deleteContents();
		htmlFragment = range.createContextualFragment(text);
		element.appendChild(htmlFragment);
	}
	else
	{
		element.innerHTML = text;
	}
}

/* Standard function for generating html image tag code. */
function imageHtml(src, w, h)
{
	var imgHtml = '<img src="' + src + '" width="' + w + '" height="' + h + '" alt="" border="0" align="absmiddle">';
	return imgHtml
}

/* delete a node from the HTML page. */
function deleteNodeHtml(navBuilder, nodeId, windowObj)
{
	if (navBuilder == null || nodeId == null)
		return;
	if (windowObj == null)
		windowObj = top;
	
	var node = navBuilder.getNodeById(nodeId);
	if (node == null)
		return;
	
	var parentId = node.parentNode.getAttribute("id");

	navBuilder.deleteItem(nodeId);
	
	repaintNodeAndChildren(navBuilder, parentId, windowObj);
}

/* Repaints a node and its children on the page. */
function repaintNodeAndChildren(navBuilder, nodeId, windowObj)
{
	if (navBuilder == null || nodeId == null)
		return;
	if (windowObj == null)
		windowObj = top;

	var node = navBuilder.getNodeById(nodeId);
	if (node == null)
	{
		return;
	}
	
	var htmlContainer
	    = windowObj.document.getElementById(nodeId);
	var pathIndex = navBuilder.xmlNodeMap[nodeId].location;
	
	// Clear the container of its existing HTML content.
	insertHtml("", htmlContainer);
	htmlContainer.style.display = "none";
	 
	// Make sure the htmlString variable is empty, then build the new HTML
	// string in it.
	navBuilder.htmlString = "";
	navBuilder.buildHtmlStringFromXml(node, pathIndex);
	
	// Insert the new HTML into the parent container.
	insertHtml(navBuilder.htmlString, htmlContainer);
	
	// Check to see if the parent container is empty
	// (e.g. htmlString is still blank).
	if (navBuilder.htmlString != "")
	{
		// If parent container does have contents, display the container.
		htmlContainer.style.display = "block";
	}
}

/* insertType parameter must be one of three values: "replace" or "addToTop" or
   "addToBottom" */
function insertParsedChildNodes(navBuilder, childList, destinationXmlParent, insertType)
{
	/* Clear existing children from parent node (otherwise, new children will
	   be added to existing). */
	if (insertType == "replace")
	{
		var destinationChildList = destinationXmlParent.childNodes;
		for (var i=destinationChildList.length-1; i>=0; i--)
		{
			destinationXmlParent.removeChild(destinationChildList[i]);
		}
	}

	if (insertType == "replace" || insertType == "addToBottom")
	{
		/* Loop through child list and insert nodes into parent XML collection
		   node. Since this is done using the appendChild() method, the new
		   nodes are added to the bottom, after any existing child nodes in the
		   list. */
		for (var j=0; j<childList.length; j++)
		{
			if (childList[j].nodeType == 1)
			{
				var childNodeClone = childList[j].cloneNode(true);
				destinationXmlParent.appendChild(childNodeClone);
			}
		}
	}
	else if (insertType == "addToTop")
	{
		var destinationChildList = destinationXmlParent.childNodes;
		var originalTopNode = destinationChildList[0];

		/* Loop through child list and insert nodes into parent XML collection
		   node. Each node is inserted before the top-most existing node. */
		for (var j=0; j<childList.length; j++)
		{
			if (childList[j].nodeType == 1)
			{
				var childNodeClone = childList[j].cloneNode(true);
				destinationXmlParent.insertBefore(childNodeClone, originalTopNode);
			}
		}
	}

	/* Remap the treeMenu fragment after the new nodes have been inserted. */
	navBuilder.xmlNodeMap = new Object();
	mapXMLTree(navBuilder.xmlRoot, navBuilder.xmlNodeMap);
}

/* based on the nodes in the navBuilder, and the function pointers in the
  navBuilder (makeOpeningHtml, makeCoreHtml, makeClosingHtml), this will
  generate HTML from XML, and insert it into the page. TODO - add support for
  the 'NAVTREE' node */
function generateChildNodeDisplayCode(navBuilder, node, htmlContainer)
{
	/* Determine the location pointer value of the parent node (used as
	   argument in buildHtmlStringFromXml method call). */
	var id = node.getAttribute("id");
	var nodeLocation = "";
	var path = navBuilder.xmlNodeMap[id];
	if (path != null)
		nodeLocation = path.location;

	/* Delete contents of htmlString variable before generating new code. */
	navBuilder.htmlString = "";

	/* Generate HTML markup string for the new nodes by walking the treeMenu
	   XML fragment starting at the parent containing the new children. */
	navBuilder.buildHtmlStringFromXml(node, nodeLocation);

	/* Insert the markup for the new children into the appropriate tree menu
	   <div> container. */
	insertHtml(navBuilder.htmlString, htmlContainer);

	if (navBuilder.htmlString == "") return false
	else return true
}

/* Registers a display node information object, and returns a reference to it via id */
function registerDisplayNode(nodeId, collectionService, frameName)
{
	var displayNodeInfo = new Object();
	displayNodeInfo['nodeId'] = nodeId;
	displayNodeInfo['collectionService'] = collectionService;
	displayNodeInfo['frameName'] = frameName;
	
	var displayNodeId = "DisplayNode_" + displayNodeCounter;
	displayNodeCounter++;
	displayNodes[displayNodeId] = displayNodeInfo;
	return displayNodeId;
}

function toggleDisplayNode(displayNodeId)
{
	var displayNodeInfo = displayNodes[displayNodeId];
	toggleDisplay(displayNodeInfo['nodeId'], displayNodeInfo['collectionService'], 
		displayNodeInfo['frameName']);
}

/* DHTML function that hides or displays the children of a collection on the
   tree. */
function toggleDisplay(nodeId, collectionService, frameName)
{
	var doc = window.document;
	if (frameName != null && frameName != "")
	{
		var frame = window.frames[frameName];
		if (typeof(frame) != "undefined")
		{
			doc = window.frames[frameName].document;
		}
	}

	/* Declare variables containing the two images that need to be swapped
		ASSUMPTION: The first (and usually only) two children of the linkObject
		container will be the tree connector and the collection/folder icon
		respectively. */
	var linkObject = doc.getElementById(nodeId + "_link");
	var treeConnectorImage = linkObject.childNodes[0];
	var treeIconImage = linkObject.childNodes[1];
	var divContainer = doc.getElementById(nodeId);

	/* Toggle the display status of the associated DIV container accordingly. */
	if (treeConnectorImage.src.indexOf("closed.gif") > -1)
	{
		/* The collection service is used to dynamically generate and insert
		   child nodes for collections in the Library (index) sub-tree (for
		   nodes that don't have a collection service, their child nodes were
		   generated at the time the page is initially loaded). */

		/* Run the collection service routines only if the child nodes haven't
		   been loaded already (e.g. the <div> container doesn't already contain
		   any <table> code). */
		if (collectionService && collectionService != 'null' && divContainer.getElementsByTagName("table").length == 0)
		{
			/* This conditional was added to allow use with Javascript-based
			   collection services.  This is included to enable a broaded range
			   of customization; it isn't currently used in the standard
			   implementation. */
			if (collectionService.indexOf("javascript:") == 0)
			{
				jsLoadFunction = collectionService.split(":")[1];
				
				// This decoding is done in case the collectionService came directly 
				// from javascript.  Before it was expected that the collectionService
				// would have to be quote-safe, but that's not true anymore.
				var decodedJsLoadFunction;
				var argEval = "decodedJsLoadFunction = '" + jsLoadFunction + "'";
				eval(argEval);
				eval(decodedJsLoadFunction);
			}
			else
			{
				/* Load hidden frame with lm_dir_page.htm template. The onload
				   event of this page calls the parseChildNodesXml() function.
				   This can potentially be used with other services for
				   different customizations.*/
				hiddenActionWindow.location.replace(collectionService);
			}
			/* Note: the code that displays the container should be in the
			   collection service functions.*/
		}
		else
		{
			if (divContainer.hasChildNodes())
			{
				// Display existing child nodes.
				divContainer.style.display = "block"; 
			}
		}
		// swap to the 'open' icon
		treeConnectorImage.src = treeConnectorImage.src.replace(/closed\.gif/, "open.gif");
		treeIconImage.src = treeIconImage.src.replace(/closed\.gif/, "open.gif");
	}
	else
	{
		// Hide child nodes, swap the graphic to 'closed'
		divContainer.style.display = "none";
		treeConnectorImage.src = treeConnectorImage.src.replace(/open\.gif/, "closed.gif");
		treeIconImage.src = treeIconImage.src.replace(/open\.gif/, "closed.gif");
	}
}

/*
 * This function adds a text node of str to the element identified by id.
 */
function setTextToNode(id, str)
{
	var element = document.getElementById(id);
	var textNode = document.createTextNode(str);
	element.appendChild(textNode);
}

/* This function provides a quick way to change all item icons in a collection
   to a particular src */
function changeItemIconsTo(iconSrc, parnentId, deep)
{
	var parentNode = coreNav.getNodeById(parnentId);
	if (parentNode == null)
		return;

	var node = parentNode.firstChild;
	var nodeId;

	while(node != null)
	{
		nodeId = node.getAttribute("id");
		if (node.nodeName == "item")
			coreNav.setAttributeValue(nodeId, "icon", iconSrc);

		else if (node.nodeName == "collection")
		{
			if (deep)
				changeItemIconsTo(iconSrc, nodeId);
		}
		node = node.nextSibling;
	}
}

/* This function allow a link to control display of another */
function changeElementDisplay(displayElemId, textElemId, showText, hideText)
{
	var displayElem = document.getElementById(displayElemId);
	var displayText = showText;
	if (displayElem.style.display == "block")
	{
		displayElem.style.display = "none";
		displayText = hideText;
	}
	else
	{
		displayElem.style.display = "block";
	}
	
	var textElem = null;
	if (textElemId != null && displayText != null)
	{
		textElem = document.getElementById(textElemId);
		if (textElem != null)
		{
			textElem.firstChild.nodeValue = displayText;
		}
	}
	
}

/* Get breakable word. Since there is no standard way of wrapping word, the function is to help wrapping of long 
 * unbreakable strings. Consecutive characters that does not contain white space is considered unbreakable.
 * 
 * This function takes three inputs: string to wrap,break width and breakable characters.  
 */
function getBreakableString(unbreakableStr, width, breakableChars, searchRange)
{
	if (searchRange == null)
	{
		searchRange = 0.1;
	}
	var delta = width * searchRange; // We will search for breakableChars 20%
	var breakableStr = "";
	var lastIndex = 0;
	while (unbreakableStr.length > lastIndex + width)
	{
		var curIndex = lastIndex + width;
		var tmpIndex = getBreakableCharIndex(unbreakableStr, curIndex, curIndex - delta, curIndex + delta / 2, breakableChars);
		breakableStr += unbreakableStr.substring(lastIndex, tmpIndex + 1) + "\n";
		lastIndex = tmpIndex + 1;
	}
	if (lastIndex < unbreakableStr.length)
	{
		breakableStr += unbreakableStr.substring(lastIndex);
	}
	return breakableStr;
}

function getBreakableCharIndex(unbreakableStr, curIndex, beginIndex, endIndex, breakableChars)
{
	var index = curIndex;
	for (var i = 0; i < breakableChars.length; i ++)
	{
		var tmpIndex = unbreakableStr.lastIndexOf(breakableChars.charAt(i), curIndex);
		if (tmpIndex >= beginIndex)
		{
			index = tmpIndex;
			break;
		}
		else
		{
			tmpIndex = unbreakableStr.indexOf(breakableChars.charAt(i), curIndex);
			if (tmpIndex >= curIndex && tmpIndex <= endIndex)
			{
				index = tmpIndex;
				break;
			}
		}
	}
	return index;
}

/////////////////////////////////////////////////////////////////
//  DHTML/XML Utilities
/////////////////////////////////////////////////////////////////

var _xmlEncodeChars = new Array('&', '<', '>', '"');
var _xmlEncodeMap = new Array("&amp;", "&lt;", "&gt;", "&quot;");
/* encode a string to an xml string */
function xmlEncode(string)
{
	for (var i = 0; i < _xmlEncodeChars.length; i++)
	{
		if (string.indexOf(_xmlEncodeChars[i]) >= 0)
		{
			string = string.split(_xmlEncodeChars[i]).join(_xmlEncodeMap[i]);
		}
	}
	return string;
}

/* the ultimate browser sniffer object */
function sniffer()
{
	var n = navigator;
	/* string comparisons are much easier if we lowercase everything now.
	   to make indexOf() tests more compact/readable, we prepend a space
	   to the userAgent string (to get around '-1' indexOf() comparison) */
	var ua = ' ' + n.userAgent.toLowerCase();
	var pl = n.platform.toLowerCase(); // not supported in NS3.0
	var an = n.appName.toLowerCase();

	// browser version
	this.version = n.appVersion;

	// 'compatible' versions of mozilla aren't navigator
	this.nn = ua.indexOf('mozilla') > 0;
	if(ua.indexOf('compatible') > 0)
	{
		this.nn = false;
	}



	this.opera = ua.indexOf('opera') > 0;
	this.webtv = ua.indexOf('webtv') > 0;
	this.ie = ua.indexOf('msie') > 0;
	this.aol = ua.indexOf('aol') > 0;
	this.omniweb = ua.indexOf('omniweb') > 0;
	this.galeon = ua.indexOf('galeon') > 0;
	this.safari = ua.indexOf('safari') > 0;
	this.khtml = ua.indexOf('khtml') > 0;
	this.mozilla = ua.indexOf('gecko') > 0;
	this.firefox = ua.indexOf('firefox') > 0;

	this.major = parseInt( this.version );
	this.minor = parseFloat( this.version );

	// platform
	this.mac = ua.indexOf('mac') > 0;
	this.win = ua.indexOf('win') > 0;
	this.unix = ua.indexOf('x11') > 0;

	// workarounds
	// - IE always reports itself as version 4.0
	if (this.ie)
	{
		var actual_index = ua.indexOf("msie ");
		if (actual_index > 0)
		{
			var actual_major = ua.substring(actual_index + 5, actual_index + 6);
			var actual_version = ua.substring(actual_index + 6, actual_index + 8);
			this.major = parseInt(actual_major);
			this.minor = parseFloat(actual_version);
		}
	}
	if (this.mozilla && this.nn)
		this.nn = false;
	if (this.mozilla && this.safari)
		this.mozilla = false;

	if (this.mozilla || (this.nn && this.major > 4))
	{
		var start = ua.indexOf('rv:');
		var end = ua.indexOf(')', start);
		var rvStr = ua.substring(start + 3, end);
		this.rv = parseFloat(rvStr);
	}

	if (this.firefox)
	{
		var start = ua.indexOf('firefox/');
		var fvStr = ua.substring(start + 8);
		this.fv = parseFloat(fvStr);
	}

	return this;
}


/* This constructor function takes an element as its parameter, and creates an
   object with properties representing the element's width, height, actual X and
   Y positions within the browser window, and X and Y positions relative to its
   nearest CSS-positioned ancestor. */
function dimensionFinder(element)
{
	// if its an event
	if (element.tagName != "APPLET" && element.cancelBubble != null)
	{
		this.width = 2;
		this.height = 2;
		this.actualLeft = element.clientX + document.body.scrollLeft - 1;
		this.actualTop = element.clientY + document.body.scrollTop - 1;
		this.relativeLeft = 0;
		this.relativeTop = 0;
		return;
	}

	this.width = element.offsetWidth;
	this.height = element.offsetHeight;
	this.actualLeft = 0; // X-position within browser window
	this.actualTop = 0; // Y-position within browser window
	this.relativeLeft = 0; // X-position within nearest CSS-positioned ancestor
	this.relativeTop = 0; // Y-position within nearest CSS-positioned ancestor
	var subParent = element;
	var subParentPositioning = ""; // CSS position value of subParent
	var insideContainerBlock = true;

	while(subParent != null)
	{
		if (subParent.tagName == "APPLET")
		{
			subParent = subParent.offsetParent;
			continue;
		}

		if (subParent.currentStyle) 
		{
			// get calculated CSS position value using IE proprietary method
			subParentPositioning = subParent.currentStyle.position;
		}
		else if (document.defaultView && document.defaultView.getComputedStyle) 
		{
			// get calculated CSS position value using W3C method
			subParentPositioning = document.defaultView.getComputedStyle(subParent, "").getPropertyValue("position");
		}
		else 
		{
			// get in-line CSS position value, not reliable

			/* todo: grab the className, and the class that it
			   refers to. Parse it to see if its absolute or relative.
			   possible??? */
			subParentPositioning = subParent.style.position;			
		}

		if (subParentPositioning == "absolute" || subParentPositioning == "relative")
			insideContainerBlock = false;

		// Fix to get RTL layouts to work for IE.
		offsetLeft = subParent.offsetLeft;
		if (subParent.offsetParent != null && (subParent.offsetParent.tagName != 'BODY') && offsetLeft < -20)
		{
			offsetLeft = offsetLeft + subParent.offsetParent.clientWidth - 13;
		}

		if (insideContainerBlock)
		{
			this.relativeLeft = this.relativeLeft + offsetLeft;
			this.relativeTop = this.relativeTop + subParent.offsetTop;
		}

		if (offsetLeft > 0)
		{
			this.actualLeft = this.actualLeft + offsetLeft;
		}
		
		this.actualTop = this.actualTop + subParent.offsetTop;
		subParent = subParent.offsetParent;
	}
}


/* This function takes two elements as its parameters; it returns true if the
   elements overlap on-screen or false if they don't. */
function theseElementsOverlap(element1, element2)
{
	var element1Data = new dimensionFinder(element1);
	var element2Data = new dimensionFinder(element2);

	if ((element1Data.actualLeft + element1Data.width) > element2Data.actualLeft &&
			element1Data.actualLeft < (element2Data.actualLeft + element2Data.width) &&
			(element1Data.actualTop + element1Data.height) > element2Data.actualTop &&
			element1Data.actualTop < (element2Data.actualTop + element2Data.height))
		return true;
	else
		return false;
}


/* This function takes two parameters: a valid CSS display property value
   (either "visible" or "hidden"), and an element. It loops through
   collections of element types defined in an array at the top; if any of the
   elements in these collections overlap with the passed-in element, their
   display value is set to the passed-in display value. This is used to
   prevent layering conflicts between DHTML popups and certain types of
   elements that always display on top.

		Note: this function doen't work properly with versions of IE prior to
		5.5; also, the applet hiding doesn't work with NN prior to 7.1 or Moz
		prior to 1.3.  In either case it should fail quietly. */
function setConflictingElements(displayVal, element)
{
	// Initialize the array containing tag names of conflicting element types.
	// This function can easily be extended by adding items to the array if needed.
	var conflictingTagNames = new Array("APPLETWRAPPER");
	if (its.ie)
		conflictingTagNames = new Array("APPLET", "SELECT");

	/* Loop through collections of each of the conflicting element types, and
	   hide any that overlap with the menu. */
	for (var i=0; i<conflictingTagNames.length; i++)
	{
		var conflictingElements = document.getElementsByTagName(conflictingTagNames[i]);

		for (var j=0; j<conflictingElements.length; j++)
		{
			if (theseElementsOverlap(conflictingElements[j], element))
			{
					conflictingElements[j].style.visibility = displayVal;
			}
		}
	}
}


function createHiddenInputElement(frm, elementName, elementValue)
{
  var newElement = document.createElement("input");
  newElement.setAttribute("type", "hidden");
  newElement.setAttribute("name", elementName);
  newElement.setAttribute("value", elementValue);
  frm.appendChild(newElement);
}


/////////////////////////////////////////////////////////////////
//  for back compatibility with IE 4 and 5
/////////////////////////////////////////////////////////////////

function _array_pop() 
{
	var objItem = null;
	if (this.length > 0) 
	{
		objItem = this[this.length - 1];
		this.length--;
	}

	return objItem;
}

function _array_push() 
{
	for (var i=0; i < arguments.length; i++)
		this[this.length++] = arguments[i];
}

function _array_remove(iLoc) 
{
	var objItem = this[iLoc];
	var arrFront = this.slice(0, iLoc);
	var arrBack = this.slice(iLoc + 1, this.length);
	var arrMerged = arrFront.concat(arrBack);

	for (var i=0; i < arrMerged.length; i++)
		this[i] = arrMerged[i];
		
	this.length = arrMerged.length;
	return objItem;
}

if (Array.prototype.pop == null)
{
	Array.prototype.pop = _array_pop;
	Array.prototype.push = _array_push;
}
if (Array.prototype.remove == null)
{
	Array.prototype.remove = _array_remove;
}

/////////////////////////////////////////////////////////////////
//  select list compatibility with IE
/////////////////////////////////////////////////////////////////

var handlingOptionListEvent = 0;
var bInDropdown = false;
var bMouseOverSelect = false;
var optionListFixOnChangeCommands = new Object();

function fixOptionListForIE(selectId)
{
	var element = document.getElementById(selectId);

	if (element.tagName.toLowerCase() == 'select' && typeof(element.onchange) != 'undefined' &&
		element.onchange != null)
	{
		// Wrap the old function
		var onChangeCommand = wrapFunction(element, element.onchange);

		// Set the events to our custom events so we can fix the select
		element.onchange = handleOptionListChanged;
		element.onkeydown = handleOptionListKeyDown;
		element.onkeyup = handleOptionListKeyUp;
		element.onmousewheel = handleOptionListWheel;
		element.onclick = handleOptionListOnClick;
		element.onmousedown = handleOptionListMouseDown;
		element.onmouseenter = handleOptionListMouseEnter;
		element.onmouseleave = handleOptionListMouseLeave;

		// Set the command to execute when a true change is detected.
		optionListFixOnChangeCommands[selectId] = onChangeCommand;
	}
}

function handleOptionListMouseEnter (e)
{
	if (!e) var e = window.event;
	bMouseOverSelect = true;
}

function handleOptionListMouseLeave (e)
{
	if (!e) var e = window.event;
	bMouseOverSelect = false;
}

function handleOptionListMouseDown (e)
{
	if (!e) var e = window.event;
	if (bMouseOverSelect)
	{
		bInDropdown = (bInDropdown) ? false : true;
	}
}

function handleOptionListChanged(e)
{
	if (!e) var e = window.event;
	bInDropdown = false;
	if (handlingOptionListEvent > 0)
	{
		handlingOptionListEvent--;
	}
	else
	{
		doChangeCommand(e.srcElement.id);
	}
}

function handleOptionListKeyDown(e)
{
	if (!e) var e = window.event;
	if (e.keyCode == 9) // tab
	{
		doChangeCommand(e.srcElement.id);
	}
	else if (e.keyCode == 40 || e.keyCode == 38 
		|| ( e.keyCode >= 33 && e.keyCode <= 36 )) // up / down / pageup / pagedown / home / end keys
	{
		handlingOptionListEvent = 1;
	}
}

function handleOptionListKeyUp(e)
{
	if (!e) var e = window.event;
	if (e.keyCode == 13) // enter
	{
		doChangeCommand(e.srcElement.id);
	}
}

function handleOptionListWheel(e)
{
	if (!e) var e = window.event;
	if (bInDropdown)
	{
		handlingOptionListEvent = 0;
	}
	else
	{
		var remainder = e.wheelDelta % 120;
		var numChanged = Math.abs(( e.wheelDelta - remainder ) / 120);
		handlingOptionListEvent = numChanged;
	}
}

function handleOptionListOnClick(e)
{
	if (!e) var e = window.event;
	handlingOptionListEvent = 0;
}

function doChangeCommand(selectId)
{
	optionListFixOnChangeCommands[selectId]();
}

//
// More useful functions
//

function getFormElementValue(element)
{
	if (!element || !element.type || !element.type.toLowerCase)
	{
		return null;
	}
	var type = element.type.toLowerCase();
	if (type == "input" || type == "text" || type == "password"
		|| type == "hidden" || type == "textarea" || type == "file"
		|| type == "button" || type == "reset" || type == "submit")
	{
		return element.value;
	}
	if (type == "checkbox")
	{
		return element.checked;
	}
	if (type == "radio")
	{
		var buttons = element.form.elements[element.name];
		if (!buttons)
		{
			return null;
		}
		for (var i = 0; i < buttons.length; i++)
		{
			var element = buttons[i];
			if (element.checked)
			{
				return element.value;
			}
		}
		return "";
	}
	if (type == "select-one")
	{
		var index = element.selectedIndex;
		if (index < 0 || index >= element.options.length)
		{
			return "";
		}
		return element.options[index].value;
	}
	if (type == "select-multiple")
	{
		var selected = new Array();
		for (var index = 0; index < element.options.length; index++)
		{
			if (element.options[index].selected)
			{
				selected.push(element.options[index].value);
			}
		}
		return selected;
	}
	return null;
}

function sortSelect(obj)
{
	if (obj == null || obj.options == null)
	{
		return;
	}

	var o = new Array();
	for (var i = 0; i < obj.options.length; i++)
	{
		o[o.length] = new Option(obj.options[i].text, obj.options[i].value, obj.options[i].defaultSelected, obj.options[i].selected);
	}
	
	if (o.length > 0)
	{
		o = o.sort( 
			function(a, b)
			{ 
				if ((a.text+"") < (b.text+""))
				{
					return -1;
				}
				if ((a.text+"") > (b.text+""))
				{
					return 1;
				}
				
				return 0;
			} 
		);
	
		for (var i = 0; i < o.length; i++)
		{
			obj.options[i] = new Option(o[i].text, o[i].value, o[i].defaultSelected, o[i].selected);
		}
	}
}

function isInt(str)
{
	var i = parseInt(str);

	if (isNaN(i))
	{
		return false;
	}

	i = i.toString();
	if (i != str)
	{
		return false;
	}
	
	return true;
}

function appendOption(selectObj, optionObj)
{
	try
	{
		selectObj.add(optionObj, null); // standards compliant; doesn't work in IE
	}
	catch(ex)
	{
		selectObj.add(optionObj); // IE only
	}
} 

function prependOption(selectObj, optionObj)
{
	var oldOption = selectObj.options[0];
	try
	{
		selectObj.add(optionObj, oldOption); // standards compliant; doesn't work in IE
	}
	catch(ex)
	{
		selectObj.add(optionObj, 0); // IE only
	}
}

function getClientWidth(obj)
{
	var div = document.createElement('div');
	div.style.visibility = "hidden";
	document.body.appendChild(div);
	
	div.appendChild(obj);
	var width = obj.clientWidth;
	
	document.body.removeChild(div);
	return width;
}

function splitStringCrLf(strValues)
{
	var retVal = new Array();
	var index = 0;
	while (strValues.length > 0)
	{
		var i = strValues.indexOf("\n");
		if (i >= 0)
		{
			subStr = strValues.substring(0, i);
			if (i > 0)
			{
				if (subStr.charAt(subStr.length - 1) == "\r")
				{
					subStr = subStr.substring(0, i - 1);
				}
			}
			retVal[index] = subStr;
		}
		else
		{
			retVal[index] = strValues;
			break;
		}
		strValues = strValues.substring(i + 1);
		index++;
	}
	return retVal;
}

/*
 *  Make a string URI-friendly.
 *
 *	- Escapes all 7-bit characters with %XX except:
 *		hyphen (u002D), period (u002E), 0 thru 9,
 *		A thru Z, underscore (u005F), and a thru z.
 *	- Escapes all characters over u007F with %uXXXX
 */
function urlEncode(str)
{
	str = escape(str);
	str.replace(/\*/g, "%2A");
	str.replace(/\+/g, "%2B");
	str.replace(/\//g, "%2F");
	str.replace(/@/g, "%40");
	return str;
}

function strTrim(str)
{
   return str.replace(/^\s*|\s*$/g,"");
}
function initPageSpecificNavBuilder(nav)
{
	nav.pageHeadingMenus = new Array();
	nav.additionalMenus = new Array();
	
	nav.xmlNodeMap = new Object();
	mapXMLTree(pageNav.xmlRoot, nav.xmlNodeMap);
}

function addPageHeadingMenu(id, nav)
{
	var builder = new navBuilder();
	
	builder.makeOpeningHtml = pageHeadingMenu_MenuItem_OpeningHtml;
	builder.makeCoreHtml = pageHeadingMenu_MenuItem_CoreHtml;
	builder.makeClosingHtml = pageHeadingMenu_MenuItem_ClosingHtml;
	
	builder.xmlNodeMap = new Object();
	mapXMLTree(builder.xmlRoot, builder.xmlNodeMap);
	
	nav.pageHeadingMenus[id] = builder;
	return builder;
}

function getPageHeadingMenu(id, nav)
{
	return nav.pageHeadingMenus[id];
}

function addAdditionalPageMenu(id, nav)
{
	var builder = new navBuilder();
	
	builder.makeOpeningHtml = pageAdditionalMenu_MenuItem_OpeningHtml;
	builder.makeCoreHtml = pageAdditionalMenu_MenuItem_CoreHtml;
	builder.makeClosingHtml = pageAdditionalMenu_MenuItem_ClosingHtml;
	
	builder.xmlNodeMap = new Object();
	mapXMLTree(builder.xmlRoot, builder.xmlNodeMap);
	
	nav.additionalMenus[id] = builder;
	return builder;
}

function getAdditionalPageMenu(id, nav)
{
	return nav.additionalMenus[id];
}

function checkAllCheckboxesForTable(tableNumber, doCheck)
{
	var numForms = document.forms.length;
	for (var i=0 ; i<numForms ; ++i)
	{
		var mForm = document.forms[i];
		if (mForm.tableNumber != null && mForm.tableNumber.value == tableNumber)
		{
			mForm.isSelected.checked = doCheck;
		}
	}
}

/*
 * Wraps a function call in a new function.  This allows one to invoke
 * the function at any time with the same parameters, as thought it were
 * coming from the provided object.
 */
function wrapFunction(obj, f, args)
{
	if(typeof(args) == 'undefined' || args == null)
	{
		args = new Array();
	} 

	var F = function()
	{
	    arguments.callee.originalFunction.apply(arguments.callee.originalObject, 
	    	arguments.callee.originalArgs);
	}
	F.originalObject = obj;
	F.originalFunction = f;
	F.originalArgs = args;
	return F;
}

//
// Confidential and Proprietary for Stellent, Inc.
//
// This computer program contains valuable, confidential, and
// proprietary information.  Disclosure, use, or reproduction
// without the written authorization of Stellent is prohibited.
// This unpublished work by Stellent is protected by the laws
// of the United States and other countries.  If publication
// of this computer program should occur, the following notice
// shall apply:
//
// Copyright (c) 2003-2006 Stellent, Inc.
// All rights reserved.
//
// $Id: commonNav.js 61443 2008-03-06 19:20:53Z dlew $
//


///////////////////////////////////////////////////////
// Template: COMMON_NAV_JS
// Class: javascript:common
// Location: resources/layouts/commonNav.js
///////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////
// WARNING: This file is generated by a Content Server template 
// and is then published to the weblayout directory. Any 
// changes made to the weblayout copy will be automatically 
// overwritten by the Content Server.
///////////////////////////////////////////////////////////////
//
// This file contains the navigation XML common to most
//   layouts. It shouldn't be directly modified. You should
//   instead write a component to override the include
//   'custom_finish_layout_init' with the 'super' tag, and modify
//   the 'navBuilder' object there.
//
// You may also modify the 'nav.js' file for the specific layout,
//   but this is not recommended. Doing so would make the changes
//   less portable.
//
///////////////////////////////////////////////////////////////

function addStandardNavigationNodes(navBuilder)
{
	if (isProxiedServer)
	{
		navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==HOME','label=='+lc('wwHome'), 'target==_top',
			'url=='+httpEnterpriseCgiPath+'?IdcService=GET_DOC_PAGE&Action=GetTemplatePage&Page=HOME_PAGE');
		navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==LOCAL_HOME','label=='+instanceMenuLabel,
			'url=='+httpCgiPath+'?IdcService=GET_DOC_PAGE&Action=GetTemplatePage&Page=HOME_PAGE');
	}
	else
	{
		navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==HOME','label=='+lc('wwHome'),
			'url=='+httpCgiPath+'?IdcService=GET_DOC_PAGE&Action=GetTemplatePage&Page=HOME_PAGE');
	}

	// browse content
	navBuilder.addChildNodeTo('NAVTREE', 'collection', 'id==BROWSE_CONTENT', 'label=='+lc('wwBrowseContent'));
	navBuilder.addChildNodeTo('BROWSE_CONTENT', 'item', 'id==LIBRARY', 'label=='+lc('wwLibraryQueryFolders'),
		'url=='+httpCgiPath+'?IdcService=GET_DYNAMIC_PAGE&PageName=index');

	navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==SEARCH', 'label=='+lc('wwSearch'),
		'url=='+httpCgiPath+'?IdcService=GET_DOC_PAGE&Action=GetTemplatePage&Page=STANDARD_QUERY_PAGE');

	if (isLoggedIn)
	{
		// Add search links
		var count = 0;
		if (typeof pneSearchDocProfiles != "undefined" && pneSearchDocProfiles)
		{
			count = pneSearchDocProfiles.length;
			if (count > 0)
			{
				navBuilder.addChildNodeTo('NAVTREE', 'collection', 'id==SEARCH', 'label=='+lc('wwSearch'));
				for (var i = 0; i < count; i++)
				{
					navBuilder.addChildNodeTo('SEARCH', 'item', 'id==MY_PERSONAL_SEARCHES_'+i, 'label=='+pneSearchDocProfiles[i][0],
						'url=='+pneSearchDocProfiles[i][1]);
				}
			}
		}

		if (count > 0)
		{
			// Add the standard search link to the drop down menu link.
			navBuilder.addChildNodeTo('SEARCH', 'item', 'id==MY_PERSONAL_SEARCHES_'+count, 'label=='+lc('wwStandardSearch'),
				'url=='+httpCgiPath+'?IdcService=GET_DOC_PAGE&Action=GetTemplatePage&Page=STANDARD_QUERY_PAGE');
		}
		else
		{
			// Just add the link to the top menu.
			navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==SEARCH', 'label=='+lc('wwSearch'),
				'url=='+httpCgiPath+'?IdcService=GET_DOC_PAGE&Action=GetTemplatePage&Page=STANDARD_QUERY_PAGE');
		}
		// my stellent
		navBuilder.addChildNodeTo('NAVTREE', 'collection', 'id==MY_CONTENT', 'label=='+lc('wwMyContent'));
				
		// personal urls
		navBuilder.addChildNodeTo('MY_CONTENT', 'collection', 'id==MY_PERSONAL_URLS', 'label=='+lc('wwMyPersonalUrls'),
			'url=='+httpCgiPath+'?IdcService=GET_PORTAL_PAGE&Action=GetTemplatePage&Page=PNE_PORTAL_PERSONAL_URLS_PAGE');
		for(var i=0; i<personalUrls.length; i++)
		{
			navBuilder.addChildNodeTo('MY_PERSONAL_URLS', 'item', 'id==MY_PERSONAL_URL_'+(i+1), 'label=='+personalUrls[i][0],
				'url=='+personalUrls[i][1], 'target==_blank');
		}
		navBuilder.addChildNodeTo('MY_PERSONAL_URLS', 'item', 'id==EDIT_PERSONAL_URLs', 'label=='+lc('wwEditPersonalUrls'),
				'url=='+httpCgiPath+'?IdcService=GET_PORTAL_PAGE&Action=GetTemplatePage&Page=PNE_PORTAL_PERSONAL_URLS_PAGE');

		// saved queries
		navBuilder.addChildNodeTo('MY_CONTENT', 'collection', 'id==MY_SAVED_QUERIES', 'label=='+lc('wwMySavedQueries'),
			'url=='+httpCgiPath+'?IdcService=GET_PORTAL_PAGE&Action=GetTemplatePage&Page=PNE_PORTAL_SAVED_QUERIES_PAGE');
		for(var i=0; i<savedQueries.length; i++)
		{
			navBuilder.addChildNodeTo('MY_SAVED_QUERIES', 'item', 'id==MY_SAVED_QUERY_'+(i+1), 'label=='+savedQueries[i][0],
				'url=='+savedQueries[i][1]);
		}
		navBuilder.addChildNodeTo('MY_SAVED_QUERIES', 'item', 'id==EDIT_SAVED_QUERIES',
				'label=='+lc('wwEditSavedQueries'), 'url=='+httpCgiPath+'?IdcService=GET_PORTAL_PAGE&Action=GetTemplatePage&Page=PNE_PORTAL_SAVED_QUERIES_PAGE');

		navBuilder.addChildNodeTo('MY_CONTENT', 'item', 'id==MY_PROFILE', 'label=='+lc('wwMyProfile'),
			'url=='+httpCgiPath+'?IdcService=GET_USER_INFO');
		navBuilder.addChildNodeTo('MY_CONTENT', 'item', 'id==MY_WORKFLOW_ASSIGNMENTS',
			'label=='+lc('wwMyWorkflowAssignments'), 'url=='+httpCgiPath+'?IdcService=GET_PORTAL_PAGE&Action=GetTemplatePage&Page=WF_INQUEUE_LIST&exitUrl='+httpCgiPath+'?IdcService=GET_USER_INFO');
		navBuilder.addChildNodeTo('MY_CONTENT', 'item', 'id==MY_SUBSCRIPTIONS', 'label=='+lc('wwMySubscriptions'),
			'url=='+httpCgiPath+'?IdcService=SUBSCRIPTION_LIST&unsubscribeService=UNSUBSCRIBE_FROM_LIST&subscribeService&title=User+Subscriptions&exitUrl='+httpCgiPath+'?IdcService=GET_USER_INFO');
		if (isContributor)
		{
			navBuilder.addChildNodeTo('MY_CONTENT', 'item', 'id==MY_CHECKED_OUT_CONTENT', 'label=='+lc('wwMyCheckedOutContent'),
				'url=='+httpCgiPath+'?IdcService=CHECKIN_LIST&userOnly=1');
		}
		navBuilder.addChildNodeTo('MY_CONTENT', 'item', 'id==MY_LIST_TEMPLATES', 'label=='+lc('wwMySearchResultTemplates'),
			'url=='+httpCgiPath+'?IdcService=GET_PORTAL_PAGE&Action=GetTemplatePage&Page=PNE_LIST_TEMPLATES_PAGE&sltClass=searchResults&sltPageTitle=wwSearchResultTemplatesFor');
		
		// contribution pages
		if (isContributor)
		{
			navBuilder.addChildNodeTo('NAVTREE', 'collection', 'id==CONTENT_MANAGEMENT', 'label=='+lc('wwContentMgmt'));

			navBuilder.addChildNodeTo('CONTENT_MANAGEMENT', 'item', 'id==CHECKED_OUT_CONTENT', 'label=='+lc('wwCheckedOutCon'),
				'url=='+httpCgiPath+'?IdcService=CHECKIN_LIST');
			navBuilder.addChildNodeTo('CONTENT_MANAGEMENT', 'item', 'id==WORK_IN_PROGRESS', 'label=='+lc('wwWorkInProgress'),
				'url=='+httpCgiPath+'?IdcService=WORK_IN_PROGRESS');
			navBuilder.addChildNodeTo('CONTENT_MANAGEMENT', 'item', 'id==ACTIVE_WORKFLOWS', 'label=='+lc('wwActiveWorkflows'),
				'url=='+httpCgiPath+'?IdcService=GET_ACTIVE_WORKFLOWS');
			navBuilder.addChildNodeTo('CONTENT_MANAGEMENT', 'item', 'id==EXPIRED_CONTENT', 'label=='+lc('wwExpiredContent'),
				'url=='+httpCgiPath+'?IdcService=GET_EXPIRED');

			if (adminAtLeastOneGroup)
			{
				navBuilder.addChildNodeTo('CONTENT_MANAGEMENT', 'item', 'id==REGISTERED_PUBLISHER_PROJECTS',
					'label=='+lc('wwRegisteredProjects'), 'url=='+httpCgiPath+'?IdcService=GET_REGISTEREDPROJECTS');
			}		

			// Add pne check in links
			var count = 0;
			if (typeof pneCheckinDocProfiles != "undefined" && pneCheckinDocProfiles)
			{
				count = pneCheckinDocProfiles.length;
				if (count > 0)
				{
					// Add the drop down menu.
					navBuilder.addChildNodeTo('NAVTREE', 'collection', 'id==NEW_CHECK_IN', 'label=='+lc('wwNewCheckIn'));

					for (var i = 0; i < count; i++)
					{
						navBuilder.addChildNodeTo('NEW_CHECK_IN', 'item', 'id==MY_PERSONAL_CHECKINS_'+i, 'label=='+pneCheckinDocProfiles[i][0],
							'url=='+pneCheckinDocProfiles[i][1]);
					}
				}
			}
			if (count > 0)
			{
				navBuilder.addChildNodeTo('NEW_CHECK_IN', 'item', 'id==MY_PERSONAL_CHECKINS_'+count, 'label=='+lc('wwStandardCheckIn'),
					'url=='+httpCgiPath+'?IdcService=CHECKIN_NEW_FORM');
			}
			else
			{
				navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==NEW_CHECK_IN', 'label=='+lc('wwNewCheckIn'),
					'url=='+httpCgiPath+'?IdcService=CHECKIN_NEW_FORM');
			}
		}

		// administration
		if (isSubAdmin || isSysManager)
		{
			navBuilder.addChildNodeTo('NAVTREE', 'collection', 'id==ADMINISTRATION', 'label=='+lc('wwAdministration'));

			if (userIsAdmin)
			{
				// log files
				navBuilder.addChildNodeTo('ADMINISTRATION', 'collection', 'id==LOG_FILES', 'label=='+lc('wwLogFiles'));
				navBuilder.addChildNodeTo('LOG_FILES', 'item', 'id==CONTENT_SERVER_LOGS', 'label=='+lc('wwServerLogs'),
					'url=='+httpWebRoot+'groups/secure/logs/IdcLnLog.htm');
				navBuilder.addChildNodeTo('LOG_FILES', 'item', 'id==ARCHIVER_LOGS', 'label=='+lc('wwArchiverLogs'),
					'url=='+httpWebRoot+'groups/secure/logs/archiver/ArchiveLn.htm');
				navBuilder.addChildNodeTo('LOG_FILES', 'item', 'id==DATABASE_LOGS', 'label=='+lc('wwDatabaseLogs'),
								'url=='+httpWebRoot+'groups/secure/logs/database/DatabaseLn.htm');
			}

			if (isSubAdmin)
			{
				navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==ADMIN_APPLETS', 'label=='+lc('wwAdminApplets'),
					'url=='+httpCgiPath+'?IdcService=GET_ADMIN_PAGE&Action=GetTemplatePage&Page=ADMIN_APPLETS');
			}

			if (userIsAdmin)
			{
				navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==CONFIGURATION_FOR_INSTANCE', 'label=='+lc('wwConfigForLabel', instanceMenuLabel),
					'url=='+httpCgiPath+'?IdcService=CONFIG_INFO');
				navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==SYSTEM_AUDIT_INFO', 'label=='+lc('wwAdminReports'),
					'url=='+httpCgiPath+'?IdcService=GET_SYSTEM_AUDIT_INFO');
				navBuilder.addChildNodeTo('ADMINISTRATION', 'collection', 'id==ADMIN_ACTIONS', 'label=='+lc('wwActions'));
				navBuilder.addChildNodeTo('ADMIN_ACTIONS', 'item', 'id==VIEW_SUMMARY', 'label=='+lc('wwAdminActionsSummary'), 'titleText=='+lc('wwAdminActionsLabel'),
					'url=='+httpCgiPath+'?IdcService=GET_ADMIN_PAGE&Action=GetTemplatePage&Page=GENERIC_PAGE&Include=admin_actions_summary');
				navBuilder.addChildNodeTo('ADMIN_ACTIONS', 'item', 'id==PUBLISH_WEBLAYOUT_FILES', 'label=='+lc('wwAdminPublishWeblayout'),
					'url=='+httpCgiPath+'?IdcService=PUBLISH_WEBLAYOUT_FILES&Include=admin_actions_summary');
				navBuilder.addChildNodeTo('ADMIN_ACTIONS', 'item', 'id==PUBLISH_STATIC_FILES', 'label=='+lc('wwAdminPublishStatic'),
					'url=='+httpCgiPath+'?IdcService=PUBLISH_STATIC_FILES&Include=admin_actions_summary');					
				navBuilder.addChildNodeTo('ADMIN_ACTIONS', 'item', 'id==PUBLISH_SCHEMA', 'label=='+lc('wwAdminPublishSchemaBase'),
					'url=='+httpCgiPath+'?IdcService=CONTROL_SCHEMA&PublishSchema=1&UserPublishingRequest=1&publishOperation=base&Include=admin_actions_summary');
				navBuilder.addChildNodeTo('ADMIN_ACTIONS', 'item', 'id==PUBLISH_SCHEMA_BASE', 'label=='+lc('wwAdminPublishSchema'),
					'url=='+httpCgiPath+'?IdcService=CONTROL_SCHEMA&PublishSchema=1&UserPublishingRequest=1&publishOperation=full&Include=admin_actions_summary');
				navBuilder.addChildNodeTo('ADMIN_ACTIONS', 'item', 'id==TEST_EMAIL', 'label=='+lc('wwTestEmailFormLink'),
								'url=='+httpCgiPath+'?IdcService=GET_DOC_PAGE&Action=GetTemplatePage&Page=TEST_EMAIL_ENTRY_FORM');

				if (isContentRefineryPresent)
				{
					navBuilder.addChildNodeTo('ADMINISTRATION', 'collection', 'id==REFINERY_ADMIN', 'label=='+lc('wwRefineryAdmin'));					
					navBuilder.addChildNodeTo('REFINERY_ADMIN', 'item', 'id==FILE_FORMATS_WIZARD', 'label=='+lc('wwFileFormatsWizard'),
						'url=='+httpCgiPath+'?IdcService=DOC_FORMATS_WIZARD');
				}
				navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==PROVIDERS', 'label=='+lc('wwProviders'),
					'url=='+httpCgiPath+'?IdcService=GET_ALL_PROVIDERS');
				navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==FILTER_ADMIN', 'label=='+lc('wwFilterAdmin'),
					'url=='+httpCgiPath+'?IdcService=GET_FILTER_ADMIN_PAGE');

				if (isDynamicConverterEnabled)
					navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==TEMPLATE_CONVERSIONS', 'label=='+lc('wwTemplateConversions'),
						'url=='+httpCgiPath+'?IdcService=GET_TEMPLATE_CONVERSIONS');

				if (isJspServerEnabled)
					navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==JSP_SERVER_WEB_APP_ADMIN', 'label=='+lc('wwJspServerWebAppAdmin'),
						'url=='+httpCgiPath+'?IdcService=GET_ADMIN_PAGE&Action=GetTemplatePage&Page=WEB_APP_CONFIRM');
			}

			if (isSysManager)
				navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==ADMIN_SERVER', 'label=='+lc('wwAdminServer'),
					'url=='+httpAdminCgiPath+'?IdcService=GET_ROOT_IDC_ADMIN_PAGE', 'target==_blank');

			if (userIsAdmin)
			{
				navBuilder.addChildNodeTo('ADMINISTRATION', 'item', 'id==ENV_PACKAGER', 'label=='+lc('wwEnvironmentPackager'),
					'url=='+httpCgiPath+'?IdcService=GET_PACKAGE_ENVIRONMENT_PAGE');
			}
		}
	}
	else
	{
		navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==LOGIN', 'label=='+lc('wwLogin'),
			'url=='+httpCgiPath+'?IdcService=LOGIN&Action=GetTemplatePage&Page=HOME_PAGE&Auth=Internet', 'target==_top');

		if(allowIntranetUsers)
			navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==MICROSOFT_LOGIN', 'label=='+lc('wwMsLogin'),
				'url=='+httpCgiPath+'?IdcService=LOGIN&Action=GetTemplatePage&Page=HOME_PAGE&Auth=Intranet');
		if(registerUsers)
			navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==SELF_REGISTRATION', 'label=='+lc('wwSelfReg'),
				'url=='+httpCgiPath+'?IdcService=GET_SELF_REGISTER_PAGE&Action=GetTemplatePage&Page=SELF_REGISTER_USER');
	}
	
	navBuilder.addChildNodeTo('NAVTREE', 'item', 'id==HELP', 'label==' + lc('wwHelp'),
			'url==javascript:top.launchHelp()', 'target==');
    
}

//
// Confidential and Proprietary for Stellent, Inc.
//
// This computer program contains valuable, confidential, and
// proprietary information.  Disclosure, use, or reproduction
// without the written authorization of Stellent is prohibited.
// This unpublished work by Stellent is protected by the laws
// of the United States and other countries.  If publication
// of this computer program should occur, the following notice
// shall apply:
//
// Copyright (c) 2003-2006 Stellent, Inc.
// All rights reserved.
//
// $Id: xmldoc.js 51760 2006-12-13 00:58:06Z rpetty $
//


///////////////////////////////////////////////////////
// Template: XMLDOC_JS
// Class: javascript:common
// Location: resources/layouts/xmldoc.js
///////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////
// WARNING: This file is generated by a Content Server template 
// and is then published to the weblayout directory. Any 
// changes made to the weblayout copy will be automatically 
// overwritten by the Content Server.
//-----------------------------------------------------------------
// Javascript XML Parser Version 1.0
// by Nicholas C. Zakas
// February 12, 2001
//-----------------------------------------------------------------
// Software License
// Copyright (c) 2001 Nicholas C. Zakas.  All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer. 
//
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materials provided with the
//    distribution.
//
// 3. The end-user documentation included with the redistribution,
//    if any, must include the following acknowledgment:  
//       "This product includes software developed by the
//        Nicholas C. Zakas (http://www.nczonline.net/)."
//    Alternately, this acknowledgment may appear in the software itself,
//    if and wherever such third-party acknowledgments normally appear.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED.  IN NO EVENT SHALL NICHOLAS C. ZAKAS  BE LIABLE FOR ANY 
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------
// Any questions, comments, or suggestions should be e-mailed to 
// nicholas@nczonline.net.  For more information, please visit
// http://www.nczonline.net/.
//
// Also Required:
//	arrayex.js
//
// Revision history:
//	February 12, 2001 - Released Version 1.0
//-----------------------------------------------------------------
// This file is separated into two sections:
//	1. Objects and object methods
//	2. Helper functions
//
// Also required:
//	arrayex.js
//----------------------------------------------------------------

//node types (note: some types not used)
var NODE_ELEMENT = 1;
var NODE_ATTRIBUTE = 2;
var NODE_TEXT = 3;
var NODE_CDATA_SECTION = 4;
var NODE_ENTITY_REFERENCE = 5;
var NODE_ENTITY = 6;
var NODE_PROCESSING_INSTRUCTION = 7;
var NODE_COMMENT = 8;
var NODE_DOCUMENT = 9;
var NODE_DOCUMENT_TYPE = 10;
var NODE_DOCUMENT_FRAGMENT = 11;
var NODE_NOTATION = 12;

//error messages
var ERR_NO_DOCUMENT_ELEMENT = "Error! No documentElement specified!";

//----------------------------------------------------------------
// 1: OBJECTS AND OBJECT METHODS
//----------------------------------------------------------------

//-----------------------------------------------------------------
// Object jsXMLAttribute
// This object is akin to IXMLDOMAttribute object.
//
// Parameters:
//	name (String) - the name of the attribute.
//	value (String) - the value of the attribute.
//-----------------------------------------------------------------
function jsXMLAttribute(name, value) {
	this.name = name;
	this.value = value;
}

//-----------------------------------------------------------------
// Object jsXMLNode
// This object is akin to IXMLDOMNode object.
//
// Parameters:
//	None.
//-----------------------------------------------------------------
function jsXMLNode() {

	//attributes
	this.attributes = new Array;
	this.childNodes = new Array;
	this.firstChild = null;
	this.lastChild = null;
	this.namespaceURI = "";
	this.nextSibling = null;
	this.nodeName = "";
	this.nodeType = -1;
	this.ownerDocument = null;
	this.parentNode = null;
	this.previousSibling = null;
	
	//methods
	this.appendChild = _jsXMLNode_appendChild;
	this.cloneNode = _jsXMLNode_cloneNode;
	this.findAttribute = _jsXMLNode_findAttribute;
	this.findChild = _jsXMLNode_findChild;
	this.getAttribute = _jsXMLNode_getAttribute;
	this.hasChildNodes = _jsXMLNode_hasChildNodes;
	this.insertBefore = _jsXMLNode_insertBefore;
	this.removeAttribute = _jsXMLNode_removeAttribute;
	this.removeChild = _jsXMLNode_removeChild;
	this.replaceChild = _jsXMLNode_replaceChild;
	this.setAttribute = _jsXMLNode_setAttribute;
}

//-----------------------------------------------------------------
// Method jsXMLNode.appendChild()
// This method adds a new child to this Nodes childNodes list.
//
// Parameters:
//	new_node (jsXMLNode) - the node to add.
// Returns:
//	A jsXMLNode object representing new_node.
//-----------------------------------------------------------------
function _jsXMLNode_appendChild(new_node) {

	//set the parentNode
	new_node.parentNode = this;
	
	//set the node's information
	new_node.ownerDocument = this.ownerDocument;
	
	//assign value for previous sibling
	if (this.childNodes.length > 0) {
		new_node.previousSibling = 	this.childNodes[this.childNodes.length - 1];
		new_node.previousSibling.nextSibling = new_node;
	}
	
	//add this new_node to the array of childNodes
	this.childNodes[this.childNodes.length] = new_node;
	
	//return the new new_node
	return new_node;
}

//-----------------------------------------------------------------
// Method jsXMLNode.cloneNode()
// This method duplicates the current node and returns it as the value.
//
// Parameters:
//	recurse_children (boolean) - copy all of the Node's children too?
// Returns:
//	A jsXMLNode object that is a copy of the current Node.
//-----------------------------------------------------------------
function _jsXMLNode_cloneNode(recurse_children) {

	//create a new element
	var objNode = new jsXMLNode(this.tagName);
	
	//copy over the attributes
	//objNode.attributes = new Array(this.attributes);
	
	// bex mods
	objNode.attributes = new Array();
	for (var i=0; i<this.attributes.length; i++)
	{
		var newAttr = new jsXMLAttribute(this.attributes[i].name, this.attributes[i].value);
		objNode.attributes[i] = newAttr;
	}
	objNode.tagName = this.tagName;
	objNode.nodeType = this.nodeType;
	// end bex mods
	
	//copy over other info
	objNode.baseName = this.baseName;
	objNode.prefix = this.prefix;
	
	
	
	//copy the children?
	if (recurse_children) {
	
		//copy each of the children, recursively
		for (var i=0; i < this.childNodes.length; i++) {
			//clone the child
			var objChild = this.childNodes[i].cloneNode(true);
			
			//copy it into the new childNodes array
			objNode.appendChild(objChild);
		}
	}
	
	return objNode;
}

//-----------------------------------------------------------------
// Method jsXMLNode.findChild()
// This method finds the location of a given child in the childNodes
// list.
//
// Parameters:
//	this_node (jsXMLNode) - the child to find.
// Returns:
//	An integer representing the child location in the list, -1 if not found.
//-----------------------------------------------------------------
function _jsXMLNode_findChild(this_node) {

	//iterator, found flag, return object
	var i = 0, bFound = false;
	
	//search
	while (i < this.childNodes.length && !bFound) {
		if (this.childNodes[i] == this_node)
			bFound = true;
		else
			i++;
	}
	
	//return the object
	return (bFound ? i : -1);
}

//-----------------------------------------------------------------
// Method jsXMLNode.hasChildNodes()
// This method determines if this Node has any childNodes.
//
// Parameters:
//	Nothing.
// Returns:
//	A boolean - true if the Node has childNodes, false if not.
//-----------------------------------------------------------------
function _jsXMLNode_hasChildNodes() {
	return (this.childNodes.length > 0);
}

//-----------------------------------------------------------------
// Method jsXMLNode.insertBefore()
// This method adds a new node into the spot before the given node.
//
// Parameters:
//	new_node (jsXMLNode) - the node to add.
//	this_node (jsXMLNode) - the place to put new_node before.
// Returns:
//	Nothing.
//-----------------------------------------------------------------
function _jsXMLNode_insertBefore(new_node, this_node) {

	//check for no valid node
	if (this_node == null) {
		this.appendChild(new_node);
		return;
	}
	
	//find the child
	var iLoc = this.findChild(this_node);
	
	//get front part of array
	var arrFront = this.childNodes.slice(0, iLoc);
	
	//get back of array
	var arrBack = this.childNodes.slice(iLoc, this.childNodes.length);
	
	//delete old array
	delete this.childNodes;
	
	//create new array
	this.childNodes = arrFront.concat(new_node);
	
	//assign sibling info
	if (this.childNodes.length > 2) {
		new_node.previousSibling = 	this.childNodes[this.childNodes.length - 2];
		new_node.previousSibling.nextSibling = new_node;
	} else {
		new_node.previousSibling = 	null;
	}
	
	//add the end of the array
	if (arrBack.sort)
	{
		var i;
		for (i = 0; i < arrBack.length; i++)
		{
			this.childNodes.push(arrBack[i]);
		}
	}
	else
	{
		this.childNodes.push(arrBack);
	}
	
	//assign sibling info
	new_node.nextSibling = this.childNodes[iLoc+1];
	
	//set the parentNode
	new_node.parentNode = this;
}

//-----------------------------------------------------------------
// Method jsXMLNode.removeChild()
// This method removes a given child.
//
// Parameters:
//	this_node (jsXMLNode) - the node to remove.
// Returns:
//	A jsXMLNode object representing this_node.
//-----------------------------------------------------------------
function _jsXMLNode_removeChild(this_node) {

	//find the child
	var iLoc = this.findChild(this_node);

	//if the child is found, remove it
	if (iLoc > -1)
		this.childNodes.remove(iLoc);
	
	//return the old node
	return this_node;
}

//-----------------------------------------------------------------
// Method jsXMLNode.replaceChild()
// This method replaces the given child with a new node.
//
// Parameters:
//	new_node (jsXMLNode) - the node to add in old_node's place.
//	old_node (jsXMLNode) - the place to put new_node.
// Returns:
//	A jsXMLNode object representing old_node.
//-----------------------------------------------------------------
function _jsXMLNode_replaceChild(new_node, old_node) {

	//find the child
	var iLoc = this.findChild(old_node);
	
	//replace this location with the new node
	this.childNodes[iLoc] = new_node;
	
	//update siblings
	new_node.nextSibling = old_node.nextSibling;
	new_node.previousSibling = old_node.previousSibling;
	old_node.nextSibling = null;
	old_node.previousSibling = null;
	
	//update owner document
	new_node.ownerDocument = old_node.ownerDocument;
	old_node.ownerDocument = null;

	//return the old node
	return old_node;
}

//-----------------------------------------------------------------
// Method jsXMLNode.findAttribute()
// This method finds the location of a given attribute in the attributes
// list.
//
// Parameters:
//	attr_name (String) - the attribute name to find.
// Returns:
//	An integer representing the attribute location in the list, -1 if not found.
//-----------------------------------------------------------------
function _jsXMLNode_findAttribute(attr_name) {

	//iterator, found flag, return object
	var i = 0, bFound = false;
	
	//search
	while (i < this.attributes.length && !bFound) {
		if (this.attributes[i].name == attr_name)
			bFound = true;
		else
			i++;
	}
	
	//return the object
	return (bFound ? i : -1);
}

//-----------------------------------------------------------------
// Method jsXMLNode.getAttribute()
// This method gets the string value for the given attribute name.
//
// Parameters:
//	attr_name (String) - the attribute name to retrieve the value of.
// Returns:
//	The String value of the attribute, an empty string if it doesn't exist.
//-----------------------------------------------------------------
function _jsXMLNode_getAttribute(attr_name) {

	//find the attribute
	var iLoc = this.findAttribute(attr_name);
	var objAttribute = (iLoc > -1 ? this.attributes[iLoc] : null);
	
	//if it exists, return the value
	//return (objAttribute.value ? objAttribute.value : "");
	
	// bex mods
	return ((objAttribute && objAttribute.value) ? objAttribute.value : "");
	// end bex mods
}

//-----------------------------------------------------------------
// Method jsXMLNode.removeAttribute()
// This method removes an attribute from this element.
//
// Parameters:
//	attr_name (String) - the attribute name to remove.
// Returns:
//	Nothing.
//-----------------------------------------------------------------
function _jsXMLNode_removeAttribute(attr_name) {

	//find the attribute
	var iLoc = this.findAttribute(attr_name);
	
	//if the attribute is found, remove it
	if (iLoc > -1)
		this.attributes.remove(iLoc);
}


//-----------------------------------------------------------------
// Method jsXMLNode.setAttribute()
// This method sets an attribute to a given value.
//
// Parameters:
//	attr_name (String) - the name of the attribute.
//	value (String) - the value of the attribute.
// Returns:
//	Nothing.
//-----------------------------------------------------------------
function _jsXMLNode_setAttribute(attr_name, value) {

	//find the attribute
	var iLoc = this.findAttribute(attr_name);
	var objAttribute = (iLoc > -1 ? this.attributes[iLoc] : null);
	
	//if it exists, set the value
	if (objAttribute != null)
		objAttribute.value = value;
	else {
		//it doesn't exist, so create it
		objAttribute = new jsXMLAttribute(attr_name, value);
		
		//add it to the attributes array
		this.attributes[this.attributes.length] = objAttribute;
	}
}

//-----------------------------------------------------------------
// Object jsXMLProcessingInstruction
// This object is akin to IXMLDOMProcessingInstruction object.
//
// Parameters:
//	none.
//-----------------------------------------------------------------
function jsXMLProcessingInstruction() {

	//inherited from hsXMLNode
	this.superclass = jsXMLNode;
	this.superclass();
	
	//properties
	this.nodeType = NODE_PROCESSING_INSTRUCTION;
	
	//methods
	this.toString = _jsXMLProcessingInstruction_toString;
}

//-----------------------------------------------------------------
// Method jsXMLProcessingInstruction.toString()
// This method returns the XML contained in the element.
//
// Parameters:
//	None.
// Returns:
//	An XML string.
//-----------------------------------------------------------------
function _jsXMLProcessingInstruction_toString() {

	//declare iterator and return string
	var i = 0, retstr = "";
	
	//create opening tag
	retstr = "<?xml";

	//add this tag's attributes to the string
	for (i=0; i < this.attributes.length; i++)
		retstr += " " + this.attributes[i].name + "=\"" + this.attributes[i].value + "\"";

	//end the tag
	retstr += "?>";

	//asign the XML	
	return retstr;
}

//-----------------------------------------------------------------
// Object jsXMLElement
// This object is akin to IXMLDOMElement object.
//
// Parameters:
//	tagName (String) - the tagName for the element.
//-----------------------------------------------------------------
function jsXMLElement(tagName) {

	//inherited from hsXMLNode
	this.superclass = jsXMLNode;
	this.superclass();
	
	//attributes
	this.nodeType = NODE_ELEMENT;
	this.tagName = tagName;
	
	//check for tagname in the form prefix:baseName
	if (tagName.indexOf(":") > -1) {
		this.prefix = tagName.substr(0, tagName.indexOf(":"));
		this.baseName = tagName.substr(tagName.indexOf(":") + 1, tagName.length);	
	} else {
		this.prefix = "";
		this.baseName = "";
	}
	
	//methods
	this.getElementsByTagName = _jsXMLElement_getElementsByTagName;
	this.toString = _jsXMLElement_toString;
}


//-----------------------------------------------------------------
// Method jsXMLElement.getElementsByTagName()
// This method creates a list of elements with a given tag name.
//
// Parameters:
//	tagName (String) - the tagName of the elements you are looking for.
// Returns:
//	An Array of jsXMLElement objects with the given tagName.
//-----------------------------------------------------------------
function _jsXMLElement_getElementsByTagName(tagName) {

	//the array of elements, begins empty
	var arrResult = new Array;

	//check this node
	if (this.tagName == tagName)
		arrResult.push(this);
		
	//check the childNodes
	for(var i=0; i < this.childNodes.length; i++) {
		if (this.childNodes[i].nodeType == NODE_ELEMENT) {
			
			//get the results for this child
			var arrChildResult = this.childNodes[i].getElementsByTagName(tagName);
			
			//add the results to the array
			arrResult.push(arrChildResult);
		}			
	}
	
	//return the resulting array
	return arrResult;
}

//-----------------------------------------------------------------
// Method jsXMLElement.toString()
// This method returns the XML contained in the element.
//
// Parameters:
//	None.
// Returns:
//	An XML string.
//-----------------------------------------------------------------
function _jsXMLElement_toString() {

	//declare iterator and return string
	var i = 0, retstr = "";
	
	//create opening tag
	retstr = "<" + this.tagName;

	//add this tag's attributes to the string
	for (i=0; i < this.attributes.length; i++)
		retstr += " " + this.attributes[i].name + "=\"" + this.attributes[i].value + "\"";

	//end the tag
	if (!this.hasChildNodes()) {
		retstr += "/>";
	} else {
	
		//end the tag
		retstr += ">";
	
		//add XML for the children of this node
		//if there are children, then don't count the text for this tag
		//otherwise, include the text
		if (this.hasChildNodes()) {
			for (i=0; i < this.childNodes.length; i++)
				retstr += this.childNodes[i].toString();
		}

		//create closing tag
		retstr += "</" + this.tagName + ">";
	}

	//asign the XML	
	return retstr;
}

//-----------------------------------------------------------------
// This object is akin to IXMLDOMCharacterData object.
//
// Parameters:
//	data (String) - the data to hold.
//-----------------------------------------------------------------
function jsXMLCharacterData(data) {

	//assign text data
	this.data = data;
	this.nextSibling = null;
	this.ownerDocument = null;
	this.parentNode = null;
	this.previousSibling = null;
	
	//methods
	this.appendData = _jsXMLCharacterData_appendData;
	this.deleteData = _jsXMLCharacterData_deleteData;
	this.insertData = _jsXMLCharacterData_insertData;
	this.replaceData = _jsXMLCharacterData_replaceData;
	this.splitText = _jsXMLCharacterData_splitText;
	this.substringData = _jsXMLCharacterData_substringData;
	this.toString = _jsXMLCharacterData_toString;
}

//-----------------------------------------------------------------
// Method jsXMLCharacterData.appendData()
// This method appends the given text to the node data.
//
// Parameters:
//	text(String) - the text to append to th node data.
// Returns:
//	Nothing.
//-----------------------------------------------------------------
function _jsXMLCharacterData_appendData(text) {
	this.data += text;
}

//-----------------------------------------------------------------
// Method jsXMLCharacterData.deleteData()
// This method deletes the characters between char_offset and
// char_offset + num_chars.
//
// Parameters:
//	char_offset (int) - the index of the character to begin with.
//	num_chars (int) - the number of characters to delete.
// Returns:
//	Nothing.
//-----------------------------------------------------------------
function _jsXMLCharacterData_deleteData(char_offset, num_chars) {

	//get the characters up to and including that at char_offset
	var strFront = this.data.substr(0, char_offset);
	
	//get the characters after char_offset
	var strBack = this.data.substr(num_chars + char_offset, this.data.length - strFront.length - num_chars);
	
	//now merge these two
	this.data = strFront + strBack;
}

//-----------------------------------------------------------------
// Method jsXMLCharacterData.insertData()
// This method inserts the given text into the data at the location
// specified by char_offset.
//
// Parameters:
//	char_offset (int) - the index of the character to begin with.
//	text (String) - the text to insert into the node data.
// Returns:
//	Nothing.
//-----------------------------------------------------------------
function _jsXMLCharacterData_insertData(char_offset, text) {

	//get the characters up to and including that at char_offset
	var strFront = this.data.substr(0, char_offset);
	
	//get the characters after char_offset
	var strBack = this.data.substr(char_offset, this.data.length - strFront.length);
	
	//now merge these two with the inserted text
	this.data = strFront + text + strBack;
}

//-----------------------------------------------------------------
// Method jsXMLCharacterData.replaceData()
// This method takes a String and replaces the characters between
// char_offset and char_offset + num_chars with it.
//
// Parameters:
//	char_offset (int) - the index of the character to begin with.
//	num_chars (int) - the number of characters to replace.
//	text (String) - the string to insert into this node's data.
// Returns:
//	A string.
//-----------------------------------------------------------------
function _jsXMLCharacterData_replaceData(char_offset, num_chars, text) {

	//get the characters up to and including that at char_offset
	var strFront = this.data.substr(0, char_offset);
	
	//get the characters after char_offset
	var strBack = this.data.substr(num_chars + char_offset, this.data.length - strFront.length - num_chars);
	
	//now merge these two
	this.data = strFront + text + strBack;
}

//-----------------------------------------------------------------
// Method jsXMLCharacterData.splitText()
// This method splits this node into two nodes, with the data being
// split at char_offset.
//
// Parameters:
//	char_offset (int) - the index of the character to split at.
// Returns:
//	A string.
//-----------------------------------------------------------------
function _jsXMLCharacterData_splitText(char_offset) {
	//get the characters up to and including that at char_offset
	var strFront = this.data.substr(0, char_offset);
	
	//get the characters after char_offset
	var strBack = this.data.substr(char_offset, this.data.length - strFront.length);
	
	//now merge these two
	this.data = strFront;
	
	//create a new text node and add it to its parent
	var objNode = null;
	
	//create a new node
	switch(this.nodeType) {
		case NODE_TEXT:
			objNode = new jsXMLText(strBack);
			break;
		case NODE_CDATA_SECTION:
			objNode = new jsXMLCDataSection(strBack);
			break;
		case NODE_COMMENT:
			objNode = new jsXMLComment(strBack);
	}

	//add it after this one
	this.parentNode.insertBefore(objNode, this.nextSibling);
}

//-----------------------------------------------------------------
// Method jsXMLCharacterData.substringData()
// This method returns a String representing the characters between
// char_offset and char_offset + num_chars.
//
// Parameters:
//	char_offset (int) - the index of the character to begin with.
//	num_chars (int) - the number of characters to copy.
// Returns:
//	A string.
//-----------------------------------------------------------------
function _jsXMLCharacterData_substringData(char_offset, num_chars) {
	return this.data.substr(char_offset, num_chars);
}

//-----------------------------------------------------------------
// Method jsXMLCharacterData.toString()
// This method returns the data contained in the node.
//
// Parameters:
//	None.
// Returns:
//	A string.
//-----------------------------------------------------------------
function _jsXMLCharacterData_toString() {
	return this.data;
}

//-----------------------------------------------------------------
// Object jsXMLText
// This object is akin to IXMLDOMText ActiveX object.
//
// Parameters:
//	data (String) - text data.
//-----------------------------------------------------------------
function jsXMLText(data) {

	//inherited from hsXMLNode
	this.superclass = jsXMLCharacterData;
	this.superclass();

	//properties
	this.data = data;
	
	//assign node type
	this.nodeType = NODE_TEXT;
}

//-----------------------------------------------------------------
// Object jsXMLCDataSection
// This object is akin to IXMLDOMCDataSection ActiveX object.
//
// Parameters:
//	data (String) - text data.
//-----------------------------------------------------------------
function jsXMLCDataSection(data) {

	//inherited from jsXMLCharacterData
	this.superclass = jsXMLCharacterData;
	this.superclass();

	//propertoes
	this.data = data;
	this.nodeType = NODE_CDATA_SECTION;
	
	//methods
	this.toString = _jsXMLCDataSection_toString;
}

//-----------------------------------------------------------------
// Method jsXMLCDataSection.toString()
// This method returns the data contained in the node as a CDATA section
// string.
//
// Parameters:
//	None.
// Returns:
//	A string.
//-----------------------------------------------------------------
function _jsXMLCDataSection_toString() {
	return "<![CDATA[" + this.data + "]]>";
}

//-----------------------------------------------------------------
// Object jsXMLComment
// This object is akin to IXMLDOMComment ActiveX object.
//
// Parameters:
//	data (String) - text data.
//-----------------------------------------------------------------
function jsXMLComment(data) {

	//inherited from jsXMLCharacterData
	this.superclass = jsXMLCharacterData;
	this.superclass();
	
	//properties
	this.data = data;
	this.nodeType = NODE_COMMENT;
	
	//methods
	this.toString = _jsXMLComment_toString;
}

//-----------------------------------------------------------------
// Method jsXMLComment.toString()
// This method returns the data contained in the node as a comment
// string.
//
// Parameters:
//	None.
// Returns:
//	A string.
//-----------------------------------------------------------------
function _jsXMLComment_toString() {
	return "<!--" + this.data + "-->";
}

//-----------------------------------------------------------------
// Object jsXMLDocument
// This object is akin to IXMLDOMDocument ActiveX object.
//
// Parameters:
//	tagName (String) - the tagName of the document Element.
//-----------------------------------------------------------------
function jsXMLDocument() {

	//properties
	this.documentElement = null;
	this.parseError = false;
	
	//methods
	this.createElement = _jsXMLDocument_createElement;
	this.createNodeFromXML = _jsXMLDocument_createNodeFromXML;
	this.getElementsByTagName = _jsXMLDocument_getElementsByTagName;
	this.loadXML = _jsXMLDocument_loadXML;
	this.toString = _jsXMLDocument_toString;
}

//-----------------------------------------------------------------
// Method jsXMLDocument.createElement()
// This method creates an element with the given tagName and returns
// it as the function result.
//
// Parameters:
//	None.
// Returns:
//	A jsXMLElement object.
//-----------------------------------------------------------------
function _jsXMLDocument_createElement(tagName) {
	return new jsXMLElement(tagName);
}

//-----------------------------------------------------------------
// Method jsXMLDocument.toString()
// This method returns the XML contained in the document.
//
// Parameters:
//	None.
// Returns:
//	An XML string.
//-----------------------------------------------------------------
function _jsXMLDocument_toString() {
	return "<?xml version=\"1.0\"?>" + this.documentElement.toString();
}

//-----------------------------------------------------------------
// Method jsXMLDocument.loadXML()
// This method loads a string of XML and creates the appropriate
// JavaScript DOM to represent it.
//
// Parameters:
//	strXML (String) - an XML string.
// Returns:
//	Nothing.
//-----------------------------------------------------------------
function _jsXMLDocument_loadXML(strXML) {

	//node pointer
	var curNode = null;
	
	//stack of nodes
	var arrStack = new Array;
	
	//array of tokens in the XML
	var arrTokens = getTokensFromXML(strXML);

	//take care of document element
	this.documentElement = this.createNodeFromXML(arrTokens[1]);
	
	//set the current node to the documentElement
	curNode = this.documentElement;
	
	//evaluate all tokens
	for (var i=2; i < arrTokens.length; i++) {
		
		//check to see if this is an opening tag or a closing tag
		if (arrTokens[i].substr(0,2) == "</") {

			//closing tag, pop last parent off the stack
			curNode = arrStack.pop();

		} else {
			//create the new node
			var objNode = this.createNodeFromXML(arrTokens[i]);
			
			//add this node to its parent
			curNode.appendChild(objNode);
			
			//check to see if this node is closed or not
			if ((objNode.nodeType == NODE_ELEMENT) && (arrTokens[i].substr(arrTokens[i].length-2, 2) != "/>")) {

				//push old parent onto the stack
				arrStack.push(curNode);
				
				//set new parent
				curNode = objNode;
			}
		}	
	}	
}

//-----------------------------------------------------------------
// Method jsXMLDocument.getElementsByTagName()
// This method creates a list of elements with a given tag name.
//
// Parameters:
//	tagName (String) - the tagName of the elements you are looking for.
// Returns:
//	An Array of jsXMLElement objects with the given tagName.
//-----------------------------------------------------------------
function _jsXMLDocument_getElementsByTagName(tagName) {

	//check to see if there is a documentElement, if there is,
	//call the documentElement's getElementsByTagName method.
	if (!this.documentElement)
		alert(ERR_NO_DOCUMENT_ELEMENT);
	else
		return this.documentElement.getElementsByTagName(tagName);
	
}

//-----------------------------------------------------------------
// Method jsDocument.createNodeFromXML()
// This function takes a string and converts it into a jsXMLElement.
// The string must be in the format of:
//		<[tagName] [attrib1name]="[attrib1value]"...[attribNname]="[attribNvalue]"
// Note the lack of a closing ">"
//
// Parameters:
//	strXML (String) - an XML string in the above form.
// Returns:
//	A jsXMLElement object representing the string.
//-----------------------------------------------------------------
function _jsXMLDocument_createNodeFromXML(strXML) {
	
	//determine what type of data this is
	switch(strXML.charAt(0)) {
	
		//it's some sort of tag
		case '<':
			
			//get the tagName
			var strTagName = getTagNameFromXML(strXML);

			//determine what this is
			if (strTagName == "?xml") {
				//it's a processing instruction, ditch the closing ?>
				strXML = strXML.substr(0, strXML.length - 2);
				
				//get the attributes
				var arrAttributes = strXML.split(" ");

				//create the new element
				var objNode = new jsXMLProcessingInstruction;

				if (arrAttributes.length > 1) {
					//now get all the attributes
					for (var i=1; i < arrAttributes.length; i++) {
				
						//get the current string
						var strAttribute = arrAttributes[i];
					
						//make sure that this is more than just a blank space
						if (strAttribute.length > 1) {
							if (strAttribute.charAt(strAttribute.length-1) == "/")
								strAttribute = strAttribute.substr(0, strAttribute.length - 1);
							
							//get the name/value pair
							var arrNV = strAttribute.split("=");
						
							//set the attribute value (make sure to cut off quotes in the value)
							objNode.setAttribute(arrNV[0], arrNV[1].substr(1, arrNV[1].length-2));
						}	
					}	
				}

				//return the created node
				return objNode;
			} else if (strTagName == "![CDATA[") {
				return new jsXMLCDataSection(getCDataText(strXML));
			} else if (strTagName == "!--") {
				return new jsXMLComment(getCommentText(strXML));
			} else {

				//it's an HTML-like tag, ditch the closing signal
				strXML = strXML.substr(0, strXML.length - 1);
				
				//get the attributes
				var arrAttributes = strXML.split(" ");

				//create the new element
				var objNode = new jsXMLElement(strTagName);

				if (arrAttributes.length > 1) {
					//now get all the attributes
					for (var i=1; i < arrAttributes.length; i++) {
				
						//get the current string
						var strAttribute = arrAttributes[i];
					
						//make sure that this is more than just a blank space
						if (strAttribute.length > 1) {
							if (strAttribute.charAt(strAttribute.length-1) == "/")
								strAttribute = strAttribute.substr(0, strAttribute.length - 1);
							
							//get the name/value pair
							var arrNV = strAttribute.split("=");
						
							//set the attribute value (make sure to cut off quotes in the value)
							objNode.setAttribute(arrNV[0], arrNV[1].substr(1, arrNV[1].length-2));
						}	
					}	
				}

				//return the created node
				return objNode;
			} 
		
			//use the tagName
			break;
		
		//it's text
		default:
			//it's text
			objNode = new jsXMLText(strXML);
			
			//return the created node
			return objNode;
	}
}

//----------------------------------------------------------------
// 2: HELPER FUNCTIONS
//----------------------------------------------------------------
function getTokensFromXML(strXML) {

	var arrTemp = new Array;
	var arrTokens = new Array;
	
	//iterate through the characters
	for (var i=0; i < strXML.length; i++) {
		var c = strXML.charAt(i);
		
		//push this character into the temporary array
		if (c != '<')
			arrTemp.push(c);

		//check the value
		switch (c) {
			case '<':
				if (arrTemp.length > 0) {
					arrTokens.push(arrTemp.join(""));
					delete arrTemp;
					arrTemp = new Array;
				}
				arrTemp.push("<");
				break;
		 	case '>':
				arrTokens.push(arrTemp.join(""));
				delete arrTemp;
				arrTemp = new Array;
		}
	
	}
	
	return arrTokens;
}


function getTagNameFromXML(strXML) {

	//first check for comment
	if (strXML.indexOf("<!--") == 0)
		return "!--";
		
	//check for CDATA Section
	if (strXML.indexOf("<![CDATA[") == 0)
		return "![CDATA[";
	
	//get custom tag name
	var reTag = /<([\w\?\!\-\[]+)/;
	strXML.match(reTag);
	return RegExp.$1;
}

function getCommentText(strXML) {
	return strXML.substr(4, strXML.length - 7);
}

function getCDataText(strXML) {
	return strXML.substr(9, strXML.length - 12);
}
/*
 * Confidential and Proprietary for Oracle Corporation
 *
 * This computer program contains valuable, confidential, and
 * proprietary information.  Disclosure, use, or reproduction
 * without the written authorization of Oracle is prohibited.
 * This unpublished work by Oracle is protected by the laws
 * of the United States and other countries.  If publication
 * of this computer program should occur, the following notice
 * shall apply:
 *
 * Copyright (c) 2006-2007 Stellent, Inc.
 * All rights reserved.
 * Copyright (c) 2007-2009 Oracle Corp.
 * All rights reserved.
 *
 * $Id: commonSearch.js 82121 2010-02-24 15:56:08Z kjorisse $
 */


//////////////////////////////////////////////////////////////////
// Template: COMMON_SEARCH_JS
// Class: javascript:common
// Location: resources/layouts/commonSearch.js
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
// WARNING: This file is generated by a Content Server template 
// and is then published to the weblayout directory. Any 
// changes made to the weblayout copy will be automatically 
// overwritten by the Content Server.
//////////////////////////////////////////////////////////////////

function showHideAdvancedQueryBuilder()
{
	toggleElemDisplay('queryBuilderAdvancedOptions');

	var link = document.getElementById("queryBuilderAdvancedText");
	if (document.getElementById("queryBuilderAdvancedOptions").style.display == 'none')
	{
		link.innerHTML=wwStrings["wwShowAdvancedOptionsQueryBuilder"];
	}
	else
	{
		link.innerHTML=wwStrings["wwHideAdvancedOptionsQueryBuilder"];
	}
}

function addHiddenQueryBuilderRow()
{
	addQueryBuilderRowEx(false);
}

function addQueryBuilderRow()
{
	addQueryBuilderRowEx(true);
}

var queryBuilderOperatorWidth = "9em";
var didCalculateQueryBuilderOperatorWidth = false;
function calculateQueryBuilderOperatorWidth()
{
	if (didCalculateQueryBuilderOperatorWidth)
	{
		return;
	}

	var rowNum = 0;
	var select = createQueryBuilderOpSelectEx(rowNum, SearchIntegerField, defaultIntegerOp);
	var width = getClientWidth(select);
	var tmpWidth;
	
	select = createQueryBuilderOpSelectEx(rowNum, SearchDateField, defaultDateOp);
	tmpWidth = getClientWidth(select);
	if (tmpWidth > width)
	{
		width = tmpWidth;
	}
	
	if (typeof(SearchZoneField) != "undefined")
	{
		select = createQueryBuilderOpSelectEx(rowNum, SearchZoneField, defaultZoneOp);
		tmpWidth = getClientWidth(select);
		if (tmpWidth > width)
		{
			width = tmpWidth;
		}
	}
	
	select = createQueryBuilderOpSelectEx(rowNum, SearchTextField, defaultOp);
	tmpWidth = getClientWidth(select);
	if (tmpWidth > width)
	{
		width = tmpWidth;
	}
	
	queryBuilderOperatorWidth = width + "px";
	didCalculateQueryBuilderOperatorWidth = true;
}

function addQueryBuilderRowEx(isVisible)
{
	currentRow = queryBuilderRowCounter;
	queryBuilderRowNumbers[queryBuilderRowNumbers.length] = currentRow;

	var section = document.getElementById("queryBuilderRows");
	var tr = document.createElement("tr");
	if (!isVisible)
	{
		tr.style.display = "none";
	}
	tr.id = "QB_row_" + currentRow;
	section.appendChild(tr);
	
	// AND-OR column
	var numVisibleRows = 0;
	for (var i = 0; i < queryBuilderRowNumbers.length - 1; i++)
	{
		var rowNum = queryBuilderRowNumbers[i];
		var row = document.getElementById("QB_row_" + rowNum);
		if (row.style.display != "none")
		{
			numVisibleRows++;
		}	
	}
	var td = document.createElement("td");
	td.id = "QB_andor_" + currentRow;
	tr.appendChild(td);
	
	var andOrSelect = createQueryBuilderAndOrSelect(currentRow);
	if (numVisibleRows == 0)
	{
		andOrSelect.style.display = "none";
	}
	td.appendChild(andOrSelect);
	
	// field column
	td = document.createElement("td");
	td.id = "QB_field_" + currentRow;
	tr.appendChild(td);
	var fieldSelect = createQueryBuilderFieldSelect(currentRow);
	td.appendChild(fieldSelect);
	
	// operation column
	calculateQueryBuilderOperatorWidth();
	td = document.createElement("td");
	td.id = "QB_op_" + currentRow;
	td.style.width = queryBuilderOperatorWidth; 
	tr.appendChild(td);
	
	// value column
	td = document.createElement("td");
	td.id = "QB_val_" + currentRow;
	tr.appendChild(td);
	
	// column for browse button, choice list options
	td = document.createElement("td");
	td.id = "QB_extra_" + currentRow;
	tr.appendChild(td);
	
	// final column for icons
	td = document.createElement("td");
	td.id = "QB_icons_" + currentRow;
	td.style.whiteSpace = "nowrap";
	td.style.width = "40px";
	tr.appendChild(td);
	
	queryBuilderRowCounter++;
	numQueryBuilderRows++;
	
	if (!isVisible)
	{
		queryBuilderHiddenRows[currentRow] = true;
	}
	
	if (queryBuilderRowNumbers.length > 1)
	{
		addQueryBuilderIcons(queryBuilderRowNumbers[queryBuilderRowNumbers.length - 2]);
	}
	
	buildQueryBuilderQueryText();
}

function createQueryBuilderFieldSelect(rowNum)
{
	var fieldSelect = document.createElement("select");
	fieldSelect.id = "QB_field_select_" + rowNum;
	var fields = g_schemaDefinition.fieldSettings;
	
	var option;
	for (var key in fields)
	{
		var field = fields[key];
		
		// This check catches some strange error where IE thinks there is an undefined field
		if (typeof(field.fieldName) != "undefined")
		{
			var fieldDef = getFieldDefinition(field.fieldName);
		
			if (fieldDef.isEnabled && fieldDef.isSearchable && !convertToBool(fieldDef.isPlaceholderField, false))
			{
				if (typeof g_hiddenFields[field.fieldName] == "undefined" || !g_hiddenFields[field.fieldName])
				{
					if (typeof g_excludedFields[field.fieldName] == "undefined" || !g_excludedFields[field.fieldName])
					{
						option = document.createElement("option");
						option.text = idc.schema.getFieldCaption(field.fieldName);
						option.value = field.fieldName;
						appendOption(fieldSelect, option);
					}
				}
			}
		}
	}
	
	sortSelect(fieldSelect);
	
	option = document.createElement("option");
	option.text = "- - - - - - - - - - - - - - -";
	option.value = "";
	prependOption(fieldSelect, option);
	
	option = document.createElement("option");
	option.text = wwStrings["wwSelectAField"];
	option.value = "";
	prependOption(fieldSelect, option);
	
	fieldSelect.selectedIndex = 0;
	fieldSelect.onchange = function(){didChangeQueryBuilderField(rowNum);}
	
	return fieldSelect;
}

function createQueryBuilderAndOrSelect(rowNum)
{
	var select = document.createElement("select");
	select.id = "QB_andor_select_" + rowNum;
	select.onchange = function(){buildQueryBuilderQueryText();}
	
	var option = document.createElement("option");
	option.text = wwStrings["wwQueryBuilderAnd"];
	option.value = "and";
	appendOption(select, option);
	
	option = document.createElement("option");
	option.text = wwStrings["wwQueryBuilderOr"];
	option.value = "or";
	appendOption(select, option);
	
	return select;
}

function createQueryBuilderOpSelect(rowNum)
{
	var fieldSelect = document.getElementById("QB_field_select_" + rowNum);
	var fieldName = fieldSelect.value;
	var fieldDef = getFieldDefinition(fieldName);
	
	var opArray = null;
	var defaultOperator = null;
	
	switch (fieldDef.type)
	{
		case "Int":
		case "Decimal":
			opArray = SearchIntegerField;
			defaultOperator = defaultIntegerOp;
			break;
		case "Date":
			opArray = SearchDateField;
			defaultOperator = defaultDateOp;
			break;
		default:
			if (fieldDef.isZoneSearchField[searchEngineName])
			{
				opArray = SearchZoneField;
				defaultOperator = defaultZoneOp;
			}
			else if (fieldDef.viewName)
			{
				opArray = SearchTextField;
				defaultOperator = defaultNBFieldOp;
			}
			else
			{
				opArray = SearchTextField;
				defaultOperator = defaultOp;
			}
			break;
	}

	if (fieldName == 'xWebsiteSection')
	{
		opArray = WebsiteSectionSearchFields;
		defaultOperator = defaultOp;
	}
	if ( ( fieldName == 'xWebsites' ) || ( fieldName == 'xDontShowInListsForWebsites' ) )
	{
		opArray = WebsitesSearchFields;
		defaultOperator = defaultOp;
	}
	return createQueryBuilderOpSelectEx(rowNum, opArray, defaultOperator);
}

function createQueryBuilderOpSelectEx(rowNum, opArray, defaultOperator)
{
	var select = document.createElement("select");
	var selectedIndex = 0;
	select.id = "QB_operator_select_" + rowNum;
	select.onchange = function(){buildQueryBuilderQueryText();}
	
	for (var i = 0; i < opArray.length; i++)
	{
		var option = document.createElement("option");
		option.text = lc(opArray[i]['OpWwStrings']);
		option.value = opArray[i]['OperatorName'];
		appendOption(select, option);
		
		if (option.value == defaultOperator)
		{
			selectedIndex = i;
		}
	}
	
	select.selectedIndex = selectedIndex;
	select.style.width = queryBuilderOperatorWidth;
	
	return select;
}

function didChangeQueryBuilderField(rowNum)
{
	var select = document.getElementById("QB_field_select_" + rowNum);
	if (select.selectedIndex <= 1)
	{
		select.selectedIndex = 0;
	}
	
	document.getElementById("QB_op_" + rowNum).innerHTML = "";
	document.getElementById("QB_val_" + rowNum).innerHTML = "";
	document.getElementById("QB_extra_" + rowNum).innerHTML = "";
	
	if (select.selectedIndex > 1)
	{
		addQueryBuilderOperatorAndValueFields(rowNum);
	}
	
	buildQueryBuilderQueryText();
}

function addQueryBuilderOperatorAndValueFields(rowNum)
{
	var row = document.getElementById("QB_row_" + rowNum);
	var opCell = document.getElementById("QB_op_" + rowNum);
	var valueCell = document.getElementById("QB_val_" + rowNum);
	
	var opSelect = createQueryBuilderOpSelect(rowNum);
	
	opCell.innerHTML = "";
	opCell.appendChild(opSelect);
	
	var valueFieldHtml = '<input type="text" id="QB_value_field_' + rowNum + '" onKeyUp="buildQueryBuilderQueryText();" onKeyPress="checkForEnter(event);" onBlur="buildQueryBuilderQueryText();" onFocus="buildQueryBuilderQueryText();" />';
	valueCell.innerHTML = valueFieldHtml;
	
	var fieldName = document.getElementById("QB_field_select_" + rowNum).value;
	if (fieldName == 'xWebsiteSection')
	{
		// Hide the value field
		var field = document.getElementById("QB_value_field_" + rowNum).style.display = "none";

		// Show a friendly label field
		var labelField = document.createElement('input');
		labelField.type = 'text';
		labelField.id = 'QB_value_label_' + rowNum;
		labelField.readOnly = true;
		valueCell.appendChild(labelField);
	}
	var fieldName = document.getElementById("QB_field_select_" + rowNum).value;
	if ( ( fieldName == 'xWebsites' ) || ( fieldName == 'xDontShowInListsForWebsites' ) )
	{
		// Hide the value field
		var field = document.getElementById("QB_value_field_" + rowNum).style.display = "none";

		// Show a friendly label field
		var labelField = document.createElement('input');
		labelField.type = 'text';
		labelField.id = 'QB_value_label_' + rowNum;
		labelField.readOnly = true;
		valueCell.appendChild(labelField);
	}
	addQueryBuilderExtraRowData(rowNum);
	addQueryBuilderIcons(rowNum);
}

function addQueryBuilderExtraRowData(rowNum)
{
	var row = document.getElementById("QB_row_" + rowNum);
	var cell = document.getElementById("QB_extra_" + rowNum);
	cell.innerHTML = "";
	
	var fieldName = document.getElementById("QB_field_select_" + rowNum).value;
	var fieldDef = getFieldDefinition(fieldName);
	
	if ((fieldDef.isDependentList && fieldDef.dependentOnField) || fieldDef.fieldType == g_schemaDefinition.TREE_FIELD_TYPE)
	{
		// Field is based on a dependent choice list, so we display a browse button
		var button = document.createElement('input');
		button.type = "button";
		button.onclick = function(){window.open("/idc/idcplg?IdcService=GET_DOC_PAGE" +
		                            "&Action=GetTemplatePage&Page=SCHEMA_BROWSE_POPUP" +
		                            "&fieldName=" + fieldName + "&formName=QUERYTEXTCOMPONENTS" + 
		                            "&formField=QB_value_field_" + rowNum + "&isQuery=1" +
		                            "&execFunction=buildQueryBuilderQueryText()",
		                            fieldName + "_popupWindow",
		                            "width=525,height=525,toolbar=0,location=0");}
		button.value = lc("wwSelectDot");
		button.id = "QB_schema_browse_popup_button_" + rowNum;
		cell.appendChild(button);
	}
	else if (fieldDef.viewName)
	{
		var selectField = document.createElement('select');
		selectField.id = "QB_view_values_" + rowNum;
		selectField.name = fieldName + "_Options";
		
		selectField.onchange = function(){moveQBOptionValueToField(rowNum); buildQueryBuilderQueryText();}
		cell.appendChild(selectField);
		
		var theValues = getViewValuesFromCache(fieldDef.viewName);
		if (theValues)
		{
			publishViewValues(new Array(
				publishViewValues, fieldDef.viewName, 
				selectField.id, ""));
		}
		else
		{
			registerViewCallback(
				jsFilename(fieldDef.viewName), 
				new Array(publishViewValues, 
				fieldDef.viewName, selectField.id, ""));

			resetField(selectField, 1, lc("wwSchemaLoadingValues"), "");
			
			var viewPathInfo = constructViewPathInfo(
				fieldDef.viewName);
			loadViewValues(new Array(loadViewValues,
				viewPathInfo.url, selectField.id));
		}
	}
	if (fieldDef.type == "Date")
	{
		var lc_caption = lc(fieldDef.caption);
		var tip = lc("wwPopUpCalendarTip", lc_caption);
		var fieldID = 'QB_value_field_' + rowNum;
		var anchor = document.createElement('a');
		anchor.href = "javascript:pucToggleCalendar('" + fieldID + "')";
		anchor.style.verticalAlign = "middle";
		anchor.innerHTML = '<img border="0" width="20" height="19" ' +
			' alt="' + tip + '" title="' + tip + '"' +
			' style="cursor:pointer; cursor:hand; vertical-align: middle;"' +
			' src="/idc/images/PopUpCalendar/calendar.png"/>';
		cell.appendChild(anchor);

		// Update the Query Builder whenever the calendar is changed.
		var changefn = buildQueryBuilderQueryText;
		pucCreateCalendar({ id: fieldID, caption: lc_caption, onchange: changefn }, fieldID, cell);
	}
	if (fieldName == 'xWebsiteSection')
	{
		// Field is based on a dependent choice list, so we display a browse button
		var button = document.createElement('input');
		button.type = "button";
		button.onclick = function()
			{
				// Create a global object to hold the popup function callbacks
				var obj = new Object();
				obj.OnIDValue = function(websiteSection, websiteSectionLabel)
					{
						// Called when OK is pressed in the popup
						document.getElementById("QB_value_field_" + rowNum).value = websiteSection;
						document.getElementById("QB_value_label_" + rowNum).value = websiteSectionLabel;
						buildQueryBuilderQueryText();
					}
				obj.OnReset = function(object)
					{
						// Called when the popup page is refreshed.  Re-set the callback functions
						if (document.Object)
						{
							object.callback=document.Object;
						}
					}

				document.Object = obj;
				window.OnReset = obj.OnReset;

				// Show the popup
				var currentSection = document.getElementById("QB_value_field_" + rowNum).value;
				var popupURL="/idc/idcplg?IdcService=SS_CHOOSE_WEBSITE_SECTION&websiteSection="+currentSection;
				var popup=window.open(popupURL,"_browse",'toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,resizable=1,width=500,height=400');
				if (navigator.appName.substring(0,8)=="Netscape")
				{
					popup.location=popupURL;
				}
				popup.callback=obj;
			}
		button.value = lc("wwSelectDot");
		button.id = "QB_website_browse_popup_button_" + rowNum;
		cell.appendChild(button);
	}
	if ( ( fieldName == 'xWebsites' ) || ( fieldName == 'xDontShowInListsForWebsites' ) )
	{
		// Field is based on a dependent choice list, so we display a browse button
		var button = document.createElement('input');
		button.type = "button";
		button.onclick = function()
			{
				// Create a global object to hold the popup function callbacks
				var obj = new Object();
				obj.OnIDValue = function(websiteIdsString, websiteInfoArray)
					{
						// Called when OK is pressed in the popup
						document.getElementById("QB_value_field_" + rowNum).value = websiteIdsString;
						var newValue = "";
						if( websiteInfoArray.length > 0 )
						{
							var siteInfo = websiteInfoArray[0];
							newValue = siteInfo.siteName+" ("+siteInfo.siteId+")";
						}
						document.getElementById("QB_value_label_" + rowNum).value = newValue;
						buildQueryBuilderQueryText();
					}
				obj.OnReset = function(object)
					{
						// Called when the popup page is refreshed.  Re-set the callback functions
						if (document.Object)
						{
							object.callback=document.Object;
						}
					}

				document.Object = obj;
				window.OnReset = obj.OnReset;

				// Show the popup
				var websitesList = document.getElementById("QB_value_field_" + rowNum).value;
				var extraParams = '&showClear=true&listType=radio';
				var popupURL="/idc/idcplg?IdcService=SS_CHOOSE_WEBSITES&xWebsites=" + websitesList + extraParams;
				var popup=window.open(popupURL,"_browse",'toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,resizable=1,width=300,height=400');
				if (navigator.appName.substring(0,8)=="Netscape")
				{
					popup.location=popupURL;
				}
				popup.callback=obj;
			}
		button.value = lc("wwSelectDot");
		button.id = "QB_website_browse_popup_button_" + rowNum;
		cell.appendChild(button);
	}
}

function addQueryBuilderIcons(rowNum)
{
	if (queryBuilderDisabledRows[rowNum] || queryBuilderHiddenRows[rowNum])
	{
		return;
	}

	var row = document.getElementById("QB_row_" + rowNum);
	var iconCell = document.getElementById("QB_icons_" + rowNum);
	var fieldName = document.getElementById("QB_field_select_" + rowNum).value;
	
	var txt = "";
	if (fieldName.length > 0)
	{
		txt += '<a href="javascript:deleteQueryBuilderRow(' + rowNum + ');"><img border="0" src="' + httpSkinRoot + 'closebox.gif" alt="' + lc("wwDeleteQueryBuilderRow") + '" /></a>';
	}
	
	if (rowNum == queryBuilderRowNumbers[queryBuilderRowNumbers.length - 1] && fieldName.length > 0)
	{
		txt += ' <a href="javascript:addQueryBuilderRow();"><img border="0" src="' + httpSkinRoot + 'add_item.gif" alt="' + lc("wwAddQueryBuilderRow") + '" /></a>';
	}
	iconCell.innerHTML = txt;
}

function deleteQueryBuilderRow(rowNum, allowEmptyTable)
{
	var row = document.getElementById("QB_row_" + rowNum);
	row.parentNode.removeChild(row);
	
	var found = false;
	var i = 0;
	var prevRowNum = -1;
	while (!found && i < queryBuilderRowNumbers.length)
	{
		var tmpRowNum = queryBuilderRowNumbers[i];
	
		if (tmpRowNum == rowNum)
		{
			found = true;
			queryBuilderRowNumbers.splice(i, 1);
		}
		else
		{
			prevRowNum = tmpRowNum;
		}
		i++;
	}
	
	found = false;
	i = 0;
	var firstEditableRowNum = -1;
	while (!found && i < queryBuilderRowNumbers.length)
	{
		var tmpRowNum = queryBuilderRowNumbers[i];
	
		if (!queryBuilderHiddenRows[tmpRowNum])
		{
			found = true;
			firstEditableRowNum = tmpRowNum;
		}
		i++;
	}
	
	if (firstEditableRowNum >= 0)
	{
		var newFirstRow = document.getElementById("QB_row_" + firstEditableRowNum);
		var andOrCell = newFirstRow.getElementsByTagName("td").item(0);
		andOrCell.innerHTML = "";
	}
	
	numQueryBuilderRows--;
	if (numQueryBuilderRows == 0 && !allowEmptyTable)
	{
		addQueryBuilderRow();
	}
	else if (numQueryBuilderRows > 0)
	{
		var newFinalRowNum = queryBuilderRowNumbers[queryBuilderRowNumbers.length - 1];
		if (!allowEmptyTable &&
			(queryBuilderHiddenRows[newFinalRowNum] || queryBuilderDisabledRows[newFinalRowNum]))
		{
			addQueryBuilderRow();
		}
		else
		{
			addQueryBuilderIcons(queryBuilderRowNumbers[queryBuilderRowNumbers.length - 1]);
		}
	}
	
	buildQueryBuilderQueryText();
}

function sortSearchOperatorArray(a, b)
{
	return a.OperatorOrder - b.OperatorOrder;
}

function buildQueryBuilderQueryText()
{
	var queryText = "";
	for (var i = 0; i < queryBuilderRowNumbers.length; i++)
	{
		var rowNumber = queryBuilderRowNumbers[i];
		var fieldSelect = document.getElementById("QB_field_select_" + rowNumber);
		if (fieldSelect.value.length > 1)
		{
			var fieldName = fieldSelect.value;
			var fieldDef = getFieldDefinition(fieldName);
			
			if (typeof(fieldDef.fieldName) != "undefined")
			{
				// Get conjunction
				var conj = "";
				if (queryText.length > 0)
				{
					var andOrSelect = document.getElementById("QB_andor_select_" + rowNumber);
					if (!andOrSelect || andOrSelect.value == "and")
					{
						conj = conjunction;
					}
					else
					{
						conj = orConjunction;
					}
				}
				
				var clause = buildQueryTextForQueryBuilderRow(fieldName, rowNumber);
				if (clause.length > 0)
				{
					queryText = queryText + conj + clause;
				}
			}
		}
	}
	
	document.getElementById("currentQueryFieldValues").value = calculateQueryBuilderQueryFieldValues();
	
	document.QUERYTEXTCOMPONENTS.QueryBuilderQuery.value = queryText;
}

function buildQueryTextForQueryBuilderRow(fieldName, rowNum)
{
	var value = strTrim(document.getElementById("QB_value_field_" + rowNum).value);
	var opSelect = document.getElementById("QB_operator_select_" + rowNum);
	var op = opSelect.options[opSelect.selectedIndex].value
	
	if (value == '')
	{
		return '';
	}
	
	var fieldSelect = document.getElementById("QB_field_select_" + rowNum);
	if (fieldSelect.value.length > 1)
	{
		var fieldName = fieldSelect.value;
		var fieldDef = getFieldDefinition(fieldName);
		
		if (fieldDef.type == "Date" && value.length == 0)
		{
			return "";
		}
		
		return buildQueryTextFromFieldOperatorValue(fieldName, op, value);
	}
	else
	{
		return "";
	}
}

function buildQueryTextFromFieldOperatorValue(fieldName, op, value)
{
	var opMap = getOpMap();
	var queryElement = opMap[op];
	if (op.length > 0 && queryElement.length > 0)
	{
		var text = "";
		if (fieldName == "dClbraName")
		{
			fieldName = "dDocAccount";
			if (value.length > 0)
			{
				text = "prj/" + value;
			}
		}
		else
		{
			text = value;
		}
		
		text = strTrim(text);
		text = escapeFieldValue(op, text);
		text = substituteQuery(queryElement, "%V", text);
		text = substituteQuery(text, "%F", fieldName);
		
		return text;
	}
}

function toggleQueryBuilderModifyQueryText(checkbox)
{
	document.QUERYTEXTCOMPONENTS.QueryBuilderQuery.disabled = !checkbox.checked;

	for (var i = 0; i < queryBuilderRowNumbers.length; i++)
	{
		var rowNum = queryBuilderRowNumbers[i];
		if (queryBuilderTmpDisabledRows[rowNum] || !queryBuilderDisabledRows[rowNum])
		{
			disableEnableQueryBuilderRow(rowNum, checkbox.checked);
			queryBuilderTmpDisabledRows[rowNum] = checkbox.checked;
		}
	}
	
	if (!checkbox.checked)
	{
		for (var i = 0; i < queryBuilderRowNumbers.length; i++)
		{
			addQueryBuilderIcons(queryBuilderRowNumbers[i]);
		}
	}
	
	buildQueryBuilderQueryText();
}

function calculateQueryBuilderQueryFieldValues()
{
	var queryBuilderFieldValues = "";
	for (var i = 0; i < queryBuilderRowNumbers.length; i++)
	{
		var rowNum = queryBuilderRowNumbers[i];
		var fieldSelect = document.getElementById("QB_field_select_" + rowNum);
		if (fieldSelect.selectedIndex > 1)
		{
			var fieldName = fieldSelect.value;
			var fieldDef = getFieldDefinition(fieldName);
			
			// Get conjunction
			var conj = "";
			if (queryBuilderFieldValues.length > 0)
			{
				var andOrSelect = document.getElementById("QB_andor_select_" + rowNum);
				queryBuilderFieldValues += '\n' + andOrSelect.value;
			}
			
			var value = strTrim(document.getElementById("QB_value_field_" + rowNum).value);
			var opSelect = document.getElementById("QB_operator_select_" + rowNum);
			var op = opSelect.options[opSelect.selectedIndex].value
			queryBuilderFieldValues += '\n' + fieldName + '\n' + op + '\n' + value;
		}
	}

	return queryBuilderFieldValues;
}

function deleteAllQueryBuilderRows()
{
	var i = 0;
	while (queryBuilderRowNumbers.length > 0)
	{
		deleteQueryBuilderRow(queryBuilderRowNumbers[0], true);
	}
}

function changedTargetedQuickSearchSelection()
{
	var select = document.getElementById("TargetedQuickSearchSelection");
	if (select.selectedIndex == select.options.length - 1)
	{
		window.location = "/idc/idcplg?IdcService=GET_PORTAL_PAGE&Action=GetTemplatePage&Page=TARGETED_QUICK_SEARCH_LIST";
	}

	if (select.options[select.selectedIndex].value.length == 0)
	{
		select.selectedIndex = 0;
	}
}

function repopulateQueryBuilderForm(queryBuilderFieldValues)
{
	deleteAllQueryBuilderRows();

	for (var i = 0; i < queryBuilderFieldValues.length; i = i + 4)
	{
		var conj = queryBuilderFieldValues[i];
		var fieldName = queryBuilderFieldValues[i + 1];
		var op = queryBuilderFieldValues[i + 2];
		var value = queryBuilderFieldValues[i + 3];
		var fieldDef = getFieldDefinition(fieldName);
		
		if (typeof(value) == "undefined")
		{
			value = "";
		}
		
		addQueryBuilderRow();
		var rowNum = queryBuilderRowNumbers[queryBuilderRowNumbers.length - 1];
		
		if (i != 0)
		{
			var conjSelect = document.getElementById("QB_andor_select_" + rowNum);
			if (conj == "or")
			{
				conjSelect.selectedIndex = 1;
			}
		}
		
		var fieldSelect = document.getElementById("QB_field_select_" + rowNum);
		fieldSelect.value = fieldName;
		didChangeQueryBuilderField(rowNum);

		var opSelect = document.getElementById("QB_operator_select_" + rowNum);
		opSelect.value = op;
				
		var valueField = document.getElementById("QB_value_field_" + rowNum);
		valueField.value = value;
		
		var viewSelect = document.getElementById("QB_view_values_" + rowNum);
		if (viewSelect)
		{
			var setViewFieldValue = function(arg)
			{
				arg[1].value = arg[2];
			}
			
			registerViewCallback(
				jsFilename(fieldDef.viewName), 
				new Array(setViewFieldValue, viewSelect, value));
		}
		
	if( fieldName == 'xWebsiteSection' )
	{
		var label = g_xWebsiteSectionLabels[ value ];
		if( !(typeof( label ) == 'undefined') )
		{
			document.getElementById("QB_value_label_" + rowNum).value = label;
		}
	}
	if ( ( fieldName == 'xWebsites' ) || ( fieldName == 'xDontShowInListsForWebsites' ) )
	{
		var label = g_xWebsitesLabels[ value ];
		if( !(typeof( label ) == 'undefined') )
		{
			document.getElementById("QB_value_label_" + rowNum).value = label;
		}
	}
	}
	
	if (numQueryBuilderRows == 0)
	{
		addQueryBuilderRow();
	}
	else
	{
		buildQueryBuilderQueryText();
	}
}

function assignFieldValues(opElt, fieldElt, fieldValues)
{
	var i = 0;
	while (i + 2 < fieldValues.length)
	{
		var field = fieldValues[i];
		var opChoice= fieldValues[i+1];
		var value = fieldValues[i+2];
		var isMatch = 0;
		if (fieldElt.name == field)
		{
			if (opElt.name == "op")
			{
				//alert("Examining options list for " + field + ".");
				var j = 0;
				for (j = 0; j < opElt.length; j++)
				{
					if (opElt.options[j].value == opChoice)
					{
						opElt.selectedIndex = j;
						isMatch = 1;
					}
				}
			}
			else
			{
				//alert("Comparing optValue " + opElt.value + " to " + opChoice + " for field " + field + ".");
				if (opElt.value == opChoice)
				{
					isMatch = 1;
				}
			}
			if (isMatch)
			{
				fieldElt.value = value;
			}
		}
		i += 3;
	}
}

function addQueryBuilderPreSetFieldRows()
{
	deleteAllQueryBuilderRows();
	
	// We do this in a 2-pass algorithm to ensure that info-only fields are always
	// displayed first in the UI.
	addQueryBuilderPreSetInfoOnlyFieldRows(true);
	addQueryBuilderPreSetInfoOnlyFieldRows(false);
	
	addQueryBuilderRow();
}

function addQueryBuilderPreSetInfoOnlyFieldRows(infoOnly)
{
	for (var fieldName in g_docMetaFieldValues)
	{
		var fieldDef = getFieldDefinition(fieldName);
		var fieldValue = g_docMetaFieldValues[fieldName];
	
		if (typeof fieldValue == "undefined")
		{
			fieldValue = "";
		}
		var rowNum;
		var fieldSelect;
		
		if (fieldDef.fieldName)
		{
			if (g_infoOnlyFields[fieldName])
			{
				if (!infoOnly)
				{
					continue;
				}
			}
			else if (infoOnly)
			{
				continue;
			}
		
			if (g_hiddenFields[fieldName] || !fieldDef.isEnabled)
			{
				addHiddenQueryBuilderRow();
				var rowNum = queryBuilderRowNumbers[queryBuilderRowNumbers.length - 1];
				var fieldSelect = document.getElementById("QB_field_select_" + rowNum);
				
				var parent = fieldSelect.parentNode;
				var input = document.createElement('input');
				input.type = "text";
				input.value = fieldName;
				input.id = "QB_field_select_" + rowNum;
				parent.removeChild(fieldSelect);
				parent.appendChild(input);
				
				addQueryBuilderOperatorAndValueFields(rowNum);
			}
			else
			{
				addQueryBuilderRow();
				rowNum = queryBuilderRowNumbers[queryBuilderRowNumbers.length - 1];
				fieldSelect = document.getElementById("QB_field_select_" + rowNum);
				fieldSelect.value = fieldName;
				didChangeQueryBuilderField(rowNum);
			}
			
			document.getElementById("QB_value_field_" + rowNum).value = fieldValue;
			
	if( fieldName == 'xWebsiteSection' )
	{
		var label = g_xWebsiteSectionLabels[ fieldValue ];
		if( !(typeof( label ) == 'undefined') )
		{
			document.getElementById("QB_value_label_" + rowNum).value = label;
		}
	}
	if ( ( fieldName == 'xWebsites' ) || ( fieldName == 'xDontShowInListsForWebsites' ) )
	{
		var label = g_xWebsitesLabels[ fieldValue ];
		if( !(typeof( label ) == 'undefined') )
		{
			document.getElementById("QB_value_label_" + rowNum).value = label;
		}
	}
			if (g_infoOnlyFields[fieldName])
			{
				disableEnableQueryBuilderRow(rowNum, true);
			}
		}
	}
}

function hideQueryBuilderRow(rowNum)
{
	var tr = document.getElementById("QB_row_" + rowNum);
	tr.style.display = "none";
	
	var theRow = -1;
	for (var i = 0; i < queryBuilderRowNumbers.length; i++)
	{
		var rowNum = queryBuilderRowNumbers[i];
		var row = document.getElementById("QB_row_" + rowNum);
		
		if (row.style.display != "none")
		{
			theRow = rowNum;
			break;
		}	
	}
	
	if (theRow >= 0)
	{
		var andor = document.getElementById("QB_and_or_" + theRow);
		andor.style.display = "none";
	}
	
	queryBuilderHiddenRows[rowNum] = true;
}

function disableEnableQueryBuilderRow(rowNum, doDisable)
{
	var row = document.getElementById("QB_row_" + rowNum);
	var allInputs = row.getElementsByTagName('input');
	for (var i = 0; i < allInputs.length; i++)
	{
		allInputs[i].disabled = doDisable;
	}
	    
	var allSelects = row.getElementsByTagName('select');
	for (var i = 0; i < allSelects.length; i++)
	{
		allSelects[i].disabled = doDisable;
	}
	
	if (doDisable)
	{
		var iconCell = document.getElementById('QB_icons_' + rowNum);
		iconCell.innerHTML = "";
	}
	else
	{
		addQueryBuilderIcons(rowNum);
	}
	
	queryBuilderDisabledRows[rowNum] = doDisable;
}

function setTargetedQuickSearchSelection(selection)
{
	var elem = document.getElementById("targetedQuickSearchLabel");
	elem.innerHTML = "&nbsp;";
	var text = document.createTextNode('');
	if (selection != "")
	{
		text = document.createTextNode(lc(targetedQuickSearches[selection]["Label"]));
	}
	elem.appendChild(text);
	
	if (selection == '')
	{
		// Ensures that in Trays view we reset the ResultCount when we clear the selection
		document.MINISEARCHFORM.ResultCount.value = document.MINISEARCHFORMVARS.ResultCount.value;
	}
	
	document.MINISEARCHFORM.TargetedQuickSearchSelection.value = selection;
}

function editTargetedQuickSearchesPage()
{
	var page = "/idc/idcplg?IdcService=GET_PORTAL_PAGE&Action=GetTemplatePage&Page=TARGETED_QUICK_SEARCH_LIST";
	
	if (!top.contentFrame || top.contentFrame.window == window)
	{
		window.location = page;
	}
	else
	{
		window.contentFrame.location = page;
	}
}

function isQueryBuilderQueryModified(queryBuilderQuery, origQueryText, origQueryFullText)
{
	if (typeof(origQueryFullText) == "undefined" || origQueryFullText == "")
	{
		return !(queryBuilderQuery == origQueryText);
	}
	else
	{
		return !(origQueryText == "(" + queryBuilderQuery + ") " + conjunction + " (" + origQueryFullText + " )");
	}
}

function selectProfileForSearchPopup(selectObj, searchPopupType, callback, fieldNames, urlParams)
{
	var url = selectObj.options[selectObj.selectedIndex].value;
	if (url.length > 0)
	{
		showSearchPopup(searchPopupType, callback, fieldNames, urlParams, url);
	}
	
	selectObj.selectedIndex = 0;
}

function showSearchPopup(searchPopupType, callback, fieldNames, urlParams, url)
{
	if (typeof(url) == "undefined")
	{
		url = httpCgiPath + "?IdcService=GET_DOC_PAGE&Action=GetTemplatePage&Page=STANDARD_QUERY_PAGE";
	}
	
	url += "&coreContentOnly=1&SearchPopup=" + searchPopupType;
	
	if (typeof(urlParams) != "undefined")
	{
		for (key in urlParams)
		{
			url += "&" + urlEncode(key) + "=" + urlEncode(urlParams[key]);
		}
	}
	
	if (typeof(fieldNames) != "undefined" && fieldNames.length > 0)
	{
		var f = fieldNames[0];
		for (var i = 1; i < fieldNames.length; i++)
		{
			f += "," + fieldNames[i];
		}
		url += "&SearchPopupFields=" + f;
	}
	
	window.idcSearchPopupCallback = callback;
	
	var popup = window.open(url, "_searchPopup", 'toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,resizable=1,width=800,height=650');
	popup.focus();
}

function searchPopupAddSelected(tableNumber)
{
	var values = new Array();

	var numForms = document.forms.length;
	for (var i=0 ; i<numForms ; ++i)
	{
		var mForm = document.forms[i];
		if (mForm.tableNumber != null && mForm.tableNumber.value == tableNumber)
		{
			var value = eval("searchPopupValues" + mForm.tableNumber.value + "_" + mForm.rowNumber.value);
			values.push(value);
		}
	}
	
	window.opener.idcSearchPopupCallback(values);
	window.close();
}

