As I've said before, one of the great things TurboGears has given us is "widgets", which bundle together the visual/behavioural/content aspects of a component in terms of Javascript, form fields, or other HTML, as well as the validation and conversion of whatever is entered into the browser into something useful to you as a programmer. Toscawidgets is the chosen heir of the "widgets" component in TurboGears, hopefully delivering the concept to the other Python frameworks.
This is devastatingly effective for form fields, and great for displaying interesting widgets on your screen, but you can also just use it to add simple things like a single CSS or Javascript file unrelated to specific widgets.
In TurboGears 1.0, there is a slot for CSS from widgets, and there are three slots for Javascript widgets - named "head", "bodytop", and "bodybottom". But, unfortunately, nothing as simple as, say, the link to my RSS for RSS auto-discovery in gibe, my web log engine (ToscaWidgets has genericised everything into resources that can be in those same locations). But we can just cheat by pretending to be CSS until I switch over to ToscaWidgets:
class FeedLink(widgets.Source):
template = """
<link rel="alternate" href="$src" title="$title" type="$type" />
"""
params = ['title', 'type']
params_doc = {
'src': 'The feed URL',
'title': 'Title for the feed',
'type': 'MIME type for the feed'
}
retrieve_css = widgets.set_with_self
class FeedLinks(widgets.Widget):
def retrieve_css(self):
return [
FeedLink(src=routes.url_for('rss2.0.xml'), title="RSS 2.0",
type="application/rss+xml"),
FeedLink(src=routes.url_for('atom1_0'), title="Atom 1.0",
type="application/atom+xml"),
]
feedlinks = FeedLinks()
The first (FeedLink) is a widget that describes a single auto-discovery (or other "alternate") link, based on URL, title, and type provided. As you can see, retrieve_css is being used - set_with_self does some magic and eventually the template given in the template attribute is rendered.
The second (FeedLinks) is a simple widget that builds up multiple FeedLink objects and returns them in a list.
While not strictly required, I create a FeedLinks object named feedlinks.
Behind the scenes, I add gibe.feeds.feedlinks to the tg.include_widgets list in my config/app.cfg, which ensures that this widget is available on every page.
The end result is kinda boring, actually:
<link href="/blog/rss2.0.xml" type="application/rss+xml"
rel="alternate" title="RSS 2.0">
<link href="/blog/atom1.0" type="application/atom+xml"
rel="alternate" title="Atom 1.0">
I did something similar to add Javascript-based syntax highlighting. TurboGears already comes with a dp.SyntaxHighlighter widget in turbogears.widgets.links, named (aptly) SyntaxHighlighter. Unfortunately, I don't like that dp.SyntaxHighlighter uses textareas as the base for source code. I'd rather use a <pre> and a class. So I had to change it. But if you're happy with the way it does things, it's really as simple as adding turbogears.widgets.SyntaxHighlighter to your tg.include_widgets in config/app.cfg, and any appropriately named and classed textarea will be automatically syntax highlighted.
Adding Google Analytics at the bottom of the page was just as simple. I created the following module:
class Analytics(widgets.Widget):
template = """
<div py:strip="True" xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "$analytics_key";
urchinTracker();
</script>
</div>
"""
params = ['analytics_key']
params_doc = {'analytics_key': 'Google Analytics Key'}
location = widgets.js_location.bodybottom
def retrieve_javascript(self):
if not self.analytics_key:
return []
else:
return widgets.set_with_self(self)
def add_for_location(self, location):
return location == self.location
analytics_key = cherrypy.config.get("analytics.key", None)
analytics_js = Analytics(analytics_key = analytics_key)
Add to tg.include_widgets in config/app.cfg, eventually coming out to:
tg.include_widgets = ['gibe.syntaxhighlighting.syntaxhighlighter','gibe.feeds.feedlinks','gibe.analytics.analytics_js']
The beautiful part of all of this is that I didn't need to change any existing code or any of my templates to add RSS auto-discovery, syntax highlighting, and Google Analytics. When I have a proper "plugin architecture" in gibe, managing tg.include_widgets manually won't be necessary either - just add the plugin and you have the functionality.
0 Responses
Have your say