DHTML Lab - dhtmlab.com - Hierarchical Menus Ver. 3 - Addendum IV (v3.04) | 4 | WebReference

DHTML Lab - dhtmlab.com - Hierarchical Menus Ver. 3 - Addendum IV (v3.04) | 4

Logo

Hierarchical Menus Ver. 3 - Addendum IV (v3.04)
the Navigator 4.x crash()


Special thanks to David Cole, who assisted in the testing of this fix.

History

Originally our menus did not display a "hand" cursor for Navigator, since our menu items were not true links. That is, they did not have the <A HREF> tag, using instead event handlers and assignment to the location property. The Explorer version used the cursor property to display a "hand" cursor.

After reader demand, we inserted links in the items, using the link() method, to force a "hand" cursor for Navigator. In version 3.0, the linkIt() function, called whenever the user clicks an item, looked like this:

function linkIt() {
   if (this.linkText.indexOf("javascript") != -1)
      {eval(this.linkText); return}
   menuLoc.location.href = this.linkText;
}

Here, in linkIt(), we decided whether to execute a javascript statement or navigate to a new page.

In version 3.02, however, we attempted to fix a bug introduced by the links:

When javascript statements were executed by the menus (instead of page navigation), the statements were executed twice! You can re-read this discussion in addendum II.

We solved this problem (or so we thought) by changing the links to dummy links, using javascript:void(0), and modifying linkIt().

In fact, this is how we described our solution, then:

The problem is overcome by ensuring that all clicks are handled by the item itself and not by the A tag. In fact, the A tag becomes a dummy tag, its sole purpose being to create a "hand" cursor for friendlier navigation. We accomplish this by giving all A tags in menu items a javascript:void(0) URL. This special JavaScript URL uses the void operator to evaluate an expression without returning a value. Since the expression to be evaluated is 0, nothing happens. A dummy HREF is created!

htmStrOver =
  htmStr.fontcolor(this.container.menuFontOver).link("javascript:void(0)");
htmStr = htmStr.link("javascript:void(0)");

We can add a further mechanism to avoid the double-link, by adding a return false to the linkIt() function:

function linkIt() {
   if (this.linkText.indexOf("javascript")!=-1){
      eval(this.linkText);
      return true
   }
   menuLoc.location.href = this.linkText;
   return false;
}

Looking at this function, with hindsight, it seems odd. We navigate to a new page using location.href (which essentially terminates function execution, as the page is unloaded) yet we have a return immediately following, to avoid the link kicking in. In Explorer, this does not cause a problem, yet in Navigator it sometimes causes a browser crash after the new page appears and the user attempts to move their mouse. This does not occur in frameset documents since the return false is properly executed, the unloaded page being different from the controlling page that contains the script. (i.e. the main frame unloads, but the nav frame has the script, which continues execution)

So we are back to square one with this fix.

First of all, lets bring linkIt() to its pre-3.02 state, making it a little more elegant in the process by omitting the return and using else instead:

function linkIt() {
   if (this.linkText.indexOf("javascript")!=-1) eval(this.linkText)
   else menuLoc.location.href = this.linkText;
}

Next, we have to ensure that the <A HREF> dummy links are never executed. In Navigator, we can accomplish this by capturing all click events in a menu, and cancelling their default action. One way, would be like this:

function killClicks() {
   return false
}
menuReference.document.captureEvents(Event.CLICK);
menuReference.document.onclick = killClicks;
Note: Recall that click events, unlike mouseover, mouseout, mousedown and mouseup are events of the layer's document object, not the layer itself.

Since our event handling function has only one line, we are better off just assigning the function itself to the event handler, instead of pointing to it:

menuReference.document.captureEvents(Event.CLICK);
menuReference.document.onclick = function(){return false};

We can now insert these statements in the Navigator-specific part of menusetup(), which establishes the look and behavior of menu elements:

function menuSetup(hasParent,openCont,openItem) {
   .
   .
   .
   if (NS4) {
      this.bgColor = this.menuBorCol;
      this.fullHeight = this.lastItem.top + this.lastItem.clip.bottom + borWid;
      this.clip.right = this.menuWidth;
      this.clip.bottom = this.fullHeight;

// 3.04 - capture all clicks to avoid A HREF navigation
      this.document.captureEvents(Event.CLICK);
      this.document.onclick = function(){return false};
   }
   .
   .
   .
}

Using this method, all link clicks are cancelled automatically, without using the linkIt() function.

On the next page, we reproduce the complete hierMenus.js external file. Please upgrade to this new version.


Produced by Peter Belesis and

All Rights Reserved. Legal Notices.
Created: Dec 20, 1998
Revised: Dec 20, 1998

URL: http://www.webreference.com/dhtml/column21/addendum4/col21addIV4.html