DHTML Lab: Hierarchical Menus Ver. 2 (Cross-Browser/Frames); Menu Display | WebReference

DHTML Lab: Hierarchical Menus Ver. 2 (Cross-Browser/Frames); Menu Display


Logo

Hierarchical Menus Ver. 2 (Cross-Browser/Frames)
menu display

WebReference

Parameters used for the menus on this page:

menuWidth = 120;
childOverlap = 20;
childOffset = 0;
perCentOver = null;
secondsVisible = .5;
fntCol = "blue";
fntSiz = 10;
fntBold = false;
fntItal = false;
fntFam = "sans-serif";
backCol = "#DDDDDD";
overCol = "white";
overFnt = "black";
borWid = 2;
borCol = "brown";
borSty = "solid";
itemPad = 6;
imgSrc = "tri.gif";
imgSiz = 10;
separator = 1;
separatorCol = "red";
isFrames = false;

Menu Animated GIF
Animated GIF demonstrating heirarchical menus for non-DHTML browsers.

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

The [cc] symbol denotes code continuation. The code is part of the preceding line. It is placed on a new line for column formatting considerations only.

When the user passes the mouse over our in-page links, the popUp() function is called to position and show the menus. It expects two arguments, the menu to display as a string value, and the event object, created by the mouseover:

function popUp(menuName,e){
  if (beingCreated) return;
  if (!beingCreated && !areCreated) startIt();
  hideAll();
  currentMenu = eval(menuName);
  if (!isFrames) {
    xPos = (NS4) ? e.pageX : event.x;
    yPos = (NS4) ? e.pageY : event.y;
  }
  else {
   if (IE4) menuLocBod = menuLoc.document.body;
   switch (navFrLoc) {
    case "left":
     xPos = (NS4) ? menuLoc.pageXOffset : menuLocBod.scrollLeft;
     yPos = (NS4) ? (e.pageY-pageYOffset) + menuLoc.pageYOffset :
[cc]                event.clientY + menuLocBod.scrollTop;
     break;
    case "top":
     xPos = (NS4) ? (e.pageX-pageXOffset) + menuLoc.pageXOffset :
[cc]                event.clientX + menuLocBod.scrollLeft;
     yPos = (NS4) ? menuLoc.pageYOffset : menuLocBod.scrollTop;
     break;
    case "bottom":
     xPos = (NS4) ? (e.pageX-pageXOffset) + menuLoc.pageXOffset :
[cc]                event.clientX + menuLocBod.scrollLeft;
     yPos = (NS4) ? menuLoc.pageYOffset + menuLoc.innerHeight :
[cc]                menuLocBod.scrollTop + menuLocBod.clientHeight;
     break;
    case "right":
     xPos = (NS4) ? menuLoc.pageXOffset + menuLoc.innerWidth :
[cc]                menuLocBod.scrollLeft + menuLocBod.clientWidth;
     yPos = (NS4) ? (e.pageY-pageYOffset) + menuLoc.pageYOffset :
[cc]                event.clientY + menuLocBod.scrollTop;
     break;
   }
  }
  currentMenu.moveTo(xPos,yPos);
  currentMenu.keepInWindow()
  currentMenu.isOn = true;
  currentMenu.showIt(true);
}

Menus in Frame? For Sure!

In version 1, popUp() first checked the value of areCreated. If it was false, it returned. Only when areCreated was true (when the menus had been created), would the remainder of the statements execute. In the frames version, if the one-line statement for the main frame onLoad handler did not exist, the menus would not be created upon page load.

Much of the feedback on Version 1 revolved around this frame-based problem: If the authors do not have access to the page loaded into the main frame, to add the statement, then the menus do not appear in the frame.

The solution is: if the menus in the main frame are not created automatically when the frame's page loads, then they should be created when the user mouses over the link. The beingCreated variable, initialized in initVars(), helps us track this behaviour:

  if (beingCreated) return;
  if (!beingCreated && !areCreated) startIt();

If the menus are in the process of being created, then beingCreated is true, and popUp() returns. If the menus are not being created and they are not already created, it means the onLoad handler in the frame's page does not exist or has not kicked in. In this case, startIt() is called to initiate menu creation.

Note:
It is not a good idea to use the menus to link to pages not on your server. Our tests have shown that Navigator 4 allows modification of these pages to include menus, but Explorer 4 may generate an "Access Denied" error, and not generate the menus. We advise linking to pages on your server, only.

Live Example:
The four form buttons in the left column open a window that demonstrates the four navigation frame positioning options and after-load menu creation.

The only time that popUp() executes the remainder of its statements is when areCreated is true, that is, when the menus exist.

First, popUp() assures that all menus are hidden, by calling hideAll(). Then it assigns the menu-in-question to our currentMenu menu-tracking variable.

  hideAll();
  currentMenu = eval(menuName);

Menu Positioning

Next, popUp() determines where to position the top-level menu. The x-y coordinates are assigned to xPos and yPos, respectively.

If we are not using frames, our menu will appear where the mouseover occurred:

xPos = (NS4) ? e.pageX : event.x;
yPos = (NS4) ? e.pageY : event.y;

If our menu is to appear in a frame, then the navFrLoc variable will contain one of four string values: "left", "top", "right" or "bottom". Using the switch statement, we execute specific statements based on the value of navFrLoc. switch was discussed in detail in column19.

All the frame-based positioning statements are natural variations on the original frame positioning discussed in column18.

For code clarity, we create menuLocBod to represent Explorer's menuLoc.document.body object.

if (IE4) menuLocBod = menuLoc.document.body;
switch (navFrLoc) {
 case "left":
  xPos = (NS4) ? menuLoc.pageXOffset : menuLocBod.scrollLeft;
  yPos = (NS4) ? (e.pageY-pageYOffset) + menuLoc.pageYOffset :
[cc]             event.clientY + menuLocBod.scrollTop;
  break;
 case "top":
  xPos = (NS4) ? (e.pageX-pageXOffset) + menuLoc.pageXOffset :
[cc]             event.clientX + menuLocBod.scrollLeft;
  yPos = (NS4) ? menuLoc.pageYOffset : menuLocBod.scrollTop;
  break;
 case "bottom":
  xPos = (NS4) ? (e.pageX-pageXOffset) + menuLoc.pageXOffset :
[cc]             event.clientX + menuLocBod.scrollLeft;
  yPos = (NS4) ? menuLoc.pageYOffset + menuLoc.innerHeight :
[cc]             menuLocBod.scrollTop + menuLocBod.clientHeight;
  break;
 case "right":
  xPos = (NS4) ? menuLoc.pageXOffset + menuLoc.innerWidth :
[cc]             menuLocBod.scrollLeft + menuLocBod.clientWidth;
  yPos = (NS4) ? (e.pageY-pageYOffset) + menuLoc.pageYOffset :
[cc]             event.clientY + menuLocBod.scrollTop;
  break;
 }

Once the values of xPos and yPos have been determined, the menu is positioned; kept within the browser window boundaries; its isOn tracking property set to true; and finally, made visible:

currentMenu.moveTo(xPos,yPos);
currentMenu.keepInWindow()
currentMenu.isOn = true;
currentMenu.showIt(true);

Now, let's review what happens when the user mouses over the menu.


Produced by Peter Belesis and

All Rights Reserved. Legal Notices.
Created: May. 22, 1998
Revised: May. 22, 1998

URL: http://www.webreference.com/dhtml/column20/hier2Popup.html