This article was originally published in PC Pro and is reproduced with permission.
Last month we touched on frame navigation and how to refresh multiple frames with a single mouse click.
This month we're looking at one of the most common uses for such a technique: a classic left-frame navigation panel. Imagine a product catalogue Web site for a computer hardware company, with several layers of information. The first layer of navigation might have divisions like computers, printers and modems. The next layer could divide computers into servers, desktops and laptops, with a third layer containing the actual model descriptions. A similar tree structure might be repeated for the other main divisions of the catalogue. It's easy to see that a few top-level categories could lead into hundreds, if not thousands, of individual pages.
So how do you design a left-frame navigation system to look after that lot? First and most obvious is to have a series of static pages, each linked to another, so there would be a main menu page, a computers menu page, a servers menu page and so on. While this is probably the easiest scheme to visualise, it will also be the most complex to maintain.
The alternative would be to keep everything in one page. DHTML and JavaScript would allow you to create a page which automatically updates itself to show the relevant content as each item is clicked. The DHTML code might look something like:
<DIV ID="Out0">
<a ID="Out1" CLASS="Outline" STYLE="cursor: hand">Item 1</a><BR>
<DIV ID="Out1display" STYLE="display:None">
<a ID="Out2" CLASS="Outline" STYLE="cursor: hand">Item 1.1</a><BR>
<DIV ID="Out2display" STYLE="display:None">
<a href="dummy.html">Item 1.1.1</a><BR>
<a href="dummy.html">Item 1.1.2</a><BR>
</DIV>
<a href="dummy.html">Item 1.2</a><BR>
</DIV>
<a href="dummy.html">Item 2</a><BR>
</DIV>
This would be used in conjunction with a JavaScript function as follows:
<SCRIPT LANGUAGE="JavaScript">
function clickHandler() {
var targetId, srcElement, targetElement;
srcElement = window.event.srcElement;
if (srcElement.className == "Outline") {
targetId = srcElement.id + "display";
targetElement = document.all(targetId);
if (targetElement.style.display == "none") {
targetElement.style.display = "";
} else {
targetElement.style.display = "none";
}
}
}
document.onclick = clickHandler;
</SCRIPT>
Within the DHTML code, all of the anchors used to control the collapsing and expanding of elements are given the class 'Outline'. The elements which will be shown when the anchor is clicked are given the same class, with the same ID as the anchor except that 'display' is added to the end (Out2Display, for example). The JavaScript function sets itself up as a click handler for the whole page, and passes anything that isn't of the class 'Outline' straight through. Otherwise, it toggles the display status of the item that has an ID equal to <clicked anchor's ID+'display'>. When viewed in older browsers, which don't understand the in-line style of syntax, the whole page will show up fully expanded.
This is much better solution than having lots of individual menu files, but it still suffers from one big problem - size. If that menu contains hundreds or thousands of items the DHTML or JavaScript file will be enormous. However, rather than processing the menu like this using client-side code, we could move all the clever bits to the server side. All we need is a left.asp or left.pl function (or other) that can remember where we are in the menu structure and generate the appropriate page content.
Perhaps the main reason for doing all of this processing is to improve site maintainability. One thing that really helps in this respect is to separate the data from the code and the HTML. You can achieve this by storing the site menu structure in a separate file from the menu data (that is, the model descriptions). Therefore, whenever you need to add a new page to the site you don't have to change left.asp but just add a new line to the menu data file.
How might this work? Let's look at how parts of left.asp could be constructed. First read the menu data file in. Obviously, you won't want to do this every time left.asp is processed - that would be too heavy on server resources. Instead, what we've done is to read the file into an array and store it in a session variable so that the array is available next time round. Then, next time, if the array has already been set up there's no need to read it again.
if session('leftmenudone') <> 1 then
dim menu()
redim menu(1000,3)
Public linestuff
menuitems = 0
Dim fs, f, dummy
Set fs = CreateObject('Scripting.FileSystem Object')
Set f = fs.OpenTextFile('d:\inetpub\wwwroot\ menu.txt')
Do while f.AtEndOfStream <> True
dummy = f.Readline
menuitems = menuitems + 1
linestuff = split(dummy,',',3,1)
for jj = 0 to 2
menu(menuitems,jj) = linestuff(jj)
next
loop
f.Close
session('leftmenu') = menu
session('leftmenudone') = 1
else
menu = session('leftmenu')
end if
You'll notice that for this simple menu example we're reading just three items from the text file and using a comma to separate them. The first item will be a combination of item ID and menu depth, the second will be a description and the third will be the page to show in the main frame when this item is clicked (if there's no page to go to then this third parameter will be set to zero). So a fragment of the menu file might look like:
0200000,Computers,0
0210000,Desktops,0
0211000,Pentium,0
0211100,XYZ 33,xyz33.html
0211200,XYZ 66,xyz66.html
0211300,XYZ 133,xyz133.html
0211400,XYZ 250,xyz250.html
021200,Pentium II,0
021210,ABC 266,ABC266.html
021220,ABC 450,ABC450.html
etc.
The code to actually process the menu is extremely simple, something along the lines of:
arg = request.querystring('arg')
if arg = '' then
arg = '0'
end if
for menuitem = 0 to ubound(menu)
level = len(arg)
disp = menu(menuitem,1)
do while level > 0
if (left(menu(menuitem,0),level) = left(arg,level)) AND (mid(menu(menuitem,0),level+2,1) = '0')then 'we're in this level
if menu(menuitem,2) = '0' then 'no specified document
if mid(menu(menuitem,0),3,1) = '0' and left(arg+'0000',3) = left(menu(menuitem,0),3) then 'toggle open sections
response.write '<a href=''/left.asp?arg=0'' target=''leftframe''>'&disp&'</a><br>'
else
response.write '<a href=''/left.asp?arg='&left(menu
(menuitem,0),instr(2,menu(menuitem,0),'0',1)-1)&''' target=''leftframe''>'&disp&'</a><br>'
end if
else 'a page in the main frame
response.write '<a href='''&menu(menuitem,2)&''' target=''mainframe''>'&disp&'</a><br>'
end if
exit do
end if
level = level - 1
loop
next
This all looks fairly boring, so maybe some graphics could cheer it up. Well, that's easy enough. Let's just examine the description field, and if the file is in GIF format then load it as a graphic rather than displaying it as text. So replace the existing line which sets 'disp' with the following code:
if right(menu(jj,1),4) = '.gif' then
disp = '<img src='''&menu(jj,1)&''' border=0>'
else
disp = menu(jj,1)
end if
All articles Copyright CST Group Limited ©1997-2024
Let's Talk
Whether you have a new or existing project, we’d love to hear from you.
Our experienced team thrive on problem solving and working with your business goals in mind.