JavaScript TreeView

Current version


Ich habe leider keine große Lust, diese Dokumentation ins Deutsche zu übersetzen, bin aber gerne bereit, Fragen zu beantworten:   eMail an mich  (Simon Harston) genügt.

Ein Anwendungsbeispiel gibt es bei den Seiten der   DGGF e.V.


You can   download  this complete documentation from to read it offline and use the files as templates for your TreeView. Just unzip the downloaded file into a new directory and open index.htm in your browser. Please read the   readme.txt  too.


For a visitor to your web site, there are few things more disconcerting than being lost in Cyberspace. It's scary being lost in a site when you came in the front door - it's even worse if you happen to pop in from a search engine or through a link. All of a sudden you're plopped into the middle of a site and unless the web designer has really done his or her job, you're pretty clueless about where to go next.

But with TreeView, you can create neat index menus that function just like Windows Explorer folder hierarchies. They are easy to use, and - this will delight you - easy to create. So stop letting your visitors get lost. Get TreeView and put some signposts up in your web.

This documentation describes the JavaScript TreeView code I originaly wrote for the pages of the DGGF (Deutsche Gesellschaft für Gute Forschungspraxis e.V.). You may wish to have a look at the   DGGF-pages after reading this documentation, and see what I've made of the code there.

What is a TreeView?

TreeView features in brief

Copyright / Standard disclaimers


First of all, I'll explain the major changes you'll need to make to the pages of your current web site to use TreeView. Please also have a look at the files that came with this documentation, they contain some minor additions to what I explain here.

To begin with, let's have a look at the default file, index.htm. Use this nice trick in the <HEAD>-tag to make sure the page is always the topmost frame of the browser window:

<SCRIPT LANGUAGE="JavaScript"> <!--
function myError(msg, url, line) { return true; }
window.onerror = myError; = "JS_TreeView_docu"; // uniqueID
window.defaultStatus = "JavaScript TreeView documentation";
if (top.frames.length > 0) // ensure full-screen
  top.location.href = self.location.href; // --> </SCRIPT>

Note also that I have given the window a default status bar text and unique ID. The unique ID is later used in the documents of the site to check whether the TreeView frame is loaded. I will explain how that works in the section   TreeView - Ensuring it's loaded . You should change the ID from the one given here. Basically, each web site using TreeView has to have their own unique ID. Please only use numbers '0'-'9', letters 'a'-'z' and 'A'-'Z', or the underscore '_'. Do not use '.', '-', '+', ' ' etc.

Next, we'll check if index.htm is being loaded with a reference to another file. This happens when you load a file without the TreeView frame, or could be used by people wishing to link to a page on your site. This is in fact the really neat feature that allows bookmarking of files inside frames.

prm = ""+ self.location.href; pos = prm.indexOf("href=");
if (pos > -1 && top.main) {
 var newPage = prm.substring(pos + 5, prm.length);
 if (document.images) top.main.location.replace(newPage);
 else top.main.location.href = newPage; }

As you can see, the code checks for the value of href, and loads the page if there is one stated. Let's imagine you wished to reference the file one.htm, section #beta directly from another web site. Your link reference would be either one of these two links:

The only difference is whether you use the search or the hash part of the URL. I'll explain the difference and give an example for you to see that it works in the section   TreeView - Ensuring it's loaded .

But for now, let's continue with index.htm: You'll now need to define a frameset, so that the TreeView is at the side of your page, and the content is in a main window. Look at this part of the page index.htm:

 BORDER="3" ONLOAD="setFrameContent();" ONRESIZE="resizeReload();">
  <FRAME SRC="ix_js.htm" NAME="index" MARGINHEIGHT="5" MARGINWIDTH="0">
 <FRAME SRC="treeview.htm" NAME="main" MARGINHEIGHT="5" MARGINWIDTH="10">

You will need to edit the source of the frame main to your needs, it should point to a standard welcome page of some sort.

Now we'll habe a look at what modifications are necessary in ix_js.htm. Near the beginning of the <SCRIPT> area you'll find a block like this:

UniqueID = "JS_TreeView_docu";   // ID of this TreeView
DocRoot = "./";   // path to the linked documents
ImgRoot = "grafix/hlp/";   // path to the symbol images
FrameSet = "index.htm";   // where is the frameset-definition?
ImgWidth = 14;   // the width of the symbol image-files
ImgHeight = 18;   // the height of the symbol image-files
EntryHeight = ImgHeight;   // the height of each line in the TreeView
InitialKey = "d+*";   // branches to show initialy
CurrPageFG = "#FFFFFF";   // text colour for the current page
CurrPageBG = "#000099";   // background color  for the current page
LinkCurrPage = true;   // should the current page marker be a link too?
TreeRootHint = "";   // hint ('quick-tip') for tree root
NormalPageHint = "";   // hint for page symbol
LinkedPageHint = "";   // hint for linked book symbol
OpenBookHint = "close";   // hint for open books
ClosedBookHint = "open";   // hint for closed books
OpenBookStatus = "Close sub-list";   // status text for open books
ClosedBookStatus = "Open sub-list";   // status text for open books
window.defaultStatus = "JavaScript TreeView documentation";
FontFace = "'Garamond Condensed','Times New Roman',Times,serif"; // the font to use
navExplain  = "\nThis page normally belongs inside a navigation";
 +" frame.\n\nIs it OK to reload the page as designed ?";

Change these variables to your needs. First of all, set your Unique ID. You could also change the explanation message displayed if you haven't loaded it into a frame. Then, you may wish to put all the symbol images (ix_*.gif) in a separate directory called ix_imgs, and all your documents in another called docs. And you may want to have the books with the keys 'c' and 'e' open by default (when the user visits your site). Just separate the list of initially open keys with a colon. And then you can make changes to the hints and status messages (for example use a different language), and change the colour that the current document indicator is displayed in. The changes you'd need for all those settings would look like this:

[... unchanged lines snipped ...]
UniqueID = "Whatever_ID";
DocRoot = "docs/";
ImgRoot = "ix_imgs/";
InitialKey = "c:e";
window.defaultStatus = "My wonderful world";

A note to keep in mind for later: TreeRootHint takes precedence over the LinkedPageHint.

TreeView - The symbols

Let's have a look at the little images that make up the tree ...

The closed book. This means there is a list hidden (i.e. not shown). There would normally be the plus-box to the left of the book, so that you could open the list. (file: ix_book.gif)
      The plus-boxes. These show you can open up a sub-list. You need two versions, one for the middle of a list, and one for the end of a list. (files: ix_listp.gif and ix_endp.gif)
The open book. This means there is a sub-list shown. There would normally be the minus-box to the left of the book, so that you could close (hide) the list. (file: ix_open.gif)
      The minus-boxes. These show you can close a sub-list. You need two versions, one for the middle of a list, and one for the end of a list. (files: ix_listm.gif and ix_endm.gif)
The leaf (well, actually it's a page, but one speaks of the leaf of a tree, so I'm calling it leaf). This means that this entry is a document you can see, and that there are no more sub-lists available below this entry. (file: ix_leaf.gif)
The linked book. This is used for leaves that are links to other sites or a collection of pages that have their own TreeView. There are no more sub-lists below this entry. (file: ix_link.gif)
      These are the lines used to link up leaves to the books and to draw a vertical line past some other sub-lists. (files: ix_list.gif and ix_line.gif)
Don't worry, it's not your eye-sight going on this one. It really is a blank space exactly the width of the other symbols. You need this one to indent some items. (file: ix_space.gif)
      These symbols aren't actually used in the tree, but you can use them in your pages for references to previous and following sections within a page. (files: ix_up.gif and ix_down.gif)

Well, those are the standard TreeView symbols, located in grafix/hlp/. I've also packed some other symbol-collections in the documentation ZIP. Have a look at these little example trees:
 Standard TreeView style
 open folder
 local document
 remote document
 closed folder

    local references

 Windows Explorer style
 open folder
 local document
 remote document
 closed folder

    local references

 Windows XP style
 open folder
 local document
 remote document
 closed folder

    local references

 Macintosh Finder style
 open folder
 local document
 remote document
 closed folder

    local references

 OS/2 Explorer style
 open folder
 local document
 remote document
 closed folder

    local references

 Style for dark backgrounds
 open folder
 local document
 remote document
 closed folder

    local references

 Numbered list style
 chapter one
 section one
 section two
 section three
 section four
 section five
 section six
 section seven
 section eight
 section nine
 chapter two
 index / references
 related material

    local references

See:   numbered list example


Gadgets (for xImgs)

Whichever of these symbol-collections you'd like to use, just set the ImgRoot accordingly. You could even create and use your own symbols - and I'd be interested to see them! Infact, the Windows XP style was sent to me by Martin Maedler, and the inverted style was an idea from Andreas Eltzner - thanks to you both!

TreeView - Tree structure

Now for the structure of the JavaScript index. It is located in ix_js.htm. Near the top of the file, just after the 'local definitions' section, you'll find a block of commands with names like initTree, sub_Book, lastBook, sub_Page, etc. This is the definition of the tree structure. Please note that every branch of the tree must have a unique 'key' to identify it (but the multi-line entries consist of two consecutive entries with the same key).


 document title (key: '*')
 introduction (key: 'a')
 chapter one (key: 'b')
 section one.alpha (key: 'ba')
 section one.beta (key: 'bb')
 [...] (long entry) (key: 'bb')
 section one.gamma (key: 'bc')
 chapter two (key: 'c')

The keys must also define the logical structure of the tree. I recommend using the letters of the alphabet, as that gives you more possible tree-entries than if you use numbers (But you can use numbers if you want to - if the structure of your pages never has more than ten documents in each level, you can use keys '0' to '9'). The root-entry always has the key '*'. Here is an example: You've got a document with an introduction, followed by two chapters, 'one' and 'two'. In chapter one, there are also three sections, 'one.alpha', 'one.beta (long entry)' and 'one.gamma'. Have a look at the resulting structure. In this example, chapter two is only offered as a link to another TreeView structure, that's why it's got the 'linked book' symbol.

Note the two entries using the same key, creating a long entry with a line-break.

TreeView - Tree definition

Well, now you know what the keys are for. But now you'll want to know how to create the tree. Well, it's not that difficult really. All you have to do is convert the structure of the tree into a list of calls to the functions listed below. They in turn generate the tree, and they automatically take care of indenting the structure where necessary.

These are the functions that are provided for defining the tree structure:

initTree( <text>[|<status>], <key>, [ <link>, [<opts>] ]);
sub_Book( <text>[|<status>], <key>, [ <link>, [<opts>] ]);
lastBook( <text>[|<status>], <key>, [ <link>, [<opts>] ]);
sub_Page( <text>[|<status>], <key>, [ <link>, [<opts>] ]);
lastPage( <text>[|<status>], <key>, [ <link>, [<opts>] ]);

<key> is the unique key for the entry and <link> is the link you want the entry to refer to. Don't forget that normaly the DocRoot-variable is always prepended to the <link> target. There is a way of surpressing this, so as to be able to make external links to other sites: In this case just put the | (pipe) symbol in front of your link (i.e. write | The parameter <text> is the description of the entry. Normally the same text is used in the tree and the status bar of the browser. However, if <text> contains a pipe symbol ('|'), then the text up to that is interpreted as the text to be displayed in the tree, and the following text is displayed in the status bar when you move the mouse over the link in the tree.

This is especially helpful when you have entries using more than one line, as this is how you can set the status bar to show the complete entry. Talking of multiple line entries, that is what the <opts> parameter is for. If you wish to make an entry spread over as many lines as you want, add the string "cntd." as the last parameter to the second and following line of above mentioned functions. If the entry is a single line, just omit the <opts> parameter.

But that is not all the <opts> parameter is for. If you add the string "link" to the initTree or to a leaf entry, it will not use the standard symbol, but will use the linked book instead. This might be used if you are offering links to other sites, or if the entry leads to a big topic that is too big to add to this TreeView, and / or has it's own TreeView. For instance, a link to the online documentation for some software you've written would use the linked book symbol, as it is not sensible to add the complete index for the documentation to your site index. Within the secondary TreeView, you would add "link" to the initTree entry to offer a link back to the main site. Remember that the use of "link" in the <opts> parameter only works on initTree, sub_Page and lastPage entries, it is ignored on sub_Book and lastBook entries.

And there's still more to do with the <opts> parameter. You can add a custom target for the entry. By adding target=_blank to the parameter for instance, you would open up that link in a new browser window.

If you haven't got a <link> for an entry, you can just omit it. However, to make a multi-line entry without a link, you will have to write an empty string ("") for <link>.

You should always start your tree definition with an initTree command, as it initialises various variables needed for building the tree. Also, you should always finish the tree with a call to end_Tree.

Use end_Book to revert the indentation created by sub_Book and lastBook.

The only difference between sub_Book and lastBook is that lastBook uses the 'end of list' symbols, whereas sub_Book draws the joining line downwards towards later entries. The same applies for sub_Page and lastPage: sub_Page draws the downward lines, lastPage doesn't.

Note that the depth of the tree is not limited as far as I know (I've tried a tree with 10 sub-levels), and length of each level is only limited by the number of letters in the alphabet - 'a' to 'z' should be enough surely? (If not, <key> is in fact case sensitive, so you could continue with 'A' to 'Z' after the 'a' to 'z' entries). And by the way, the order in which the keys are added doesn't matter at all, so long as for instance 'af' and 'ab' leaves are under the 'a' book, then the 'af' leaf can be added before the 'ab' leaf. This is great for moving tree sections around when the structure of your site changes. So long as the depth of the pages in the tree haven't changed, just move the pages wherever you like.

Please also note that it is very important to use '\"' (backslash quote) instead of '&quot;' to encode quotation marks in <text>, otherwise Microsoft Internet Explorer won't display them. However, feel free to use any HTML-Tags you'd like to. But because of the use as a delimiter for <status>, do not use the '|' (pipe) character.

TreeView - An example

Remember the example I used to explain the structure of the tree? Here it is again ...


 document title (key: '*')
 introduction (key: 'a')
 chapter one (key: 'b')
 section one.alpha (key: 'ba')
 section one.beta (key: 'bb')
 [...] (long entry) (key: 'bb')
 section one.gamma (key: 'bc')
 chapter two (key: 'c')

To create this tree, you'd have to add the following function calls to ix_js.htm:

initTree("<B>document title</B>","*", "index.htm");
 sub_Page("<I>introduction</I>"  "a", "intro.htm");
 sub_Book("<I>chapter one</I>",  "b", "one.htm");
  sub_Page("section one.alpha",  "ba","one.htm#alpha");
  sub_Page("section one.beta|section one.beta (long entry)",
  sub_Page("[...] (long entry)|section one.beta (long entry)",
  lastPage("section one.gamma",  "bc","one.htm#gamma");
 lastPage("<I>chapter two</I>",  "c", "two.htm","link");

Note that you can use HTML-Entities in the text and anchors in the links. Please take the time to thoroughly understand what each command and value in the code means.

You can now have a look at the above   example  in the TreeView frame on the left. Don't forget to restore the original   TreeView index when you've finished playing around.

TreeView - Implementation

And now I guess you are ready to write your own index. If you're rewriting your existing pages to incorporate this code, please make a backup first. Anyway, start with the default document index.htm. Then continue with creating your index in ix_js.htm. Take great care that you have the structure of your site clearly in mind when setting the keys for the index entries. When you've finished with ix_js.htm, add a non-JavaScript version of the tree to ix.htm, so that users without capable browsers can get to your pages (admittidly it's a little harder for them, but at least it's possible).

The last step is then to add the code to every page that checks that TreeView is loaded and - if you wish it to - updates the 'current-view' indicator. Note that the index will work without any change to your content pages, so you can check the look of the index before changing them. You should only start editing your pages when you know exactly which page corresponds to which key, otherwise you may have to go back and change every page again later.

TreeView - Current document

Once you've created the index and it's working, you may want to add code to the pages you have so that they update the 'current-view' indicator. It's really easy. Just extend the <BODY>-tag, adding an ONLOAD-event. The code should look like this:

<BODY ONLOAD="if (top.index && top.index.loaded) top.index.index('[<show>]+<current>')">

show is a list of keys for entries you definitely want visible and current is the key of the current document (i.e. the key of the document you're adding the code to). Note that the entire statement for the ONLOAD-event must be in one line, no line-feeds are allowed here.

Normally, you should omit show, only giving current the document key. This way, the index is left the way it is, only updating the current document indicator. Any branches that were open are left open. Only branches to the current document are automatically opened, ensuring that the branch to the current document is visible. Here's an example that only updates the indicator for a file with the key 'cf':

<BODY ONLOAD="if (top.index && top.index.loaded) top.index.index('+cf')">

However there might be situations where you would want to have the index defined in a specific way. In this case, just add all the keys for all the branches you want visible, putting ':' (colons) between the keys. Note that you can write the keys in any order. For instance, when viewing a document about some software you've written (key 'cf'), you might want to expand the branches to the FAQ-document (key 'ga'), the download area (key 'h'), and also to the online usage reference (key 'cfa'). In this case, your ONLOAD-statement would look like this:

<BODY ONLOAD="if (top.index && top.index.loaded) top.index.index('cf:ga:h:cfa+cf')">

On the other hand, you may wish to leave the tree as it is, but delete the current document indicator. In that case, use '.' for current, and omit show:

<BODY ONLOAD="if (top.index && top.index.loaded) top.index.index('+.')">

TreeView - Ensuring it's loaded

While we're talking about the code necessary in each document, I want to show you how to make sure the TreeView frame is loaded even if the page is loaded directly (i.e. without the TreeView frame). This might happen if somebody else offers a link directly to a page of your content. Or somebody might bookmark a page somewhere deep down in your site. In both cases they wouldn't get the TreeView, as they wouldn't have loaded the frameset defined in index.htm.

Well, the problem can be solved. You may remember I described giving the window a unique ID in the section   Preparations . This can now be used to check whether the TreeView frame is loaded. The following code should be added to the <HEAD> of each document in your site:

<SCRIPT LANGUAGE="JavaScript"> <!--
function myError(msg, url, line) { redirect(); return true; }
window.onerror = myError; window.defaultStatus = "JavaScript TreeView";
function redirect() { if (window.stop) window.stop();
 var newPage = "index.htm[#|?]href=thisfile.htm#anchor";
 if (document.images) top.location.replace(newPage);
 else top.location.href = newPage;
} if (""+window.innerWidth != "0") // NS4:not printing
if (( == "JS_TreeView_docu" && top.frames.length == 0)
 || ( != "JS_TreeView_docu")) {
 text = "\nThis page normally belongs inside a navigation frame.\n\n";
 if (confirm(text +"Is it OK to reload the page as designed ?"))
  redirect(); } // --> </SCRIPT>

As you can see, this document (filename thisfile.htm) checks that the window it's being loaded into belongs to the site it was written for (this example page was written for a site called JS_TreeView_docu) and that it's not being loaded into the topmost frame. If either test fails, the code asks the user whether he or she wishes to load the TreeView navigation. If so, it loads the top document containing the frame definition, and sends it's own filename plus an anchor as either the search or the hash value, depending on whether you use '?' or '#'. As described in the section   Preparations , the frame document then loads the referenced file.

To see what I'm talking about, try loading treeview.htm#dg directly into a new window. Use   this link  to do just that (it uses the TARGET-tag to open a new window). Note the way the link even jumps directly to a section in the document.

Now you may remember that I said earlier that you could use either the search ('?') or the hash ('#') part of the URL for sending the filename you want loaded into the frameset. Well, there are two things that you should think about:

To sum all that up: If you're writing pages for offline reading (documentation etc.), or you plan to use anchors in the references, or if your ISP doesn't allow using the search part of the URL, use the '#' character in front of the href-parameter to index.htm. Otherwise (in fact only if you really care about the people still using Microsoft Internet Explorer v.3.x), use the '?' character.



Known Issues


The future

Comments please

For now, that's all I can think of that's important. But please, send any comments / suggestions / criticism to me, Simon Harston, by eMail at !

Copyright  © 2004-02-26  jSh:Services