#106: Using Five Views for Navigational Elements/Slots
- Contents
This proposal aims to define the interfaces (in the Zope 3 sense) that the navigation-related views should provide.
- Proposed by
- Sidnei da Silva
- Proposal type
- Architecture
- Assigned to release
- State
- completed
Motivation
Too much logic can be found on the templates that provide navigational elements in the Plone UI.
Customizing simple stuff like:
- What objects show/don't on the navigation tree and breadcrumbs
- Using a different/shorter label (default is Title) for navigation tree and breadcrumbs
- Deciding if an item is selected or not in the navigation tree/breadcrumb
- Deciding or not to expand a node in the navigation tree
Proposal
- Moving all the logic from templates and helper scripts into View classes that can be tested.
- Moving policy decisions (what attribute to use as title, when to show or not an item in navigation/breadcrumbs) to Adapters.
Alternate/Additional Proposal
Use VHM rooting as the prime source of rooting. Example:
Accessing http://host/VirtualHostBase/http/math.foo.org:80/math/VirtualHostRoot/doc1/ would automatically root the navigation at '/math'.
Apply rooting to catalog searches too
Have a toggle to opt-out of automatic rooting.
Implementation
Breadcrumbs
Here, the use of Views would also simplify a lot the logic behind building breadcrumbs. Currently, this is hardcoded in the method createBreadCrumbs in the plone_utils tool, effectively making customization impossible without replacing the whole plone_utils tool by a custom version or monkey patching the method.
The proposed solution is to use a breadcrumbs view, that could be accessed by context/@@breadcrumbs.
The default implementation of this view then could behave pretty much like it's done in Zope 3, by returning querying the container's breadcrumbs view and appending the information about the current node to that.
(In Zope 3, breadcrumbs is actually a method of the IAbsoluteURL View)
Sample Code:
...
def breadcrumbs(self):
context = self.context
request = self.request
container = aq_parent(context)
if container is None or not ITraversable.providedBy(container):
bc = ({'name': context.getId(),
'url': context.absolute_url()
},)
else:
view = getViewProviding(container, IAbsoluteURL, request)
bc = tuple(view.breadcrumbs())
name = context.getId()
bc += ({'name': name,
'url': ("%s/%s" % (base[-1]['url'], name))
},)
return bc
...
Slots/Portlets
Left/Right slots (a.k.a. portlets) are looked up by the script prepare_slots. By default it looks for an attribute of the object (including acquisition) and checks if the value is callable.
While the whole thing looks rather reasonable, the use of an extra attribute on the object itself and possible acquisition make it hard to discover, and mix content and presentation.
Here, again, the use of a View, say context/@@slots would help by abstracting the presentation-dependent aspect which is the list of slots to display out of the content object into a presentation-specific component.
Again, a default View could be provided that still looks up the values in attributes/acquisition to keep backwards compatibility, while allowing for greater customization without having to touch content-space for changing the slots to bee displayed.

