Netscape DevEdge

Skip to: [content] [navigation]

This resource is obsolete and is provided for reference purposes only.

JavaScript DHTML Collapsible Lists

A Cross-Browser Collapsible List with support for Navigator 4.x, Internet Explorer 4.x, Internet Explorer 5.x and Netscape 6

By Michael Bostock, Netscape Production Engineer
Updated for Netscape 6 and DOM 1 Compliant Browsers by Bob Clary
Updated for Macintosh by Seth Dillingham

Last Updated: February 3, 2003

Contents

News

xbCollapsibleLists was a port of Michael Bostock's original JS DHTML Collapsible Lists so that it would support Netscape 6 and other browsers based upon Mozilla and Gecko. The intent in performing the port was to illustrate techniques that could be used to port Navigator 4 only Layer based DHTML to support Netscape 6. However, the popularity of xbCollapsibleLists as a tool continues to grow.

Our mission as Evangelists is to not provide reusable Script libraries and maintain them, but to provide educational materials which will help Web Developers to support Netscape 6. With this in mind, We do not have the time or resources to continue to maintain xbCollapsibleLists in order to continue to add requested features and would like to find a new maintainer for xbCollapsibleLists. Please contact us if you want to become the maintainer of xbCollapsibleLists.

Introduction

If you're managing a site with a lot of content, you undoubtedly have some sort of scheme to organize that information. Furthermore, you've probably organized it into a hierarchical list. This way, users don't have to look at all of your pages to find the one page they want. On the other hand, to get to that one page, your users probably have to travel through several levels of the hierarchy tree. So while the tree organizes content, it puts more distance between the page your users want and the root. How does one fix this? Collapsible lists.

Collapsible lists have been available for a long time, but now DHTML allows for the creation of more functional and more adaptable lists. Pre-DHTML, collapsible lists (such as those by Danny Goodman) had to live in their own frame and use cookies to store the state of the list. Not so with these lists! The JavaScript DHTML Collapsible List library lets you create lists with the functionality you need for a real solution. Plus, these lists can be stylized to fit even the most far-out Web sites.

Cross-Browser Support

This tool has been updated and rewritten to support Netscape Navigator 4.x, Netscape 6, Internet Explorer 4.x, and Internet Explorer 5.x on Windows and Internet Explorer 5 on Macintosh. It uses the Cross-Browser xbStyle Style API to support multiple browsers. Note that the Collapsible Lists code for Netscape 6/Gecko and Internet Explorer currently uses the innerHTML property of Elements that is available only in Netscape 6 and Internet Explorer 5.

Note that since Navigator 4 is explicitly supported on this page, the use of tables for layout have been curtailed since they can cause Navigator 4 to crash. This Tool is for legacy applications only, and should not be used with forward looking Standards compliant web sites.

Changes

View Change Log

The original list written by Michael Bostock has been extensively rewritten to use portable cross browser JavaScript. The code has been reformatted for readability; the List Object creation has been rewritten to take advantage of Object Prototypes thus eliminating redundant assignment of Object methods; platform/browser dependent code has been factored into separate code sections thereby improving maintainability; the xbStyle API is used to support cross browser style manipulations; support for DOM 1 compliant browsers such as Netscape 6 and Internet Explorer 5.x have been added; the requirement that explicit styles and divs be coded into the destination HTML page has been removed by adding support for Internet Explorer 4.x to create new elements.

2002-09-06 - Mark's Table positioned example has been updated to resolve a problem in Mozilla 1.0.1 and Netscape 7

2002-09-04 - Modified examples to use local versions of external scripts from the xbProjects scripts, and to correct a problem with the initialization of the xbLibrary script manager when loading scripts from the examples directory rather than the xbProjects directory.

2002-08-08 - Changed to use latest xbStyle. The practical browser sniffer script ua.js is no longer needed.

2002-03-04 - Mark Filanowicz <mfilanowicz@filanowicz.necoxmail.com>, has contributed another example illustrating how to position a list using tables.

2002-02-26 - Mark Filanowicz <mfilanowicz@filanowicz.necoxmail.com> has contributed a patch to xbCollapsibleLists.js which allows you to click on a list heading to open a list rather than just clicking on the list handle images.
Mark has also contributed a modified version of the events.html example which illustrates the ability to display an xbCollapsibleList with a specific sublist already open as well as allowing the list to be automatically positioned.

2002-02-15 - clarified example to note that Netscape Navigator requires the empty script block to properly initialize the functions defined in xbDOM.js.

2002-02-11 - fixes posted to xbDOM.js, xbStyle.js, xbCollapsibleLists which affect support for Internet Explorer 4. Thanks to Rob Johnston <rob_johnston@hotmail.com> for reporting the problem and helping with testing.

2002-02-11 - Fixed incorrectly spelled xbGetElementById in xbCollapsibleList line 381. Thanks to Rob Johnston <rob_johnston@hotmail.com> for the heads up.

2002-01-14 - Fixed reference to old global function expand to new version using the xbcl_ prefix xbcl_expand in the event.html example.

2001-12-12 - Changed all global functions to use xbcl_ as a prefix to reduce name collisions with other libraries

2001-11-15 - Moved the examples and source to a separate directory and included a zip file that includes all needed files for the installation.

2001-11-09 - Seth Dillingham has contributed a new version of xbCollapsibleLists.js that works with Internet Explorer on Macintosh computers. Please let us know how well this improved Macintosh support works for you. New, updated API documentation will be made available in the near future.

Examples

How to use the Library

To use the library, you first have to include it and the other scripts it depends upon. Download examples.zip which contains xbCollapsibleLists.js as well as the Library Manager script xbLibrary.js, the xbDOM API xbDOM.js, and the xbStyle API xbStyle.js to your local hard drive. Next, you'll probably want to add a function that is called when the page loads. This way, the list appears when the page loads. (Of course, if you want to, you can load the list at a later time.) The top of your HTML document should look something like this:

<HEAD>
<!-- Note this empty script block is required for Netscape Navigator 4.x -->
<SCRIPT LANGUAGE="JavaScript1.2"></SCRIPT>
<!-- Include the other scripts used by xbCollapsibleLists -->
<SCRIPT LANGUAGE="JavaScript1.2" SRC="xbLibrary.js"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript1.2">
  // xbLibrary is used to conditionally load script files.
  // tell xbLibrary load the scripts from the current directory
xblibrary = new xbLibrary('.');
</SCRIPT>
<SCRIPT LANGUAGE="JavaScript" SRC="xbDOM.js"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript1.2" SRC="xbStyle.js"></SCRIPT>
<!-- Include xbCollapsibleLists -->
<SCRIPT LANGUAGE="JavaScript1.2" SRC="xbCollapsibleLists.js"></SCRIPT>
<!-- define your onload handler -->
<SCRIPT LANGUAGE="JavaScript">
function init() {
// insert code here
}
</SCRIPT>
</HEAD>
<BODY ONLOAD="init();">

The "ONLOAD" attribute in the <BODY> tag will call the init() function when the page loads. You then have to write some code inside init() to actually create the list. Start by creating a new List object:

var width = 350, height = 22;
myList = new List(true, width, height, "#CCCCCC");

The first argument is a boolean that specifies whether the list is initially visible. The second argument specifies the width, the third the height (both in pixels). The fourth argument is the background color of the list. If you don't specify a background color, the list will be transparent.

Next we add items:

myList.addItem("This is an item!");

The argument to addItem() is a string. This string can be plain text (as above) or a string of HTML. You can include a link, an image, practically anything. Items will appear in the list in the order they are added from the top down.

Sublists

Of course, creating a list with only one level isn't collapsible. To make a collapsible list, we need multiple levels. This means that we need to create sublists. These are the lists that show up when we expand the list, and they hide when we collapse the list. To make a sublist, first create a new List object:

subList = new List(false, width, height, "#CCCCCC");
subList.addItem("This is a sub item!");

Now we simply add that to the main list.

myList.addList(subList, "Some sub-items:");

Now a new item will appear on the root level (part of myList ) with an arrow next to it. Click on the arrow, and the subList will show up. By specifying which sublists are initially visible (the first argument to the List object constructor), you determine how the list looks when it initially loads. When you're adding sublists, you can create as many levels as you want (within reason). Adding new sublists to existing sublists using the same method as described above. (Create a new List object, add a couple items to it, and then call addList() from the list you want to contain the sublist.)

When you're done adding items and sublists, you have to build the list:

myList.build(100,20);

Here "100" refers to the x coordinate of the list, and "20" to the y coordinate. Note that you only have to build the outermost (parent) list. So, no matter how many sublists you have, you should only call build() once on the outermost list.

Tip

When building your list, make sure that the window is big enough to fit the list with every sublist completely expanded. If it won't fit on the screen, you can add HTML spacers into the BODY of your document so that the user can scroll down. An easy way to do this is to add an empty <DIV> tag, like so:

<STYLE TYPE="text/css">
#spacer { position: absolute; height: 800; }
</STYLE>
</HEAD>
<BODY ONLOAD="init();">
<DIV ID="spacer"></DIV>

Additional Functionality

There's quite a range of additional functionality built-in to the List object that lets you create lists in a wide range of styles. You've seen already that you can specify background colors for lists. This means that each sublist can have a different color, allowing you to visually differentiate content in your list. In fact, you have control over the background colors of every individual element in the list. To specify a unique color for an individual list item, use an additional argument in the addList() or addItem() functions. For example,

myList.addItem("I am yellow!", "#FFFF00");

would create an item that is yellow, regardless of the color of the parent list. (The color of the parent list was specified in the List object constructor.)

If you wanted to apply a text styling to the list as a whole, you can use the setFont() function. For example:

myList.setFont("<FONT COLOR='white' SIZE=-1>","</FONT>");

This would make every item in the list white and one size smaller. You could put the HTML styling into the addItem() or addList() text, but this lets you apply fonts over the list as a whole.

To further differentiate content, you can also specify varying widths and heights of your sublists in the List object constructor. For example, suppose you wanted a list of people with their pictures. The outer list could just have their names and have a height of 22 pixels. The sublist which contained the pictures could have a height of 70 to show the pictures.

You can also specify a parent layer to contain the list. This way, you could have control over the list as a whole. For example, if the parent layer was draggable, the list would be draggable. Specify a parent layer using the parentElement attribute:

myList.parentElement = document.layers.container;

You can also specify the amount of indentation for the list. Do this using the setIndent() function:

myList.setIndent(20);

If you specify an indent of 0, all items will be on the same level, though there will still be space reserved for the arrow on the left side. To eliminate this space, you can use an indent of -1. Here is an example showing the difference between different indents. You should specify the indent for each sublist, as indentation is not inherited from the parent list. To get the style you want, it's best to just play around with it for a while.

Finally, there is also event-level control. If you specify the "onexpand" attribute of the List object with a function, that function will be called when the list is expanded. Inside the function that is called (which you must define), "this" will refer to the list that was expanded. The function will also be passed the id of the list that was expanded. Each list has a unique ID, starting at 0 and going up by one with each new List object. Here's an example of how to use this feature: first, set the attribute:

myList.onexpand = colorize;

Now define the colorize() function:

function colorize(id) {
  if(this.bgColor != "red") {
    this.bgColor = "red";
    this.needsUpdate = true;
  }
}

Note that you have to set the "needsUpdate" attribute to true if you want the list to actually be updated. This is so that the expand process isn't slowed down at all if you don't want to update. You can do a great deal of things inside the colorize() function. You can change the height of the list, or even add new items or sublists! (If you add new items or sublists, or if you change the height, you'll also want to set the "needsRewrite" attribute to true as well.) This feature was designed to give you added styling and functionality, but it's up to you to be creative in how to use it. Feel free to experiment! (Here's an example I came up with.)

Note for techies: The function associated with onexpand will be called before the list is actually expanded so that changes you make (e.g., bgColor ) will show up when the list is expanded. If you want to gather information about the list after it has been expanded (for example, the new height), you should use the "postexpand" property.

In my example, I also took advantage of the fact that you can access a sublist's parent through the "parent" attribute, that the "id" attribute of the list reflects its ID, and that you can access all the lists on a page through the "document.lists" array.

Additional Information

To speed the initial loading time of the lists, sublists are only loaded as they become visible. Thus, no matter how many nested lists you add to the main list, the initial loading time stays the same. Sublists that were not initially visible are loaded when the user opens them for the first time.

When you add items to the list, you are not merely passing text - you are passing a string of HTML. Consequently, you can pass in hyperlinks, images, or whatever you desire. For example l.addItem("<A HREF='index.html'>Main Page</A>") will add an item which is a link to the "Main Page."

In Navigator 4.0, JavaScript positioned content loses shaped when the window is resized. The xbStyle API automatically reloads the page whenever the browser window is resized.

References

About the Authors

Michael Bostock is a class of 2000 student at Princeton University in New Jersey. He is a Computer Science major in the Engineering school.

Bob Clary, an Evangelist in TE/DS, develops documentation and sample code to promote the use of Netscape 6 and Standards Compliant browsers

Seth Dillingham is president of Macrobyte Resources, the lead developer of Conversant, and he keeps an online journal.

A+R