Log in |
Implementing robust, automatic navigation barsAutomated 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. Ill update this HowTo from time to time as I learn new tricks. Tricks I'm planning to learn and document are:
In the mean time, the more obvious problems in the code are listed in detail after each code segment. Revision History
StrategyThe 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. ImplementationHere'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_navbarbreadcrumbs:<br> <dtml-var standard_html_breadcrumbs> <dtml-if "PARENTS[0].objectValues(['DTML Document']) != []"> <p> <dtml-var subitem_heading><br> <dtml-in "PARENTS[0].objectValues(['DTML Document'])" sort=meta_type skip_unauthorized> <a href="<dtml-var id>"><dtml-var id></a><BR> </dtml-in> </dtml-if> <dtml-if "PARENTS[0].objectValues(['DTML Folder']) != []"> <p> <dtml-var subfolder_heading><br> <dtml-in "PARENTS[0].objectValues(['DTML Folder'])" sort=meta_type skip_unauthorized> <a href="<dtml-var id>"><dtml-var id></a><BR> </dtml-in> </dtml-if> Problems with this code include:
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:
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> <a href="/">home</a> <dtml-else> <dtml-if sequence-end> <br> <b><a href="<dtml-var absolute_url>"><dtml-var id></a></b> <dtml-else> <br> <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:
SummaryAutomatic 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. |