Aller au contenu. | Aller à la navigation

Outils personnels

Navigation

Vous êtes ici : Accueil / Articles / Using five.grok to add viewlets

Using five.grok to add viewlets

Par Vincent Fretin publié 31/12/2008 10:00, Dernière modification 18/01/2009 12:04
How to add new viewlets with five.grok in a Plone product.

Update 2009-01-18: I simplified the AdViewlet base class according to feedback of Sylvain Viollon on the grok-dev mailing-list. (Be sure to use viewlet/getBanner instead of view/getBanner in the template)

Whaou! It's so simple to add new viewlets with five.grok, no need to worry about ZCML, all is in Python code. I can create a viewlet with 2 lines of code.

I'll show you the code I wrote to add viewlet managers and viewlets to my Plone Site to add advertisements.

The buildout was created with paster create -t plone3_buildout and the myproject.theme egg was created with paste create -t plone3_theme in the src directory.

First, in the setup.py file in the myproject.theme egg, you add five.grok:

...
install_requires=[
    'setuptools',
    'five.grok',
],
...

In buildout.cfg, change it like this:

[buildout]
...
versions = versions
eggs =
    ...
    z3c.autoinclude
develop =
    ...
    src/myproject.theme

[versions]
# ./bin/buildout -vvvvv|sed -ne 's/^Picked: //p' | sort | uniq
z3c.autoinclude = 0.2.2

five.grok = 1.0a2
grokcore.component = 1.5.1
grokcore.formlib = 1.0
grokcore.security = 1.0
grokcore.view = 1.2.1
grokcore.viewlet = 1.0
martian = 0.11
zope.app.zcmlfiles = 3.5.0
zope.securitypolicy = 3.4.1

[instance]
zcml =
    ...
    z3c.autoinclude-meta
    myproject.theme

In src/myproject.theme/myproject/theme/configure.zcml:

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:browser="http://namespaces.zope.org/browser"
    xmlns:plone="http://namespaces.plone.org/plone"
    xmlns:grok="http://namespaces.zope.org/grok"
    i18n_domain="myproject.theme">

  <includeDependencies package="." />
  <grok:grok package=".adviewlets" />

</configure>

If you don't want to use z3c.autoinclude, remove all occurrences of it in the buildout.cfg and change in configure.zcml <includeDependencies package="." /> by <include package="five.grok" />

Now the interesting part, the adviewlets.py module you just grokked in configure.zcml. I wanted here to create several viewlets in several viewlet managers, including Plone viewlet managers and that all viewlets use the same template. So I created an AdViewlet class that all my viewlets inherit.

Here is the code of adviewlets.py:

from five import grok
from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
from plone.app.layout.viewlets.interfaces import IPortalHeader
from zope.interface import Interface

# Apply on everything.
grok.context(Interface)
# Use templates directory to search for templates.
grok.templatedir('templates')

class AdViewlet(grok.Viewlet):
    grok.baseclass()
    # Set the name of the searched template to adviewlet.
    # By default it's the class name in lowercase.
    # But by adding the directive explicitly, you set
    # the template name for inherited classes as well.
    grok.template('adviewlet')

    def getBanner(self):
        # do a search with self.context and self.request
        # and return an image object

class AdTopViewlet(AdViewlet):
    grok.viewletmanager(IPortalHeader)

class AdHomeViewletManager(grok.ViewletManager):
    grok.name('admanager.home')

class AdHomeViewlet(AdViewlet):
    grok.viewletmanager(AdHomeViewletManager)


class AdRightTopViewletManager(grok.ViewletManager):
    grok.name('admanager.righttop')

# Set the viewletmanager for all viewlets of that file to
# AdRightTopViewletManager. This one will be used unless you specify an
# another viewletmanager directive at the class level.
grok.viewletmanager(AdRightTopViewletManager)

class AdRightTopViewlet1(AdViewlet):
    pass
class AdRightTopViewlet2(AdViewlet):
    pass
class AdRightTopViewlet3(AdViewlet):
    pass

Some explanations here. All viewlets are for any context, because of grok.context(Interface).

You registered a AdTopViewlet for portal-header viewlet manager. For this one, you can't use grok.order(int) on AdTopViewlet to indicate the order of the viewlet within this Plone viewlet manager. You always have to edit the profile/default/viewlets.xml to indicate the order.

For the other viewlets registered with your just created viewlet managers, you can use grok.order(int) on each viewlet. No problem.

The template/adviewlet.pt template looks like this:

<div tal:attributes="id viewlet/__name__">
  <img tal:replace="structure viewlet/getBanner" />
</div>

here the id will be the viewlet class name in lowercase.

To finish, insert the content provider in your templates.

In your home page, insert:

<div tal:content="structure provider:admanager.home"/>

And in a right portlet:

<div tal:content="structure provider:admanager.righttop"/>

It's done.

You may be interested in grok.require, grok.layer directives. For more information, read grokcore.viewlet, grokcore.security, grokcore.view on pypi.

Very important: don't include grokcore.* packages yourself, all the grokcore package are already registered by five.grok. In the given examples, replace grokcore.security, grokcore.view by simply grok to use it in your code.