With all the prep work done for navigation, adding a menu is simplicity itself.  Remember that the site index view will render the Navigation provider (viewlet manager) which in turn renders the viewlets for the current context.  So basically, the viewlets are sensitive to context, and for IArticles, the context is either an instance of a Grok4Noobs application, or a NoobsArticle.

For NoobsArticle, we want a button which navigates up a level toward the site root.  The single instance of Grok4Noobs is  the root, so we don't want the PreviousLevel viewlet rendered for that class.

class PreviousLevelMenuEntry(MenuItem):
    '''  A menu item for articles with parent articles. IOW NoobsArticle
    '''
    grok.context(NoobsArticle)
    grok.order(-4)
    title = mtitle = u'Up a level'
    link = u'..'
    mclass = 'nav buttons'
    def condition(self):
        self.title = self.context.__parent__.navTitle
        self.image = self.static['up.png']
        return True

The grok.order() call manages the placement of the menu items.  This one is at the top of the list.  The title gets displayed on the button.  The link is simple text in this case for traversing up a level.  mclass is used to style the button, and condition() decides whether or not to display the button.

Then we want to render button links to the previous and next pages, which are siblings of the current article.

class PrevMenuEntry(MenuItem):
    '''  A menu item for previous articles in the list
    '''
    grok.context(NoobsArticle)
    grok.order(-3)
    title = mtitle = u'Prev Page'
    mclass = 'nav buttons'
    @property
    def link(self):
        title = quote_plus(self.context.prev)
        return self.context.__parent__[title]
    def condition(self):
        if getattr(self.context, 'prev', None) is not None:
            self.title = self.context.prev
            self.image = self.static['left.png']
            return True

Here, link is defined as a property, returning the object representing the previous sibling.  Of course, the button is conditional depending on there being an actual sibling.

We do the same thing for the next sibling:

class NextMenuEntry(MenuItem):
    '''  A menu item for articles next in the list
    '''
    grok.context(NoobsArticle)
    grok.order(-2)
    title = mtitle = u'Next Page'
    mclass = 'nav buttons'
    @property
    def link(self):
        title = quote_plus(self.context.next)
        return self.context.__parent__[title]
    def condition(self):
        if getattr(self.context, 'next', None) is not None:
            self.title = self.context.next
            self.image = self.static['right.png']
            return True

Then, for articles which contain more than just one child article, we want to add a button which navigates to the sorter.  The sorter has already been discussed in quite some detail:

class SorterLink(MenuItem):
    ''' A conditional menu item which shows for articles with more than one child
    '''
    grok.context(IArticle)
    grok.order(-1)
    title = u'Change menu order'
    link = u'sorter'
    mclass = 'nav buttons'

    def condition(self):
        return len(self.context) > 1

Not really a part of the general navigation, and again only for NoobsArticles which are contained in other articles, we want to support a delete button.  This button renders itself right at the top of the navigation area:

class DeleteButton(grok.Viewlet):
    '''  Renders a delete button into the navigation area
    '''
    grok.viewletmanager(Navigation)  # Render into the Navigation area
    grok.context(NoobsArticle)       # for normal articles

The DeleteButton() viewlet has an associated template which accomplishes the actual rendering:

<div class='buttons'>
    <a tal:attributes="href python:viewlet.view.url(context,data={'delete':1})">
      Delete this page
    </a>
</div>

The edit, add and cancel buttons are already rendered by the generic viewlet defined for the Menu viewlet (in menu.py) as discussed previously:

class Menu(grok.Viewlet):
    grok.viewletmanager(Navigation)  # Render into the Navigation area
    grok.context(ILayout)            # for all instances of ILayout

and the full menu template as displayed in the Navigation area is duplicated here for your reference:

<div class='MenuHeader' tal:condition="context/navTitle | nothing">
    <h5 tal:content="context/navTitle" />
</div>

<div class='buttons' tal:condition="context/navTitle | nothing">
    <a tal:attributes="href python:viewlet.view.url(context,data={'edit':1})">Edit</a>
    <a tal:attributes="href python:viewlet.view.url(context,data={'add':1})">Add</a>
    <a tal:attributes="href python:viewlet.view.url(context)">Cancel</a>
</div>

<ul class='menu'>
    <div tal:replace='structure provider:menuitems' />
</ul>

 

Grok 4 Noobs

Site Navigation: Context sensitive menus