To support this, my plugin needs the ability to inject arbitrary
snippets into the user interface. I have actually done a little
prototype already, but I thought I'd try and start a discussion on
what would be a desirable way to do this.
Everyone can see the pretty picture of my prototype at work here:
http://www.visophyte.org/blog/2007/10/05/a-posterity-based-email-visualization-says-what/
And my bzr branch with my changes is here:
http://www.visophyte.org/rev_control/bzr/posterity/visbrero-posterity/
In brief, what I've implemented is an IChromeDecorator interface
managed by a ChromeDecoratorManager (which hosts the extension point).
The controller views then inject the manager into their template
'data' and the templates invoke the manager object at each decoration
point with information about the decoration point and any relevant
data. The ChromeDecoratorManager then invokes the decorator with the
info and returns it. (I had to make posterity honor the posterity
data directory's 'plugins' dir too.)
For additional reference, here's the interface I'm using, which may be
more generic than desired; the other style I could imagine is one
interface per view being decorated...
class IChromeDecorator(Interface):
"""Add additional chrome to the conversation or conversation index views.
This may be too generic an interface.
"""
def get_decoration_points(self):
"""Return a list/tuple of tuples of the form (view, placement) where
view is the chrome view being decorated (ex: 'conversation-index',
'conversation') and placement is view-specific. Multiple placements
may be specified for a single view.
Current valid views:
- conversation-index: A list of conversations.
- conversation: A list of messages.
- message: A single message in a conversation.
"""
def decorate(self, view, placement, **data):
"""Called for a specific view and placement (as listed by
get_decoration_points) with view-specific data.
"""
Andrew
Actually, as Posterity uses Genshi, you can use Genshi's stream
matching and filtering functionality to do this.
Trac 0.11dev has a comparable extension point, ITemplateStreamFilter:
<http://trac.edgewall.org/browser/trunk/trac/web/api.py?
rev=5945#L582>
The current Genshi trunk has a module that's pretty cool for actually
implementing the filtering:
<http://genshi.edgewall.org/wiki/Documentation/
filters.html#transformer>
A different approach would be to allow plugins to dynamically add
template inclusions, and those included template would define
py:match directives.
Cheers,
Chris
--
Christopher Lenz
cmlenz at gmx.de
http://www.cmlenz.net/
> Actually, as Posterity uses Genshi, you can use Genshi's stream
> matching and filtering functionality to do this.
> The current Genshi trunk has a module that's pretty cool for actually
> implementing the filtering:
> A different approach would be to allow plugins to dynamically add
> template inclusions, and those included template would define
> py:match directives.
Excellent suggestions, thank you. I think py:match is the way to go
unless you're game for some changes to genshi or I overlooked
something in my investigation...
Can you think of an easy way to ensure that a Transformer's
InjectorTransformation can easily feed the injected content through
Template.exec/eval/flatten _using the context of the source document_?
I want the ability to inject content on a per-message basis in a
conversation and I want to be able to get at the iteration variables
and locals of the py:for directive that is used to iterate over the
messages.
The cleanest approach I can think of right now is to change things to
allow InjectorTransformation to pass the injected content through the
generate()-ing template's fundamental filters using the generating
context.
That could be accomplished by:
1a) Make core.Stream aware of the context, have Template.generate()
pass it, and have Stream.filter/__or__ pass it as well.
(Alternatively, in these special cases, Transformers could just be
added to a Template's 'filters' list.)
1b) Fix all existing filters to not explode when passed a context.
2) Make Transformer and InjectorTransform meaningfully aware of the context.
3) Make the context include directly or indirectly the list of the
Template's "filters". So InjectorTransformation could chain through
all those filters for injected content.
Presumably, the py:match/_match mechanism could also be altered to use
Transforms under the hood (and gain some new features).
Andrew