DHTML Lab: Cross-Browser Hierarchical Menus; User Interface | WebReference

DHTML Lab: Cross-Browser Hierarchical Menus; User Interface


Logo

Cross-Browser Hierarchical Menus
getting the menus on the page

Webreference

Contents

Open the menus above to remind yourself that this is a technique worth learning.

In longer script listings, cross-browser code is blue, Navigator-specific code is red, and Explorer code is green.

The HTML Links

Recall that we placed links with onMouseOver and onMouseOut handlers, wherever we want our menus to appear on our page. The links in the left column, for example, have this HTML:

<P><A HREF="/"
      onMouseOver = "popUp('elMenu1',event)"
      onMouseOut = "popDown('elMenu1')">
         Webreference</A></P>
<P><A HREF="/index2.html"
      onMouseOver="popUp('elMenu2',event)"
      onMouseOut="popDown('elMenu2')">
         Contents</A></P>

In Explorer, the event object is created and passed implicitly to any function the event handler calls. We therefore do not require the second argument for popUp(), as we do for Navigator. Its inclusion, however, is harmless.

Note: Remember to use elMenu1, elMenu2, elMenu3 as the first arguments for popUp() and popDown(). Do not confuse these element identifiers with the array identifiers (arMenu1, arMenu2, etc.).

Displaying the Top Level Menu

The only browser-specific code in our popUp() function is the assignment to xPos and yPos of the mouse's x-y coordinates. Explorer prefers event.x and event.y to define them.

function popUp(menuName,e) {
   if (!areCreated) return;
   hideAll();
   currentMenu = eval(menuName);
   xPos = (NS4) ? e.pageX : event.x;
   yPos = (NS4) ? e.pageY : event.y;
   currentMenu.moveTo(xPos,yPos);
   currentMenu.keepInWindow();
   currentMenu.isOn = true;
   currentMenu.showIt(true);
}

Keeping the Menus in the Client Window

The keepInWindow() function is primarily concerned with element and window measurement, and element positioning. Unfortunately, the two browsers don't agree on the properties used. The logic is exactly the same, just the property names differ.

All the properties have been discussed and used before many times. It is a simple procedure to create a cross-browser function, but it involves a lot of ifs. To minimize them, we have used just one if...else statement to contain browser-specific code. This leads to quicker execution and easier reading, but more typing, since some statements are repeated.

function keepInWindow() {
  scrBars = 20;
  if (NS4) {
    winRight = (keep with next line)
(window.pageXOffset + window.innerWidth) - scrBars;
    rightPos = this.left + menuWidth;
   
    if (rightPos > winRight) {
      if (this.hasParent) {
        parentLeft = this.parentMenu.left;
        newLeft = ((parentLeft-menuWidth) + childOverlap);
        this.left = newLeft;
      }
      else {
        dif = rightPos - winRight;
        this.left -= dif;
      }
    }
    winBot = (keep with next line)
(window.pageYOffset + window.innerHeight) - scrBars;
    botPos = this.top + this.fullHeight;
    if (botPos > winBot) {
      dif = botPos - winBot;
      this.top -= dif;
    }
  }
  else {
    winRight = (keep with next line)
(document.body.scrollLeft + document.body.clientWidth) - srcBars;
    rightPos = this.style.pixelLeft + menuWidth;
	
    if (rightPos > winRight) {
      if (this.hasParent) {
        parentLeft = this.parentMenu.style.pixelLeft;
        newLeft = ((parentLeft - menuWidth) + childOverlap);
        this.style.pixelLeft = newLeft;
      }
      else {
        dif = rightPos - winRight;
        this.style.pixelLeft -= dif;
      }
    }
    winBot = (keep with next line)
(document.body.scrollTop + document.body.clientHeight) - scrBars;
    botPos = this.style.pixelTop + this.fullHeight;
    if (botPos > winBot) {
      dif = botPos - winBot;
      this.style.pixelTop -= dif;
    }
  }
}

The logic of keepInWindow() was, of course, discussed in our previous column.

You may see the result by mousing over these right-aligned links:

Webreference

Contents

The showIt() Visibility Toggle

Since our elements are dynamically created, Navigator insists on show/hide values for its visibility property. Explorer accepts the CSS-compliant visible/hidden values.

function showIt(on) {
 if (NS4) {this.visibility = (on) ? "show" : "hide"}
 else {this.style.visibility = (on) ? "visible" : "hidden"}
}

Hiding All Menus

Our hideAll() function is the same for both browsers:

function hideAll(){
   for(i=1; i<topCount; i++) {
      temp = eval("elMenu" + i);
      temp.isOn = false;
      if (temp.hasChildVisible) temp.hideChildren();
      temp.showIt(false);
   }   
}

onMouseOut

The function called when we mouse out of a link, popDown() is also the same for both browsers:
function popDown(menuName){
   if (!areCreated) return;
   whichEl = eval(menuName);
   whichEl.isOn = false;
   whichEl.hideTop();
}

The boring stuff is over. The remaining pages will introduce a few new properties.


Produced by Peter Belesis and

All Rights Reserved. Legal Notices.
Created: Feb. 27, 1998
Revised: Feb. 27, 1998

URL: http://www.webreference.com/dhtml/column15/menu2Start.html