[Grok-dev] Re: Skinning/themeing

Martin Aspeli optilude at gmx.net
Sat May 19 17:45:05 EDT 2007


Martijn Faassen wrote:
> kevin at mcweekly.com wrote:
> [snip]
>> Yes, that's what it's for, to relate viewlet name -> viewletmanager name.
>> This does bring up a good point, where is the line drawn for
>> convention-over-configuration. I think that Martijn and Phillip have
>> done a great job of deliberating this and I certainly defer to them in
>> these aesthetic matters.
> 
> I'm still grasping to find my way around viewlets. I think we need to do 
> some more thinking before we fold this into the Grok core (which I hope 
> we can over time). Hopefully we can find out a way to make this less 
> magic without increasing the verbosity. On my end, this will require 
> some thought about what viewlets are for. If we could (somehow) get rid 
> of one of the entities (viewlet reference in view, viewlet manager and 
> viewlets) that would help. If we can fix the ordering issue by taking 
> definition order by default that would also help.

I don't find viewlets so bad, but maybe that's just because I've been 
using them for a while. I'll try to explain them the way I see them, if 
that helps. I'm sure you understand them too, but maybe the perspective 
is useful.

  - A "content provider" is just a named component (multi-adapter) which 
can be rendered as part of a view - I think a "snippet" would've been a 
better name. You use them like this:

   <div tal:content="structure:content-provider-name" />

  - A "content provider" is registered (as a named multi-adapter) for 
(context, request, view). This allows you to have a different 
implementation for different types of context, request (skin) and the 
view it's being made part of

  - A "viewlet manager" is a special case of a "content provider"

  - A "viewlet manager" has a particular interface (though the 
<browser:viewletManager /> ZCML directive will generate one for you if 
you didn't specify one)

  - Any number of "viewlets" can be registered for a "viewlet manager" 
(via the aforementioned interface).

  - When the "viewlet manager" "content provider" is rendered, it will 
look up all "viewlets" assigned to it, order them, and render them. 
Different types of "viewlet managers" may render e.g. a border around 
its "viewlets" or perform some kind of filtering.

The end result is that you can define "holes" (to avoid using the word 
"slot") in a page where your code or other people's code can plug in new 
viewlets. In Plone 3, for example, we have lots of viewlets:

http://dev.plone.org/plone/browser/plone.app.layout/trunk/plone/app/layout/viewlets/configure.zcml#L33

These are referenced in various places, such as main_template:

http://dev.plone.org/plone/browser/CMFPlone/trunk/skins/plone_templates/main_template.pt#L122

Now, Plone and third party products can register viewlets for e.g. the 
"above content" viewlet manager on the lines shown above. This means 
that I can, for example:

  o Show banner ads on all pages, regardles of context type, skin or view

  o Add a "rate this content item" box on any IRatable

  o Show a "give feedback" form on all views marked with IUserFeedback

  o Override a viewlet for a particular skin (i.e. marker on the request)

In a Grok sense, I think the registration can be simplified a bit. I 
haven't looked too closely at megrok.quarry, but I think this uses these 
patterns or something similar:

class AboveContent(grok.ViewletManager):
     """A viewlet manager for things above the content
     """

     grok.name('abovecontent')

     # maybe override update(), render() or filter() here
     # if we need special semantics

And in a template:

     <div tal:replace="structure provider:abovecontent />

To register some new viewlets:

class BannerAds(grok.Viewlet):
     """A viewlet showing ads, on any context
     """
     grok.viewlet_manager(AboveContent)

     def render(self):
         ...

class Ratings(grok.Viewlet):
     """Show ratings on any IRatable
     """
     grok.viewlet_manager(AboveContent)
     grok.context(IRatable)

     def render(self):
         ...

class FeedbackForm(grok.Viewlet):
     """Show the feedback form on any IUserFeedback-marked view
     """
     grok.viewlet_manager(AboveContent)
     grok.view(FeedbackForm

     def render(self):
         ...


Those are a few examples. Note that the viewlets could come from an 
entirely different package to the viewlet manager.

Even if you don't need this kind of pluggability, viewlets can make your 
life easier because you can manage "tangental" or "infrastructural" UI 
elements separately, across views. Things like portlet columns (which in 
Plone 3 are content providers, not viewlets, because they use 
plone.portlets to allow changes in what's being shown where at runtime), 
footers and so forth can make sense as viewlets. If you find that you 
need another one, or need some more complex rendering for common UI 
elements (say, to have different behaviour depending on a user's role) 
then those elements can be managed (and evolve) separately from the views.

Martin



More information about the Grok-dev mailing list