Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: The ideal tree-style menu

  1. #1
    Join Date
    Jan 2006
    Posts
    22
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default The ideal tree-style menu

    I am looking for a tree-style menu which accomplsihes the following:

    1. Uses normal ol, ul, li for markup/
    2. Opening one member closes down its siblings.
    3. Has some way to remember the state or use a particular tag to open up the tree on to a certain location.
    4. Does not require the use of images.
    5. And, of course, is as cross-browser as possible.

    Am i living in a dream or does something like this exist?

  2. #2
    Join Date
    Jan 2006
    Posts
    22
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    http://www.dynamicdrive.com/dynamicindex1/navigate1.htm does an excellent job at mearing all the requirements.

    But how can it be changes so that opening a folder causes sibling folders to be closed?

  3. #3
    Join Date
    Aug 2004
    Posts
    10,143
    Thanks
    3
    Thanked 1,008 Times in 993 Posts
    Blog Entries
    16

    Default

    Well, there is no built in way to collapse the previous sibling when another one is expanded. However, a little hacking should do the trick. Inside the .js file, find the function:

    Code:
    ddtreemenu.expandSubTree=function(treeid, ulelement){
    ddtreemenu.flatten(treeid, "contract")
    "
    "
    }
    The line in red is new. This should work, but it's untested.
    Last edited by ddadmin; 01-03-2007 at 10:13 AM.

  4. #4
    Join Date
    Jan 2006
    Posts
    22
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Thanks for your help, but that caused an error and the entire menu to be opened up.

    Your further help would really be appreciated.

  5. #5
    Join Date
    Aug 2004
    Posts
    10,143
    Thanks
    3
    Thanked 1,008 Times in 993 Posts
    Blog Entries
    16

    Default

    Ok, there was a typo in the code I posted above (which has been corrected), though it doesn't matter- it didn't work. lol Looks like such a feature (collapse previous sibling) will take a little more than just a few lines of hacking to achieve. This means I'll have to update this script officially, which by my current schedule is probably a couple of weeks away.

  6. #6
    Join Date
    Jan 2006
    Posts
    22
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Thanks.

    On a seperate note... i've been looking into your script more carefully and wandered...

    Wouldn't it make more sense for the parents to be given a className of open or closed (as opposed to rel="xxx") and then the individual sections could be styled according to class names in the style sheet.

    I am no JS-guy, so please correct me if i am wrong, but wouldn't this significantly reduce the size of the script and also give more design control through the stylesheet?

  7. #7
    Join Date
    Jan 2007
    Location
    Surrey, UK
    Posts
    16
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by ddadmin View Post
    Looks like such a feature (collapse previous sibling) will take a little more than just a few lines of hacking to achieve.
    I haven't looked at the script itself so this is very speculative, but can you set all siblings to closed before opening the one that should be open?

  8. #8
    Join Date
    Jan 2006
    Posts
    22
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by mike_p View Post
    I haven't looked at the script itself so this is very speculative...
    Lol!!!

  9. #9
    Join Date
    Jan 2006
    Posts
    22
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Ok... I went ahead and modified the script significantly so that all styling is in the stylesheet and that a section of the tree is recognised as being open or closed through the class name (as opposed to the rel="" tag).

    It still works the same as before, except that a lot of repetitive code has been removed. However, as i am not very well versed in JS, it would be nice if the author could have a look at the new script. If it has mistakes, then please let me know and, if not, then consider modifying the original script to reflect them.

    The new script:

    Code:
    /***********************************************
    * Simple Tree Menu- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
    * This notice MUST stay intact for legal use
    * Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
    ***********************************************/
    
    var persisteduls=new Object()
    var ddtreemenu=new Object()
    
    //////////No need to edit beyond here///////////////////////////
    
    ddtreemenu.createTree=function(treeid, enablepersist, persistdays)
    {
    	var ultags=document.getElementById(treeid).getElementsByTagName("ul")
    	if(typeof persisteduls[treeid]=="undefined")
    	{
    		persisteduls[treeid]=(enablepersist==true && ddtreemenu.getCookie(treeid)!="")? ddtreemenu.getCookie(treeid).split(",") : ""
    	}
    	for (var i=0; i<ultags.length; i++)
    	{
    		ddtreemenu.buildSubTree(treeid, ultags[i], i)
    	}
    	if(enablepersist==true) //if enable persist feature
    	{
    		var durationdays=(typeof persistdays=="undefined")? 1 : parseInt(persistdays)
    		ddtreemenu.dotask(window, function(){ddtreemenu.rememberstate(treeid, durationdays)}, "unload") //save opened UL indexes on body unload
    	}
    }
    
    ddtreemenu.buildSubTree=function(treeid, ulelement, index)
    {
    	if(typeof persisteduls[treeid]=="object")//if cookie exists (persisteduls[treeid] is an array versus "" string)
    	{ 
    		if(ddtreemenu.searcharray(persisteduls[treeid], index))
    		{
    			ulelement.parentNode.className="open";
    		}
    		else
    		{
    			ulelement.parentNode.className="closed";
    		}
    	} 
    	else if(ulelement.parentNode.className==null || ulelement.parentNode.className==false) //if no cookie and UL has NO rel attribute explicted added by user
    	{
    		ulelement.parentNode.className="closed";
    	}
    	else if(ulelement.parentNode.className=="open") //else if no cookie and this UL has an explicit rel value of "open"
    	{
    		ddtreemenu.expandSubTree(treeid, ulelement) //expand this UL plus all parent ULs (so the most inner UL is revealed!)
    	}
    
    	ulelement.parentNode.onclick=function(e)
    	{
    		var submenu=this.getElementsByTagName("ul")[0];
    		if(submenu.parentNode.className=="closed")
    		{
    			ulelement.parentNode.className="open";
    		}
    		else if(submenu.parentNode.className=="open")
    		{
    			ulelement.parentNode.className="closed";
    		}
    		ddtreemenu.preventpropagate(e)
    	}
    
    	ulelement.onclick=function(e)
    	{
    		ddtreemenu.preventpropagate(e);
    	}
    }
    
    ddtreemenu.expandSubTree=function(treeid, ulelement) //expand a UL element and any of its parent ULs
    {
    	var rootnode=document.getElementById(treeid);
    	var currentnode=ulelement;
    	currentnode.style.display="block";
    	while (currentnode!=rootnode)
    	{
    		if(currentnode.tagName=="ul"); //if parent node is a UL, expand it too
    		{
    			currentnode.parentNode.className="open";
    		}
    		currentnode=currentnode.parentNode;
    	}
    }
    
    ddtreemenu.flatten=function(treeid, action)//expand or contract all UL elements
    { 
    	var ultags=document.getElementById(treeid).getElementsByTagName("ul")
    	for (var i=0; i<ultags.length; i++)
    	{
    		ultags[i].parentNode.className=(action=="expand")? "open" : "closed";
    	}
    }
    
    ddtreemenu.rememberstate=function(treeid, durationdays)//store index of opened ULs relative to other ULs in Tree into cookie
    { 
    	var ultags=document.getElementById(treeid).getElementsByTagName("ul")
    	var openuls=new Array()
    	for (var i=0; i<ultags.length; i++)
    	{
    		if(ultags[i].parentNode.className=="open") openuls[openuls.length]=i //save the index of the opened UL (relative to the entire list of ULs) as an array element
    	}
    	if(openuls.length==0) //if there are no opened ULs to save/persist
    	{
    		openuls[0]="none open" //set array value to string to simply indicate all ULs should persist with state being closed
    	}
    	ddtreemenu.setCookie(treeid, openuls.join(","), durationdays) //populate cookie with value treeid=1,2,3 etc (where 1,2... are the indexes of the opened ULs)
    }
    
    ////A few utility functions below//////////////////////
    
    ddtreemenu.getCookie=function(Name) //get cookie value
    {
    	var re=new RegExp(Name+"=[^;]+", "i"); //construct RE to search for target name/value pair
    	if(document.cookie.match(re))
    	{//if cookie found
    		return document.cookie.match(re)[0].split("=")[1] //return its value
    	}
    	return ""
    }
    
    ddtreemenu.setCookie=function(name, value, days) //set cookei value
    {
    	var expireDate = new Date()
    	//set "expstring" to either future or past date, to set or delete cookie, respectively
    	var expstring=expireDate.setDate(expireDate.getDate()+parseInt(days))
    	document.cookie = name+"="+value+"; expires="+expireDate.toGMTString()+"; path=/";
    }
    
    ddtreemenu.searcharray=function(thearray, value) //searches an array for the entered value. If found, delete value from array
    {
    	var isfound=false
    	for (var i=0; i<thearray.length; i++)
    	{
    		if(thearray[i]==value)
    		{
    			isfound=true
    			thearray.shift() //delete this element from array for efficiency sake
    			break
    		}
    	}
    	return isfound
    }
    
    ddtreemenu.preventpropagate=function(e) //prevent action from bubbling upwards
    {
    	if(typeof e!="undefined")
    	{
    		e.stopPropagation()
    	}
    	else
    	{
    		event.cancelBubble=true
    	}
    }
    
    ddtreemenu.dotask=function(target, functionref, tasktype) //assign a function to execute to an event handler (ie: onunload)
    {
    	var tasktype=(window.addEventListener)? tasktype : "on"+tasktype
    	if(target.addEventListener)
    	{
    		target.addEventListener(tasktype, functionref, false)
    	}
    	else if(target.attachEvent)
    	{
    		target.attachEvent(tasktype, functionref)
    	}
    }
    The CSS

    Code:
    .treeview
    {
    	width:150px; 
    }
    
     /*CSS for Simple Tree Menu*/
    .treeview ul
    {
    	margin: 0;
    	padding: 0;
    }
    
    /*Style for LI elements in general (excludes an LI that contains sub lists)*/
    .treeview li
    { 
    	list-style-type: none;
    	padding-left: 12px;
    	margin-bottom: 3px;
    }
    
    .treeview li a
    {
    	background: white url(arrow.gif) no-repeat left center;
    	padding-left: 8px;
    }
    
     /* Style for LI that contains sub lists (other ULs). */
    .treeview li.open, .treeview li.closed
    {
    	cursor: hand !important;
    	cursor: pointer !important;
    }
    
     /*Style for ULs that are children of LIs (submenu) */
    .treeview li.closed ul
    {
    	display: none; /*Hide them by default. Don't delete. */
    }
    
    /*Style for LIs of ULs that are children of LIs (submenu) */
    .treeview .open ul li, .treeview .closed ul li
    { 
    	cursor: default;
    }
    
    li.closed
    {
    	background: white url(plus_sign.gif) no-repeat left 0.4em;
    }
    
    li.closed ul
    {
    	display: none;
    }
    
    li.open
    {
    	background: white url(minus_sign.gif) no-repeat left 0.4em;
    }
    
    li.open ul
    {
    	display: block;
    }
    Making siblings close upon the opening of an item is still a feature request though!!!

  10. #10
    Join Date
    Jan 2007
    Location
    Surrey, UK
    Posts
    16
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by fambi View Post
    Lol!!!
    May be you don't have much experience in coding these things. There is the simple concept of first iterating through all the siblings setting them to closed. This way you don't need to know which one to close. Then you open the one you want open.

    DDAdmin's suggestion attempted to first open the new tree then closed the specified old tree.

    The concept is sound even without me having to trawl through the particular script myself.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •