Original url at: http://www.xefteri.com/articles/show.cfm?id=10

Dynamic Tree Menu of your site

We'll see how to create a menu system that is cross-browser and includes all your site's folders/files. It uses ASP, XML and DHTML and by simply copying it to your site you have an instant Windows Explorer-like navigation of the contents.

Published: May 31, 2002
Tested with: ASP 3.0
Category: ASP


Introduction

In this article we will see how to create a dynamic folder tree control of your website's folders and files. It uses ASP, XML and DHTML and by simply copying it to your site you have an instant cross-browser, Windows Explorer-like navigation of the contents.

Features:

It is recommended, but not necessary, that you first read Generating an XML file of your website's folders/files, as well as Sam Reynoso's excellent article Enhancing the Dynamic Tree Menu System, which shows the logic used for displaying the Menu Tree. For this reason, I will only go through the changes needed to make this work. In the downloadable materials though, you can find the full source code.

To make this work for you

Files needed and what they do
createxml.asp Traverses the file system of your website and creates an XML file of the contents.
aspRoutines.asp Loads the XML file and parses it out writing the HTML code for the Tree.
default.html Frameset of the left and right frames for viewing the Tree.
menu.asp Left frame of the frameset. Calls the aspRoutines.asp functions.
content.asp Right frame of the frameset. Accepts parameters sent from the links in the left frame and performs customized actions.
/images Folder where all the images reside for properly displaying the Tree.
functions.js Javascript functions to create the DHTML behaviors.
style.css Stylesheet for the Tree.
menuitems.xml XML file of the site's contents. Generated by createxml.asp.

Tree Menu explanation

Above is a snapshot of a typical example. The Tree Menu will show up in the left frame, while the right frame is reserved for sending the path of a folder/file to it and executing some action based on that. For example, if you are creating a content management system, you might actually open up text documents for editing and display contents or properties of a folder. In the materials available for download, I simply redirect to the document and display the folder path passed. Clicking on a folder icon will expand/contract to reveal the folder's contents.

Creating the XML file

The XML file is created by createxml.asp. The output of the XML file will be a little different this time from my previous article. This is an example of what it might look like eventually:

Example of what the XML file might look like

There are 3 main elements to this file:

  1. node name is either root, folder or document.
  2. name attribute is the OS name of the folder/file.
  3. path attribute is the virtual path of the folder/file.

There are some slight differences between this createxml.asp and the one in the previous article. Specifically:

1 ...
2 strXmlFile = "<?xml version=""1.0"" ?>" & strVbCrLf & "<root name=""Site Root"" path=""/"">" & strVbCrLf
3 ...
4 Set objFile = objFSO.CreateTextFile(Server.MapPath("menuitems.xml"), True, False)
5 ...
6 '-- append node to the output unless it is the root folder
7 If thisTree > 0 Then
8     strXmlFile = strXmlFile & "<folder name=""" & objFolder.Name & """ path=""" & strFolderURL & "/""" & " loadOnDemand=""" & fnLoadOnDemand(strFolderURL) & """>" & strVbCrLf
9     objFile.Write(strXmlFile)
10 End If
11 ...
12 '-- create output string for documents
13 strXmlFile = strXmlFile & "<document name=""" & objthisFile.Name & """ path=""" & strURL & """/>" & strVbCrLf
14 ...
15 Function fnLoadOnDemand(folderPath)
16     If folderPath = "/navigation" Then
17         fnLoadOnDemand = "yes"
18     Else
19         fnLoadOnDemand = "no"
20     End If
21 End Function
22 %>

Changes:

The new function fnLoadOnDemand controls whether a particular node's children will be loaded in the resulting menu or not. It accepts the folder path as a parameter, and if it returns yes, it will load the folder's children, while if it returns no then it will not load them. This helps in deep sites where it takes a long time to render the menu tree. Customize this function to get the results you want. For example, I excluded the folder navigation manually by hard coding it in an IF statement. You might decide that your validation is to check how many files exist under a folder, and if there are let's say more than 30, then output a no.

Loading the XML file

This is done through a function called fnLoadXMLData in the aspRoutines.asp file. This file has only one change from the original: the way we load the data to be parsed. In our case, we are loading it from the XML file /navigation/menuitems.xml.

1 Function fnLoadXMLData(byRef objDocument)
2     Dim bResult
3     bResult = True
4     'Create instance of XML document object that we can manipulate
5     Set objDocument = Server.CreateObject("MSXML2.FreeThreadedDOMDocument.3.0")
6     If objDocument Is Nothing Then
7         Response.Write "objDocument object not created<br>"
8         bResult = False
9     Else
10         If Err Then
11             Response.Write "XML Document Object Creation Error - <br>"
12             Response.write Err.Description & "<br>"
13             bResult = False
14         Else
15             On Error resume Next
16             'Load up the XML document into the XML object
17             objDocument.async = False
18             bLoaded = objDocument.Load(Server.MapPath("menuitems.xml"))
19             If err <> 0 Then
20                 Response.Write err.Description & "<br>"
21                 bResult = False
22                 err = 0
23             End If
24         End If
25     End If
26     fnLoadXMLData = bResult
27 End Function

We create an instance of the MSXML component and load the menuitems.xml file we just created into it. If we encounter any errors, we output them appropriately.

Generating the HTML

Once the file is loaded, we call the sub DisplayNode, which is responsible for traversing the XML tree and properly displaying each menu item. This routine calls itself recursively and generates an HTML page containing javascript that handles showing/hiding the menu items. This sub is also in the aspRoutines.asp file.

1 Sub DisplayNode(ByVal objNodes, ByRef iElement, ByRef sLeftIndent, ByRef sOpenFolders)
2     ...
3     'Ignore NODE_TEXT node types
4     If oNode.nodeType = NODE_ELEMENT Then
5         sNodeType = oNode.nodeName
6         sAttrValue = oNode.getAttribute("name")
7         sURL = Server.URLEncode(oNode.getAttribute("path"))
8         ...
9         'Now display the document node
10 %>
11         <td height="16">
12             <img src=images/<%=fnChooseIcon(bIsLast, bIsRoot, sNodeType, bHasChildren, True)%> width=31 height=16 border=0>
13         </td>
14         <td>
15             <img src=images/pixel.gif width=2 height=1>
16         </td>
17         <td nowrap class=node>
18             <img src=images/pixel.gif width=2 height=1><a href="content.asp?document=<%=sURL%>" target=basefrm onClick=objPreviousLink=fnSelectItem(this,objPreviousLink)><%=sAttrValue%></a><img src=images/pixel.gif width=2 height=1>
19         </td>
20     </tr>
21 </table>
22 <%
23     'Otherwise this is a folder
24     Else
25         strLoadOnDemand = oNode.getAttribute("loadOnDemand")
26         'We set the LoadOnDemand value for the History folder
27         'because we want it to be populated only when clicked by the user
28         If (strLoadOnDemand = "yes") Then
29             sMode = "LoadOnDemand"
30         Else
31             sMode = ""
32         End If
33         ...
34         'Now display the folder
35 %>
36         <td height="16">
37             <img onclick="doChangeTree(this, arClickedElementID, arAffectedMenuItemID);" class=LEVEL<%=iElement%> src=images/<%=fnChooseIcon(bIsLast, bIsRoot, sNodeType, bHasChildren, bShowOpen)%> id=<%=iElement%> width=31 height=16 border=0 name="<%=sMode%>">
38         </td>
39         <td>
40             <img src=images/pixel.gif width=2 height=1>
41         </td>
42         <td nowrap class=node>
43             <img src=images/pixel.gif width=2 height=1><a href="content.asp?folder=<%=sURL%>" target=basefrm onClick=" objPreviousLink=fnSelectItem(this,objPreviousLink)"><%=sAttrValue%></a><img src=images/pixel.gif width=2 height=1>
44         </td>
45     </tr>
46 </table>
47 <%
48 ...

Changes:

Conclusion

The best use that I can think of for something like this is a Content Management System or a Web-based File Manager. If you use it for this purpose, you can add some code that calls the createxml.asp file whenever you make a change to the filesystem, and then redirect to the default.html, so that the Menu reloads and the file changes are reflected in the Tree.