Magazine |
| | Community |
| | Workshop |
| | Tools & Samples |
| | Training |
| | Site Info |
|
|
||||||||
|
Robert Carter
Site Builder Network Writer
Matt Oshry
Programmer Writer
Internet Client SDK
George Young
Web Developer Engineer
Site Builder Network
August 25, 1998
Download Microsoft Word (.DOC) format of this document (zipped, 43.2K)
Editor's note: This article is part one of a series describing the code implementation for the Site Builder Network redesign launched in June and July of 1998. If you haven't yet, you might want to read the introduction, A Tale of Two Web Teams: Touring the Redesign Code.
Contents
Building the Menu
Populate the Menus Dynamically
Bellying up to NavBar
Managing Mouseovers
What Was It You Ordered Again?
Recap
Other parts in this series
Introduction and Overview
NavFrame: Selective Frame Activation
Other Special Features and Hacks
Once we've identified users of Internet Explorer 4.0 and up, we can send them our redesigned pages. We begin with the new SBN navigation bar (we call it the NavBar). We've patterned its interface behavior to mimic that of a real Microsoft Windows® application. In that context, the NavBar entries are analogous to application menu items.
First, simple mouseovers cause the highlighted areas to turn light blue.
Figure 1. Mousing over the SBN NavBar
Clicking on a menu item causes the menu it contains to drop down, revealing second-level areas. The chosen menu item changes to light gray.
Figure 2. Clicking a NavBar item causes a drop-down menu to appear
As with Windows applications, moving the mouse along the NavBar will cause each menu item to display its menu contents without requiring another mouse click. (Go ahead, try it.) Moving the mouse outside the NavBar or the exposed menu drop-down has no effect (the menu stays just where it is, thank you) unless you click again, which will cause the menu to retract.
Moving the mouse down the exposed menu will cause each highlighted entry to be banded in royal blue (the text converts to white to remain visible against the dark background). Note that the whole row is banded in blue rather than just the text, which we accomplish by placing each entry inside its own <DIV> tag.
Figure 3. Highlighted menu items are banded in blue
Clicking on an entry in the menu sends you to its associated area or page. If you choose either the Workshop or Tools & Samples entries, you'll be propelled to our redesigned sections (well, mostly redesigned, because the Design area will keep its look).
Once we have determined what browser a visitor is using, we generate the one-row table that will house NavBar. If visitors are using Internet Explorer 4.0 or 5.0, they get the Dynamic HTML (DHTML) table; everybody else gets the downlevel version.
The differences between the two are worth noting. In the downlevel table, each cell houses a hyperlinked graphic that sends the visitor to the referenced page. In the DHTML table for Internet Explorer 4.0 and higher, the only graphic is for the SBN logo; all the other table entries are text, which enables us to use mouseovers (without loading an additional graphic for each menu title), because CSS allows us as much control over positioning and look as working with graphics would. For example, here is the menu-item table cell for the Magazine:
<DIV CLASS="clsMenu" onSelectStart="returnFalse"> <TABLE ID="idNavMenu" BORDER=0 CELLPADDING=0 CELLSPACING=0> <TR> <TD VALIGN="middle" CLASS="clsMenuTitleLabel"> <A HREF="/sitebuilder" TARGET="_top"> <IMG HEIGHT=34 WIDTH=90 BORDER=0 SRC="/sitebuilder/shared/NavBar/graphics/sbnBrand2.gif" ALT="SBN Home"></A></TD> <TD CLASS="clsMenuTD" ALIGN="center" VALIGN="top"><NOBR><DIV ID="idMenuTitle1" CLASS="clsMenuTitle"> Magazine </DIV></NOBR><IMG HEIGHT=4 WIDTH=7 BORDER=0 SRC="/sitebuilder/shared/NavBar/graphics/arrow.gif"></TD> <TD CLASS="clsMenuDivider" VALIGN="top">|</TD>
Each menu category is placed within a <DIV> tag and given an ID (the Magazine's ID is "idMenuTitle1"). The ID will be used to compile the list of items's placed in the drop-down menu.
NavBar's functionality is implemented via a JScript™ include. We established the convention that the includes would be inserted in the document footers, after all the content, copyright information, and so on. In so doing, we would always know where to check to see if code loaded when viewing the source code of a requested page.
The key file for building the DHTML menus is menus-gb.js, which is loaded for all DHTML-capable browsers. Right off the bat, menus-gb.js plunges you into the icy water of a multi-nested array. (Actually, the first snippet of code, the sMenuGB variable declaration, is for the benefit of the InetSDK content; we'll discuss it later.) Our intent in building the array was not to make things difficult code-wise, but to minimize the stress on our poor, overtaxed editors.
That's where the array comes in. By specifying how to build the menus programmatically, the editors can confine their interloping in the code to a single, easily updated section.
addMenuItem(1,"Magazine Home","/sitebuilder/magazine/default.asp") addMenuItem(1,"Ask Jane","/sitebuilder/magazine/jane.asp") addMenuItem(1,"DHTML Dude","/sitebuilder/magazine/dude.asp") addMenuItem(1,"Extreme XML","/sitebuilder/magazine/xml.asp") addMenuItem(1,"For Starters","/sitebuilder/magazine/starters.asp") addMenuItem(1,"More or Hess","/sitebuilder/magazine/hess.asp") addMenuItem(1,"Servin' It Up","/sitebuilder/magazine/server.asp") addMenuItem(1,"Site Lights","/sitebuilder/magazine/site.asp") addMenuItem(1,"Web Men Talking","/sitebuilder/magazine/webmen.asp") addMenuItem(2,"Member Community Home","/sbnmember/default.asp") . . .
There are presently six NavBar areas: Magazine, Community, Workshop, Tools & Samples, Training, and Site Info. The SBN editors add an item, as shown in the above code section, for each sub-section they wish to point users to. Magazine, for example, has nine entries: one for each columnist, plus one for the Magazine home page.
Each entry references the addMenuItem() function, the beast that builds the nested array we can avoid no longer.
var aMenus = new Array() function addMenuItem(iMenuNumber,sText,sURL) { if (null == aMenus[iMenuNumber]) { aMenus[iMenuNumber] = new Array(); } iIndex = aMenus[iMenuNumber].length; aMenus[iMenuNumber][iIndex] = new Array(1); aMenus[iMenuNumber][iIndex][0] = sText; aMenus[iMenuNumber][iIndex][1] = sURL; }
The addMenuItem() function has three parameters: iMenuNumber, sText, and sURL. iMenuNumber ties addMenuItem() to a specific menu category ("1" for Magazine, "2" for Community, and so on). sText is the actual text that will appear when the menu drops down. sURL is the URL visitors are sent to when they select that item. Using an entry from the above code, a user who selects the DHTML Dude entry from the Magazine section will be sent to /sitebuilder/magazine/dude.asp).
The condition statement immediately after the addMenuItem() function declaration creates an array for each menu item (Magazine, Community, Workshop, and so on). The iIndex assignment establishes the number of entries within a menu item (Magazine has nine entries). The aMenus element is called again, this time with a second dimension added, which builds another array within each of the menu-item arrays (the Magazine menu item now has a nine-item array "inside" it). The final aMenus call creates a third array twoelements long: sText is assigned to element "0"; sURL, to element "1" (arrays are zero-based, which means that the first item is assigned position "0", and assignment continues from there).
The net effect of all our array building is to assign a text string and a URL to each entry in every menu category. Think of it as a quasi-coordinate system. aMenus[1] refers to the Magazine section; aMenus[2], the Community section, and so on. aMenus[1][0] refers to Magazine Home, the first item in the Magazine category. aMenus[1][0][0] is the first item of the first item of the Magazine category, and refers the text string "Magazine Home".
Once we've compiled the arrays for populating the drop-down menus, we use writeMenus() to create the HTML for each array entry.
function writeMenus() { for (var i=1;i<aMenus.length;i++) { document.write("<DIV ID='idMenu" + i + "' CLASS='clsMenuItemList'>"); for (var j=0;j<aMenus[i].length;j++) { document.write("<DIV CLASS='clsMenuItem' myURL='" + aMenus[i][j][1] + "'>" + aMenus[i][j][0] + "</DIV>"); } document.write("</DIV>"); } }
The first line of writeMenus() sets up a loop on the first array index (the number of menu categories, six). Then the document.write call creates a <DIV> tag for each menu category. A <DIV> tag created for the Magazine looks like this in the page delivered to the client:
<DIV ID='idMenu1' CLASS='clsMenuItemList'>
The next loop nests a <DIV> for each menu item inside the larger <DIV> for the menu category. The Magazine Home <DIV> then becomes:
<DIV CLASS='clsMenuItem' myURL='/sitebuilder/magazine/default.asp'> Magazine Home </DIV>
We step out of the menu item loop, close the <DIV> we initialized in the menu category loop, step into the next menu category ("Community"), and continue until all the menu categories have been populated.
Voilà. The menu, she has bones.
We'll close the discussion of NavBar by focusing on the functions that tell Internet Explorer how to respond to the user's navigation on and around the NavBar.Now let's consider the functionality we're controlling.
When users mouse over the NavBar, the color of the text changes to light blue (unless another menu is active, or visible). If a user clicks on a topic, the menu associated with it appears.
If a menu is already active, mousing over a different menu category will cause the original menu to close and the menu associated with the new category to appear . If the user clicks on the category itself (or anywhere on the screen outside the exposed menu), the menu will close, and the original mouseover color scheme will be re-established.
Finally, if a menu is active and the user mouses over one of its items, the item will be highlighted in dark blue. When users click on a highlighted menu item, they will be sent to the URL associated with it.
First, we'll consider menuTitle_mouseover(), which is identical in function to the standard onmouseover() function. We've just changed the name to protect the innocent elements on the page. Seriously. But don't get panicky. This reassigning functions is an example of both DynaBinding and event caching, which we discuss in the fourth article of our series, Special Features and Hacks.
var sMenuDownID = ""; var sMenuTitleDownID = ""; function menuTitle_mouseover() { var eSrc = window.event.srcElement; if ("clsMenuTitleDown" != eSrc.className) { eSrc.className = "clsMenuTitleOver"; } if ("" != sMenuTitleDownID && "clsMenuTitleOver" == eSrc.className) { menuTitle_click(); } }
By virtue of the fact that menuTitle_mouseover() has been called (we get to that in DynaBinding), we know that the user is mousing over one of the NavBar categories. Internet Explorer assigns the element being moused over to the variable eSrc (window.event.scrElement is part of the object model). With the element identified, we now ask if its classname is equal to clsMenuTitleDown (is a menu already showing?). If not, we make it equal to clsMenuTitleOver.
The next condition asks whether sMenuTitleDownID is an empty string, and whether the CLASS name of the element equals clsMenuTitleOver. If it isn't empty (which will be the case when a menu is showing), we'll activate the menuTitle_click() function.
The menuTitle_click() function is another of those pesky re-assigned functions. This time, it reassigns the onclick() function (an example of both event binding and caching). Whenever a user clicks on any of the NavBar categories, menuTitle_click() is activated.
function menuTitle_click() { closeMenu(); var eSrc = window.event.srcElement; if (sMenuTitleDownID == eSrc.id) { eSrc.className = "clsMenuTitleOver"; sMenuTitleDownID = ""; sMenuDownID = ""; } else { cacheGlobalEvents(); sMenuTitleDownID = eSrc.id; eSrc.className = "clsMenuTitleDown"; iMenuNumber = eSrc.id.substring(eSrc.id.length-1,eSrc.id.length); sMenuDownID = "idMenu" + iMenuNumber; iTop = idNavMenu.offsetTop + eSrc.offsetHeight + 23; iLeft = idNavMenu.offsetLeft + eSrc.parentElement.parentElement.offsetLeft + 8; with (document.all[sMenuDownID]) { style.top = iTop; style.left = iLeft; style.visibility = "visible"; } } }
Because menuTitle_click() is being called, we know that the user has clicked a category. The first thing we do is call closeMenu() -- because if a menu is open, and the user clicks anywhere else,we want to first close the menu already open (closeMenu() also does other things, but we'll get to that).
Next, we again assign the variable eSrc to the element the user clicked on, and then compare the ID of that element to see if it matches the variable sMenuTitleDown. If so, we rename the class of that element to clsMenuTitleOver, which re-establishes the light-blue mouseover scheme. Because we use sMenuTitleDownID and sMenuDownID to track whether a menu topic is being displayed (and if so, which one), we need to reset the string values to blanks.
If eSrc.ID and sMenuTitleDownID are not equal (which means that the menu being moused over was not previously open), we need to open the menu associated with the topic that was clicked. Skip ahead in the else condition above until you come to where we assign sMenuTitleDownID to eSrc.ID. We make this assignment to indicate that a menu is open to all the other functions and styles that might care. Then we assign "clsMenuTitleDown" as the eSrc.classname, which will turn the topic gray instead of light-blue.
Now we need tofigure out which menu to display. First, remember the format of the IDs we gave each of the topics when we put them in the table way back when:
<DIV ID="idMenuTitle1" CLASS="clsMenuTitle"> Magazine </DIV>
Each category is sequentially numbered idMenuTitle1, idMenuTitle2, and so on. menuTitle_Click() applies a string manipulation to the ID to isolate the integer, appends that integer to the string "idMenu", and assigns the new string to sMenuDownID.
The next six lines of code provide instructions on where to place the menu. idNavMenu is the ID of the NavBar table. iTop, which refers to the top of the menu box we'll be drawing, is placed 23 pixels below the top of the NavBar table plus the height of the category entry (which puts it just below the text of the category). The same occurs with iLeft, which ends up placing the left of the menu box 8 pixels to the left of the table cell that contains the selected category entry. Finally, we draw (by making visible) all the elements in the document that match the current value of sMenuDownID. If you recall from above, "all the elements" is the menu item list for that category.
There. We've described enough of the code to give a sense of the key variable and element interactions, and the control of function execution. Most of the other functions in menus-gb.js perform similar actions with regard to mouseover events, rather than the mouse-click events we focused on.
Did you find this article useful? Gripes? Compliments? Suggestions for other articles? Write us!
© 1998 Microsoft Corporation. All rights reserved. Terms of use.