crossbrowser reusable javascript for dropdown that hides another menu when active?
October 31, 2006 6:57 PM   Subscribe

What I suspect is a fairly stupid javascript question, but one I haven't found an ideal solution for. I four menus made out of unordered lists. I'm using a modified version of the suckerfish dropdown script to make it work in IE (code inside), in one place I want 1 of the four menus to stay open except when I hover on one of the remaining menus. i.e. menu1 is visible. when I mouseover menu2, menu1 is hidden. When I mouseout of menu2 menu1 reappears.

I built the menu as four separate lists rather than containing them in a parent list as I normally would because of some tricky positioning requirements that were generating weird effects in IE6 and that, when fixed, made the menus work rather poorly. My current approach doesn't require any css hacks, either, which is a good thing now that IE7 is here. Here is the code to make the menus work in IE:

startList = function() {
if (document.all && document.getElementById) {
for (d = 1; d< 10; d++) { navroot=document.getElementById('menu'+d); for (i=0; inavroot.childnodes.length; i++) { node=navRoot.childNodes[i]; if (node.nodename="LI" ) { node.onmouseover=function() { this.classname+="over" ; if (d!=1) menu1.classname+="hide" ; } node.onmouseout=function() { this.classname=this.className.replace(" over" , ); menu1.classname=menu1.className.replace(" hide" , ); } } } } } } /code>
Those familiar with the sfhover javascript will notice the only difference in mine is for (d = 1; d< 10; d++) {/code> Of course, this only works in IE. What I need is something that works in all browsers and doesn't require adding any javascript anywhere in the body. What it should do is add a class called 'hide' to the LI in menu1 whenever the user mouses over menu2 and remove the class 'hide' from menu1 when the user mouses out. It has to work in IE6 , IE7, Firefox, and Safari. It has to not interfere with the dropdown script that is required since IE won't recognize :hover on elements other than anchors.

While I'm revealing the depths of ignorance, I'd really like to understand how to make this work. Thanks!

As a secondary, and far less important question, does anyone know where I can download IE6? I use Firefox and recently updated IE to 7 to mess around. I intended to install it alongside 6 so I could test layouts in both 6 and 7, but I seem to have uninstalled 6. Anyway. Back to the real question.
posted by Grod to Computers & Internet (6 answers total)
 
Response by poster: I swear it didn't look like that on preview. Let's try again:

startList = function() {
    if (document.all && document.getElementById) {
        for (d = 1; d< 10; d++) {br>             navRoot = document.getElementById('menu'+d);
            for (i=0; i                  node = navRoot.childNodes[i];
                 if (node.nodeName=="LI") {
                     node.onmouseover=function() {
                         this.className+="over";
                  if (d!=1) menu1.className+="hide";
                     }
                     node.onmouseout=function() {
                         this.className=this.className.replace("over", "");
                  menu1.className=menu1.className.replace("hide", "");
                  }
                 }
             }
         }
    }
}
window.onload=startList;


Those familiar with the sfhover javascript will notice the only difference in mine is for (d = 1; d< 10; d++) {/code> Of course, this only works in IE. What I need is something that works in all browsers and doesn't require adding any javascript anywhere in the body. What it should do is add a class called 'hide' to the LI in menu1 whenever the user mouses over menu2 and remove the class 'hide' from menu1 when the user mouses out. It has to work in IE6 , IE7, Firefox, and Safari. It has to not interfere with the dropdown script that is required since IE won't recognize :hover on elements other than anchors.

While I'm revealing the depths of ignorance, I'd really like to understand how to make this work. Thanks!
posted by Grod at 8:00 PM on October 31, 2006


Response by poster: I don't know where br> came from, but there should be a break there. How odd.
posted by Grod at 8:01 PM on October 31, 2006


Response by poster: CLEARLY I AM TOO STUPID to post on askMeFi

Here is the absolute correct code, not that it matters because I'm asking something else, but anyway...

startList = function() {
    if (document.all && document.getElementById) {
        for (d = 1; d< 10; d++) {br>             navRoot = document.getElementById('menu'+d);
            for (i=0; i                  node = navRoot.childNodes[i];
                 if (node.nodeName=="LI") {
                     node.onmouseover=function() {
                         this.className+="over";
                     }
                     node.onmouseout=function() {
                         this.className=this.className.replace("over", "");
                  }
                 }
             }
         }
    }
}
window.onload=startList;

posted by Grod at 8:32 PM on October 31, 2006


If you want it to work in all (modern) browsers, you can start by getting rid of the first if.

I don't feel like going into any further detail.
posted by furtive at 8:37 PM on October 31, 2006


Yes, document.all is an IE thing (although Firefox kind of supports it). If your goal is working across all browsers, you should use standards-compliant JavaScript. But there is no reason for your code to test for the presence of document.all, because you don't appear to use that.

Another thought : When you try to add classes with a string-manipulation technique like menu1.className+="hide", don't you need a space before the "hide?"

Yet another thought: I think different browsers handle the this keyword differently, and it is not always safe to assume it points to the correct object when you use it in an event-handling function.

It has to work in IE6 , IE7, Firefox, and Safari.

A tall order for any JavaScript code!

If you are new to JavaScript, I do recommend that you spend an afternoon and try out a nice prototype library, like jQuery or Prototype.js. They can make writing JS much easier, and tend to give you code that works across browsers very easily.
posted by profwhat at 8:49 PM on October 31, 2006


Best answer: like furtive, I don't have time to write your code, but here's some help.

furtive said to remove the first ifs, but the point of suckerfish is that you only need the js to help IE which doesn't support the :hover pseudo-class.

that said, you can't do what you want with just css in browsers other than IE, so you'll need to use that suckerfish script for all browsers.

what you'll need to change are the 2 functions attached to each LI that cause the class of that LI to change.

[code]node.onmouseover=function() {
this.className+="over";
}[/code]

inside of those functions, you'll have to tell the other lists/menus to hide themselves. to do that, you'll have to know which list you're in, and hide all of the others. and when you mouse out, you'll have to show them again...

also, regarding multiple IE browsers, see here, and then here

I haven't tried this with IE7 as I'm now using VMware virtual machines to run multiple IE browsers, but it worked for 5.0,5.5, and 6 together before.

good luck
posted by mrblakwell at 8:14 AM on November 1, 2006


« Older Are nearlyfreespeech.net servers globally banned...   |   Help me get into William Morris' agent trainee... Newer »
This thread is closed to new comments.