So, Henry asks me about how to do this expanding menu thing. Here’s how I was able to get this done. First, there are two ways to make things invisible using CSS. One is to set the visibility property of an object, the other is to set the display property. Setting the visibility to hidden will make it invisible, but the object will still take up the same amount of space. So, a ten line paragraph set to hidden will show ten lines of white space. Setting it to display: none will remove it from the whole flow, as if it weren’t there. Since I wanted the menus beneath to move up if one is collapsed, I chose the display method.
Next, I needed some icons. The Netscape Devedge sidebars have this whole expanding menu tree, but I only wanted one level. They use nice + and – icons too, so I stole those and edited them to remove the extra space around them. A javascript method uses those as links to open and close the menus.
Now I needed to do the programming. It’s all CSS and javascript. The CSS is involved with the menu block’s display, the javascript is used for setting the initial state of the menus, toggling the menus, and saving the state of the menus in a cookie so it appears in the same state the next time you return. To accomplish this, I used the technique of constructing a javascript class, one that represented the menus that I have. Here is that code:
function menu (name, status) {
this.name = name;
this.icon = name + "_icon";
this.status = status;
function toggle_menu () {
var divobj = document.getElementById(this.name).style;
var menuobj = document.getElementById(this.icon);
if (this.status == "1") {
menuobj.src = "minus.gif";
divobj.display = "none";
this.status = "0";
} else {
menuobj.src = "plus.gif";
divobj.display = "block";
this.status = "1";
}
}
this.toggle = toggle_menu;
function display_menu () {
var divobj = document.getElementById(this.name).style;
var menuobj = document.getElementById(this.icon);
if (this.status == "0") {
menuobj.src = "minus.gif";
divobj.display = "none";
} else {
menuobj.src = "plus.gif";
divobj.display = "block";
}
}
this.display = display_menu;
}
Note that any menu objects get the following properties: name, icon, status, and the following methods: toggle and display. After this is defined, I define an array that contains all of the menu objects I need to create. If I have more, I just add a line to this array detailing the new menu item.
var menus = new Array ();
menus[menus.length] = new menu ("entry", "1");
menus[menus.length] = new menu ("comment", "0");
menus[menus.length] = new menu ("gallery", "0");
menus[menus.length] = new menu ("link", "0");
menus[menus.length] = new menu ("archive", "0");
menus[menus.length] = new menu ("calendar_table", "0");
The keys here are that the name corresponds to the id of the menu, and the icon corresponds to the id of the +/- image id that goes with the menu. Each menu is an unordered list, and is turned on or off depending on what it’s status is, or whether it is being toggled or not. The initial display method is there to make sure the menu is displayed correctly when the page loads or re-loads. The toggle method is called whenever you click on a +/- icon, and also changes the source of the icon image to the opposite of what it was.
There is one level of abstraction between these methods and how they are called. The init_menu function is really what sets the state on load/relaod. This function loops over the menus array and displays them according to what is stored in your cookie:
function init_menu () {
var state = document.cookie;
if (state.length > 0) {
var states = state.substr(state.indexOf("=")+1);
var stati = states.split("");
for (i=0; i<stati.length; i++) {
if (menus[i]) {
menus[i].status = stati[i];
menus[i].display();
}
}
} else {
for (i=0; i<menus.length; i++) {
menus[i].display();
}
}
}
Note that it just does a cookie check and goes on about setting the display of the menus.
The last function is what is really called when you click on a +/- icon. This function also does the cookie setting so that it reflects the most recent icon click:
function show_hide(item) {
var state = "";
for (i=0; i<menus.length; i++) {
if (menus[i].name == item) {
menus[i].toggle();
}
state += menus[i].status;
}
// First expire the existing menu cookie:
document.cookie = 'menu_status=' + state + '; expires=0';
// Reset the menu cookie for one day:
var today = new Date();
var expire = new Date();
expire.setTime(today.getTime() + 1000*60*60*24);
document.cookie = 'menu_status=' + state + '; expires=' + expire.toGMTString();
}
And that’s about it. The only other supporting code is in the declarations of the menu items themselves:
<div>
<h2>
<a href="javascript:show_hide('link');">
<img id="link_icon" src="plus.gif" alt="Links Menu Icon" /></a> Links
</h2>
<ul id="link">
<li><a href="http://www.henrylewis.org/">Henry Lewis' Place</a></li>
.
.
.
</ul>
</div>
</pre>