Re: Cascading Menus

by Andrew McFarland <aamcf(at)aamcf.co.uk>

 Date:  Sun, 14 Jul 2002 19:54:15 +0100
 To:  hwg-basics(at)hwg.org
 In-Reply-To:  localhost
  todo: View Thread, Original
[Beware of cross browser incompatibility in all of these, as well as the 
accessibility issues involved. If anyone is interested, I can make the 
scripts cross browser and show you how to make them more accessible.]

At 10:50 14/07/02 -0400, Thomas Rumley wrote:
<snip />
>I'm trying to put together a cascading drop down menu from some code that 
>I got. Only problem is as soon as I move off the link which brings the 
>menu up, the menu disappears. I'm using css to position divisions which 
>holds the menu lines.
>
>I'm thinking that I need to create a mouse over/out/on/something for a 
>division. Haven't the slightest way how to do it.

<snip />

You need to modify the javascript slightly. At the moment you have

var show = 0;
function flip(me) {
         ele = document.getElementById(me);
         ele.style.visibility = show ? 'hidden' : 'visible';
         show = show ? 0 : 1;
}

and in the HTML, you have:

<.a href="foo.html" onmouseover="flip('x')"  onmouseout="flip('x')">

The onmouseout means that the link is flipped as soon as you move the mouse 
away. There are a couple of things you could do.

As you want the text to stay visible after the mouse has moved off the 
link, you could split the flip function into two, putting a delay into the 
function that hides the text:

function flip(me) {
         ele = document.getElementById(me);
         ele.style.visibility = 'visible';
}

function oflip(me) {
         ele = document.getElementById(me);
         setTimeout("ele.style.visibility = 'hidden'", 5000);
}

And modify the HTML:

<.a href="foo.html" onmouseover="flip('x')"  onmouseout="oflip('x')">

This means that the text will display for 5000 milliseconds (5 seconds) 
after the mouse moves off the link. You can see this in action on 
http://aamcf.co.uk/temp/cascade1

There are two problems with this approach. First of all, there is an 
important variable - the amount of time the text displays for - buried in 
the code. 99% of the time its better to pull these out to the top of the code:

var delay = 5000 // delay in ms

function flip(me) {
         ele = document.getElementById(me);
         ele.style.visibility = 'visible';
}

function oflip(me) {
         ele = document.getElementById(me);
         setTimeout("ele.style.visibility = 'hidden'", delay);
}

This will make it easier to change the delay to something else in the 
future - you just need to look at the first line, and not worry about the 
syntax of the setTimeout method (which I personally can never remember). 
When you have to maintain a 400 line JavaScript you will appreciate things 
being done in this way!

The other problem is probably more serious though. It is slightly user 
hostile to have text disappearing suddenly - it might take someone 6 
seconds to read to the bottom, for example. What you want is a cascading 
menu where one option disappears only when another appears.

We need a function that will hide the currently shown layer if there is 
one, and will show the required layer:

var current = ''  // create variable to hold the current layer id

function showhide(me) {
         if (current){flip(current,1)};
         flip(me,0);
         current = me;
}

function flip(me,show) {
         ele = document.getElementById(me);
         ele.style.visibility = show ? 'hidden' : 'visible';
}

Pulling flip() out of showhide makes the function simpler to read, and 
easier to maintain.

See http://aamcf.co.uk/temp/cascade2

And finally, suppose we wanted to have an option to hide the currently 
shown layer we could modify showhide like this:

function showhide(me) {
         if (current){flip(current,1)};
         if (me) {flip(me,0)};
         current = me;
}

When called, showhide now does the following:

         if there is a current layer hide it
         if there is a `me' layer, show it
         set the value of current to `me'


So you can put onmouseover="showhide()" somewhere on the page to hide the 
current layer without showing another - see

See http://aamcf.co.uk/temp/cascade3

Andrew

--
http://aamcf.co.uk/

HTML: hwg-basics mailing list archives, maintained by Webmasters @ IWA