-->
Bookmark and Share

Revenge of the Menu Bar

See the demo page for the finished version of the code.

Event Handlers for Menus

As with the menu bar buttons, we start by setting some event handlers in the tags for the menus.

<div id="menu3" class="menu"
     onmouseover="menuMouseover(event)">
<a class="menuItem" href="...">Menu 3 Item 1</a>
<a class="menuItem" href="...">Menu 3 Item 2</a>
<a class="menuItem" href="...">Menu 3 Item 3</a>
<a class="menuItem" href="..."
   onclick="return false;"
   onmouseover="menuItemMouseover(event, 'menu3_4');">
  <span class="menuItemText">Menu 3 Item 4</span>
  <span class="menuItemArrow">&#9654;</span></a>
<a class="menuItem" href="...">Menu 3 Item 5</a>
<a class="menuItem" href="..."
   onclick="return false;"
   onmouseover="menuItemMouseover(event, 'menu3_6');">
  <span class="menuItemText">Menu 3 Item 6</span>
  <span class="menuItemArrow">&#9654;</span>
</a>
</div>

On each of the items that will have a sub menu we set the link's onmouseover event to call the function menuItemMouseover(). As usual, the first argument is the event object. The second gives the ID of the sub menu to be associated with the item.

Also note the use of onclick="return false;" on the item link. This simply prevents the browser from trying to load the link's URL when it is clicked on. This can be omitted should you want to actually link a page to the item.

On the menu DIV itself, onmousover is set to call the function menuMouseover(). This time, only the event object needs to be passed.

The sub menus are defined just like the main menus, using the same HTML format and style classes. They can in turn have items with sub menus assigned to them. Below is an example.

<div id="menu3_4" class="menu">
<a class="menuItem" href="...">Menu 3-4 Item 1</a>
<div class="menuItemSep"></div>
<a class="menuItem" href="...">Menu 3-4 Item 2</a>
<a class="menuItem" href="...">Menu 3-4 Item 3</a>
<div class="menuItemSep"></div>
<a class="menuItem" href="...">Menu 3-4 Item 4</a>
<a class="menuItem" href="...">Menu 3-4 Item 5</a>
</div>

<div id="menu3_6" class="menu"
     onmouseover="menuMouseover(event)">
<a class="menuItem" href="..."
   onclick="return false;"
   onmouseover="menuItemMouseover(event, 'menu3_6_1');">
  <span class="menuItemText">Menu 3-6 Item 1</span>
  <span class="menuItemArrow">&#9654;</span></a>
<a class="menuItem" href="...">Menu 3-6 Item 2</a>
<a class="menuItem" href="...">Menu 3-6 Item 3</a>
</div>

<div id="menu3_6_1" class="menu">
<a class="menuItem" href="...">Menu 3-6-1 Item 1</a>
<a class="menuItem" href="...">Menu 3-6-1 Item 2</a>
<a class="menuItem" href="...">Menu 3-6-1 Item 3</a>
<a class="menuItem" href="...">Menu 3-6-1 Item 4</a>
</div>

Note that the onmouseover handler on the menu DIV is only required if the any of its items have sub menus. Otherwise it can be left off.

The menuItemMouseover() function will handle the task of displaying an item's sub menu while the menuMouseover() function will take care of hiding those same sub menus when they are not needed.

The Menu Item mouseover Event Handler

This function is similar to the one that displays the main menu under a button. It must deactivate any currently active sub menu, position the designated sub menu and make it visible.

Again, it first identifies the item link element that fired the event. Calling on the getContainerWith() function it also identifies the owning menu DIV element.

function menuItemMouseover(event, menuId) {

  var item, menu, x, y;

  // Find the target item element and its parent menu element.

  if (browser.isIE)
    item = getContainerWith(window.event.srcElement, "A", "menuItem");
  else
    item = event.currentTarget;
  menu = getContainerWith(item, "DIV", "menu");

The menu element is needed because we'll be adding a user defined property to it for keeping track of which sub menu is active. This is analogous to how the activeButton global variable was used to track the currently active button on the menu bar.

In fact, the next step is to check this property, named activeItem, and close any sub menu it may be referencing. Then the current item is recorded as the active one.

  // Close any active sub menu and mark this one as active.

  if (menu.activeItem != null)
    closeSubMenu(menu);
  menu.activeItem = item;

As with the active button, we change the item's appearance by adding the menuItemHighlight style class to its className property.

  // Highlight the item element.

  item.className += " menuItemHighlight";

As this class was has the same settings as the link's :hover pseudo-class, the item will appear remain highlighted even if the user moves the mouse off of it.

The sub menu, just like the menus for the buttons, needs to be initialized the first time it is displayed.

  // Initialize the sub menu, if not already done.

  if (item.subMenu == null) {
    item.subMenu = document.getElementById(menuId);
    if (item.subMenu.isInitialized == null)
      menuInit(item.subMenu);
  }

The code also saves a reference to the sub menu as a user defined property on the item named subMenu. This creates a chain of references: activeButton -> menu -> activeItem -> subMenu -> activeItem -> subMenu, etc., which will be helpful in closing menus when needed. But first, we still need to position the requested sub menu and make it visible.