You are not logged in Log in Join
You are here: Home » Members » gtk » Implementing robust, automatic navigation bars

Log in
Name

Password

 

Implementing robust, automatic navigation bars

Automated navigation bars can be tricky. Here's a cut-down version of my navigation bar implementation, and some coverage of the pitfalls I encountered along the way.

I’ll update this HowTo from time to time as I learn new tricks. Tricks I'm planning to learn and document are:

  • "Edit This Document" buttons for authenticated users.
  • Not linking to the [document, method, whatever] we're looking at.
  • Selecting which types of objects are displayed in the navbar.
  • Filtering which individual objects appear in the navbar.
  • Sorting objects in the navbar.
  • Searching from the navbar.
  • Plugging a variety of other bits into the navbar, and controlling them.

In the mean time, the more obvious problems in the code are listed in detail after each code segment.

Revision History

date description
1999/10/13 First version of the document. Illustrates the principle, and the code works, but some of the code is ugly.

Strategy

The navigation bar is heavily <b>componentized</b>. I've broken the navigation system into lots of little chunks. If I hadn't -- say, I'd put the navigation code in the header -- I'd end up with another copy of the navigation code every time I customized the look and feel in a particular folder by giving it its own standard_html_header. Later, if I had to update the navigation code, I'd have to hunt down every copy. Owch! Breaking things up means you can change just the bit you need to change, and leave the rest alone.

Everything starts from the <b>standard header and footer DTML methods</b> so that any object which uses them will get a full navigation system without having to go to any extra effort.

The navigation bar is <b>configurable using properties</b> so that you can easily adjust its appearance and behaviour without having to wade into the code itself.

Implementation

Here's how a page ends up being put together using this system:

standard_html_header
  standard_html_navbar
    standard_html_breadcrumbs
<!-- page content goes here -->
standard_html_footer

See? Nice and chunky. The majority of extra bits I'm planning to implement will be other DTML methods called by standard_html_navbar. At the moment I'm working on standard_html_authedit, which will give a login box or an "edit this page" button.

Code for these DTML methods are as follows:

standard_html_header

<HTML>
 <HEAD>
  <TITLE><dtml-var title_or_id></TITLE>
 </HEAD>
 <BODY BGCOLOR="#FFFFFF">
  <TABLE width="100%" cellspacing=3 cellpadding=3>
   <TR>
    <TD width="100" valign="top">
     <FONT size="-1"><dtml-var standard_html_navbar></FONT>
    </TD>
    <TD valign="top">
     <H1><dtml-var title_or_id></H1>

This is pretty boring. The only interesting thing I've done is use a dtml-var to include the navigation bar rather than put the code in the header itself.

standard_html_footer

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

The footer makes the heading look interesting. Maybe I'll get around to putting some kind of last-modified display, copyright notice and author information in there one day, but not today.

standard_html_navbar

breadcrumbs:<br>
<dtml-var standard_html_breadcrumbs>

<dtml-if "PARENTS[0].objectValues(['DTML Document']) != []">
  <p>
  &nbsp;<dtml-var subitem_heading><br>
  <dtml-in "PARENTS[0].objectValues(['DTML Document'])" sort=meta_type skip_unauthorized> 
    &nbsp;&nbsp;<a href="<dtml-var id>"><dtml-var id></a><BR>
  </dtml-in> 
</dtml-if>

<dtml-if "PARENTS[0].objectValues(['DTML Folder']) != []">
  <p>
  &nbsp;<dtml-var subfolder_heading><br>
  <dtml-in "PARENTS[0].objectValues(['DTML Folder'])" sort=meta_type skip_unauthorized> 
    &nbsp;&nbsp;<a href="<dtml-var id>"><dtml-var id></a><BR>
  </dtml-in> 
</dtml-if>

Problems with this code include:

  • "breadcrumbs:" should be a property, just like subitem_heading and subfolder_heading.
  • I've done pretty much the same code twice. Instead, I should have some other DTML method I can call with arguments to tell it which objects I'm interested in.
  • It looks like I'm evaluating PARENTS[0].objectValues() twice per type of object. I should stash the value somehow.
  • Dealing with documents and folders seperately was deliberate. I should permit other kinds of objects, though.
  • I only display object ids. That works fine for me, but some of you might want titles or some other property in there.
  • Indenting with "&nbsp;" is all very well and good, but what if you don't want indenting?

That said, at least I've got all of the navigation bar code in one place. To solve these problems, I only need to edit one object.

Good bits about this code are:

  • The titles for at least two of the sections are taken from properties, which makes them very easy to customize.

Potential pitfall: if you don't use skip_unauthorized in your dtml-in tags, anonymous users will be denied access to your page if they're not allowed access to any of the folders or documents underneath it. It's so important, I coloured it differently in the code above. Which reminds me, if anyone knows of something that will automatically colour DTML source in some kind of sensible manner, please let me know.

standard_html_breadcrumbs

<dtml-if expr="PARENTS[0]==PARENTS[-1]">
  <b><a href="/">home</a></b>
<dtml-else>
  <dtml-call "REQUEST.set('reverse_PARENTS', [])">
  <dtml-call "REQUEST.set('reverse_LAST', 0)">

  <dtml-in PARENTS skip_unauthorized>
    <dtml-call "reverse_PARENTS.insert(0, _['sequence-item'])">
  </dtml-in>

  <dtml-in reverse_PARENTS skip_unauthorized>
    <dtml-if sequence-start>
       &nbsp;<a href="/">home</a>
    <dtml-else>

      <dtml-if sequence-end>
        <br>&nbsp;<b><a href="<dtml-var absolute_url>"><dtml-var id></a></b>
      <dtml-else>
        <br>&nbsp;<a href="<dtml-var absolute_url>"><dtml-var id></a> 
      </dtml-if>
     
    </dtml-if>
  </dtml-in>
</dtml-if>

This is some breadcrumbs code. I lifted it from something else (the KnowledgeBase Product, I think) and made some minor customizations.

Problems with this code include:

  • I should pick up what to call the home object from a variable somewhere.
  • I only display object ids. That works fine for me, but some of you might want titles or some other property in there.
  • Indenting with "&nbsp;" is all very well and good, but what if you don't want indenting?

Summary

Automatic navigation bars aren't that hard to implement in Zope, but if you don't break them up into chunks and pay some attention to detail, you can create lots of work for yourself later. Time spent now on making your navigation code flexible and robust will more than pay for itself later as you begin giving your site its own look and feel.