
/*
================= TREE ===============
------- www.GiantIsland.com ----------
JavaScript - Dynamic tree menu with cookie persistance.
License by GiantIsland LLC, copyright 2009, www.GiantIsland.com
--------------------------------------
*/

//------------------ VARIABLES -----------------------

var TheTree = new Object();
var TheCookieTreeArray = new Array();

//------------------ FUNCTIONS -------------------

TheTree.BuildTree = function(treeid, persist, persistdays, selectedid,treetype)
{

	if (document.getElementById(treeid))
	{

		// Note: Gets a nodes list of "<ul>" node elements from the DOM, but the full DOM is used when getting parents of these individual nodes later.
		var TreeNodeArray = document.getElementById(treeid).getElementsByTagName("ul");

		// First, check cookie tree values, using regular expression to search for name-value pair inside the cookie that indicate ul nodes are open
		var cookieExpression = new RegExp(treetype + "=[^;]+","i");

		//var cookie = document.cookie.match(new RegExp('(^|;)\s*' + escape(treetype) + '=([^;\s]*)'));   
		//var test1 = (cookie ? unescape(cookie[2]) : null);  
		//alert(test1);

		var cookieValue = "";
		if (document.cookie.match(cookieExpression))
		{
			// Returns a comma separate list of "ul" nodes from top to bottom in ul-xml tree (ex. tree1=0,1,2,3)
			cookieValue = document.cookie.match(cookieExpression)[0].split("=")[1];
			if (persist == true && cookieValue != "")
			{
				// Stores comma-separated array in the cookie object
				TheCookieTreeArray = cookieValue.split(",");
			}
			else
			{
				TheCookieTreeArray.clear();
			}
		}

		// Build tree, looping through each UL child node, one at a time.
		// Node: All nodes are given an "empty tree" icon and all nodes expanded before this subtree builder starts
		// (as unordered HTML list looks like a tree by default).

//alert(TreeNodeArray[0].childNodes[0].nodeType);
//alert(TreeNodeArray.length);
//alert(TreeNodeArray[0].childNodes.length);

		for (var i = 0; i < TreeNodeArray.length; i++)
		{

			// Set special "user folder icons"
			for (var j = 0; j<TreeNodeArray[i].childNodes.length; j++)
			{
				// First, make sure not isnt a text node, as it will not have attributes...
				if (TreeNodeArray[i].childNodes[j].nodeType == 1)
				{
					if (TreeNodeArray[i].childNodes[j].getAttribute('userid') != undefined)
					{
						if (TreeNodeArray[i].childNodes[j].getAttribute('userid') != "" && TreeNodeArray[i].childNodes[j].getAttribute('userid') != 0)
						{
							if (TreeNodeArray[i].childNodes[j].childNodes[0].nodeType == 1)
							{
								TreeNodeArray[i].childNodes[j].childNodes[0].className = "userclosed";//IE only
							}
							else if (TreeNodeArray[i].childNodes[j].childNodes[1].nodeType == 1)
							{
								TreeNodeArray[i].childNodes[j].childNodes[1].className = "userclosed";//All non-IE browsers
							}
							else
							{
								//TreeNodeArray[i].childNodes[j].childNodes[0].className = "userclosed";//everyone else
							}
						}
					}
				}
			}

			TheTree.BuildSubTree(treeid, TreeNodeArray[i], i)

		}

		// If system uses cookie tree state values, open tree based on those settings below...
		if (persist == true)
		{
			if (!isNaN(persistdays))
			{
				if (persistdays <= 0)
				{
					persistdays = 1;
				}
				else
				{
					persistdays = parseInt(persistdays);
				}
			}
			else
			{
				persistdays = 1;
			}

			// Set Cookie Tree State when page unloads from browser (or onclick)...
			var CallFunction = function(){TheTree.SetCookieTreeState(treeid, persistdays,treetype)};
			var tasktype=(window.addEventListener)? "unload" : "onunload";

			if (window.addEventListener)
			{
				window.addEventListener(tasktype, CallFunction, false);
			}
			else if (window.attachEvent)
			{
				window.attachEvent(tasktype, CallFunction);
			}
		}
	}
	else
	{
		alert('Sorry, the XML tree files appear to be invalid or corrupted.\nPlease go to the tree folder inside this module and\nsee if the XML files are valid by opening them in a web browser,\nthen correcting any errors using a text editor.');
	}

	if (selectedid != undefined)
	{
		if (document.getElementById(selectedid))
		{
			var SelectedNode = document.getElementById(selectedid);
			SelectedNode.childNodes[0].className = SelectedNode.childNodes[0].className + " selected";
			//alert(SelectedNode.childNodes[0].nodeName);
		}
	}
}

//------------------------------------------------

// This code works on a single <UL> element in the tree, adding events, hiding-showing, etc
TheTree.BuildSubTree = function(treeid, ULTreeNode, index)
{
//alert(treeid);

	// First, change the CSS icon for the parent node (li of the ul), indicating it is a node with children.
	// Note: All <ul> elements MUST have children, by HTML definition, so if present, a node icon is set on its parent <li> wrapper element.
	ULTreeNode.parentNode.className="closed";//parent li
	//ULTreeNode.parentNode.childNodes[0].className="";//commented out, so setting of user icon folders works above


	//alert(ULTreeNode.nodeName);
	//alert(ULTreeNode.getAttribute("rel"));
	//alert(TheCookieTreeArray.length);

	// FIRST, CHECK IF USER HAS SET XML UL NODE TO OPEN BY DEFAULT (ex. rel="open" on <ul> attribute)!
	if (ULTreeNode.getAttribute("rel")=="open")
	{

		// Expand Parent Tree Nodes: Check "rel" user-based attribute setting placed on node, indicating it needs to be opened.
		// So, expand this node, plus all parents above it.
		var rootnode = document.getElementById(treeid);
		var currentnode = ULTreeNode;
		//currentnode.className="closed";
		//set the opened icon on the anchor element of the parent li tag
		//currentnode.parentNode.childNodes[0].className="opened";

		// Loop up the tree through all parents, and if a "ul" node, display and set to open icon
		while (currentnode != null && currentnode.getAttribute('id') != rootnode.getAttribute('id'))
		{
			if (currentnode.nodeName.toLowerCase() == "ul")
			{
				// Expand next parent node...
				currentnode.setAttribute("rel", "open"); //indicate it's open
				//currentnode.className="closed";
				currentnode.parentNode.className="opened";

				//set the opened folder on the anchor element of the parent li tag
				if (currentnode.parentNode.getAttribute('userid') != undefined)
				{
					if (currentnode.parentNode.getAttribute('userid') != "" && currentnode.parentNode.getAttribute('userid') != 0)
					{
						currentnode.parentNode.childNodes[0].className = "useropened";
					}else{
						currentnode.parentNode.childNodes[0].className="openedanchor";
					}
				}else{
					currentnode.parentNode.childNodes[0].className="openedanchor";
				}

			}
			//alert(currentnode.nodeName.toLowerCase());
			//alert(rootnode.getAttribute('id'));
			currentnode = currentnode.parentNode;
		}	
	}


	// NEXT, TRY COOKIE CACHE: Check if cookie has stored cached array value indicating the node should be opened. If so, show it, else hide it.
	if (TheCookieTreeArray.length > 0)
	{ 

		// COOKIE CHECK: Searches an array for the entered ul node index. If found, delete value from array, but flag node as opened.
		var isfound = false;

		// If the current subtree node is same index in list of ul nodes, means cookie cache shows this as expanded
		for (var i=0; i<TheCookieTreeArray.length; i++)
		{
			if (TheCookieTreeArray[i] == index)
			{
				isfound = true;
				TheCookieTreeArray.shift(); //delete this element from array
				break;
			}
		}
		
		// Note: "rel" attribute is used to indicate opened-closed nodes. This also allows users to flag HTML as opened, too.
		if (isfound == true)
		{
			// Set cookie node and its parent as open.
			ULTreeNode.setAttribute("rel", "open");
			//ULTreeNode.className="folder_closed";//set ul
			ULTreeNode.parentNode.className="opened";//set li

			//set the opened folder on the anchor element of the parent li tag
			if (ULTreeNode.parentNode.getAttribute('userid') != undefined)
			{
				if (ULTreeNode.parentNode.getAttribute('userid') != "" && ULTreeNode.parentNode.getAttribute('userid') != 0)
				{
					ULTreeNode.parentNode.childNodes[0].className = "useropened";
				}else{
					ULTreeNode.parentNode.childNodes[0].className="openedanchor";
				}
			}else{
				ULTreeNode.parentNode.childNodes[0].className="openedanchor";
			}

			//alert('ULTreeNode-' + ULTreeNode.nodeName + ':' + 'ULTreeNode.parentNode-' + ULTreeNode.parentNode.nodeName);
		}
		else
		{
			// First make sure, if user has already explicitly set the node to open, do not close.
			if (ULTreeNode.getAttribute("rel")!="open")
			{
				ULTreeNode.setAttribute("rel", "close");//will be used later to hide this ul element in the tree.
			}
		}

	}// NO COOKIE DATA FOUND FOR UL NODE!
	else if (ULTreeNode.getAttribute("rel") == null || ULTreeNode.getAttribute("rel") == false)
	{
		// Close node, as cookie cache and user rel attribute both not set to open.
		ULTreeNode.setAttribute("rel", "close");
	}


	// TOGGLE OPEN-CLOSE AFFECT : Now add custom events to this "ul" node's parent
	ULTreeNode.parentNode.onclick = function(e)
	{

		var submenu = this.getElementsByTagName("ul")[0];// this is the first li node under the parent

		if (submenu.getAttribute("rel") == "close")
		{
			submenu.style.display = "block";
			submenu.setAttribute("rel", "open");
			ULTreeNode.parentNode.className="opened";
			//set the opened icon on the anchor element of the parent li tag
			if (selectedid != undefined)
			{

				if (ULTreeNode.parentNode.getAttribute('userid') != undefined)
				{
					if (ULTreeNode.parentNode.getAttribute('userid') != "" && ULTreeNode.parentNode.getAttribute('userid') != 0)
					{
						if (ULTreeNode.parentNode.id == selectedid)
						{
							ULTreeNode.parentNode.childNodes[0].className="useropened selected";
						}
						else
						{
							ULTreeNode.parentNode.childNodes[0].className="useropened";
						}
					}else{
						if (ULTreeNode.parentNode.id == selectedid)
						{
							ULTreeNode.parentNode.childNodes[0].className="openedanchor selected";
						}
						else
						{
							ULTreeNode.parentNode.childNodes[0].className="openedanchor";
						}
					}
				}else{
					if (ULTreeNode.parentNode.id == selectedid)
					{
						ULTreeNode.parentNode.childNodes[0].className="openedanchor selected";
					}
					else
					{
						ULTreeNode.parentNode.childNodes[0].className="openedanchor";
					}
				}

			}
			//alert(ULTreeNode.parentNode.id);
		}
		else if (submenu.getAttribute("rel") == "open")
		{
			submenu.style.display = "none";
			submenu.setAttribute("rel", "close");
			ULTreeNode.parentNode.className="closed";
			//set the closed icon on the anchor element of the parent li tag
			ULTreeNode.parentNode.childNodes[0].className="selected";
			if (selectedid != undefined)
			{

				if (ULTreeNode.parentNode.getAttribute('userid') != undefined)
				{
					if (ULTreeNode.parentNode.getAttribute('userid') != "" && ULTreeNode.parentNode.getAttribute('userid') != 0)
					{
						if (ULTreeNode.parentNode.id == selectedid)
						{
							ULTreeNode.parentNode.childNodes[0].className="userclosed selected";
						}
						else
						{
							ULTreeNode.parentNode.childNodes[0].className="userclosed";
						}
					}else{
						if (ULTreeNode.parentNode.id == selectedid)
						{
							ULTreeNode.parentNode.childNodes[0].className="selected";
						}
						else
						{
							ULTreeNode.parentNode.childNodes[0].className="";
						}
					}
				}else{
					if (ULTreeNode.parentNode.id == selectedid)
					{
						ULTreeNode.parentNode.childNodes[0].className=" selected";
					}
					else
					{
						ULTreeNode.parentNode.childNodes[0].className="";
					}
				}
			}
			//alert(ULTreeNode.parentNode.id);
		}

		TheTree.StopEventBubble(e);

	}

	ULTreeNode.onclick = function(e)
	{
		TheTree.StopEventBubble(e);
	}

}

//------------------------------------------------

// Expand or contract all tree elements
TheTree.ExpandCollapse = function(treeid, type)
{
	var TreeNodeArray = document.getElementById(treeid).getElementsByTagName("ul");//get all ul nodes
	for (var i = 0; i<TreeNodeArray.length; i++)
	{
		// Collapse or expand all ul nodes...
		if (type == "expand")
		{
			TreeNodeArray[i].style.display = "block";
			TreeNodeArray[i].setAttribute("rel", "open");
			TreeNodeArray[i].parentNode.className="opened";

			//set the closed icon on the anchor element of the parent li tag
			if (TreeNodeArray[i].parentNode.getAttribute('userid') != undefined)
			{
				if (TreeNodeArray[i].parentNode.getAttribute('userid') != "" && TreeNodeArray[i].parentNode.getAttribute('userid') != 0)
				{
					TreeNodeArray[i].parentNode.childNodes[0].className = "useropened";
				}else{
					TreeNodeArray[i].parentNode.childNodes[0].className="openedanchor";
				}
			}else{
				TreeNodeArray[i].parentNode.childNodes[0].className="openedanchor";
			}

		}
		else
		{
			TreeNodeArray[i].style.display = "none";
			TreeNodeArray[i].setAttribute("rel", "close");
			TreeNodeArray[i].parentNode.className="collapsed";

			if (TreeNodeArray[i].parentNode.getAttribute('userid') != undefined)
			{
				if (TreeNodeArray[i].parentNode.getAttribute('userid') != "" && TreeNodeArray[i].parentNode.getAttribute('userid') != 0)
				{
					TreeNodeArray[i].parentNode.childNodes[0].className = "userclosed";
				}else{
					TreeNodeArray[i].parentNode.childNodes[0].className="";
				}
			}else{
				TreeNodeArray[i].parentNode.childNodes[0].className="";
			}
		}

		// *** SPECIAL : Use the code below to loop through all functions for enabling creation of end and start +/- node graphics
		// This loops all child nodes, to get last one
		/*
		var item = TreeNodeArray[i].lastChild;//loop through ul nodes
		while (!item.tagName || item.tagName.toLowerCase() != "li")
		{
     		item = item.previousSibling;
		}
		item.childNodes[0].setAttribute("style", "background:blue;");
		item.childNodes[0].style.color = "green";
		item.childNodes[0].style.background = "red";
		item.childNodes[0].style.color = "green";
		*/
	}
}

//------------------------------------------------

// Store index of opened nodes into a cookie
TheTree.SetCookieTreeState = function(treeid, durationdays,treetype)
{

	var TreeNodeArray = document.getElementById(treeid).getElementsByTagName("ul");

	var theNumericNodeArray = new Array();

	for (var i = 0; i<TreeNodeArray.length; i++)
	{
		if (TreeNodeArray[i].getAttribute("rel") == "open")
		{
			// Save the index value of the ul in the vertical ul list
			theNumericNodeArray[theNumericNodeArray.length] = i;
		}
	}

	if (theNumericNodeArray.length == 0)
	{
		// If there are no opened ULs to save/persist, set array value to string to simply indicate all ULs should persist with state being closed
		theNumericNodeArray[0] = "none open";
	}

	// populate cookie with value treeid=1,2,3
	var expireDate = new Date();
	// set cookie expiration date for the tree nodes listing
	var expstring = expireDate.setDate(expireDate.getDate() + parseInt(durationdays));
	document.cookie = treetype + "=" + (theNumericNodeArray.join(",")) + "; expires=" + expireDate.toGMTString() + "; path=/";

}

//------------------------------------------------

// Stop events from bubbling up to the parent nodes...
TheTree.StopEventBubble = function(e)
{
	if (typeof e != "undefined")
	{
		e.stopPropagation();
	}
	else
	{
		event.cancelBubble = true;
	}
}

//------------------------------------------------



