The Site Builder Network Navigation Bar

Sue Ledoux
Developer Technology Engineer
Microsoft Corporation

May 30, 1997

MSDN Editor's note: Sue Ledoux originally wrote this article for publication on the Microsoft Site Builder Network Web site—hence the references to "our readers" and "our site" that are sprinkled throughout this article.

Introduction

Over the last few years, Web pages have evolved from simple containers for text, a few pictures, and some hyperlinks, to sites that are starting to look like full-fledged applications. The availability of ActiveX™ controls has enabled Web authors to add rich functionality to their Web pages. As we add controls and scripts to our own Site Builder Network site, we would like to share with you anything that you, as a Web author, might find useful for your own sites.

Many of our readers expressed interest in the sitewide navigation bar we added during our February 1997 redesign. (See the Workshop home page at http://www.microsoft.com/workshop/default.asp.) The navigation bar (the line of choices you see below the spheres on the Workshop home page and at the top of each page throughout the site) consists of pop-up, cascading menus that give users instant access to all the sections of the Site Builder Network site. We implemented the Site Builder Network navigation bar using two controls: the Microsoft® IPTD Image control and the Microsoft Web Navigator control. The Image control simply displays an image and responds to mouseover events. The Web Navigator control is more interesting, and thus is the primary focus of this article.

In this article, we've provided the Web Navigator control for use on your own pages, and I've described how to use the control through Visual Basic® Scripting Edition (VBScript). However, note that the control has undergone reasonable but not exhaustive testing. The Site Builder Network team consists of a harried, overworked bunch of people with haunted eyes and no lives. With daily site updates and frenzied pace dictated by a maniacal overlord (well, OK, we actually like the guy a lot), some team members can barely remember where they live, let alone guarantee that the control will work on other sites. So, we've provided the Web Navigator control as a public service and recommend that, should you choose to use it, you be good little sitebuilders and do your own testing.

What Are We Looking At?

The Web Navigator control creates pop-up, cascading menus for your Web page. These menus are much like the ones you know and love from your good old Windows®-based applications. Probably like many of you, we took menus for granted until we started producing Web pages. As our sites became more extensive, we realized that our valuable screen real estate was being chewed up by navigational links. So we decided that we needed a control to give us back our menus.

Cascading menus can obviously be used for many things, but we use them exclusively to facilitate navigation on our site, so I'll use our site as the sample container to demonstrate the use of the Web Navigator control.

At the top of each page on this site, you will see the Site Builder Network navigation bar. This is the line of choices that includes "Site Builder,” “What’s New,” “Find It,” “Products,” “Technologies,” and “Downloads,” with little red markers underneath the menu names. A square marker indicates that the menu is a “leaf node,” and that clicking it will send you off to some other page. A downward-facing arrow tells you that clicking the menu name will bring up a pop-up menu with additional choices. These menus look very similar to your typical Windows cascading menus.

Forget all that mumbling—a picture speaks a thousand words, right? Here’s an actual screen shot from the Site Builder Workshop page showing the result of clicking “Site Builder” and then “Magazine” from the navigation bar. If you then click any of the three choices presented ("Columnists," "Feature Stories," or "Archive"), you’ll be whisked away to the appropriate page because none of these menu items have the little sideways arrow (indicating more submenus).

Figure 1. The result of clicking “Site Builder” and then “Magazine” from the navigation bar

There is no limit to the depth to which you can cascade the menus, but good sense in user interface design should prevail, of course. We chose to go no deeper than three levels, because we decided that a deeper structure would be confusing and unwieldy to navigate.

The caller supplies the text labels for the menu items, and provides the x and y coordinates (relative to the container) of the top left of the menu. If the container application is positioned on the screen in such a way that part of the menu would be hidden, its position is automatically recalculated so that the entire menu becomes visible.

The Web Navigator is not a very complicated control, but it's certainly a useful one. Let’s have a look at how you would use this control on a Web page.

Note   The Web Navigator control was originally designed for use only on the Site Builder Network Web site, so for now, because of an idiosyncrasy involving the window handles of the container, the control works only in Internet Explorer. However, a fix is in the works and the next version will be usable in any container that knows how to host ActiveX controls.

Exported Methods

Let’s start by listing the methods that the Web Navigator control exports and briefly discussing their functionality and parameters. This will give you a rough idea of how the Web Navigator control works. Later on, we’ll go into more detail about how the methods are used.

Methods from the Dispatch Interface

The Web Navigator control exports five methods from the dispatch interface: AddItem(), RemoveAllItems(), GetItemValue(), GetItemLabel(), and Popup().

AddItem

void AddItem(BSTR id, BSTR label, BSTR value, BSTR parentId);

You use the AddItem() method to specify the menu items that will be on your pop-up menu, including menu items that will be on any submenus. This method accepts four parameters:

RemoveAllItems

void RemoveAllItems();

This method clears all stored menu data previously defined through calls to AddItem().

GetItemValue

BSTR GetItemValue(BSTR id);

This method returns the user-defined data associated with a menu item, as specified in the value parameter of the previous AddItem() call for that ID.

GetItemLabel

BSTR GetItemLabel(BSTR id);

The GetItemLabel() method returns the text label of the menu item, as specified in the label parameter of the previous AddItem() call for that ID.

Popup

void Popup(short x, short y);

This method displays the pop-up menu at the coordinates (relative to the container) specified by the x and y parameters. The menu must have been previously defined using calls to the AddItem() method.

Methods from the Event Interface

Web Navigator control exports one method, OnClick(), from the event interface.

OnClick

void OnClick(BSTR id);

This method is invoked when the OnClick event is fired within the Popup() routine, after the user has clicked a menu item. The ID of the menu item is passed back as a parameter.

Calling the Control

Let's look at the source code for a Site Builder Workshop page to see how we’ve used the Web Navigator control on our site. See Appendix A and Appendix B for the topmenu.asp and topmenudata.asp file listings. These files contain the HTML and VBScript code that creates the Site Builder Network navigation bar you see on many of our pages. The topmenu.asp file is pulled in with an #include statement by each Active Server Pages (ASP) page that displays the navigation bar, and the topmenu.asp file, in turn, includes the topmenudata.asp file.

Let’s start at the beginning and walk through the files. I will gloss over formatting details, and I will assume that you are comfortable with simple HTML and VBScript. However, even if you’ve never used VBScript before, the Web Navigator control is simple and straightforward, and you’ll pick up what you need very quickly.

We’ll start with topmenu.asp. The first little bit does a browser sniff to determine whether the browser can host ActiveX controls and checks to see whether the Site Builder Network controls have been properly installed. You can skip down past this part, and find the section that looks like this:

<%else
   if bc.ActiveXControls then%>
<SCRIPT LANGUAGE="VBScript">
<!--
dim Site, Imgdir
Site = "http://" & location.host
Imgdir = Site + "/sitebuilder/graphics/"

Sub window_onLoad()
Ld iSB,"nav-sb.gif"
Ld iSB,"nav-sb-on.gif"
Show iSB,"nav-sb.gif"
...

This is the beginning of the section we’re interested in. After some administrative tasks (storing the site path in a variable called Site and the image path in ImgDir), the code continues with VBScript that is used to access the control and to create, destroy, and communicate with pop-up menus in response to user actions. (We used VBScript, but you can use JavaScript or any other scripting language that is supported by ActiveX controls.)

I’m going to jump ahead in the script to the definitions of two subroutines, Ld() and Show(), that we'll use later. These subroutines are designed to work with the instances of the Image control used to display the navigation bar labels.

The reason the author of this program used such short subroutine names and moved all of the repetitive work into these subroutines was to save download time for the page. For example, by using the Ad() subroutine (explained below), over 100 instances of “Menu1.AddItem” were replaced with “Ad()”. Moving the functioning to a central place also simplified modifications to the page.

The Ld() subroutine accepts two parameters: the identifier for the object that is displaying a particular label, and the filename of an image to be displayed on the label. (The object identifier corresponds to the ID= attribute that was set when the control was instantiated.) Setting the LoadPictureToCache property to the image filename will, as you would expect, load the image into the Internet cache on the end user’s machine. You’ll recall that the Imgdir path was set up at the beginning of this discussion. The images are pre-loaded to improve the performance of image switching when the mouse rolls over the menu titles. Ld() looks like this:

sub Ld (obj, pic)
set lobj = obj
lobj.LoadPictureToCache=Imgdir + pic
end sub

The Show() subroutine accepts the same two parameters, but in this case, setting the picture property of the object has the effect of actually displaying the image on the screen.

sub Show (obj, pic)
set lobj = obj
lobj.picture=Imgdir + pic
end sub

Now, if we go back to where we left off, you’ll see the window_onLoad() subroutine. (This routine is called after the main browser window is loaded and the OnLoad event is fired from the browser’s Window object; you can use it to perform your initialization tasks.) Within this subroutine you’ll see six sets of script instructions—one for each label on the navigation bar. The first set looks like this:

Ld iSB,"nav-sb.gif"
Ld iSB,"nav-sb-on.gif"
Show iSB,"nav-sb.gif"

Each label has two images associated with it: one for the regular view (black text, nav-sb.gif) and one for the highlighted view (blue text, nav-sb-on.gif). This little chunk of code loads both pictures into the cache, and then displays the image for the regular view. These three lines are repeated for the other five labels, with the appropriate object identifiers and image filenames specified.

Once the labels are set up in window_onLoad(), you’ll see the Ld() and Show() subroutines (which we’ve already talked about) defined. What follows next are twelve subroutines (two for each label) that handle MouseEnter and MouseExit events. (These are events that were defined by the Image control.) Here’s the pair of subroutines for the first label:

Sub iSB_MouseEnter()
Show iSB,"nav-sb-on.gif"
end sub

Sub iSB_MouseExit()
show iSB,"nav-sb.gif"
end sub

Pretty straightforward stuff: When the mouse enters the label, the highlight image is displayed, and when it leaves, the regular image is displayed.

Next we have six subroutines (one for each label) that handle the Click events. The first one looks like this:

Sub iSB_Click()
frames(0).SB_Menu
end sub

When the user clicks the “Site Builder” label, the SB_Menu() subroutine is called. As you’ll see, this is the routine that actually builds the menus and submenus for the “Site Builder” choice. You’ll notice that four of the labels have code that looks like the snippet above. The other two labels don’t have associated submenus; clicking them simply takes you to a different page. The subroutines handling the Click events for these labels look like this:

Sub iWN_Click()110
top.location.href= Site + "/sitebuilder/whatsnew.htm"
end sub

Next we have the subroutine that is called when the Web Navigator control receives a Click event. Note that we’re talking about the Web Navigator control now, not the Image control. This event is fired from within the Web Navigator control when the user selects a menu item that doesn’t have an associated submenu.

Sub Menu1_OnClick(id)
   url = menu1.GetItemValue(id)
   top.location.href=url
end sub

This code snippet marks the end of the section that controls the Web Navigator control. The next section in topmenu.asp contains the HTML that creates instances of the Web Navigator control to display the Site Builder Network navigation bar.

Instantiating the Control

Recall that we are using the Image control to display the individual components (labels) of the navigation bar. The specifics of the Image control are outside the scope of this article, but I will explain how we used the controls together to create our navigation bar and pop-up menus. The Web Navigator control does not depend on the Image control; it can be used independently in whatever manner you choose. (For example, you could give the control a user interface using Dynamic HTML. For examples of mouseover highlighting and other special effects, see the Dynamic HTML site at http://www.microsoft.com/workshop/author/dhtml/.

Starting with the TABLE tag, we’ve got a single table row (the <TR> tag) containing six table cells (defined with <TD> tags). Here’s what the first one looks like:

<TD ALIGN=LEFT VALIGN=TOP WIDTH="70">
      <OBJECT ID="iSB" WIDTH=71 HEIGHT=28
       CLASSID="CLSID:5E3E59C4-7847-11D0-9081-0080C76A0985">
      <PARAM NAME="_ExtentX" VALUE="2990">
      <PARAM NAME="_ExtentY" VALUE="661">
      </OBJECT>
</TD>

This code instantiates the control (specified by the CLASSID attribute) that will draw the image for the “Site Builder” label on the navigation bar. This instance of the control is named “iSB” and given dimensions using the WIDTH and HEIGHT attributes.

The code is duplicated for the remaining five labels on the navigation bar. Each <TD> block creates another instance of the control and gives it a unique identifier. These identifiers will be used to determine when a particular label has been selected by a user.

After the six labels of the navigation bar have been set up in table cells, we create an instance of the Web Navigator control with the following HTML code:

<OBJECT ID="Menu1" WIDTH=0 HEIGHT=0
       CLASSID="CLSID:F5131C24-E56D-11CF-B78A-444553540000"
       CODEBASE="#version=1,0,0,9">
      <PARAM NAME="_Version" VALUE="65536">
      <PARAM NAME="_ExtentX" VALUE="2646">
      <PARAM NAME="_ExtentY" VALUE="1323">
      <PARAM NAME="_StockProps" VALUE="0">
</OBJECT>

You may notice that this HTML is just tacked on to the last table cell of the navigation bar. There’s no particular reason for this—it doesn’t matter where the code goes.

Because only one pop-up menu can be active at any time, we need only one instance of this control. The instance is named “Menu1”. The WIDTH and HEIGHT attributes are set to 0 because the control does not display a visual element as part of the page layout; instead, it “floats” over the page and thus does not affect the layout of the page. The CODEBASE attribute describes where to find the control; see the "Setting Up the Control" section later in this article for a more detailed description of this attribute.

We’ve reached the end of the relevant code in topmenu.asp. The rest of the code is contained in topmenudata.asp and consists of script that builds the menu items. The contents of topmenudata.asp is pulled into topmenu.asp using this line of code:

<IFRAME src="/sitebuilder/global/topmenudata.asp" height=1 width=1></IFRAME>

As a result of using a floating frame (which contains no visual elements, and thus is “invisible”), the topmenudata.asp reference is treated as an URL and therefore cached. If we had simply included the file, it would have been reread every time a user accessed the page.

Defining Menu Items

The topmenudata.asp file contains the subroutines that actually build the pop-up menus. The file starts out with a cleanup routine, called when the OnUnload event of the window is fired, that removes all menu items:

Sub window_onunload()
call parent.Menu1.RemoveAllItems()
end sub

Next you’ll see the Ad() routine, which is a helper function to add items to menus. It looks like this:

sub Ad (cde,lbl,menuitem,par)
dim temp
temp = lbl
if lcase(cde)= parent.MarkMenu then 
   temp = "> " & temp
else
   temp = "   " & temp
end if
parent.Menu1.AddItem cde,temp,menuitem,par
end sub

The Ad() subroutine accepts four parameters that roughly correspond to the parameters of AddItem() that we described earlier:

The pop-up menus are used to navigate around the Site Builder Network site. The MarkMenu variable keeps track of which page the user is on. If we are adding the menu item that corresponds to our current location, a “>” is prepended to the text label of the menu item, and the four parameters are passed through to the AddItem() method of the Web Navigator control.

AddItem() does not actually display the pop-up menu—it simply provides a means to iteratively feed the structure of the menu and submenus to the Web Navigator control. This data is stored until the request to display the menu is received.

The last thing that we need to discuss is the SB_Menu() subroutine. Recall that this subroutine is invoked when the “Site Builder” label on the navigation bar receives the Click event. (There’s also FI_Menu() for the "Find It" menu, P_Menu() for the "Products" menu, and so on.) The SB_Menu() subroutine starts out like this:

Sub SB_Menu()
parent.Menu1.RemoveAllItems
Ad "sbho","Home","/sitebuilder/default.htm",""
Ad "sbab","About This Site","/sitebuilder/about/about.asp",""
Ad "sbma","Magazine","",""
   Ad "sbco","Columnists","/sitebuilder/columnists/default.asp","sbma"
   Ad "sbfe","Feature Stories","/sitebuilder/features/default.asp","sbma"
   Ad "sbwh","Archive","/sitebuilder/archive/default.asp","sbma"

First we call the RemoveAllItems() method of the Web Navigator control to clear any menu information previously stored through AddItem() calls. We then use the Ad() subroutine to add each menu item for the “Site Builder” pop-up menu. Each menu item is given a unique identifier.

Items that don’t have associated submenus (for example, “Home”) pass in the target URL for that menu. Items with submenus (for example, "Magazine") leave this parameter blank. Also, note the last parameter on items that are part of submenus. This parameter identifies the parent menu. (For example, the last parameter for the "Columnists" menu item is "sbma," which identifies the "Magazine" menu.) For the first level of the pop-up menu, this parameter is blank.

You get the idea—it’s pretty simple to set up the menu and submenu structure. Then, once all of the menu items have been defined, we make the call that will actually display the menu:

call parent.Menu1.Popup (parent.iSB.screenx - 2, parent.iSB.screeny + 22)

We got the x and y coordinates of the “Site Builder” menu, and we figured out where we want the pop-up menu to reside in relation to that. Then we call the Popup() method of the Web Navigator control. This will display the menu, including any submenus the user might choose. When the user clicks a menu item, the identifier of that item will be sent back via the Menu1_OnClick() subroutine that we discussed earlier.

Setting Up the Control

Making the control available to users who access your Web page is a simple matter: You describe where the control can be found using the CODEBASE attribute, and you have a few options. First, you can explicitly specify the location of the .CAB file for the control as follows:

<OBJECT ID="Menu1" WIDTH=0 HEIGHT=0
   CLASSID="CLSID:F5131C24-E56D-11CF-B78A-444553540000"
   CODEBASE="http://www.yourserver.com/subdirectory/ikcntrls.cab#version=1,0,0,9">

Simply put the .CAB file that we’ve provided below on your server somewhere, and substitute the appropriate path in the CODEBASE attribute for the control.

Click here to copy the the Web Navigator control .CAB file.

If the user already has the control installed (which they will if they’ve visited the Site Builder Network site), and the version number of the control is at least as high as the version specified in the CODEBASE attribute, they’re ready to go. If not, the control will automatically be downloaded and set up properly; this process takes less than a minute.

Alternatively, you can omit the URL entirely. In this case, if the user does not have the control installed, it will be downloaded from the object store at activex.microsoft.com. In other words, we’ve put the Web Navigator control in Microsoft's ActiveX object store, and by omitting the URL in the CODEBASE statement, you signal to Internet Explorer that it should look there. This ensures that your users receive the most recent version of the control.

The Web Navigator control uses the Microsoft Foundation Class Library (MFC) version 4.1 run time, which ships with Internet Explorer 3.0.

Coming Soon

As I mentioned earlier, a fix is in the works to allow the Web Navigator control to work properly from any container, in addition to Internet Explorer. When we get this work done, we’ll post the source code for the control, and explain how it was implemented.

That's It!

The Web Navigator control is really a simple control to use, but it makes a world of difference when you want to present a multitude of choices on your Web pages in an organized, hierarchical manner, and you want to save precious screen real estate for actual content. I hope you will find it as useful as we have.

Appendix A: topmenu.asp

<% Set bc = Server.CreateObject("MSWC.BrowserType")
On Error Resume Next
Err.Clear
sbn_install = "f"
sbn_install = prop("sbn_install")
if Err.Number then
   sbn_install = "f"
   Err.Clear
End if
if bc.ActiveXControls = true and sbn_install <> "f" and sbn_install <> "t" then %>
<html>
<head>
<script language=vbscript>
<!--
sub window_onload()
top.location.href = "/sitebuilder/setup/download.asp?return_url=" & top.location.href
end sub
-->
</script>

</head>
<!--TOOLBAR_START-->
<!--TOOLBAR_EXEMPT-->
<!--TOOLBAR_END-->
</html>

<%else
   if bc.ActiveXControls then%>
<SCRIPT LANGUAGE="VBScript">
<!--
dim Site, Imgdir
Site = "http://" & location.host
Imgdir = Site + "/sitebuilder/graphics/"

Sub window_onLoad()
Ld iSB,"nav-sb.gif"
Ld iSB,"nav-sb-on.gif"
Show iSB,"nav-sb.gif"
Ld iWN,"nav-wn.gif"
Ld iWN,"nav-wn-on.gif"
Show iWN,"nav-wn.gif"
Ld iFI,"nav-fi.gif"
Ld iFI,"nav-fi-on.gif"
Show iFI,"nav-fi.gif"
Ld iP,"nav-p.gif"
Ld iP,"nav-p-on.gif"
Show iP,"nav-p.gif"
Ld iT,"nav-t.gif"
Ld iT,"nav-t-on.gif"
Show iT,"nav-t.gif"
Ld iD, "nav-d.gif"
Ld iD, "nav-d-on.gif"
Show iD, "nav-d.gif"
end sub

sub Ld (obj, pic)
set lobj = obj
lobj.LoadPictureToCache=Imgdir + pic
end sub

sub Show (obj, pic)
set lobj = obj
lobj.picture=Imgdir + pic
end sub

Sub iSB_MouseEnter()
Show iSB,"nav-sb-on.gif"
end sub

Sub iSB_MouseExit()
show iSB,"nav-sb.gif"
end sub

Sub iWN_MouseEnter()
show iWN,"nav-wn-on.gif"
end sub

Sub iWN_MouseExit()
show iWN,"nav-wn.gif"
end sub

Sub iFI_MouseEnter()
show iFI,"nav-fi-on.gif"
end sub

Sub iFI_MouseExit()
show iFI,"nav-fi.gif"
end sub

Sub iP_MouseEnter()
Show iP,"nav-p-on.gif"
end sub

Sub iP_MouseExit()
Show iP,"nav-p.gif"
end sub

Sub iT_MouseEnter()
Show iT,"nav-t-on.gif"
end sub

Sub iT_MouseExit()
Show iT,"nav-t.gif"
end sub

Sub iD_MouseEnter()
Show iD,"nav-d-on.gif"
end sub

Sub iD_MouseExit()
Show iD,"nav-d.gif"
end sub

Sub iSB_Click()
frames(0).SB_Menu
end sub

Sub iWN_Click()
top.location.href= Site + "/sitebuilder/whatsnew.htm"
end sub

Sub iFI_Click()
frames(0).FI_Menu
end sub

Sub iP_Click()
frames(0).P_Menu
end sub

Sub iT_Click()
frames(0).T_Menu
end sub

Sub iD_Click()
top.location.href=Site + "/sbnmember/download/download.asp"
end sub

Sub Menu1_OnClick(id)
   url = menu1.GetItemValue(id)
   top.location.href=url
end sub
-->
</SCRIPT>
<!--TOOLBAR_START-->
<!--TOOLBAR_EXEMPT-->
<!--TOOLBAR_END-->

 <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0>
    <TR>
    <TD ALIGN=LEFT VALIGN=TOP WIDTH="87">
      <OBJECT ID="iSB" WIDTH=71 HEIGHT=28
       CLASSID="CLSID:5E3E59C4-7847-11D0-9081-0080C76A0985">
      <PARAM NAME="_ExtentX" VALUE="2990">
      <PARAM NAME="_ExtentY" VALUE="661">
      </OBJECT>
    </TD>
    <TD ALIGN=LEFT VALIGN=TOP>
      <OBJECT ID="iWN" WIDTH=90 HEIGHT=28
       CLASSID="CLSID:5E3E59C4-7847-11D0-9081-0080C76A0985">
      <PARAM NAME="_ExtentX" VALUE="2990">
      <PARAM NAME="_ExtentY" VALUE="661">
      </OBJECT>
    </TD>
    <TD ALIGN=LEFT VALIGN=TOP>
      <OBJECT ID="iFI" WIDTH=54 HEIGHT=28
       CLASSID="CLSID:5E3E59C4-7847-11D0-9081-0080C76A0985">
      <PARAM NAME="_ExtentX" VALUE="2990">
      <PARAM NAME="_ExtentY" VALUE="661">
      </OBJECT>
    </TD>

    <TD ALIGN=LEFT VALIGN=TOP>
      <OBJECT ID="iP" WIDTH=71 HEIGHT=28
       CLASSID="CLSID:5E3E59C4-7847-11D0-9081-0080C76A0985">
      <PARAM NAME="_ExtentX" VALUE="2990">
      <PARAM NAME="_ExtentY" VALUE="661">
      </OBJECT>
    </TD>
    <TD ALIGN=LEFT VALIGN=TOP>
      <OBJECT ID="iT" WIDTH=95 HEIGHT=28
       CLASSID="CLSID:5E3E59C4-7847-11D0-9081-0080C76A0985">
      <PARAM NAME="_ExtentX" VALUE="2990">
      <PARAM NAME="_ExtentY" VALUE="661">
      </OBJECT>
   </TD>

    <TD ALIGN=LEFT VALIGN=TOP>
      <OBJECT ID="iD" WIDTH=62 HEIGHT=28
       CLASSID="CLSID:5E3E59C4-7847-11D0-9081-0080C76A0985">
      <PARAM NAME="_ExtentX" VALUE="2990">
      <PARAM NAME="_ExtentY" VALUE="661">
      </OBJECT>

      <OBJECT ID="Menu1" WIDTH=0 HEIGHT=0
       CLASSID="CLSID:F5131C24-E56D-11CF-B78A-444553540000"
       CODEBASE="#version=1,0,0,9">
      <PARAM NAME="_Version" VALUE="65536">
      <PARAM NAME="_ExtentX" VALUE="2646">
      <PARAM NAME="_ExtentY" VALUE="1323">
      <PARAM NAME="_StockProps" VALUE="0">
      </OBJECT>
<IFRAME src="/sitebuilder/global/topmenudata.asp" height=1 width=1></IFRAME>
   </TD>
</TR>
</TABLE>
   <%else%>

 <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0>
    <TR>
    <TD ALIGN=LEFT VALIGN=TOP WIDTH="87">
      <A HREF="/sitebuilder/nav-sb.htm" TARGET="_top"><IMG SRC="/sitebuilder/graphics/nav-sb.gif" WIDTH="71" HEIGHT="28" BORDER="0" ALT="Site Builder"></A>
   </TD>
    <TD ALIGN=LEFT VALIGN=TOP>
      <A HREF="/sitebuilder/whatsnew.htm" TARGET="_top"><IMG SRC="/sitebuilder/graphics/nav-wn.gif" WIDTH="90" HEIGHT="28" BORDER="0" ALT="What's New"></A>
   </TD>
    <TD ALIGN=LEFT VALIGN=TOP>
      <A HREF="/sitebuilder/nav-fi.htm" TARGET="_top"><IMG SRC="/sitebuilder/graphics/nav-fi.gif" WIDTH="54" HEIGHT="28" BORDER="0" ALT="Find It"></A>
   </TD>
    <TD ALIGN=LEFT VALIGN=TOP>
      <A HREF="/sitebuilder/nav-p.htm" TARGET="_top"><IMG SRC="/sitebuilder/graphics/nav-p.gif" WIDTH="71" HEIGHT="28" BORDER="0" ALT="Products"></A>
   </TD>
    <TD ALIGN=LEFT VALIGN=TOP>
      <A HREF="/sitebuilder/nav-t.htm" TARGET="_top"><IMG SRC="/sitebuilder/graphics/nav-t.gif" WIDTH="95" HEIGHT="28" BORDER="0" ALT="Technologies"></A>
   </TD>

    <TD ALIGN=LEFT VALIGN=TOP>
      <A HREF="/sbnmember/download/download.asp" TARGET="_top"><IMG SRC="/sitebuilder/graphics/nav-d.gif" WIDTH="62" HEIGHT="28" BORDER="0" ALT="Downloads"></A>
   </TD>
</TR>
</TABLE>

   <%end if%>
<%end if%>

Appendix B: topmenudata.asp

<HTML>
<BODY bgcolor=white>
<SCRIPT LANGUAGE="VBScript">
<!--

Sub window_onunload()
call parent.Menu1.RemoveAllItems()
end sub

sub Ad (cde,lbl,menuitem,par)
dim temp
temp = lbl
if lcase(cde) = parent.MarkMenu then 
   temp = "> " & temp
else
   temp = "   " & temp
end if
parent.Menu1.AddItem cde,temp,menuitem,par
end sub

Sub SB_Menu()
parent.Menu1.RemoveAllItems
Ad "sbho","Home","/sitebuilder/default.htm",""
Ad "sbab","About This Site","/sitebuilder/about/about.asp",""
Ad "sbma","Magazine","",""
   Ad "sbco","Columnists","/sitebuilder/columnists/default.asp","sbma"
   Ad "sbfe","Feature Stories","/sitebuilder/features/default.asp","sbma"
   Ad "sbwh","Archive","/sitebuilder/archive/default.asp","sbma"
Ad "sbme","Membership","",""
   Ad "sbnho","Home","/sbnmember/default.asp","sbme"
   Ad "sble","Membership Level Info","/sbnmember/levels/levels.asp","sbme"
   Ad "sbap","Registration","/sbnmember/apply/apply.asp","sbme"
   Ad "sblo","Member Lounges","/sbnmember/lounges/lounges.asp","sbme"
   Ad "sbms","Member Showcase","/sbnmember/showcase/default.asp","sbme"
   Ad "sbcs","Case Studies","/sitebuilder/webadvantage/default.asp","sbme"
   Ad "sbfa","FAQ","/sbnmember/faq/member-faq.asp","sbme"
   Ad "sbdo","Downloads","/sbnmember/download/download.asp","sbme"
Ad "sbwo","Workshop","",""
   Ad "sbwho","Home","/workshop/default.asp","sbwo"
   Ad "sbcon","Contents List","/workshop/contents.asp","sbwo"
   Ad "sbau","Authoring","/workshop/author/default.asp","sbwo"
   Ad "sbde","Design","/workshop/design/default.asp","sbwo"
   Ad "sbpr","Programming","/workshop/prog/default.asp","sbwo"
   Ad "sbsi","Server","/workshop/server/default.asp","sbwo"
   Ad "sbac","Active Platform","/activeplatform/default.asp","sbwo"
   Ad "sbwe","Web Gallery","/gallery/default.asp","sbwo"
   Ad "sbwr","Write Us","/sitebuilder/write-us.asp",""
call parent.Menu1.Popup (parent.iSB.screenx - 2, parent.iSB.screeny + 22)
end sub

Sub FI_menu()
parent.Menu1.RemoveAllItems
Ad "fise","Search","/search/default.htm",""
Ad "fiin","Indexes","/workshop/index/default.asp",""
Ad "fire","Resources","",""
   Ad "fias","Ask Us","/sitebuilder/resource/ask.asp","fire"
   Ad "fiev","Events","/sitebuilder/resource/events.asp","fire"
   Ad "fifa","FAQs","/sitebuilder/faq/default.asp","fire"
   Ad "fima","Mailing Lists","/sitebuilder/resource/mail.asp","fire"
   Ad "fims","Member Showcase","/sbnmember/showcase/default.asp","fire"
   Ad "fine","Newsgroups","/sitebuilder/resource/news.asp","fire"
   Ad "fisp","Specs and Standards","/standards/default.asp","fire"
   Ad "fisu","Support","/sitebuilder/resource/support.asp","fire"
   Ad "fite","Technology Sites","/sitebuilder/resource/tech.asp","fire"
   Ad "fiot","Other Resources","/sitebuilder/resource/other.asp","fire"
call parent.Menu1.Popup (parent.iFI.screenx - 2, parent.iFI.screeny + 22)
end sub

Sub P_menu()
parent.Menu1.RemoveAllItems
Ad "pac","ActiveX Controls","",""
   Ad "pacc","ActiveX controls gallery","/activex/gallery/","pac"
   Ad "pht","HTML Layout Control","/workshop/author/layout/","pac"
   Ad "pmi","Microsoft Agent","/workshop/prog/agent/","pac"
Ad "pbr","Browsing and Viewing","",""
   Ad "pie","Internet Explorer 3.0","/ie/default.asp","pbr"
   Ad "pie4","Internet Explorer 4.0","/ie/ie40/","pbr"
   Ad "piea","Internet Explorer Add-Ins","/ie/download/","pbr"
   Ad "pisdn","ISDN for Windows","/windows/getisdn/","pbr"
   Ad "pja","Java support","/ie/ie3/java.htm","pbr"
   Ad "pve","Viewer for Excel","/msexcel/internet/viewer/","pbr"
   Ad "pvp","Viewer for PowerPoint","/mspowerpoint/internet/viewer/","pbr"
   Ad "pvw","Viewer for Word","/msword/internet/viewer/","pbr"
   Ad "pvr","VRML support","/ie/ie3/vrml.htm","pbr"
Ad "pco","Conferencing and Chat","",""
   Ad "pcom","Microsoft Chat","/ie/comichat/","pco"
   Ad "pne","NetMeeting","/netmeeting/","pco"
Ad "pim","Images and Interactive Media","",""
   Ad "pam","ActiveMovie","/devonly/tech/amov1doc/","pim"
   Ad "pdi","DirectX","/devonly/tech/dx3doc/","pim"
   Ad "pgif","GIF Animator","/imagecomposer/","pim"
   Ad "pic","Image Composer","/imagecomposer/","pim"
   Ad "pnw","NetShow","/netshow/","pim"
   Ad "pppt","PowerPoint Animation Player","/mspowerpoint/internet/player/","pim"
Ad "pla","Languages","",""
   Ad "pjs","JScript","/jscript/","pla"
   Ad "pvbcce","Visual Basic Control Creation Edition","/vbasic/controls/","pla"
   Ad "pvbs","Visual Basic Scripting Edition (VBScript)","/vbscript/","pla"
   Ad "pvj","Visual J++","/visualj/","pla"
Ad "pacm","Publishing and Debugging Tools","",""
   Ad "paxc","ActiveX Control Pad","/workshop/author/cpad/","pacm"
   Ad "pfp","FrontPage","/frontpage/","pacm"
   Ad "phh","HTML Help","/workshop/author/htmlhelp/","pacm"
   Ad "piaa","Internet Assistant for Access","/msaccess/internet/ia/","pacm"
   Ad "piae","Internet Assistant for Excel","/msexcel/internet/ia/","pacm"
   Ad "piap","Internet Assistant for PowerPoint","/mspowerpoint/internet/ia/","pacm"
   Ad "pias","Internet Assistant for Schedule+","/msscheduleplus/internet/ia/","pacm"
   Ad "piaw","Internet Assistant for Word","/msword/internet/ia/","pacm"
   Ad "pdbw","Microsoft dbWeb","/workshop/prog/dbweb/","pacm"
   Ad "psd","Script Debugger for Internet Explorer","/workshop/prog/scriptie/","pacm"
   Ad "pvi","Visual InterDev","/vinterdev/","pacm"
   Ad "pvss","Visual SourceSafe","/ssafe/","pacm"
   Ad "pwpw","Web Publishing Wizard","/windows/software/webpost/","pacm"
Ad "pss","Server Software","",""
   Ad "pcis","Commercial Internet System","http://backoffice.microsoft.com/product/cis/system.asp","pss"
   Ad "pis","Index Server","/ntserver/info/indexserver.htm","pss"
   Ad "piis","Internet Information Server (IIS)","/workshop/server/default.asp","pss"
   Ad "pils","Internet Locator Server (ILS)","/netmeeting/ils/","pss"
   Ad "psis","Site Server","http://backoffice.microsoft.com/products/siteserver/","pss"
   Ad "psse","Site Server Enterprise","http://backoffice.microsoft.com/products/SiteServerE/default.asp","pss"
   Ad "pps","Proxy Server","/proxy/","pss"
   Ad "psql","SQL Server","/sql/","pss"
   Ad "pntser","Windows NT Server","/ntserver/","pss"
Ad "pdp","Developer Products","",""
   Ad "msdn","MSDN","/msdn/","pdp"
   Ad "vst","Visual Studio","/vstudio/","pdp"
   Ad "dpl","Developer Products Listing","/msdn/products/","pdp"
call parent.Menu1.Popup (parent.iP.screenx - 2, parent.iP.screeny + 22)
end sub

Sub T_menu()
parent.Menu1.RemoveAllItems
Ad "tap","Active Platform","/activeplatform/default.asp",""
Ad "tccs","Cascading style sheets","/workshop/author/css/css-f.htm",""
Ad "tdht","Dynamic HTML","/workshop/author/dhtml/",""
Ad "tau","HTML authoring","/workshop/author/default.asp",""
Ad "tie4","Internet Explorer 4.0 technologies","/workshop/prog/ie4/",""
Ad "tin","Intranets","/intranet/default.htm",""
Ad "java","Java","/java/",""
Ad "tsdk","SDKs","",""
   Ad "taxm","ActiveX SDK (Mac)","/workshop/prog/sdk/mac/","tsdk"
   Ad "taxp","ActiveX SDK (PC)","/workshop/prog/sdk/","tsdk"
   Ad "taxd","Design-time Control SDK","/workshop/prog/sdk/dtctrl/","tsdk"
   Ad "tdx","DirectX SDK","/msdownload/directx3.htm","tsdk"
   Ad "tinet","Internet Client SDK (PC)","/workshop/prog/inetsdk/","tsdk"
   Ad "tjsdk","Java SDK","/java/pre-sdk/","tsdk"
   Ad "tmp","Microsoft Platform SDK","/msdn/sdk/","tsdk"
   Ad "tnm","NetMeeting SDK","/netmeeting/sdk/","tsdk"
   Ad "wwsdk","Web Wizard SDK","/workshop/prog/sdk/webwiz/","tsdk"
Ad "tsec","Security","",""
   Ad "tmisf","Security Technologies","/workshop/prog/default.asp#sec","tsec"
   Ad "tseca","Authenticode","/workshop/prog/default.asp#auth","tsec"
   Ad "tcapi","Cryptography and CryptoAPI","/workshop/prog/default.asp#crypto","tsec"
   Ad "tpfx","Personal Information Exchange (PFX)","/workshop/prog/default.asp#sec","tsec"
   Ad "tssl","Secure Sockets Layer (SSL)","/workshop/prog/default.asp#sec","tsec"
   Ad "tsa","Security Advisor","/security/","tsec"
   
Ad "tser","Server","",""
   Ad "tasp","Active Server Pages (ASP)","/workshop/server/default.asp","tser"
   Ad "tisapi","ISAPI","/win32dev/apiext/isalegal.htm","tser"
Ad "ttyp","Typography","/truetype/",""
Ad "twcm","Web content management","/workshop/author/plan/vssweb-f.htm",""
Ad "tot","Other","",""
   Ad "tcab","Cabinets (CAB)","/workshop/prog/cab/","tot"
   Ad "tcifs","Common Internet File System (CIFS)","/workshop/prog/cifs/","tot"
   Ad "tcom","Component Object Model (COM)","/workshop/prog/com/","tot"
   Ad "tdt","Development technologies","/msdn/","tot"
   Ad "tdcom","Distributed COM (DCOM)","/workshop/prog/com/","tot"
   Ad "tmnp","NetMeeting","/netmeeting/","tot"
   Ad "tpptp","Point-to-Point Tunneling Protocol (PPTP)","/ntserver/info/pptp.htm","tot"
   Ad "turlm","URL monikers","/workshop/prog/prog-gen/moniker-f.htm","tot"
   Ad "twb","WebBrowser","/workshop/prog/sdk/docs/iexplore/","tot"
   Ad "twpapi","WebPost API","/workshop/prog/sdk/docs/webpost/","tot"
   Ad "twiapi","WinInet API","/workshop/prog/sdk/docs/wininet/","tot"
call parent.Menu1.Popup (parent.iT.screenx -2, parent.iT.screeny + 22) 
end sub
-->
</SCRIPT>
</body>
</html>

Did you find this article useful? Gripes? Compliments? Suggestions for other articles? Drop me a line at suel@microsoft.com and let me know.