Essential JavaScript

Extending Dreamweaver: Let Dreamweaver Create Your Menus


Welcome to the third part of my Dreamweaver series. While part one was an introduction to Dreamweaver's menu configuration and commands, we created our own first command in the second part by introducing the Dreamweaver DOM basics.

Today's menu is a bit more sophisticated; we'll be using various features and API functions to build a new object that will have Dreamweaver create a tree-style menu for your site's navigation in a single click.


Just as with our previous columns, you will need Dreamweaver or Dreamweaver Ultradev version 3 or later to use our examples. You can download a free 30-day evaluation copy of Dreamweaver 4 at Macromedia. A recommended additional reading is Macromedia's Extending Dreamweaver, which contains the complete docs and lists and explains all JavaScript APIs.

In order to deploy the new object we will create on your site, you will need to activate JavaScript and some basic CSS support, as the object uses CSS's display property. Be sure to check for your target audience before using this object in your projects -- some of the platforms supported are Mozilla/Netscape 6, Internet Explorer 5.x for Windows and Macintosh, and Opera.

The Idea

So, what's this all about? In many cases, when you're building your site, you'll organize the files in such a manner that your directory structure can be directly modeled into a navigation system. For hierarchical structures, a tree-style menu has proven to be very useful, since it's a natural way to display this kind of structure.

The idea is actually simple: use a bunch of Dreamweaver API functions, which will scan your complete site or a subfolder of it to build a tree-style hierarchical menu widget automatically. The menu items are being created from the file names -- an enhanced version could also scan the files for their titles. See the examples page for samples of the menus being created.

Working with Files

Dreamweaver defines dozens of functions to work with files that are divided into different APIs. The File I/O API contains 10 different functions that form a basic set to work with files; for example, you can create, read, or delete files and folders or their attributes. The methods of the File I/O API can be accessed via the DWfile object.

Also in Essential JavaScript:

Extending Dreamweaver with its JavaScript API

Accessing Dreamweaver's JavaScript API

Creating Themes with CSS and JavaScript

You're limited to working with file:// URIs with this API; in order to access a document out on the Web, you have to use the HTTP API, which is unfortunately only available in Dreamweaver 4. The HTTP API consists of only seven functions; these are enough to let you get and post data to any valid HTTP server.

The file manipulation functions are responsible for opening, browsing, and saving documents and style sheet files inside the editor environment. The largest function group, containing about 50 functions, handles the site files and site map. Among other things, these functions allow you to check links, make and retrieve selections, access current sites, define new sites, check out files. These functions are invoked as methods of the site object that are always available.

Step 1: Get the Selection

OK, this is where we need to start. We must access the selection and make sure that it's only a single folder; it will later act as the menu structure's root node (I'll only excerpt the interesting parts of the source code -- you can either browse the code directly or download it from our library):

var sel = site.getSelection(); // return an array of selected file names
  var folder = sel[0]; // get the first file of the selection
  if (DWfile.getAttributes(folder) != "D") { // is it a directory?
    // error

getSelection() returns an array of strings, which are absolute file:// URIs of the files selected. The next function, getAttributes(), is part of the File I/O API; it returns either R (read only), D (directory), H (hidden) or S (system). After checking all values, we could continue by reading the contents of the folder by calling the listFolder() method which returns an array of file names:

var files = DWfile.listFolder(folder);

But things are a little more complicated than that. What happens if this folder contains one or more sub-folders? listFolder() only operates on the selected folder itself; it won't descend into any containing folders. We have to solve this task in our algorithm.

The solution comes in the form of one of the most powerful programming techniques: recursion.

  Related Reading:
DreamWeaver 4: The Missing Manual

DreamWeaver 4: The Missing Manual
By Dave McFarland
July 2001 (est.)
0-596-00097-9, Order Number: 0979
420 pages (est.), $24.95 (est.)

Using Recursion

Basically, we're creating a function which scans the content of a folder and calls itself when it encounters another folder. Thus we make sure to get the complete directory structure under a given root folder.

We won't dive into all of recursion's details here. However, just remember one of the most important facts about recursion: every time you make a function call inside of a function, the JavaScript interpreter leaves a reference to the calling function on the so-called stack, which is needed to return to this function after the called function returned. This behavior allows us to easily implement a function which creates a hierarchical menu -- actually, we're only translating one system into another, since a tree-style menu is also a recursive structure.

Step 2: Rebuild the Directory Structure

Instead of directly building the HTML code needed, we create an in-memory representation of the directory structure. I created two small JavaScript classes called File and Folder, which is an extension of File. Starting with a Folder instance, which is created from the selected folder, the list() function rebuilds a complete representation of the directory structure under the root folder selected.

Inside list(), we use the already introduced DWfile.listFolder(). We iterate the list of files, if any, and differ between files and folders. In every case we're instantiating a new object File or Folder and appending it to the current folder's files array; in the case of a folder, we simply call list() and do it again.

One thing you should be aware of are Dreamweaver's files, such as TMP files or _notes folders. The code filters these, so they're not included into the menu. Due to the recursive behavior, list() returns with the root folder again.

If you're wondering why we're not directly creating the HTML code, I'll be covering that in future columns, along with concepts including feeding data like this directly to an graphical application like Fireworks and creating your own site maps with a single click.

Step 3: Create the Menu's Code

Aside from a few caveats, let's look at what we need to do to finish this exercise. First, we must be able to model a hierarchical structure, i.e., use indentation to show relations between items. The next thing is to create a mechanism to open and close folders. Both problems are solved easily with CSS.

Remember the way CSS lays out its contents? It makes a distinction between boxes and inline elements. Basically, the difference is that a box always occupies a rectangular area on the screen and wants to reside on its own line, whereas inline elements flow on the page. So to create an indented tree structure, we simply use boxes with a margin to the left. Both files and folders go into the generic box element DIV and have their own assigned style classes. The boxes are stacked upon each other and create a tree automatically.

In order to make the tree become "live," folders are treated specially. The difference is that a folder, naturally, contains more items. The name of the folder is always visible; the contents may not be. Actually, a folder must be represented by two containers -- the first one takes the folder's name and an icon, the second one holds the contents of the folder.

While the file links directly point to URLs, the folder links point to a small JavaScript function which is called toggleMenu(). This function receives an element's ID and toggles CSS's display property. This property contains all the magic needed to display an element as a box element or to completely hide it, which means it takes no space on screen (in contrast to the effect of thevisibility property).

When you have such a link, the trick is to pass the ID of the element, which serves as the container for the folder's content. So the folder's content becomes visible or invisible, but the name always stays. Additionally, a small plus or minus sign shows the state of the folder. But how do we create a really individual ID?

Once again, recursion is the solution. The code is recursive, already; we only add a few snippets of code. The trick is to create an ID of the current folder's location inside the tree. Consider the root folder having ID "0." The first parent item can be addressed as "0.1." The second one might be a folder; it has ID "0.2." The child items of this folder can be addressed by "0.2.1," "0.2.2," etc. We're passing a initial value of "0" to the first call of traverse() (which is the actual recursive workhorse inside createTree()), and appending a dot (.) and the iteration index. That's almost it. To make the ID even more individual, you could prepend something like "menuitem."

After climbing through the folder structure, the function createTree() returns a string containing the complete menu, which can be easily inserted into an HTML document.


That's it for today. You can find some examples of the menus being created on our examples page. The complete code can, as always, be found in our JavaScript library.

Claus Augusti is O'Reilly Network's JavaScript editor.

Read more Essential JavaScript columns.

Return to the JavaScript and CSS DevCenter.

Copyright © 2017 O'Reilly Media, Inc.