[Zope] HOWTO: 'Tree Tag Global Navigation'

Amos Latteier amos@aracnet.com
Thu, 22 Apr 1999 12:19:27 -0700


Hello Zope Folks,

Ken Manheimer and David Ascher justly complained about the 'Tree Tag Global
Navigation' HowTo, and so I've revised it.

  http://www.zope.org/Documentation/HowTo/DTML/treetag

For your convenience the text of the HowTo follows below.

-Amos

--

Zope's tree tag makes creating tree widgets easy. One obvious use of
this facility is to create a global navigation system for a website.
How can this be done?

There are a number of ways but probably the most easy is to put a tree
tag in the 'standard_html_header' DTML Method in the top level Folder.
By default new DTML Documents and DTML Methods use the
'standard_html_header' and 'standard_html_footer' to start and end
their HTML. This gives you a simple mechanism for creating a
consistent look and feel across web pages. It also allows you to
change the look and feel in an area of the web site by overriding the
'standard_html_header' and/or 'standard_html_footer' within a given
Folder.

So now that we have a strategy let's get down to brass tacks. Here's
a sample 'standard_html_header' and 'standard_html_footer' that will
place the content of a web page inside a table and place a
navigation tree in the left table cell.

  standard_html_header::

    <HTML><HEAD><TITLE><!--#var title_or_id--></TITLE></HEAD>
    <BODY BGCOLOR="#FFFFFF">
    <TABLE BORDER="1">
    <TR VALIGN="top">
    <TD><!--#var sidebar--></TD>
    <TD>

  standard_html_footer::

    </TD></TR></TABLE>
    </BODY>
    </HTML>


Well this is fine and good, but what should the 'sidebar' object that
draws our navigation device look like, and why not put it directly in
the 'standard_html_header'? The reason for decomposing the 'sidebar'
information is to allow us to override the 'standard_html_header' and
'sidebar' separately. It is entirely possible that we may want to have
a slightly different side bar or HTML header in different Folders. By
using different objects we can mix and match without having to rewrite
everything if we just want to change one component of a page.

As for what the 'sidebar' object should look like, it should be a DTML
Document or DTML Method (it doesn't matter), and here's a sample of
how to draw a tree widget.

  sidebar::

    <!--#tree
      expr="PARENTS[-1]"
      branches_expr="objectValues('Folder')"
    -->
    <A HREF="<!--#var absolute_url-->"><!--#var id--></A>
    <!--#/tree-->

How does this work? Recall that the tree tag draws a tree widget
given a hierarchical collection of objects. The 'expr' and
'branches_expr' attributes of the tree tag tell it how to gather a
collection of objects. The content between the open and closing tree
tags is rendered for each tree item.

In this case the 'expr' attribute tells the tag to start drawing the
tree with the object known as 'PARENTS[-1]' which is the root Zope
Folder. If this seems obscure, remember that the PARENTS variable is
a list of containing objects traversed by Zope on its way to the
published object. 'PARENTS[-1]' is Python's way of saying referring
to the last element of that list, which is always the top level Zope
object, since it is always traversed first on the way to the
published object. 

The 'branches_expr' attribute tells the tree tag how to gather
sub-objects given a root object. In this case the expression says to
call the 'objectValues' method with 'Folder' as an argument. Recall
that 'objectValues' is a standard Zope method which returns an
object's sub-objects. The 'Folder' argument tells the method to only
return sub-Folders, rather than all sub-objects. 

The HTML Anchor tag inside the tree tag provides links to each
sub-Folder by using the 'absolute_url' method to generate a URL for
the Folder, and the 'id' method to generate the name of the link.

So in sum, we can see that the tree tag is called in such a way as
to start from the top level Zope folder and iterate over all its
sub-Folders. This gives us a global navigation widget.

There are lots of way to improve this simple navigation system. A
more advanced global navigation widget might perform tests on
sub-Folders before displaying them, such as testing for
authorization, or testing for attributes such as 'private'. This
could be implemented by writing a DTML Method or an External Method
and using it in place of 'objectValues' in the 'branches_expr'
attribute. Another enhancement might check for a 'see_also'
attribute on Folders and display related links in addition to a
global tree. The global tree could also be dressed up. It could
display links to Folders in different colors, or fonts, or include
icons for some Folders, or it could use the Folder titles instead of
Folder ids as link text.