Description
This script provides a non-JavaScript dependent tree menu. In the absense of JavaScript, the menu will automatically start minimized, thus remaining accessible to those without JavaScript enabled.
Demonstration
Implementation
The trick that makes this menu work is the fact that it uses JavaScript to minimize the menu as soon as it loads. Basically, it is set up like this. Each item is contained in a <div>. The subitems need to be contained in their parent's <div>. So, if you want a menu that has the first level item with one submenu item, and then one other top level item, the code would look like this:
<div id="menu_container"> <div class="item"><span><img src="images/minus.gif" width="9" height="9"> one</span> <div class="item"><a href="#">two</a></div> <div class="item"><a href="#">three</a></div> </div> <div class="item"><a href="#">four</a></div> </div> <script type="text/javascript"> if (document.getElementById) { //if DOM compliant init(); } </script>
Note how the two subitems are contained inside their parent item's <div>. Also, the bit of JavaScript that comes right after the menu is what tells compliant browsers to minimize the menu.
If you need certain items to start in the down position, you can use the startup variable at the top of the script to do this. There is a comment in the script directly below this variable that explains how it works.
Images Needed (right click -> save as)
Code
<style type="text/css"> #menu_container { color: #527FA8; background: #f5f5f5; border: 1px solid #819ebb; width: 200px; padding: 3px; } .item { cursor: default; margin-left: 15px; display: block; } #menu_container a { color: #527FA8; background: transparent; text-decoration: none; } </style> <script type="text/javascript"> /*##################################################### # This script is Copyright 2003, Infinity Web Design # # Written by Ryan Brill - [email protected] # # All Rights Reserved - Do not remove this notice # #####################################################*/ startup = ""; //Comments on this below /* * COMMENTS ABOUT THE startup VARIABLE - * Leave the startup variable blank to run as normal, enter 1 to start with the entire menu maximized. * Additionally, each item can be either be displayed or not displayed in the following fashion: * 1|1|1|1|0|0|1|1 where 1's mean to display, and 0's mean not to display. So, in that * example, the first, second, third and fourth items would be displayed, the fifth and * sixth would not be displayed, and the seventh and eigth would be displayed on startup. Be sure * you set all top level items (items without submenus) to 1, or they will never be displayed! */ function init() { menu = document.getElementById("menu_container"); //get the container element spans = menu.getElementsByTagName("span"); //grab all the spans for (i=0; i<spans.length; i++) { spans[i].onclick = showhide; //set the onclick to run the showhide funcion for each span } /*Initialize the menu. For browsers without JavaScript enabled, it will remain in it's down state*/ divs = menu.getElementsByTagName("div"); //grab all the divs str = ""; allcookies = document.cookie; //get the cookies if (allcookies) { pos = allcookies.indexOf("menu="); //get the position of the start of our cookie if (pos != -1) { start = pos + 5; //set start to the beginning of our cookies value end = allcookies.indexOf(";", start); //get to the end of our cookie if (end == -1) { end = allcookies.length; //or get to the end of all cookies (if it is the last one) } str = allcookies.substring(start, end); //grab our cookies value (from start to end) } else if (startup != "") { //if startup is not blank str = startup; //grab the values out of startup } } if (str.length > 0) { //if we found the cookie to set display to block or none str = str.replace(/1/g, "block"); //replace 1 with block str = str.replace(/0/g, "none"); //replace 0 with none str = str.split("|"); //split at the pipe while (str.length <= divs.length) { //if we have more divs that display (block|none) to fill it with str[str.length] = "block"; //fill array with blocks } for (i=0; i<divs.length; i++) { if (str[i] == "block") { //if it needs to be block divs[i].style.display = str[i]; //display } else { divs[i].style.display = str[i]; //hide } if (divs[i].childNodes[0].childNodes[0].src != undefined && str[i+1] == "none") { //if div contains an image, and if the next div's display is none divs[i].childNodes[0].childNodes[0].src = "images/plus.gif"; //set image for down state } } } else { for (i=0; i<divs.length; i++) { child = divs[i].getElementsByTagName("div"); //grab all the child divs for (j=0; j<child.length; j++) { child[j].style.display = "none"; //hide } if (divs[i].childNodes[0].childNodes[0].src != undefined) { //if the div contains an image divs[i].childNodes[0].childNodes[0].src = "images/plus.gif"; //set image for down state } } } } function showhide() { obj = this.parentNode; //get parent element (div in our case) elems = obj.childNodes; //get child nodes for (i=0; i<elems.length; i++) { if (elems[i].tagName == "DIV") { //if child node is a div if (elems[i].style.display == "none") { //if elemnt is elems[i].style.display = "block"; //display this.childNodes[0].src = "images/minus.gif"; //set image for down state } else { elems[i].style.display = "none"; //hide this.childNodes[0].src = "images/plus.gif"; //set image for up state } } } menu = document.getElementById("menu_container"); //get the container element divs = menu.getElementsByTagName("div"); //grab all the divs val = ""; for (i=0; i<divs.length; i++) { display = (divs[i].style.display == "" || divs[i].style.display == "block") ? 1 : 0; //set display to 1 or 0 depending on the display value of the div val += display+"|"; //concatenate the value } val = val.substring(0,val.length-1); //strip off the final pipe (|) document.cookie = "menu="+val; } </script> </head> <body> <div id="menu_container"> <div class="item"><span><img src="images/minus.gif" width="9" height="9"> one</span> <div class="item"><a href="#">two</a></div> <div class="item"><span><img src="images/minus.gif" width="9" height="9"> three</span> <div class="item"><span><img src="images/minus.gif" width="9" height="9"> four</span> <div class="item"><span><img src="images/minus.gif" width="9" height="9"> four</span> <div class="item"><a href="#">five</a></div> </div> </div> </div> <div class="item"><a href="#">six</a></div> </div> <div class="item"><a href="#">seven</a></div> </div> <script type="text/javascript"> if (document.getElementById) { //if DOM compliant init(); } </script>
Tested in: IE6, IE5.5, IE 5, IE 4, Netscape 7, Netscape 6 Netscape 4.7, Mozilla Firebird, Mozilla 1.4, and Opera 7.
Works or degrades well in: IE6, IE5.5, IE 5, IE 4, Netscape 7, Netscape 6 Netscape 4.7, Mozilla Firebird, Mozilla 1.4, and Opera 7.
Doesn't work or doesn't degrade work in: N/A
Copyright© 2003, Infinity Web Design