DHTML Lab: Hierarchical Menus, I; Menu Navigation | WebReference

DHTML Lab: Hierarchical Menus, I; Menu Navigation


DHTML Hierarchical Menus, Part I
navigating the menus



Navigate the menus above. The event handler firings are reflected in the browser status bar, below.

To properly develop the inter-menu navigation code, we must first understand how the mouseover and mouseout event firing works.

Our instinct probably tells us that the events for the menus and items follow this order:
move over a menu: the menu's mouseover fires, then the item's mouseover fires.
move out of a menu: the item's mouseout fires, then the menu's mouseout.

This order may apply under certain conditions, but it doesn't in our technique. Keep in mind that an item's left and right boundaries are exactly the same as the menu's left and right boundaries. The first item's top boundary is the same as the menu's top, and the last item's bottom boundary is the same as the menu's bottom.

When we enter or leave a menu, we are entering or leaving an item as well. That is, two elements are in line for the same event, the mouseover or the mouseout. In Navigator, when two elements fire the same event at exactly the same time, the topmost element in the page element hierarchy handles the event first. Then it is passed down for handling to element's lower than it in the page hierarchy.

Therefore, when we enter a menu, the menu's mouseover fires, then the item's. When we leave a menu, again the menu's mouseout fires first, then the item's.

Open the menus in the left column and watch the browser status bar as you navigate the menus. The event, and the element it is attached to, will appear in the order that they occur.

With this behaviour understood, we can build the functions that handle the mouseover and mouseout events for the menus and items.

Mousing OVER a Menu

As we shall see later, the exciting stuff happens with the item event handlers. Here, in menuOver(), variables are simply updated to reflect state.

function menuOver() {
 this.isOn = true;
 isOverMenu = true;
 currentMenu = this;
 if (this.hideTimer) clearTimeout(this.hideTimer);

The menu's isOn property is set to true, as is the global isOverMenu. The currentMenu global variable is updated to store the menu element as the menu in use. If the hideTimer property is anything but null, it means a timer is running that will soon make this menu disappear. If this is the case, hideTimer is cleared with clearTimeout().

Mousing OVER an Item

When we mouse over an item, we are either just entering the menu, or have just left another item in the same menu. First, of course, we change the item's background color producing the rollover effect the user expects.

function itemOver(){
 this.bgColor = overCol;
 if (this.container.hasChildVisible) {
 if(this.hasMore) {
  this.childY = this.pageY + childOffset;
  this.childX = (keep with next line)
this.container.left + (menuWidth - childOverlap);
  this.container.hasChildVisible = true;
  this.container.visibleChild = this.child;

Next, we check for any child menus of the menu that may be visible. If there is a child menu visible, we call the menu's hideChildren method, which will hide the child menu unless it belongs to the item being moused over. This last case will exist when we mouse over an item from its visible, already-navigated child menu.

Finally, we determine if the item has a child menu of its own by evaluating the item's hasMore property. If it does, the item's child property will reflect the identity of the child menu. We then locate where the child menu is to be positioned, making allowances for the childOverlap and the childOffset parameters, which we defined in our in-page script. Then we move the child menu to these coordinates.

Using the child menu's keepInWindow method, we ensure that it will appear in the browser window. Two new properties are set for the item's containing menu: hasChildVisible, which simply reflects that the menu has one of its items' child menus visible; and visibleChild, which stores the actual child menu that is visible.

With all the overhead tasks complete, and the child menu correctly positioned, it is made visible.

Mousing OUT of a Menu

The function called when we mouse out of a menu is even simpler than the mouseover one. Two state variables are set to false:

function menuOut() {
 this.isOn = false;
 isOverMenu = false;

Mousing OUT of an Item

When we leave an item, we first change the background color back to the original color.

function itemOut(){ 
 this.bgColor = backCol;
 if (!isOverMenu)
  allTimer = setTimeout("currentMenu.hideTree()",10);

When we mouse out of an item, we may be simply moving to another item or we may be leaving the menu itself. We know that it is the latter case, if isOverMenu is false, since the menu's mouseout event will have fired first and this variable will have been updated. If we are moving out of a menu, then the menu's (currentMenu) hideTree method is called in 10 milliseconds using the setTimeout() method. This delayed execution is assigned to the allTimer variable.

Why delayed execution? Because we may be moving to the child menu. There is no way to determine in Navigator which element we are moving to. If we are moving to a child menu, the 10 milliseconds will give us more than enough time to move to the child and programatically stop the timer from executing. As we'll see on the next page, hideTree() will first check to see if we are still navigating the menu tree. If we are not, it means our mouse is over a non-menu part of the page, and the menus will be hidden.

Macintosh Behaviour Note: Navigator on the Macintosh seems to halt script execution when the mouse leaves the browser's client window. Moving the mouse back into the client area resumes script execution. That is, if the user moves the mouse at light speed off the menu and onto the toolbar or "chrome" part of the browser, part of the menu tree might be left stranded and visible. This will rarely happen, of course. When the user brings the mouse back in, the menus will diappear. This platform-specific oddity does not occur in the Windows version.

Finally, let's look at the functions that hide the menus.

Produced by Peter Belesis and

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

URL: http://www.webreference.com/dhtml/column14/menuOver.html