Drop-Down Menus : Menu « GUI Components « JavaScript DHTML






Drop-Down Menus

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/tr/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- 
     Example File From "JavaScript and DHTML Cookbook"
     Published by O'Reilly & Associates
     Copyright 2003 Danny Goodman
-->
<html>
<head>
<title>Recipe 10.8</title>
<style id="main" type="text/css">
body {background-color:#eeeeee; font-family:Arial,Helvetica,sans-serif; font-size:12px;}
h1 {font-size:2.0em; font-weight:bold}
</style>
<style rel="stylesheet" type="text/css">

.menuWrapper {
              position:absolute; 
              width:162px; 
              background-color:#339966; 
              visibility:hidden; 
              border-style:solid; 
              border-width:2px; 
              border-color:#EFEFEF #505050 #505050 #EFEFEF;
              display:block;
              padding:3px; 
             }
.menuItem    {
              cursor:pointer; 
              font-size:12px; 
              font-family:Arial, Helvetica, sans-serif; 
              border-bottom:1px solid #505050; 
              border-top:1px solid #EFEFEF;
              padding-left:10px; 
              color:black; 
              background-color:#339966; 
              text-decoration:none; 
              position:absolute; 
              left:0px; 
              width:159px; 
              height:1.4em;
              display:block;
              line-height:1.4em
             }
.menuItemOn  {
              cursor:pointer; 
              font-size:12px; 
              font-family:Arial, Helvetica, sans-serif; 
              border-bottom:1px solid #505050; 
              border-top:1px solid #EFEFEF;
              padding-left:10px; 
              color:#000000; 
              background-color:#33ff00; 
              text-decoration:underline; 
              position:absolute; 
              left:0px; 
              width:159px; 
              height:1.4em;
              display:block;
              line-height:1.4em
             }

</style>

<script language="JavaScript" type="text/javascript">
// global menu state
var menuReady = false;

// pre-cache menubar image pairs
if (document.images) {
    var imagesNormal = new Array();
    imagesNormal["home"] = new Image(20, 80);
    imagesNormal["home"].src = "home_off.jpg";
    imagesNormal["catalog"] = new Image(20, 80);
    imagesNormal["catalog"].src  = "catalog_off.jpg";
    imagesNormal["about"] = new Image(20, 80);
    imagesNormal["about"].src  = "about_off.jpg";

    var imagesHilite = new Array();
    imagesHilite["home"] = new Image(20, 80);
    imagesHilite["home"].src = "home_on.jpg";
    imagesHilite["catalog"] = new Image(20, 80);
    imagesHilite["catalog"].src  = "catalog_on.jpg";
    imagesHilite["about"] = new Image(20, 80);
    imagesHilite["about"].src  = "about_on.jpg";
}

function getElementStyle(elem, IEStyleProp, CSSStyleProp) {
    if (elem.currentStyle) {
        return elem.currentStyle[IEStyleProp];
    } else if (window.getComputedStyle) {
        var compStyle = window.getComputedStyle(elem, "");
        return compStyle.getPropertyValue(CSSStyleProp);
    }
    return "";
}

// carry over some critical menu style sheet attribute values
var CSSRuleValues = {menuItemHeight:"18px",
                     menuItemLineHeight:"1.4em",
                     menuWrapperBorderWidth:"2px",
                     menuWrapperPadding:"3px",
                     defaultBodyFontSize:"12px"
                    };

// specifications for menu contents and menubar image associations
var menus = new Array();
menus[0] = {mBarImgId:"menuImg_1",
            mBarImgNormal:imagesNormal["home"],
            mBarImgHilite:imagesHilite["home"],
            menuItems:[],
            elemId:""
           };
menus[1] = {mBarImgId:"menuImg_2",
            mBarImgNormal:imagesNormal["catalog"],
            mBarImgHilite:imagesHilite["catalog"],
            menuItems:[ {text:"Deluxe Line", href:"catalog_deluxe.html"},
                        {text:"Budget Line", href:"catalog_budget.html"},
                        {text:"Export", href:"catalog_export.html"},
                        {text:"Order Print Catalog", href:"catalog_order.html"}
                      ],
            elemId:""
           };
menus[2] = {mBarImgId:"menuImg_3", 
            mBarImgNormal:imagesNormal["about"],
            mBarImgHilite:imagesHilite["about"],
            menuItems:[ {text:"Press Releases", href:"press.html"},
                        {text:"Executive Staff", href:"staff.html"},
                        {text:"Map to Our Offices", href:"map.html"},
                        {text:"Company History", href:"history.html"},
                        {text:"Job Postings", href:"jobs.html"},
                        {text:"Contact Us", href:"contact.html"}
                      ],
            elemId:""
           };

// create hash table-like lookup for menu objects with id string indexes
function makeHashes() {
    for (var i = 0; i < menus.length; i++) {
        menus[menus[i].elemId] = menus[i];
        menus[menus[i].mBarImgId] = menus[i];
    }
}

// assign menu label image event handlers
function assignLabelEvents() {
    var elem;
    for (var i = 0; i < menus.length; i++) {
        elem = document.getElementById(menus[i].mBarImgId);
        elem.onmouseover = swap;
        elem.onmouseout = swap;
    }
}

// invoked from init(), generates the menu div elements and their contents.
// all this action is invisible to user during construction
function makeMenus() {
    var menuDiv, menuItem, itemLink, mbarImg, textNode, offsetLeft, offsetTop;
    
    // determine key adjustment factors for the total height of menu divs
    
    var menuItemH = 0;
    var bodyFontSize = parseInt(getElementStyle(document.body, "fontSize", "font-size"));
    // test to see if browser's font size has been adjusted by the user
    // and that the new size registers as an applied style property
    if (bodyFontSize == parseInt(CSSRuleValues.defaultBodyFontSize)) {
        menuItemH = (parseFloat(CSSRuleValues.menuItemHeight));
    } else {
        // works nicely in Netscape 7
        menuItemH = parseInt(parseFloat(CSSRuleValues.menuItemLineHeight) * bodyFontSize);
    }
    var heightAdjust = parseInt(CSSRuleValues.menuWrapperPadding) + 
        parseInt(CSSRuleValues.menuWrapperBorderWidth);
    if (navigator.appName == "Microsoft Internet Explorer" && 
        navigator.userAgent.indexOf("Win") != -1 && 
        (typeof document.compatMode == "undefined" || 
        document.compatMode == "BackCompat")) {
        heightAdjust = -heightAdjust;
    }
    
    // use menus array to drive div creation loop
    for (var i = 0; i < menus.length; i++) {
        menuDiv = document.createElement("div");
        menuDiv.id = "popupmenu" + i;
        // preserve menu's ID as property of the menus array item
        menus[i].elemId = "popupmenu" + i;
        menuDiv.className = "menuWrapper";
        if (menus[i].menuItems.length > 0) {
            menuDiv.style.height = (menuItemH * menus[i].menuItems.length) - 
            heightAdjust + "px";
        } else {
            // don't display any menu div lacking menu items
            menuDiv.style.display = "none";
        }
        // define event handlers
        menuDiv.onmouseover = keepMenu;
        menuDiv.onmouseout = requestHide;

        // set stacking order in case other layers are around the page
        menuDiv.style.zIndex = 1000;
        
        // assemble menu item elements for inside menu div
        for (var j = 0; j < menus[i].menuItems.length; j++) {
            menuItem = document.createElement("div");
            menuItem.id = "popupmenuItem_" + i + "_" + j;
            menuItem.className = "menuItem";
            menuItem.onmouseover = toggleHighlight;
            menuItem.onmouseout = toggleHighlight;
            menuItem.onclick = hideMenus;
            menuItem.style.top = menuItemH * j + "px";
            itemLink = document.createElement("a");
            itemLink.href = menus[i].menuItems[j].href;
            itemLink.className = "menuItem";
            itemLink.onmouseover = toggleHighlight;
            itemLink.onmouseout = toggleHighlight;
            textNode = document.createTextNode(menus[i].menuItems[j].text);
            itemLink.appendChild(textNode);
            menuItem.appendChild(itemLink);
            menuDiv.appendChild(menuItem);
        }
        // append each menu div to the body
        document.body.appendChild(menuDiv);
    }
    makeHashes();
    assignLabelEvents();
    // pre-position menu
    for (i = 0; i < menus.length; i++) {
        positionMenu(menus[i].elemId);
    }
    menuReady = true;
}

// initialize global that helps manage menu hiding
var timer;

// invoked from mouseovers inside menus to cancel hide
// request from mouseout of menu bar image et al.
function keepMenu() {
    clearTimeout(timer);
}

function cancelAll() {
    keepMenu();
    menuReady = false;
}

// invoked from mouseouts to request hiding all menus
// in 1/4 second, unless cancelled
function requestHide() {
    timer = setTimeout("hideMenus()", 250);
}

// "brute force" hiding of all menus and restoration
// of normal menu bar images
function hideMenus() {
    for (var i = 0; i < menus.length; i++) {
       document.getElementById(menus[i].mBarImgId).src = menus[i].mBarImgNormal.src;
       var menu = document.getElementById(menus[i].elemId)
       menu.style.visibility = "hidden";
    }
}

// set menu position just before displaying it
function positionMenu(menuId){
    // use the menu bar image for position reference of related div
    var mBarImg = document.getElementById(menus[menuId].mBarImgId);
    var offsetTrail = mBarImg;
    var offsetLeft = 0;
    var offsetTop = 0;
    while (offsetTrail) {
        offsetLeft += offsetTrail.offsetLeft;
        offsetTop += offsetTrail.offsetTop;
        offsetTrail = offsetTrail.offsetParent;
    }
    if (navigator.userAgent.indexOf("Mac") != -1 && 
        typeof document.body.leftMargin != "undefined") {
        offsetLeft += document.body.leftMargin;
        offsetTop += document.body.topMargin;
    }
    var menuDiv = document.getElementById(menuId);
    menuDiv.style.left = offsetLeft + "px";
    menuDiv.style.top = offsetTop + mBarImg.height + "px";
}

// display a particular menu div
function showMenu(menuId) {
    if (menuReady) {
        keepMenu();
        hideMenus();
        positionMenu(menuId);
        var menu = document.getElementById(menuId);
        menu.style.visibility = "visible";
    }
}

// menu bar image swapping, invoked from mouse events in menu bar
// swap style sheets for menu items during rollovers
function toggleHighlight(evt) {
    evt = (evt) ? evt : ((event) ? event : null);
    if (typeof menuReady != "undefined") {
        if (menuReady && evt) {
            var elem = (evt.target) ? evt.target : evt.srcElement;
            if (elem.nodeType == 3) {
                elem = elem.parentNode;
            }
            if (evt.type == "mouseover") {
                keepMenu();
                elem.className ="menuItemOn";
            } else {
                elem.className ="menuItem";
                requestHide();
            }
            evt.cancelBubble = true;
        }
    }
}

function swap(evt) {
    evt = (evt) ? evt : ((event) ? event : null);
    if (typeof menuReady != "undefined") {
        if (evt && (document.getElementById && document.styleSheets) && menuReady) {
            var elem = (evt.target) ? evt.target : evt.srcElement;
            if (elem.className == "menuImg") {
                if (evt.type == "mouseover") {
                    showMenu(menus[elem.id].elemId);
                    elem.src = menus[elem.id].mBarImgHilite.src;
                } else if (evt.type == "mouseout") {
                    requestHide();
                }
                evt.cancelBubble = true;
            }
        }
    }
}

// create menus only if key items are supported
function initMenus() {
    if (document.getElementById && document.styleSheets) {
        setTimeout("makeMenus()", 5);
        window.onunload=cancelAll;
    }
}


</script>
</head>
<body onload="initMenus()">
<h1>Drop-Down Menus</h1>
<hr />

<div id="menubar">
<a href="index.html"><img id="menuImg_1" class="menuImg" 
src="home_off.jpg" border="0" height="20" 
width="80"></a><a href="catalog.html"><img id="menuImg_2" 
class="menuImg" src="catalog_off.jpg" border="0" height="20" 
width="80"></a><a href="about.html"><img id="menuImg_3" 
class="menuImg" src="about_off.jpg" border="0"
height="20" width="80"></a>
</div>

</body>
</html>


           
       








Related examples in the same category

1.Application Menubar Example
2.[DOM Menu] :: Example 1 :: Horizontal Menu
3.[DOM Menu] :: Example 2 :: KDE Keramik Style Menu
4.[DOM Menu] :: Example 3: Brainjar.com 'Revenge of the Menubar' Style Menu
5.[DOM Menu] Example 4: Vertical Menu
6.[DOM Menu] :: Example 5 :: Two Menus
7.[DOM Menu] :: Example 6 :: Flash Hiding
8.Menu bar for an inner fake window
9.Fly in Menu item
10.Not too fancy menu with toolbar
11.Custom Contextual Menu(content sensitive)
12.Menu with sound
13.Menu based on Javascript
14.popup menu (content sensitive menu)
15.Complete Source Code for the Menu
16.Slide out menu
17.Dynamic menu: fly in
18.Menu and submenu
19.Slide out menu with i18N
20.Menu: XP, win 98 style
21.Simple drop-down menu example with layer
22.Build a simple fancy menu
23.Add/delete menu items
24.Customizable layout: customize menu layout
25.Vertical layout menu
26.Easy skinable menu with CSS
27.Menu Item properties
28.Direct link menu
29.Context menu: popup menu
30.Black Menu
31.Dropdown menu