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

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

Logo

Hierarchical Menus Ver. 3 - Addendum IV (v3.04)
the Navigator 4.5 eval() bug


Several readers have been quick to point out that the Navigator 4.5 fix in version 3.03 did not address the true source of the problem. Consequently, the solution proposed was not universal, solving only the problem as it appears in the menu script. Other scripts, for other techniques, might present the same problem, and our solution would be useless.

As usual, our thanks to Luca Passani, first with this new solution, and special thanks to Martin Honnen who defined the problem:

"The bug with
eval(whichEl + "= new Layer(elWidth,whichContainer)");
is not as capricious as described by you. It's a bug with eval inside a function where an argument was not passed a value but is later assigned one. Eval for some reasons doesn't know that value."

If the above does not make any sense, a quick look at the version 3.03 discussion of this problem may be in order. There, we identified the offending statement correctly, but attributed the problem to the statement's evaluation of the new Layer() constructor.

In reality, the problem resides with the statement's evaluation of the whichContainer variable.

How, so? Here is the complete pre-version 3.03 makeElement() function, which does not work in Navigator 4.5:

function makeElement(whichEl,whichWidth,whichParent,whichContainer) {
   if (NS4) {
      if (whichWidth) {
         elWidth = whichWidth;
      }
      else {
         elWidth = (whichContainer) ? whichContainer.menuWidth : whichParent.menuWidth;
         if (whichContainer) elWidth = elWidth-(borWid*2)-(itemPad*2);
      }
      if (!whichContainer) whichContainer = menuLoc;
      eval(whichEl + "= new Layer(elWidth,whichContainer)");
   }
   else {
      elStr = "<DIV ID=" + whichEl + " STYLE='position:absolute'></DIV>";
      menuLoc.document.body.insertAdjacentHTML("BeforeEnd",elStr);
      if (isFrames) eval(whichEl + "= menuLoc." + whichEl);
   }
   return eval(whichEl);
}

Here, also, is the description of the function's purpose published in the version 3.03 addendum:

Whenever we need to create a positioned element, (layer), whether it be the container menu (both browsers) or a component menu item (Navigator-only), we call makeElement(), passing four arguments:

1. whichEl:
the identifier for the new layer, as a string. For example, if we are creating the menu container which we will eventually refer to as elMenu1, we pass "elMenu1" as a string. This argument is used by both browsers.
2. whichWidth:
the wrapping width of the layer. This is a required argument of the new Layer() constructor, which we use to create layers on-the-fly. We only use it when creating a top-level menu (a parent menu). All other levels in the same menu tree, and menu items, get their wrapping width from the parent. Therefore, it has an integer value when a parent menu is being created, and a null value for all other cases. This argument is used only by Navigator, as the width is applied dynamically after creation in Explorer.
3. whichParent:
The top-level menu identifier in the menu tree. This argument is an object (eg. elMenu1, elMenu2, etc.) if the menu being created is a child menu or item and a null value if the menu is a parent. This argument is used only by Navigator, since it is used to obtain the width for any child menus and all items.
4. whichContainer:
Necessary if the layer is a menu item. It identifies the menu the item is to be placed in. If the argument is omitted, the script assumes that the layer is a menu and creates it within the window object, represented by the menuLoc variable. Again this argument is Navigator-specific, since makeElement() is used only for menu creation (not item creation) in Explorer.

Recall that for Navigator, we call makeElement() from makeMenuNS(), in this way:

function makeMenuNS(isChild,menuCount,parMenu,parItem) {
   .
   .
   .
   if (!isChild) {
      tempWidth = tempArray[0] ? tempArray[0] : menuWidth;
      menu = makeElement("elMenu" + menuCount,tempWidth);
            // only two arguments passed
   }
   else {
      menu = makeElement("elMenu" + menuCount,null,parMenu);
            // only three arguments passed
   }
   .
   .
   .
}

We choose to omit the unecessary arguments, passing, on one occasion, two arguments and on the other, three arguments. We leave it to makeElement() to check the value of the arguments. If they are missing, it acts accordingly. Or so we thought.

On the next page, we'll demonstrate the behavior of eval() within a function, if it uses an undefined argument.


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/col21addIV2.html