|
Home
Articles
FAQs
Xref
Games
Software
Books
About
Feedback
Find
Site Map
irt.org | Articles | Dynamic HTML (DHTML) | Creating a JavaScript site map
Published on: Saturday 3rd January 1998 By: Martin Webb
Most Web sites use either simple hypertext links or image links to
allow visitors to navigate around the various linked pages. These
techniques, although tried and tested, do not necessarily give an
indication of the breadth and depth of the site. Using the JavaScript
described in this article, you will be able to include a visual
representation of your site that can be dynamically expanded and
collapsed, enabling visitors to quickly identify which parts of the
site they wish to explore.
The site map could be written completely in HTML. But this would
require a separate file, and therefore a separate request to the
server, for each different view of the site map. This article
describes how to implement a dynamic site map using images, frames and
JavaScript, using just three files for Netscape Navigator, and for
Microsoft Internet Explorer, a few additional, small images. The
difference between treatments for the two browsers is due to Netscape
Navigator's inclusion of undocumented and unsupported internal-gopher
images that we can utilize.
There are nine undocumented internal-gopher images which we can use in
Netscape Navigator 4. You may have actually come across them when
viewing a directory listing in Netscape Navigator 4:
If you are viewing this article in another broswer, e.g. Microsoft Internet Explorer, FireFox etc then the
above images will not be displayed. Therefore, I have created the
following .GIF images which can be used instead:
The JavaScript detailed later in this article will use the alternate .GIF images.
To enable the site map to be dynamic and allow the contents to change
without downloading any additional files from the server, we need to
be able to redisplay/reload the document. Normally, this would
overwrite all the contents of the document, including the JavaScript
source code and, more importantly, the current values of the
JavaScript variables. However, by using frames, we are able to store
the JavaScript and JavaScript variables in the document that defines
the frameset, i.e., the parent frame, and then only redisplay one or
another of the child frames.
We'll use the following simple frameset definition contained within
the sitemap.htm file:
<head>
<script language="JavaScript"><!--
/* this will contain the JavaScript detailed later */
//--></script>
</head>
<frameset cols="50%,*">
<frame src="menu.htm" name="menu">
<frame src="dummy.htm" name="content">
</frameset>
|
The sitemap.htm file also contains 99% of your JavaScript code.
When using JavaScript and a frameset definition in the same document,
the JavaScript is usually held between the <head>and
</head> tags. Otherwise, it is possible that neither the
JavaScript nor the frameset will be processed correctly. The actual
JavaScript is detailed in the rest of the article.
menu.htm, loaded into the menu frame, contains the 1% of the
JavaScript necessary to request and display the site map. The
background color is set to white, and whatever is returned from the
parent frames ShowSiteMap() function is output to the document:
<body bgcolor="#FFFFFF">
<script language="JavaScript"><!--
document.write(parent.ShowSiteMap());
//--></script>
</body>
|
dummy.htm, loaded into the content frame, contains just the
body tags to ensure that the background color is set to white:
<body bgcolor="#FFFFFF"></body>
|
The site map will be displayed in the menu frame. When a document is
selected in the site map, it will be shown in the content
frame. However, the JavaScript source code that enables the site map
to be displayed will be held in the parent frame, i.e., the
sitemap.htm file.
Below is the JavaScript source code that is required in the
sitemap.htm file, as well as the contents of the site map
file structure, i.e., the list of files and their connection with one
another.
The location of the current window is manipulated to obtain the path
of the currently loaded document. The baseHREF will then be used later
to give the absolute path to a file/menu in the site map and when
changing the text displayed in the status bar. We'll assume that the
site map is located in the fictitious directory:
http://xxx.yyy.zzz/abc123/
The next three JavaScript functions -- File(), Menu() and Add() --
define the objects and methods used to create a tree hierarchy of
files and menus.
The following File() function is actually a constructor function for
File objects, as it will be invoked later using the new operator,
e.g., new File('index.html','text').
function File(name,type) {
this.name = name; // the name of the file to appear in the site map
this.type = type; // image/binary/movie/text/sound/telnet/unknown/index
this.path = baseHREF; // initial path, built when adding nested objects
}
|
The following Menu() function is a constructor function for Menu
objects. It is similar to the File constructor, except that it has
three additional properties, as well as Add, a user-defined method
(e.g., Menu.Add() ) and Contents, a built-in JavaScript Object.
The use of Object() effectively creates an empty array. Unlike Array()
it is fully supported in earlier releases of JavaScript.
The value of the open property is conditional on whether open
parameter has a value or is null, i.e., a value has not been
passed. This avoids the need to set each and every Menu object's open
property; we can omit them, whereby they will default to false.
function Menu(name,ref,open) {
this.name = name; // the name of the file/menu to appear in the site map
this.type = 'menu';
this.path = baseHREF; // initial path, built up when adding nested objects
this.ref = ref; // reference to the object being constructed
if (!open) // optional value indicating if object is open or closed
this.open = false;
else
this.open = true;
this.index = 0; // initial number of items in Contents
this.Add = Add; // Add is a Menu method e.g. Menu.Add()
this.Contents = new Object(); // adds an empty built-in JavaScript Object
}
|
The following Add() function is used as a method of Menu, e.g.,
Menu.Add(). The obj parameter is added to the Contents[] array of the
referenced Menu object, and the index property of the referenced Menu
is increased by one. The path property of obj is set to the path of
the owning Menu object plus the name property of obj.
function Add(obj) {
this.Contents[this.index++] = obj;
obj.path = this.path + '/' + obj.name;
}
|
What we have implied, but not yet stated, is that the obj parameter is
actually an object that has been created somewhere else in the
script. Using File(), Menu() and Add() we can create a structure that
links files together in a hierarchical tree structure. For example,
the following would first create a Menu object called rootMenu, and
then a File object which would be added to the Contents array of the
rootMenu object:
rootMenu = new Menu('home','rootMenu',true);
rootMenu.Add(new File('index.html','index'));
|
To add another File object to the rootMenu is as simple as:
rootMenu.Add(new File('email.html','text'));
|
To add a Menu object to the rootMenu require two lines, as we need a
variable name for the object to which we can refer later:
docMenu = new Menu('documents','docMenu');
rootMenu.Add(docMenu);
|
If we had done it in one line, we wouldn't be able to add File objects
to the docMenu:
docMenu.Add(new File('readme.txt','text'));
docMenu.Add(new File('logo.gif','image'));
|
So, in theory, our example object structure looks something like this:
rootMenu -+- index.html
|
+- email.html
|
+- docMenu ---+- readme.txt
|
+- logo.gif
|
The object structure shows the order in which the objects are
added. Therefore, if we want all the Menu objects to appear before the
File objects in a particular menu, and all the objects to appear in
alphabetical order, we just need to make sure that they are added to
the Contents array of the owning Menu object in the correct order:
rootMenu = new Menu('home','rootMenu',true);
docMenu = new Menu('documents','docMenu');
rootMenu.Add(docMenu);
docMenu.Add(new File('logo.gif','image'));
docMenu.Add(new File('readme.txt','text'));
rootMenu.Add(new File('email.html','text'));
rootMenu.Add(new File('index.html','index'));
|
Now the structure will, in theory, look like this:
rootMenu -+- docMenu ---+- logo.txt
| |
| +- readme.gif
+- email.html
|
+- index.html
|
Now we'll show how to output the site map to the menu frame using both
images and text links.
The following Show() function iterates around the object stucture
building up an HTML table of images and text links of the currently
open menus and their contents. It holds the HTML to be displayed in
the output variable which is then returned to the menu.htm
document for display in the menu frame. The starting point within the
object structure will normally be the rootMenu, although this does not
always have to be the case. You may prefer to show only a small
section of the structure, e.g., the contents of a menu hidden deep in
the object structure:
function Show(obj) {
if (obj.type == 'menu')
var anchor = '<a href="javascript:parent.OpenMenu(parent.' + obj.ref + ')"';
else
var anchor = '<a href="' + obj.path + '" target="content"';
anchor += ' onMouseover="window.status=\'' + obj.path + '\'; return true"';
anchor += ' onMouseout="window.status=\'\'; return true">';
var picture = '<img src="' + obj.type + '.gif" align="absbottom" border="0" width="20" height="21">';
var output = '<table border=0><tr>' +
'<td valign=top>' + anchor + picture + '</a></td>' +
'<td><font face="arial">' + anchor + obj.name + '</a>';
if (obj.open)
for (var i=0; i<obj.index; i++)
output += Show(obj.Contents[i]);
output += '</td></tr></table>';
return output;
}
function ShowSiteMap() {
return Show(rootMenu);
}
function OpenMenu(obj) {
obj.open = !obj.open;
window.menu.location.href = window.menu.location.href;
}
|
The Show() function first builds up the anchor to be displayed. If the
current obj objects type property is "menu," then the anchor will
contain a javascript:url to the OpenMenu() function. It will be
something like:
<a href="javascript:parent.OpenMenu(parent.rootMenu)" onMouseover="window.status='http://xxx.yyy.zzz/abc123/';return true" onMouseout="window.status='';return true">
|
You may now begin to appreciate why we need a ref property for each
Menu object. We need the name of the variable holding the Menu object
to be able to pass it to the OpenMenu() function. Without this we
wouldn't be able to refer to a particular Menu object directly.
Note that, as both the function and variable are defined in the Menu
frame's parent frame, they both require a reference to the parent
frame. Otherwise, neither the function nor the variable will be found.
If the type property is not "menu," then the anchor will
contain a link to the absolute URL of the file, like this:
<a href="http://xxx.yyy.zzz/abc123/index.html" target="content"
onMouseover="window.status='http://xxx.yyy.zzz/abc123/index.html';return true"
onMouseout="window.status='';return true">
|
Next, the picture to be displayed in the link is built up:
<img src="menu.gif" align="absbottom" border="0" width="20" height="21">
|
The beginning of the HTML table is then constructed using two columns,
one containing the image link and the other containing the text
link. If the obj objects open property is true, then for each entry in
the Contents array, the Show() function is invoked to embed yet
another table within the current table. Finally, the HTML table is
closed and the contents of output are returned to the caller of the
OpenMenu() function.
The OpenMenu() function, which completes the JavaScript, when invoked
will toggle the open property of the current obj object, and then
reload the document in the menu frame.
The ShowSiteMap() function is invoked by the menu.htm
document, which in turn invokes the Show() function with the rootMenu,
i.e., the initial Menu object:
What actually happens when a menu link is selected is that the Menu
object is passed by the menu.htm document to the OpenMenu()
function in the sitemap.htm document. The OpenMenu()
function then toggles the open property of the Menu object before
reloading the contents of the menu frame, which then calls the Show()
function in the parent frame to rebuild the site map -- all within the
blink of an eye.
You can try out a sample site map: sitemap.htm.
If you use the above three HTML files (sitemap.htm,
dummy.htm and menu.htm) on your own site, and then
amend the tree structure using the Menu and File functions, you will
be able to create a dynamic site map that your visitors can explore
without the need for further downloads from the server. This will aid
your visitors to locate the area of your site in which they are most
interested without having to navigate a multitude of links.
You could further enhance the site map to use your own images or
create others for specific filetypes.
The content frame could have an initial document loaded, perhaps
explaining how to use the site map. The frameset can be enhanced to
remove the border and to make the frames nonresizable.
You could include + and - gifs to indicate how to close and open the
menus; this could be combined with additional menu images that show
the menu image as open or closed, or you could include an indicator
against the menu that contains the document currently being viewed in
the content frame, i.e., a "You are Here" type of indicator.
You don't even need to build up the path of each file as it's added to
the object structure! You can pass the complete relative or absolute
URL as a parameter, which can be a local or a remote file and can, if
required, use protocols other than http -- ftp:, mailto: and even
javascript:.
Feedback on 'Creating a JavaScript site map'
View the profile on Martin Webb and the list of other Articles by Martin Webb.
|