DHTML Lab: Hierarchical Menus, I; The Complete Code 3/3 | WebReference

DHTML Lab: Hierarchical Menus, I; The Complete Code 3/3


Logo

  DHTML Hierarchical Menus, Part I
  SPECIAL EDITION; the director's cut 3/3

The Hierarchical Menu Routines (hierMenus.js)

This file, along with the external array file, may be download in ZIP format

/*hierMenus.js
* By Peter Belesis. v1.0 980220
* Copyright (c) 2001 Peter Belesis. All Rights Reserved.
* Originally published and documented at http://www.dhtmlab.com/
* Available solely from INT Media Group. Incorporated under exclusive license.
* Contact licensing@internet.com for more information.
*/
semi = ";";
styleStr = "<STYLE TYPE='text/css'>"
styleStr += ".items {"
styleStr += "width:" + menuWidth + semi
styleStr += "color:"+ fntCol + semi
styleStr += "font-size:"+ fntSiz + semi
styleStr += "font-weight:"+ fntWgh + semi
styleStr += "font-style:"+ fntSty + semi
styleStr += "font-family:"+ fntFam + semi
styleStr += "border-width:" + borWid + semi
styleStr += "border-color:" + borCol + semi
styleStr += "border-style:" + borSty + semi
styleStr += "line-height:" + linHgt + semi
styleStr += "}"
styleStr += "</STYLE>";
 
document.write(styleStr);
if (perCentOver != null) {
    childOverlap = (perCentOver/100) * menuWidth
}
mSecsVis = secondsVisible*1000;
imgStr = "<IMG SRC=" + imgSrc + " WIDTH=" + imgSiz + " HEIGHT=" + imgSiz +" BORDER=0 VSPACE=2 ALIGN=RIGHT>"
topCount = 1;
areCreated = false;
isOverMenu = false;
currentMenu = null;
allTimer = null;
function menuSetup(hasParent,lastItem,openCont,openItem) {
    this.menuOver = menuOver;
    this.menuOut = menuOut;
    this.onmouseover = this.menuOver;
    this.onmouseout = this.menuOut;
    
    this.keepInWindow = keepInWindow;
    this.showIt = showIt;
    
    this.hideTree = hideTree
    this.hideParents = hideParents;
    this.hideChildren = hideChildren;
    this.hideTop = hideTop;
    
    this.hasChildVisible = false;
    this.isOn = false;
    
    this.hideTimer = null;
    this.fullHeight = lastItem.top + lastItem.document.height;
    this.clip.bottom = this.fullHeight;
    if (hasParent) {
        this.hasParent = true;
        this.parentMenu = openCont;
        this.parentItem = openItem;
        this.parentItem.child = this;
    }
    else {
        this.hasParent = false;
        this.hideSelf = hideSelf;
    }
}
  
function itemSetup(arrayPointer,whichArray) {
    this.bgColor = backCol;
    this.clip.right = menuWidth;
    this.visibility = "inherit";
    this.itemOver = itemOver;
    this.itemOut = itemOut;
    this.onmouseover = this.itemOver;
    this.onmouseout = this.itemOut;
    this.dispText = whichArray[arrayPointer];
    this.linkText = whichArray[arrayPointer+1];
    this.hasMore = whichArray[arrayPointer+2];
    
    if (this.linkText.length>0) {
        this.linkIt = linkIt;
        this.onfocus = this.linkIt;
    }
    
    this.container = this.parentLayer;
        
    if (this.hasMore) {
        htmStr = imgStr + this.dispText;
    }
    else {
        htmStr = this.dispText;
    }
    layStr = "<SPAN CLASS=items>" + htmStr+ "</SPAN>";
    this.document.write(layStr);
    this.document.close();
    if (arrayPointer == 0) {
        this.top = 0;
    }
    else {
        this.top = this.prevItem.top + this.prevItem.document.height - borWid;
    }
    this.left = 0;
}
function makeElement(whichEl,whichContainer) {
    if (arguments.length==1) whichContainer = window;
    eval(whichEl + "= new Layer(menuWidth,whichContainer)");
    return eval(whichEl);
}
function makeTop() {
    status = "Creating Hierarchical Menus";
    while(eval("window.arMenu" + topCount)) {
        topArray = eval("arMenu" + topCount);
        topName = "elMenu" + topCount;
        topMenu = makeElement(topName);
        topMenu.setup = menuSetup;
        topItemCount = 0;
        for (i=0; i<topArray.length; i+=3) {
            topItemCount++;
            topItemName = "item" + topCount + "_" + topItemCount;
            topItem = makeElement(topItemName,topMenu);
            if (topItemCount >1)
                topItem.prevItem = eval("item" + topCount + "_" + (topItemCount-1));
            topItem.setup = itemSetup;
            topItem.setup(i,topArray);
            if (topItem.hasMore) makeSecond();
        }
        
        topMenu.setup(false,topItem);
        topCount++
    }
    status = "Menus Created"
    areCreated = true;
}
function makeSecond() {
    secondCount = topCount + "_" + topItemCount;
    
    secondArray = eval("arMenu" + secondCount);
    secondName = "elChild" + secondCount;
    
    secondMenu = makeElement(secondName);
    secondMenu.setup = menuSetup;
    secondItemCount=0;
    for (j=0; j<secondArray.length; j+=3) {
        secondItemCount++;
        secondItemName = "item" + secondCount +"_" + secondItemCount;
        secondItem = makeElement(secondItemName,secondMenu)        
        
        if (secondItemCount >1)
            secondItem.prevItem = eval("item" + secondCount  + "_" + (secondItemCount-1));
        secondItem.setup = itemSetup;
        secondItem.setup(j,secondArray);
        if (secondItem.hasMore) makeThird();
    }
    secondMenu.setup(true,secondItem,topMenu,topItem);
}
function makeThird() {
    thirdCounter = secondCount + "_" + secondItemCount 
    
    thirdArray = eval("arMenu" + thirdCounter);
    thirdName = "elGrandChild" + thirdCounter;
    thirdMenu = makeElement(thirdName)
    
    thirdMenu.setup = menuSetup;
    thirdItemCount=0;
    for (k=0; k<thirdArray.length; k+=3) {
        thirdItemCount++;
        thirdItemName = "item" + thirdCounter + "_" + thirdItemCount;
        thirdItem = makeElement(thirdItemName,thirdMenu);
        if (thirdItemCount >1)
            thirdItem.prevItem = eval("item" + thirdCounter + "_" +(thirdItemCount-1));
        thirdItem.setup = itemSetup;
        thirdItem.setup(k,thirdArray);
    }
    thirdMenu.setup(true,thirdItem,secondMenu,secondItem);
}
function linkIt() {
    location.href = this.linkText;
}
function showIt(on) {
    this.visibility = (on) ? "show" : "hide";
}
function keepInWindow() {
    scrBars = 20;
    winRight = (window.pageXOffset + window.innerWidth) - scrBars;
    rightPos = this.left + menuWidth;
    
    if (rightPos > winRight) {
        if (this.hasParent) {
            parentLeft = this.parentMenu.left;
            newLeft = ((parentLeft - menuWidth) + childOverlap);
            this.left = newLeft;
        }
        else {
            dif = rightPos - winRight;
            this.left -= dif;
        }
    }
    winBot = (window.pageYOffset + window.innerHeight) - scrBars;
    botPos = this.top + this.fullHeight;
    if (botPos > winBot) {
        dif = botPos - winBot;
        this.top -= dif;
    }
}
function popUp(menuName,e){
    if (!areCreated) return;
    hideAll();
    currentMenu = eval(menuName);
    xPos = e.pageX;
    yPos = e.pageY;
    currentMenu.moveTo(xPos,yPos);
    currentMenu.keepInWindow()
    currentMenu.isOn = true;
    currentMenu.showIt(true);
}
function popDown(menuName){
    if (!areCreated) return;
    whichEl = eval(menuName);
    whichEl.isOn = false;
    whichEl.hideTop();
}
function menuOver() {
    this.isOn = true;
    isOverMenu = true;
    currentMenu = this;
    if (this.hideTimer) clearTimeout(this.hideTimer);
}
function menuOut() {
    this.isOn = false;
    isOverMenu = false;
}
function itemOver(){
    this.bgColor = overCol;
    if (this.container.hasChildVisible) {
        this.container.hideChildren(this);
    }            
    if(this.hasMore) {
        this.childY = this.pageY + childOffset;
        this.childX = this.container.left + (menuWidth - childOverlap);
        this.child.moveTo(this.childX,this.childY);
        this.child.keepInWindow();
        this.container.hasChildVisible = true;
        this.container.visibleChild = this.child;
        this.child.showIt(true);
    }
}
function itemOut() { 
    this.bgColor = backCol;
    if (!isOverMenu) allTimer = setTimeout("currentMenu.hideTree()",10);
}
function hideAll() {
    for(i=1; i<topCount; i++) {
        temp = eval("elMenu" + i);
        temp.isOn = false;
        if (temp.hasChildVisible) temp.hideChildren();
        temp.showIt(false);
    }    
}
function hideTree() {
    allTimer = null;
    if (isOverMenu) return;
    if (this.hasChildVisible) {
        this.hideChildren();
    }
    this.hideParents();
}
function hideChildren(item) {
    if (this.visibleChild.hasChildVisible) {
        this.visibleChild.visibleChild.showIt(false);
        this.visibleChild.hasChildVisible = false;
    }
    if (!this.isOn || !item.hasMore || this.visibleChild != this.child) {
        this.visibleChild.showIt(false);
        this.hasChildVisible = false;
    }
}
function hideParents() {
    if (this.hasParent) {
        this.showIt(false);
        if (this.parentMenu.hasParent) {
            this.parentMenu.isOn = false;        
            this.parentMenu.showIt(false);
            this.parentMenu.parentMenu.isOn = false;
            whichEl = this.parentMenu.parentMenu
        }
        else {
            this.parentMenu.isOn = false;
            whichEl = this.parentMenu;
        }
    }
    else {
        whichEl = this;
    }
    whichEl.hideTop();
}
function hideTop() {
    whichEl = this;
    this.hideTimer = setTimeout("whichEl.hideSelf()",mSecsVis);
}
function hideSelf() {
    this.hideTimer = null;
    if (!this.isOn && !isOverMenu) { 
        this.showIt(false);
    }
}
window.onload = makeTop;

Next column, we'll look at adapting this technique to Explorer 4, and create a cross-browser version.


Produced by Peter Belesis and

All Rights Reserved. Legal Notices.
Created: Feb. 19, 1998
Revised: Feb. 19, 1998

URL: http://www.webreference.com/dhtml/column14/allCode3.html