|
Articles | Creating A Java
script Site Map | back
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. You may have actually come across them
when viewing a directory listing in Navigator:

If you are viewing this article in Microsoft Internet
Explorer, the above images will not be displayed. Therefore, I have created the
following .GIF images which can be used for Microsoft Internet Explorer:

The JavaScript detailed later in this article will use
either the internal-gopher images or the alternate .GIF images, depending on
which browser is being used.
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.
Microsoft Internet Explorer does not support the
undocument internal gopher/ftp images used by Netscape Navigator. Therefore, we
need to be able to identify which browser is being used. We define a boolean
variable MSIE, with a value of true if the browser being used is Microsoft
Internet Explorer, or false if it isn't:
<head>
<script language="JavaScript"><!--
if (navigator.appName == 'Microsoft Internet Explorer') var MSIE =
true; else var MSIE = false;
|
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">';
if (MSIE) var picture = '<img src="' + obj.type + '.gif" align="absbottom"
border="0" width="20" height="21">';
else var picture = '<img src="internal-gopher-' + obj.type + '" align=
"absbottom" border="0">';
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;
}
//--></script>
</head>
|
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. If the browser being used is Microsoft Internet Explorer, then images
supplied by the Web site are used, again depending on the type property:
<img src="menu.gif" align="absbottom" border="0" width="20" height="21">
|
If the browser is Netscape Navigator, the undocumented
internal-gopher images are used:
<img src="internal-gopher-menu" align="absbottom" border="0">
|
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. However, if you restrict
yourself to the nine internal-gopher images, then, at least for Netscape
Navigator, there will be no need for the browser to wait for the images to be
downloaded.
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:.
Articles | Creating A Java
script Site Map |
back
|