//============================================================+
// File name   : menutree.js
// Begin	   : 2004-03-31
// Last Update : 2004-07-26
// 
// Description : Converts an unordered list to an 
//               explorer-style tree, with clickable icons.
//               To make this work, simply add one line to your HTML:
//               <script language="JavaScript" type="text/javascript" src="jscripts/menutree.js"></script>			  
//               and then make the top UL of your nested unordered list of class "menutree".
//
// Author: Nicola Asuni
//
// (c) Copyright:
//               Tecnick.com S.r.l.
//               Via Ugo Foscolo n.19
//               09045 Quartu Sant'Elena (CA)
//               ITALY
//               www.tecnick.com
//               info@tecnick.com
//============================================================+

// set CSS classes names
var mt_class_name = "menutree";
var mt_class_open = "itemopen";
var mt_class_closed = "itemclosed";
var mt_class_bullet = "itembullet";
var list; // tree list
var max_tree_level = 0; // max tree level

addCBEvent(window, "load", buildDynamicTree, false);
printLevelConsole();

/**
 * builds elements tree
 */ 
function buildDynamicTree() {
	// We don't actually need createElement, but we do
	// need good DOM support, so this is a good check.
	if (!document.createElement) {
		return;
	}
	uls = document.getElementsByTagName("ul");
	for (uli = 0; uli < uls.length; uli++) {
		ul = uls[uli];
		if ((ul.nodeName == "UL") && (ul.className == mt_class_name)) {
			list = ul;
			processList(list, 0);
			break; // process only the first list
		}
	}
}

/**
 * process list elements
 * @param ul DOM element
 * @param int level current level
 */ 
function processList(ul, level) {
	max_tree_level = Math.max(max_tree_level, level); //get max number of levels
	for (var itemi = 0; itemi < ul.childNodes.length; itemi++) {
		var item = ul.childNodes[itemi];
		if (item.nodeName == "LI") {
			//item.setAttribute("tabindex", "0"); //set tabindex attribute
			item.className = mt_class_bullet;
			// search sub UL iterating things in this LI
			for (var sitemi = 0; sitemi < item.childNodes.length; sitemi++) {
				var sitem = item.childNodes[sitemi];
				if (sitem.nodeName == "UL") {
					associateELC(item, true);
					processList(sitem, level+1);
					break;
				}
				else {
					associateELC(sitem, false);
				}
			}
		}
	}
}

/**
 * associate onclick event to nodes
 * @param item DOM element
 * @param boolean node is true when the item is a node
 */
function associateELC(item, node) {
	if ((node) && (item.className.indexOf(mt_class_open) == -1)) {
		item.className = mt_class_closed;
	}
	addCBEvent(item, 'click', function(e){return nodeEvent(item, node, e);}, false);
	//addCBEvent(item, 'keypress', function(e){return nodeEvent(item, node, e);}, false);
}

/**
 * Action for list nodes (collapse / expand)
 * @param item DOM element
 * @param boolean node is true when the item is a node
 * param event e
 */
function nodeEvent(item, node, e) {
	if (node) {
		item.className = (item.className == mt_class_open) ? mt_class_closed : mt_class_open;
	}
	// event should be bubbled up the hierarchy as usual (avoid recursive event calls)
	if (!e) {var e = window.event;}
	e.cancelBubble = true;
	e.returnValue = true; // this allows the default action execution on Microsoft DOM (e.g. href)
	if (e.stopPropagation) {e.stopPropagation();} // stop event propagation on W3C DOM
	//if (e.preventDefault) {e.preventDefault();} // this prevent default action execution on W3C DOM (e.g. href)
	return true; // this allows the default action execution (e.g. href)
}

/**
* Adds an eventListener for browsers which support it.
* cross-browser event handling for IE5+,  NS6 and Mozilla 
* Written by Scott Andrew.
* @param obj element where to apply event
* @param evType event type
* @param fn function to executo on event
* @param useCapture true = event handler is set for the capturing phase, false = the event handler is set for the bubbling phase
*/
function addCBEvent(obj, evType, fn, useCapture) {
	if (obj.addEventListener) {
		obj.addEventListener(evType, fn, useCapture);
		return true;
	} else if (obj.attachEvent) {
		var r = obj.attachEvent("on"+evType, fn);
		return r;
	} else {
		return false;
	}
}

/**
 * expand or collapse the entire tree all list elements
 * @param ul DOM node element
 * @param boolean mode if true close, if false open all
 * @param int level the current level
 * @param int maxlevel maximum level to expand (-1 = expand all)
 */ 
function expanderAll(ul, mode, level, maxlevel) {
	if ((maxlevel >= 0) && (level >= maxlevel)) {
		return;
	}
	for (var itemi = 0; itemi < ul.childNodes.length; itemi++) {
		var item = ul.childNodes[itemi];
		if (item.nodeName == "LI") {
			if (mode) {
				// close all
				if (item.className == mt_class_open) {
					item.className = mt_class_closed;
				}
			}
			else {
				// open all
				if (item.className == mt_class_closed) {
					item.className = mt_class_open;
				}
			}
			if (item.childNodes) {
				// Iterate things in this LI
				for (var sitemi = 0; sitemi < item.childNodes.length; sitemi++) {
					var sitem = item.childNodes[sitemi];
					if (sitem.nodeName == "UL") {
						expanderAll(sitem, mode, level+1, maxlevel); //recursive call
						break;
					}
				}
			}
		}
	}
}

/**
 * closes all list elements
 */ 
function closeAll() {
	expanderAll(list, true, 0, -1);
	document.levelconsole.tlevel.value = 0;
}

/**
 * opens all list elements
 */ 
function openAll() {
	expanderAll(list, false, 0, -1);
	document.levelconsole.tlevel.value = max_tree_level;
}

/**
 * opens the list until the specified level
 * @param int level maximum level to open
 */ 
function openLevel(level) {
	// fix level range
	if (level > max_tree_level) {
		level = max_tree_level;
	}
	if (level < 0) {
		level = 0;
	}
	// collapse list
	expanderAll(list, true, 0, -1);
	// expand list
	expanderAll(list, false, 0, level);
}

/**
 * decrease current view level
 */ 
function decreaseLevel() {
	// fix level range
	if (document.levelconsole.tlevel.value > 0) {
		document.levelconsole.tlevel.value--;
	}
	openLevel(document.levelconsole.tlevel.value);
}

/**
 * increase current view level
 */ 
function increaseLevel() {
	// fix level range
	if (document.levelconsole.tlevel.value < max_tree_level) {
		document.levelconsole.tlevel.value++;
	}
	openLevel(document.levelconsole.tlevel.value);
}

/**
 * print some form buttons to handle levels views
 */ 
function printLevelConsole() {
	document.write('<div class="levelconsole">\n');
	document.write('<form name="levelconsole" id="levelconsole">\n');
	document.write('<label for="tlevel" title="strumenti per mostrare e nascondere i livelli">GESTIONE LIVELLI: </label>\n');
	document.write('<input type="button" name="decrease" id="decrease" value="-" onclick="decreaseLevel()" title="riduce l\'espansione di un livello" />');
	document.write('<input type="text" name="tlevel" id="tlevel" value="0" size="1" maxlength="2" readonly="readonly" title="mostra l\'attuale livello di visualizzazione" />');
	document.write('<input type="button" name="increase" id="increase" value="+" onclick="increaseLevel()" title="aumenta l\'espansione di un livello" />\n');
	document.write('<input type="button" name="expandall" id="expandall" value="espandi" onclick="openAll()" title="espande l\'albero sottostante per intero" />\n');
	document.write('<input type="button" name="closeall" id="closeall" value="collassa" onclick="closeAll()" title="collassa l\'albero sottostante fino al primo livello" />\n');
	document.write('</form>\n');
	document.write('</div>\n');
	document.levelconsole.tlevel.value = 0;
}
//============================================================+
// END OF FILE                                                 
//============================================================+