/*
  
   自动将一个普通的html列表改为折叠的树状目录

						Version 1.2
			last modified 2001/2/25         

                     by starfish
                   starifh.h@china.com

    注意：此代码只适用于ie！在ie 5.0下测试通过，虽然没有在ie 4.0下测试，但是在ie 4.0也应该可以使用
                     
	使用说明：
	  1。建立一个id为"tree"的div，在其内部按照目录树的层次结构建立一个普通的html列表（注意不能是数字列表，即必须用UL和LI标记），
      2。按照标准HTML语法，每个LI标记内最多只能有一个UL标记；
      3。每个LI标记内可以添加别的html元素；
      4。在网页的<head>...</head>之间加上 <script src="tree.js"></script>，
         其中tree.js为本文件的名称，必要时加上相对路径；
      5。如果需要指定目录和树叶的图片，在第四步加上的<script src="tree.js"></script>
         之后（注意一定要加在tree.js后面，次序不能颠倒）加上
		 <script>
          leaf_img="dc.gif";//指定叶节点图片
          branch_close_img="bs.gif"; //指定目录关闭时的图片
          branch_open_img="bo.gif";  //指定目录打开时的图片
          indent=20;  //缩进20px;
         </script> 
         其中dc.gif是叶节点的图片，bs.gif是目录关闭时的图片，bo.gif是目录打开时的图片
         indent=20指定下一级的目录项相对上一级的缩进量为20px；
         如果不加这几句，默认没有图片，而默认缩进为20px;
      6。如果某些列表项需要指定图片，可以在第2步时建立html列表时指定，例如如果列表中有一项为：
         <li leaf_img="custom.gif">some item</li> 则该列表项将会使用custom.gif作图片，
		 如果该列表项不是叶结点，而是目录节点，则可以为其指定目录打开时的图片open_img和目录关闭时的图片close_img
		 例如：
         <li open_img="custom_open.gif" close_img="custom_close.gif">custom item 1
		 <ul>
			<li leaf_img="custom.gif"> sub item 1 </li>
			<li> sub item 2 </li>
		 </ul>
		 </li>
		 没有指定图片的节点将使用默认的图片， branch_close_img（目录关闭时的图片），
		 branch_open_img（目录打开时的图片）和leaf_img（叶节点图片）。
      7。在网页的body标记内加上 onload="init()" ，例如：
         <body bgcolor="#FFFFFF" text="#000000" onload="init()" >
      8。当前选中的节点的类为selected,其他未选中的节点类为selected，可以通过lastSelected访问当前选中的节点；
	     可以利用CSS自定义选中的节点和未选中的节点的外观；
      9。函数说明：
          init(); 
            初始化，必须加在body的onload事件中；
          locate(s) 
            根据URL s定位，s必须是绝对地址;如果在某个节点中找到指向s的
            链接(<A href=s>的形式)，则返回该节点，但是不做任何事，如果要选中该节点，必须调用LocateNode(locate(s));
		  LocateNode(r) 
		    根据节点r(一个LI元素)在树中定位，并将包含r的目录打开，r如果是一个目录则将r的目录打开
          openAll() 
            将所有的目录打开
          closeAll()
            将所有的目录关闭
         lastSelected 指向当前选择的LI元素,可以通过它来访问树中下一个节点
         select(e) 选择节点e，e 必须是一个LI元素,如果e 是目录则将它的目录打开；
         GetLink(e)  e是一个LI元素，返回e里面的第一个A元素
         nextNode(e)  找到节点e在树中的下一个相邻节点，e 必须是LI元素
		 prevNode(e)  找到节点e在树中的上一个相邻节点，e 必须是LI元素
*/

var leaf_img="";   //叶节点图片
var branch_close_img=""; //分支关闭时的图片
var branch_open_img="";  //分支打开时的图片
var indent=100;  //左边缩进,默认值20px
var lastSelected=null; //指向当前选择的LI元素,可以通过它来访问树中下一个节点

//============================ 以下是初始化部分 ==================================

function init() //初始化
{   if (document.all.tree==null) return; 
	var coll = document.all.tree.children.tags("UL");
	var s="";
	if (coll!=null)
	   for (var i=0;i<coll.length;i++)
		{
			s+="<ul>"+initUL(coll[i])+"</ul>";	
		}
	document.all.tree.innerHTML=s; //画出目录树
}

function initUL(r)  //初始化UL tag,返回修改后的r的innerHTML
{   
	var sn="";
	var cli=r.children.tags("LI");
	if (cli!=null)
		for (var i=0;i<cli.length;i++)
			sn+=initLI(cli[i]);				  
   return sn;
}


function initLI(r)  //初始化LI tag,返回修改后的r的outerHTML
{		    
  var si=r.innerHTML;
  var p=si.length;  
  var sn="";
  var leaf=true;
  var cul=r.children.tags("UL");
  if (cul!=null&&cul.length>0)  //如果r有子表
  {	  p=si.indexOf("<UL>");      //找到子表的起始位置p
  	  leaf=false;            //r不是树叶
	  for (var i=0;i<cul.length;i++)
	  	sn+="<ul style='display: none; margin-left:"+indent+";'>"+initUL(cul[i])+"</ul>";	  		
  }  
  var oimg=(r.open_img!=null)? r.open_img:branch_open_img;
  var cimg=(r.close_img!=null)? r.close_img:branch_close_img;
  var limg=(r.leaf_img!=null)? r.leaf_img:leaf_img;	
  var imgstr="";
  if (leaf) imgstr="<img leaf_img='"+limg+"' src='"+limg+"'>";  
	else imgstr="<img open_img='"+oimg+"' close_img='"+cimg+"' src='"+cimg+"'>";
  sn="<li class='"+((leaf)? "leaf":"branch")+"' style='list-style-type:none'>"+
	  "<span status='closed' onclick='doclick(this)' style='Cursor:hand;'>"+
      imgstr+
	  " <span class='unselected'>"+
  	  si.substring(0,p)+
	  "</span>"+
	  "</span>"+
	  sn+
	  "</li>";  
  return sn;  	
}

//============================ 以上是初始化部分 ==================================


//====================== 以下函数响应鼠标单击事件 =================================

function doclick(r)  //响应鼠标单击事件,r是一个span元素
{  
   if (r.parentElement.className=="branch") //如果选择的是树枝（r的parentElement是一个LI元素）
   {
	 //alert(r.status);
	 if (r.status=="closed") r.status="opened"; else r.status="closed"; //改变节点r的状态标记
	// alert(r.status);
	 var cul=r.parentElement.children.tags("UL"); 
	 if (cul!=null)	 
		 for (var i=0;i<cul.length;i++)
			if (r.status=="closed")  cul[i].style.display="none"; else cul[i].style.display="block";
	 var mm=r.children[0]; //r一共有两个儿子元素，第一个为IMG元素，mm指向r的第一个儿子图片
	 if (r.status=="closed") mm.src=mm.close_img; else mm.src=mm.open_img; //切换图片	 
   }   
   if (lastSelected!=null) lastSelected.children[0].children[1].className="unselected";  //改变上一次选择的节点的外观
   r.children[1].className="selected";  //改变当前选择的节点的外观，r.children[1]是一个SPAN元素
   //注意，上面两句次序不能颠倒
   lastSelected=r.parentElement;  //改变当前选择的节点
}

//====================== 以上函数响应鼠标单击事件 =================================



//======================== 以下函数根据绝对URL在树中定位 ==========================

function locate(s)  //根据url=s 定位，s必须是绝对地址，返回所找到的LI节点,但是不做任何事
{	
 if (document.all.tree==null) return;  
 var coll = document.all.tree.children.tags("UL");
 var e;

	if (coll!=null)
	   for (var i=0;i<coll.length;i++)
	   {
	    e=FindInUL(coll[i],s);  //在每棵子树中找；
	   	if (e!=null) return(e); 
	   	} 
	return(null);
}

function FindInUL(r,s)  //在UL tag r中定位s
{    
	var cli=r.children.tags("LI");
	var e;
	if (cli!=null&&cli.length>0)
		for (var i=0;i<cli.length;i++)
		 {  		 	
		 	e=FindInLI(cli[i],s);
			if (e!=null) return(e);
		}	
   return(null);  
}

function FindInLI(r,s) //在LI tag r中定位s
{
	var lnk=GetLink(r); //返回LI节点r里面的第一个A元素
	if (lnk!=null&&lnk.href==s) 
	 {  
		//LocateNode(r);  //定位节点r		
	 	return(r);
	 }	
	var cul=r.children.tags("UL");
	var e;
	if (cul!=null&&cul.length>0) 
		for (var i=0;i<cul.length;i++)
		{
			e=FindInUL(cul[i],s);
 			if (e!=null) return(e);		
		}		
	return(null);
}

//======================== 以上函数根据绝对URL在树中定位 ==========================

function GetLink(e)  //e是一个LI元素，返回e里面的第一个A元素
{
	if (e==null) return(null);
	var lnk=e.children[0].children[1].children.tags("A");
	if (lnk==null||lnk.length==0) return(null);	else return(lnk[0]);
}

function select(e) //选择节点e，e 必须是一个LI元素,将e的父辈目录全部打开，e如果是目录也将其打开
{	  
   if (e==null) return;
   if (lastSelected!=null) lastSelected.children[0].children[1].className="unselected";  //改变上一次选择的节点的外观
   e.children[0].children[1].className="selected";  //改变当前选择的节点的外观，e.children[0].children[1]是一个SPAN元素
   //注意，上面两句次序不能颠倒
   lastSelected=e;  //改变当前选择的节点
   if (e.className=="branch")  //如果e是树枝
   {
	   e.children[0].status="opened";
	   var mm=e.children[0].children[0];  //切换图片
	   mm.src=mm.open_img;
	   var cul=e.children.tags("UL");
	   if (cul!=null)	   
		  for (var i=0;i<cul.length;i++)
			cul[i].style.display="block";	   
   }
}



//===================== 以下函数根据节点r(一个LI元素)在树中定位 ====================

function LocateNode(r) //定位节点r,成功则返回true，否则返回false
{
	if (document.all.tree==null) return; 
	var coll = document.all.tree.children.tags("UL");
	if (coll!=null)
	   for (var i=0;i<coll.length;i++)
			if (FindNodeInUL(coll[i],r)) return(true);//在每棵子树中找节点r；	   	
	return(false);
}

function FindNodeInUL(t,r)  //在UL tag t中定位节点r
{   
	var cli=t.children.tags("LI");
	if (cli!=null&&cli.length>0)
		for (var i=0;i<cli.length;i++)
		 {  		 	
		 	if (FindNodeInLI(cli[i],r))
			{
			    t.style.display="block";  //改变t的可视性
			    return(true);
			}
		}	
   return(false);  
}

function FindNodeInLI(t,r) //在LI tag t中定位节点r
{	
	if (t==r) 
	 {
	 	select(t);  //选中LI节点t
	 	return(true);
	 }	
	var cul=t.children.tags("UL");
	if (cul!=null&&cul.length>0) 
		for (var i=0;i<cul.length;i++)
		{
			if (FindNodeInUL(cul[i],r))
			{
				t.children[0].status="opened";
				var mm=t.children[0].children[0];  //切换t的图片
				mm.src=mm.open_img;
				return(true);
			}
		}		
	return(false);
}



//===================== 以上函数根据节点r(一个LI元素)在树中定位 ====================


//========================= 以下函数将所有的目录关闭 ==============================

function closeAll() //将所有的目录折叠
{   if (document.all.tree==null) return; 
	var coll = document.all.tree.children.tags("UL");
	if (coll!=null)
	   for (var i=0;i<coll.length;i++)
	    { 
			var cli=coll[i].children.tags("LI");
			if (cli!=null&&cli.length>0)
	      		for (var j=0;j<cli.length;j++)	closeLI(cli[j]);    	 	 	   	
	   	}
	if (lastSelected!=null) lastSelected.children[0].children[1].className="unselected";  //改变上一次选择的节点的外观
	lastSelected=null; 	
}
	

function closeLI(r)  //将节点r(一个LI元素）里面的各层关闭
{
	var cul=r.children.tags("UL");
	if (cul!=null&&cul.length>0) //如果r是目录
	{	
		r.children[0].status="closed";
		var mm=r.children[0].children[0];
		mm.src=mm.close_img;       //切换目录图片
		for (var i=0;i<cul.length;i++)
		{
			var cli=cul[i].children.tags("LI");
			if (cli!=null)			
				for (var j=0;j<cli.length;j++) closeLI(cli[j]);
			cul[i].style.display="none";
		}
	}
}

//========================= 以上函数将所有的目录关闭 ==============================

//========================= 以下函数将所有的目录打开 ==============================

function openAll()  //将所有的目录打开
{  
	if (document.all.tree==null) return; 
	var coll = document.all.tree.children.tags("UL");
	if (coll!=null)
	   for (var i=0;i<coll.length;i++)
	    { 
			var cli=coll[i].children.tags("LI");
			if (cli!=null&&cli.length>0)
	      		for (var j=0;j<cli.length;j++)	openLI(cli[j]);    	 	 	   	
	   	}
	if (lastSelected!=null) lastSelected.children[0].children[1].className="unselected";  //改变上一次选择的节点的外观
	lastSelected=null; 	
}	

function openLI(r)  //将节点r(一个LI元素）里面的各层打开
{
	var cul=r.children.tags("UL");
	if (cul!=null&&cul.length>0) //如果r是目录
	{	
		r.children[0].status="opened";
		var mm=r.children[0].children[0];
		mm.src=mm.open_img;       //切换目录图片
		for (var i=0;i<cul.length;i++)
		{
			var cli=cul[i].children.tags("LI");
			if (cli!=null)			
				for (var j=0;j<cli.length;j++) openLI(cli[j]);
			cul[i].style.display="block";
		}
	}
}

//========================= 以上函数将所有的目录关闭 ==============================


//====================== 以下函数找到树中下一个相邻节点 ============================

/*
nextNode(e) 找到节点e在树中的下一个相邻节点，返回值为一个LI元素
Algorithm:
	1.如果e有儿子，返回e 的第一个儿子；否则
	2.如果e没有父亲，则失败返回,否则
	3.如果e不是他的父亲的最后一个儿子，返回e的父亲的下一个儿子，即e的弟弟；否则
	4.e=e的父亲，转2；
*/
function nextNode(e)  //找到节点e在树中的下一个相邻节点，e 必须是LI元素
{   
	if (e==null||e.tagName!="LI") return(null);
	var cul=e.children.tags("UL"); 
	if (cul!=null&&cul.length>0)  //如果e有儿子
	{ 
	  var t=cul[0].children.tags("LI"); 
	  if (t!=null&&t.length>0) 	
	  	return(t[0]);  //返回e 的第一个儿子;	 	
	}	
	var par,i,son;
	while (true)
	{
		par=e.parentElement;  //par是e的父亲元素，应该是一个UL元素
		if (par==null||par.tagName!="UL") return(null);//如果e没有父亲，则失败返回	
		son=par.children.tags("LI");
		if (son!=null&&son.length>0)
			for (i=0;i<son.length;i++) 
				if (son[i]==e) break; //找到e在其父亲的儿子中的索引
		i++;
		if (i<son.length) return(son[i]);//e不是他的父亲的最后一个儿子，返回e的父亲的下一个儿子
		e=par.parentElement;  //e现在是一个LI元素
		if (e==null||e.tagName!="LI") return(null);
	}	
}


//====================== 以下函数找到树中上一个相邻节点 ============================

/*
prevNode(e) 找到节点e在树中的上一个相邻节点，
Algorithm:
	1.如果e有哥哥，返回e的哥哥，否则
	2.如果e有父亲，则返回e的父亲,否则失败返回；	
*/
function prevNode(e)  //找到节点e在树中的上一个相邻节点，e 必须是LI元素
{   
	if (e==null||e.tagName!="LI") return(null);
	var par,i,son;		
	par=e.parentElement;
	if (par==null||par.tagName!="UL") return(null);//如果e没有父亲，则失败返回		
	son=par.children.tags("LI");	
	if (son!=null&&son.length>0)
		for (i=0;i<son.length;i++) 
			if (son[i]==e) break; //找到e在其父亲的儿子中的索引	
	if (i>0) return(son[i-1]);//e不是他的父亲的第一个儿子，返回e的父亲的上一个儿子		
	par=par.parentElement;
//	while (par!=null&&par.tagName!="BODY"&&par.tagName!="LI") par=par.parentElement;
	if (par!=null&&par.tagName=="LI") return(par);
							else return(null);
		
}