[Zope] Problems creating auto-navigation links (LONG)

Dave Lehman davelehman@loewen.com
Thu, 13 Sep 2001 13:47:11 -0500


>I am having a lot of problems trying to get a breadcrumb or tree or
>other page-by-page, automatically generated navigational scheme put
>into place on my Zope site. I have a sense that I may be trying too
>hard or that I've created some complexity here that I didn't need to
>(or that my ISP has done so).

I have just finished wrestling with exactly this problem! Coincidentally
enough, also on a Zope site at Hurrah. (And I would strongly concur that
David Elkins is very helpful and knowledgeable. I'm sure if you ask him,
he'll shake his head and tell you all kinds of stories about me...)

Here are the problems I encountered, and how I overcame them. In this
example, I have a Zope CMF site inside a folder called "portal". My domain
name points directly to the portal folder, so when users go to
"http://www.mysite.com" they are already at the root of my CMF site,
instead of having to go into the portal folder.

That is:
   http://www.mysite.com is mapped to
http://mysite.hurrah.com/cgi-bin/Zope.cgi/portal/

1. If possible, breadcrumbs should display the friendly-reading title for
each folder instead of the usually cryptic Id

Most breadcrumb implementations that i had found just iterated back through
the id's of all the parent folders. But instead of displaying:
   home/my_folder/folder125/some_story

I wanted to display something like:
   Home / My Folder / Stories / The Quest for the Holy Grail

However, it *should* use the Id if you forgot to assign a title to a
certain folder.

After going a couple of rounds with DTML and Python, and pleading my
ignorance to the list, Tres Seaver finally did things The Right Way(tm) and
supplied a Python script (see below) which returns a data structure that
could be used to create the actual breadcrumbs.

2. Each breadcrumb should be hyperlinked to it's folder, except for the
"leaf" breadcrumb, which is the page you're currently on.

OK, now we're getting somewhere. This is minor, but took a bit of thinking
on my part. I wanted each step of the breadcrumb "chain" to be a hyperlink
to that actual folder (so that the user could step back to any part of the
folder hierarchy) except for the leaf folder-- which is the user's current
location.

Once I had the right python script, this turned out to be just a TAL
condition statement:
   tal:condition="repeat/crumb/end"

3. The hyperlinks returned by a breadcrumb should only start at the "root"
of the CMF site, which isn't (necessarily) the same as the root of your
Zope installation

So I had it *almost* working, but the hyperlinks for each breadcrumb
returned something like "http://mysite.com/portal/folder1" when what I
wanted was "http://mysite.com/folder1". Initially, I wrote thought I would
have to augment my python script to manually strip out the "portal" section
of the URL, but that seemed unnecessarily ugly (and thank goodness it was).

The key here was to create a "SiteRoot" object in my /portal folder to tell
Zope that it should make this folder look like the root of the site to the
website visitor. Now the "crumb/url" returned by the page template is
correct.

The code I used is shown below. It looks simple once you have all the
pieces, but for a Zope-Newbie like myself, it took a bit of work to figure
out how to get exactly what I wanted.

But at least I had confidence all along that Zope *could* do what I wanted,
if I just could figure out how...

I'm sure all this is as clear as mud. Please let me know if you want more
clarification.

Regards,
Dave

--------------------
(This page template is pretty of ugly-- i'm obviously no ZPT guru-- so
anyone should feel free to clean this up!) but does the job. It creates the
breadcrumbs string, hyperlinked at each level except the leaf, and displays
the Title for that folder, when possible.)

"breadcrumb_zpt" (PageTemplate)
* put in portal_skins/custom folder

<div tal:define="crumbs here/breadcrumbs">
  <span tal:repeat="crumb crumbs">/
    <span tal:condition="repeat/crumb/end">
      <span tal:condition="crumb/title"
            tal:replace="crumb/title">title</span>
      <span tal:condition="not:crumb/title"
            tal:replace="crumb/id">id</span>
    </span>
    <span tal:condition="not:repeat/crumb/end">
      <a href="url" tal:attributes="href crumb/url">
        <span tal:condition="crumb/title"
              tal:replace="crumb/title">title</span>
        <span tal:condition="not:crumb/title"
              tal:replace="crumb/id">id</span>
      </a>
    </span>
  </span>
</div>

--------------------

"Breadcrumbs" (Python script)
* put in root CMF folder

## Script (Python) "breadcrumbs.py $Revision: 1.1 $"
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=include_root=1
##title=Return breadcrumbs
##
from string import join

result = []
portal_url = context.portal_url()

if include_root:
    result.append( { 'id'      : 'root'
                   , 'title'   : context.portal_properties.title()
                   , 'url'     : portal_url
                   }
                 )

relative = context.portal_url.getRelativeContentPath( context )
portal = context.portal_url.getPortalObject()

for i in range( len( relative ) ):
    now = relative[ :i+1 ]
    obj = portal.restrictedTraverse( now )
    result.append( { 'id'      : now[ -1 ]
                   , 'title'   : obj.Title()
                   , 'url'     : portal_url + '/' + join( now, '/' )
                   }
                 )

return result

--------------------

SiteRoot object
* if necessary, install the "SiteRoot" product
* go to your CMF folder (or wherever you want the root to be) and
  create a SiteRoot object

title: whatever
base: http://www.mysite.com
path: /