/*

Copyright Notice



File Tree Menus in JavaScript version 1.0b

Created by James Holladay, June 2009

Copyright James Holladay 2009, All Rights Reserved.

This script is provided as free for personal or academic use, provided that this copyright notice remains intact.

This script can be added upon or modified for personal or academic use.

This script my not be re-released, in whole or in part. If you have written extensions and wish to release them

with all or part of this script, please contact me.

For commercial use, please contact me.

http://i-code.net/

*/



/*

Version History



v1.0a

	This is the original finished script. It loads automatically and has all functions written as global functions.

v1.0b

	This script is identical to v1.0a in every way, except that functions are within an object, meaning they won't

	interfere with other scripts that may use the same function names. Also, calls to expandAll() and collapseAll()

	require the object in front of them. example: fileTree.expandAll();

	

Future versions:

	Future versions are planned, with the intention of improving layout and positioning. Suggestions for additional

	functions are always welcome. Future versions may support showing icons on some lists and not others, on the same

	page.

*/



/*

How to use this script

	a. Change the siteURL() function to return the URL of your server.

	b. Decide whether or not each line should have 24x24 icons. This true/false value should be updated in the icons() function.

	c. Add <script type="text/javascript" src="fileTree.js"></script> to the head section of the page or template. Copy this JavaScript file to your server and edit the path as necessary.

	d. Add the HTML code for your list, give the outer-most list (OL or UL) the class name "tree".

	e. Add any buttons you need to run specific functions.



Functions that should be customized:

	siteURL()	returns your Site URL (THIS SHOULD BE CHANGED TO YOUR SERVER'S URL)

	icons()		returns true/false; Whether or not 24x24 icons are used on each line, and folder icons used on each collapsing line.

	

Example list code:

	<ul class="tree nostyle">

		<li>

			<a href="../../../">Home</a>

			<ul>

				<li>

					<a href="../../">Programming</a>

					<ul>

						<li>

							<a href="../">JavaScript</a>

							<ul>

								<li>

									<a href=".">File Tree</a>

								</li>

							</ul>

						</li>

					</ul>

				</li>

			</ul>

		</li>

	</ul>



Creating special buttons to expand or collapse lists:

	Version 1.0a:

		<a onclick="expandAll('root');">Expand All</a>		This would expand all collapsible lists within the list with the ID 'root'.

		<a onclick="collapseAll('root');">Collapse All</a>	This would collapse all collapsible lists within the list with the ID 'root'.

		<a onclick="expandAll();">Expand All</a>			This would expand all collapsible lists in the entire page.

		<a onclick="collapseAll();">Collapse All</a>		This would collapse all collapsible lists in the entire page.



	Version 1.0b:

		<a onclick="fileTree.expandAll('root');">Expand All</a>		This would expand all collapsible lists within the list with the ID 'root'.

		<a onclick="fileTree.collapseAll('root');">Collapse All</a>	This would collapse all collapsible lists within the list with the ID 'root'.

		<a onclick="fileTree.expandAll();">Expand All</a>			This would expand all collapsible lists in the entire page.

		<a onclick="fileTree.collapseAll();">Collapse All</a>		This would collapse all collapsible lists in the entire page.
		fileTree.getLineText(elem.firstChild);						This gets the text (A) node off of the LI element
*/



fileTree = {

	siteURL: function(){

		return 'http://i-code.net/';

	},

	icons: function(){

		return false; //whether or not icons are being used

	},

	findCollapsible: function(){

		if(arguments.callee.done){

			return;

		}

		arguments.callee.done = true;

		var elem = document.getElementsByTagName("*");

		var numberOfElements = elem.length;

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

			if((elem[i].tagName == "UL") || (elem[i].tagName == "OL")){ //it is a valid list tag

				if(fileTree.containsClassName(elem[i], "tree")){ //if the list should be made collapsible
					if(elem[i].parentNode.tagName != "PRE"){

						fileTree.makeCollapsible(elem[i]);
					}
				}

			}

		}

	},

	makeCollapsible: function(elem){

		if(fileTree.containsClassName(elem, "tree") && elem.tree == 'done'){

			return;

		}

		else{

			var showIcons = fileTree.icons();

			if(elem && !showIcons && !fileTree.containsClassName(elem, "tree")){ //keeps the list from being position:relative, which ruins custom positioning

				elem.style.position = 'relative';

				elem.style.left = '-11px';

			}

			//this squishes the list a little for narrow columns

			else if(elem && !fileTree.containsClassName(elem, "tree") && !fileTree.containsClassName(elem.firstChild, "icon")){ //keeps the list from being position:relative, which ruins custom positioning

				elem.style.position = 'relative';

				elem.style.left = '-2px';

			}

			if(elem && elem.nodeType == 1){

				var hasChildren = false;

				var children = elem.childNodes;

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

					if(children[i].tagName == "UL" || children[i].tagName == "OL" || children[i].tagName == "LI"){

						hasChildren = true;

					}

				}

				//this caused spacing issues

				/*if(!hasChildren && elem.tagName == "LI"){//window.alert("NO CHILDREN"); //adds blank image to line items with no children

					var bgB = document.createElement("IMG");

					bgB.style.position = 'relative';

					bgB.style.top = 0;

					bgB.style.left = -2;

					bgB.src = fileTree.siteURL()+'images/file-tree/blank.png';

					bgB.tree = 'done';

					fileTree.getParentLI(elem).insertBefore(bgB,fileTree.getParentLI(elem).firstChild);

					elem.tree = 'done';

				}*/

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

					if(children[i].tree != 'done'){

						if(children[i].nodeType == 1){

							if(children[i].tagName == "UL" || children[i].tagName == "OL" || children[i].tagName == "LI"){

								if(children[i].tagName == "LI"){

									if(!fileTree.containsClassName(elem, "collapsible") && !fileTree.containsClassName(elem, "tree")){

										fileTree.addClassName(elem, "collapsible"); //add class

										if(showIcons){

											var bgA = document.createElement("IMG");

											bgA.style.position = 'relative';

											bgA.style.top = 6;

											bgA.style.left = 4;

											bgA.style.paddingRight = '2px';

											bgA.src = fileTree.siteURL()+'images/file-tree/folder-open.png';

											bgA.collapsed = 'img';

											fileTree.getParentLI(elem).insertBefore(bgA,fileTree.getParentLI(elem).firstChild);

										}

										var bgE = document.createElement("IMG");

										bgE.style.position = 'relative';

										bgE.style.top = 1;

										bgE.style.left = -3;

										bgE.src = fileTree.siteURL()+'images/file-tree/minus.png';

										bgE.tree = 'done';

										bgE.collapsed = 'img';

										bgE.className = 'plusminus';

										bgE.onclick = function(){

											fileTree.showHide(this, showIcons);

										}

										fileTree.getParentLI(elem).insertBefore(bgE,fileTree.getParentLI(elem).firstChild);

										elem.tree = 'done';

									}

									else if(fileTree.containsClassName(elem, "tree")){

										elem.tree = 'done';

									}

								}

								else{

									elem.style.position = 'relative';

									elem.style.left = '-11px';

								}

								fileTree.makeCollapsible(children[i]);

							}

						}

					}

				}

			}

			else if(fileTree.getNextSibling(elem).nodeType == 1){

				fileTree.makeCollapsible(fileTree.getNextSibling(elem));

			}

			else if(fileTree.getNextSibling(elem.parentNode).nodeType == 1){

				fileTree.makeCollapsible(fileTree.getNextSibling(elem.parentNode));

			}
			//fill root LI items with blank images so all child node align
			if(!hasChildren && fileTree.containsClassName(elem.parentNode, "tree")){
				elem.style.position = 'relative';

									elem.style.left = '0px';
			}

		}

	},

	getParentLI: function(n){

		while(n && n.tagName != "LI"){

			if(fileTree.containsClassName(n, "tree")){

				return n;

			}

			n = n.parentNode;

		}

		return n;

	},

	getNextSibling: function(n){

		while(n && n.nodeType != 1){

			n = n.nextSibling;

		}

		return n;

	},
	getLineText: function(n){
		if(!n){
			return;
		}

		while(n && n.tagName != "A"){

			n = n.nextSibling;

		}

		return n;

	},
	toggle: function(e, showIcons, force){
		if(!showIcons){
			showIcons = false;	
		}
		if(!force){
			force = 0;
		}
		if(!e || e.nodeType != 1){
			e = document.getElementById(e);
		}
		e = e.firstChild;
		if(!e){
			return; //ERROR
		}
		fileTree.showHide(e, showIcons, force);
	},
	getElement: function(elem){
		if(!elem || elem.nodeType != 1){
			elem = document.getElementById(elem);
		}
		if(!elem){
			return; //ERROR
		}
		return elem;
	},
	expand: function(elem){
		elem = fileTree.getElement(elem);
		if(elem.tagName == "UL"){
			elem = elem.firstChild.firstChild;
		}
		else if(elem.tagName == "LI"){
			elem = elem.firstChild;
		}
		fileTree.showHide(elem, fileTree.icons(), 1);
	},
	collapse: function(elem){
		elem = fileTree.getElement(elem);
		if(elem.tagName == "UL"){
			elem = elem.firstChild.firstChild;
		}
		else if(elem.tagName == "LI"){
			elem = elem.firstChild;
		}
		fileTree.showHide(elem, fileTree.icons(), -1);
	},
	showHide: function(elem, showIcons, force){
		elem = fileTree.getElement(elem);

		var elemP = fileTree.getParentLI(elem);

		if(!force){

			force = 0; //0=no forcing; 1=force open; -1=force close

		}

		else if(force < 0){

			elemP.collapsed = ''; //this will make the list collapse

		}

		else if(force > 0){

			elemP.collapsed  = 'true'; //this will force the list to expand

		}

		if(elemP.collapsed != 'true'){

			for(i=0; i<elemP.childNodes.length; i++){

				if(elemP.childNodes[i].nodeType == 1){

					if(elemP.childNodes[i].collapsed != 'img' && elemP.childNodes[i].tagName != "A"){ //do not show/hide the image

						elemP.childNodes[i].style.display = 'none';

					}

				}

			}

			elemP.collapsed = 'true';

			elem.src = fileTree.siteURL()+'images/file-tree/plus.png';

			if(showIcons){

				elem.nextSibling.src = fileTree.siteURL()+'images/file-tree/folder.png';

			}

		}

		else{

			for(i=0; i<elemP.childNodes.length; i++){

				if(elemP.childNodes[i].nodeType == 1){

					if(elemP.childNodes[i].collapsed != 'img' && elemP.childNodes[i].tagName != "A"){ //do not show/hide the image

						elemP.childNodes[i].style.display = '';

					}

				}

			}

			elemP.collapsed = '';

			elem.src = fileTree.siteURL()+'images/file-tree/minus.png';

			if(showIcons){

				elem.nextSibling.src = fileTree.siteURL()+'images/file-tree/folder-open.png';

			}

		}

	},

	expandAll: function(id, num){

		if(!num){

			var num = 1;

		}

		if(!id){

			var elem = document.body.getElementsByTagName("*");

		}

		else{

			var elem = document.getElementById(id).getElementsByTagName("*");

		}

		var plusminusArray = new Array();

		var showIcons = fileTree.icons();

		for(i=elem.length; i>0; i--){

			if(elem[i] && elem[i].nodeType == 1 && elem[i].tagName == "IMG"){ //it is a valid list tag

				if(fileTree.containsClassName(elem[i], "plusminus")){ //if the list should be made collapsible

					plusminusArray.push(i);

				}

			}

		}

		while(plusminusArray.length){

			fileTree.showHide(elem[plusminusArray[0]], showIcons, num);

			plusminusArray.shift();

		}

	},

	collapseAll: function(id, num){

		if(!num){

			var num = -1;

		}

		if(!id){

			var id = false;

		}

		fileTree.expandAll(id, num);

	},

	containsClassName: function(elem, classToAdd){
		elem = fileTree.getElement(elem);

		var classes = elem.className;

		if(!classes){ //not a member of any class

			return false;

		}

		if(classes == classToAdd){ //elem is a member of only this one class

			return true;

		}

		return classes.search("\\b" + classToAdd + "\\b") != -1; //return whether or not elem's class atribute contains the className string

	},

	addClassName: function(elem, classToAdd){

		var classes = elem.className;

		classes += " ";

		elem.className = classes + classToAdd;

	}

}



//allow Mozilla to load automatically

if(document.addEventListener){

	document.addEventListener("DOMContentLoaded", fileTree.findCollapsible, false);

}

//allow Internet Explorer to load automatically

/*@cc_on @*/

/*@if (@_win32)

	document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");

	var script = document.getElementById("__ie_onload");

	script.onreadystatechange = function(){

		if(this.readyState == "complete"){

			fileTree.findCollapsible(); //call the onload handler

		}

	};

/*@end @*/



//allow Safari to load automatically

if(/WebKit/i.test(navigator.userAgent)){

	var _timer = setInterval(function(){

		if(/loaded|complete/.test(document.readyState)){

			fileTree.findCollapsible(); // call the onload handler

		}

	}, 10);

}



//allow other browsers to load automatically

window.onload = fileTree.findCollapsible;
