DHTML Lab: Hierarchical Menus Version 3 | 19 | WebReference

DHTML Lab: Hierarchical Menus Version 3 | 19


Logo

Hierarchical Menus: Version 3
Navigator menu re-creation

WebReference

Click the link above to reveal menu. Click anywhere on the page to hide menu.

Parameters used for the menus on this page:

menuVersion = 3;
menuWidth = 120;
childOverlap = 50;
childOffset = 5;
perCentOver = null;
secondsVisible = .5;
fntCol = "blue";
fntSiz = "10";
fntBold = false;
fntItal = false;
fntFam = "sans-serif";
backCol = "#DDDDDD";
overCol = "#FFCCCC";
overFnt = "blue";
borWid = 1;
borCol = "#CC0000";
borSty = "solid";
itemPad = 3;
imgSrc = "tri.gif";
imgSiz = 10;
separator = 1;
separatorCol = "red";
keepHilite = true; 
NSfontOver = false;
clickStart = true;
clickKill = true;
showVisited = "";
isFrames = false;

Background Reading:

startIt():
  column 18
  column 20

event capturing:
  column 3

NS click problem:
  column 3

NS resize bug:
  DHTML Diner

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

startIt()

The startIt() function, called when the page/frameset loads, has several important additions.

function startIt() {
  isLoaded = true;
  if (isFrames) {
    menuLoc = eval("parent.frames." + mainFrName);
    if (NS4) {
      loader.captureEvents(Event.LOAD);
      loader.onload = NSloaded;
      menuLoc.onunload = NSunloaded;
    }
    if (IE4) {
      menuLoc.document.body.onunload = IEunloaded;
    }
  }
  else {
    menuLoc = window;
  }
  menuLoc.nav = nav = window;
  if (clickKill) {
    if (NS4) menuLoc.document.captureEvents(Event.MOUSEDOWN);
    menuLoc.document.onmousedown = clicked;
  }
  if (NS4) setTimeout("loader.onresize=reDo",2000);
  makeTop();  
}

First of all, isLoaded is set to true, since the page/frameset has now loaded.

Next, we determine where the menus will appear, menuLoc, as in the previous versions.

If the menus are in a frameset (isFrames), then we have new code for handling the main page load and unload. For Explorer, the unload event calls a new function, IEunloaded(). For Navigator, the procedure is a little more complicated.

Capturing a Frame Load for Navigator

In a frameset, the second statement in our script,

loader.onload = startIt;
directs the parent frameset to call startIt(), when its load event fires, that is, when all the child frames have loaded. In other words, when the frameset has completely loaded. A one-time occurrence.

An immensely powerful and useful feature of the NS4 event capturing model is the ability of the frameset to capture all event firings of a type in all child frames. To achieve this, we must first capture an event, using the captureEvents() method. The following two statements tell the frameset to be on the alert for any load events in its children frames, and if a load event fires, to call the NSloaded() function:

      loader.captureEvents(Event.LOAD);
      loader.onload = NSloaded;

The NSloaded() function looks like this:

function NSloaded(e){
  if (e.target.name == mainFrName) {
    initVars();
    startIt();
  }
}

This ability is only vaguely alluded to in the Netscape DHTML documentation. I discovered it by accident, and have not seen it used anywhere. It solves one of the main problems our menu script had: the re-creation of menus immediately upon a new page loading in the main frame!

Here's how it works:

  1. We direct the frameset to capture all load event firings in the child frames:
    loader.captureEvents(Event.LOAD);
  2. If a load occurs the NSloaded() function should be called:
    loader.onload = NSloaded;
  3. The load event is implicitly passed as an argument to NSloaded(), represented by the standard e:
    function NSloaded(e){
  4. The frameset will capture and direct the load event, whenever it fires, and for all load event firing elements. This includes page loads, layer loads and image loads. We need to isolate and handle only the main frame page loads. The target property of the event stores the object that fired the event, so we compare the NAME= attribute of the object to mainFrName. If they match, we know that the menu frame has just loaded:
      if (e.target.name == mainFrName) {
  5. If the user, therefore, has loaded the main frame with a new page, we initialize the variables and call startIt() to rebuild the menus:
        initVars();
        startIt();

Menu Frame unload

When our menu frame unloads, the NSunloaded() function is called:


      menuLoc.onunload = NSunloaded;

NSunloaded() simply sets isLoaded to false, as we are now in the process of loading a new page:

function NSunloaded(){
    isLoaded = false;
}

Arranging for Menu Hide with the click Event

Back to our discussion of startIt().

If clickKill is true, startIt() captures the mousedown event for the document and directs it to the clicked() function. We want to capture the click event, but since NS4 has a quirky document.onclick, we use document.onmousedown for stable and similar results. The clicked() function will execute whenever a user presses a mouse button in your page, and hide the menus if they are not being navigated.

if (clickKill) {
if (NS4) menuLoc.document.captureEvents(Event.MOUSEDOWN);
menuLoc.document.onmousedown = clicked;
}

We'll discuss clicked() later, when we look at the menu-hiding functions.

Navigator resize Problem, Revisited

There has been feedback on NS4 sometimes reloading a page endlessly. This is due to the load/resize bug documented in the DHTML Diner. To help avoid it, increase the millisecond interval between a load and the setting of the resize handler. Here we set it to 2000 (two seconds), hoping that the user does not resize the window in that time.

If the user does resize the window, our standard reDo() function is called, here modified for added functionality:

function reDo(){
    initVars();
    NSresized = true;
    menuLoc.location.reload();
}

Our variables are initialized, the NSresized is set to true, and the menu window/frame is reloaded. The first two statements only have an effect if we are in a frameset document, as a full-page reload clears all variables.

We'll come back to NSresized later, when discussing the menu display functions. For know, it must be mentioned that we need to track a window resize, since some of our script functionality will be lost. Our frameset load event capturing will be cancelled, so we will have to rebuild our menus manually. Once NSresized is set to true, it is never reset to false.

When startIt() exits, it calls makeTop(), to begin menu creation. Before we get to menu creation, let's look at how we rebuild the menus automatically in Explorer


Produced by Peter Belesis and

All Rights Reserved. Legal Notices.
Created: Sept. 03, 1998
Revised: Sept. 03, 1998

URL: http://www.webreference.com/dhtml/column21/hier3Start.html