Megrok.navigation lets you easily add all sorts of menus to a site.
Menus are implemented as viewletmanagers, and items as viewlets.
You can also override the default templates by registering your own IPageTemplate
>>> import grok
>>> class MySite(grok.Container, grok.Application):
... pass
>>> grok_component('mysite', MySite)
True
>>> root = getRootFolder()
>>> root['site'] = site = MySite()
Let us now define a menu
We’ll first define an Interface, so that later on we won’t need to redefine some
menus after we redefined
the Navigation menu, so this is not necessary to do, although it can lessen
dependencies.
>>> from zope.security.testing import Principal, Participation
>>> from zope.security.management import newInteraction, endInteraction
>>> participation = Participation(Principal('zope.anybody'))
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> newInteraction(participation)
>>> nav = Navigation(site, request, grok.View(site, request))
>>> nav.update()
>>> len(nav.viewlets)
0
>>> print nav.render()
<ul class="">
</ul>
megrok.navigation uses zope.pagetemplate (or megrok.pagetemplate) to allow you to
override the default templates.
Let’s define a template based on divs, instead of ul
>>> mt = """<div tal:attributes='class menu/cssClass'>
... <tal:repeat tal:repeat='item menu/items'
... tal:replace='structure item/render'/>
... </div>"""
>>> from megrok import pagetemplate
>>> class DivMenu(pagetemplate.PageTemplate):
... template = grok.PageTemplate(mt)
... pagetemplate.view(navigation.interfaces.IMenu)
>>> grok_component('divmenu', DivMenu)
True
>>> it = """<div tal:attributes='class menu/cssItemClass'>
... <a tal:attributes="href item/link;
... title viewlet/description|nothing">
... <img tal:condition="item/icon | nothing"
... tal:attributes="src item/icon"/>
... <span tal:replace="item/title"/></a>
... <tal:replace tal:condition="item/submenu | nothing"
... tal:replace="structure provider:${item/submenu}"/>
... </div>"""
>>> class DivMenuItem(pagetemplate.PageTemplate):
... template = grok.PageTemplate(it)
... pagetemplate.view(navigation.interfaces.IMenuItem)
>>> grok_component('divmenuitem', DivMenuItem)
True
>>> print actions.render()
<div class="">
<div class="">
<a href="http://127.0.0.1/site/foo/fooindex">
<BLANKLINE>
Details</a>
<BLANKLINE>
</div>
<div class="">
<a href="http://127.0.0.1/site/foo/fooedit">
<BLANKLINE>
Edit</a>
<BLANKLINE>
</div>
<div class="">
<a href="http://127.0.0.1/site/foo/fooprotected">
<BLANKLINE>
Manage</a>
<BLANKLINE>
</div>
</div>
But what if you want 2 different templates for items to be used in different menus?
You never specify any Items
yourself, so you can’t tell them to implement a different interface and register the
template to that interface.
To allow this, the itemsimplement directive was introduced.
>>> class IIconItem(navigation.interfaces.IMenuItem):
... pass
>>> class IconMenu(navigation.Menu):
... grok.name('icons')
... navigation.itemsimplement(IIconItem)
... navigation.globalmenuitem('http://grok.zope.org', 'Grok!',
... icon='icon.jpg')
>>> grok_component('nav', IconMenu)
True
>>> it = """<img tal:condition="item/icon | nothing"
... tal:attributes="src item/icon"/>"""
>>> class IconMenuItem(pagetemplate.PageTemplate):
... template = grok.PageTemplate(it)
... pagetemplate.view(IIconItem)
>>> grok_component('iconmenuitem', IconMenuItem)
True
>>> icons = IconMenu(site, request, grok.View(site, request))
>>> icons.update()
>>> print icons.render()
<div class="">
<img src="icon.jpg" />
</div>