TurboGears
----------
-Integrating Jinja into TurboGears works pretty much the same.
-
-Basically all you have to do is to edit the application configuration file at
-``application/config/app.cfg`` and change `global.tg.defaultview` and
-provide the jinja options:
-
-.. sourcecode:: ini
-
- [global]
- tg.defaultview = 'jinja'
- jinja.init_callback = yourapplication.yourmodule.setup_function
-
-Now you have to edit the file `yourapplication.yourmodule` and add a
-`setup_function` callback that creates an environment:
-
-.. sourcecode:: python
-
- from jinja import Environment, FileSystemLoader
-
- def setup_function(options):
- return Environment(loader=FileSystemLoader('path/to/templates'))
-
-This solution isn't the best but currently the only thing you can do. There is
-a discussion about improving the plugin interface so that this can be solved
-in a more elegant way.
-
-Also here exists the same limitation regarding dotted notation, see the
-snipped and information in the pylons section.
+The TurboGears template plugin interface is broken by design and
+there is currently no way to embed Jinja templates in TurboGears.
.. _TurboGears: http://www.turbogears.org/
tag is encountered the next item from the list is rendered.
If you pass it just one argument it's meant to be a sequence.
+
Active Menu Item
================
{% extends "layout.html" %}
{% set active_page = "index" %}
+
+
+Sitemap
+=======
+
+To create a sitemap you can either use the ``for`` tag or a ``macro``
+that calls itself. The datastructures should look like this:
+
+.. sourcecode:: python
+
+ {'sitemap': [
+ dict(
+ caption='Pages',
+ children=[
+ dict(href='index.html', caption='Index'),
+ dict(href='downloads.html', caption='Downloads'),
+ dict(
+ caption='Users',
+ children=[
+ dict(href='peter.html',
+ caption='Peter'),
+ dict(href='max.html',
+ caption='Max'),
+ dict(href='suzan.html',
+ caption='Suzan')
+ ]
+ ),
+ dict(
+ caption='Files',
+ children=[
+ dict(
+ caption='Images',
+ children=[
+ dict(href='vienna.html',
+ caption='Vienna'),
+ dict(href='roma.html',
+ caption='Roma'),
+ dict(href='tokyo.html',
+ caption='Tokyo')
+ ]
+ ),
+ dict(
+ caption='Videos',
+ children=[
+ dict(href='party.html',
+ caption='Party')
+ ]
+ )
+ ]
+ )
+ ]
+ ),
+ dict(caption='Foo', href='foo.html')
+ dict(caption='About', href='about.html')
+ ]}
+
+Now you can create a sitemap using ``for``:
+
+.. sourcecode:: html+jinja
+
+ <ul class="sitemap">
+ {% for item in sitemap recursive %}
+ <li><a href="{{ item.href|e }}">{{ item.caption|e }}</a>
+ {% if item.children %}<ul>{{ loop(item.children) }}</ul>{% endif %}</li>
+ {% endfor %}
+ </ul>
+
+Or by using a ``macro`` that calls itself:
+
+.. sourcecode:: html+jinja
+
+ {% macro render_sitemap items %}
+ {% for item in items %}
+ <li><a href="{{ item.href|e }}">{{ item.caption|e }}</a>
+ {% if item.children %}<ul>{{ render_sitemap(item.children) }}</ul>{% endif %}</li>
+ {% endfor %}
+ {% endmacro %}
+ <ul class="sitemap">{{ render_sitemap(sitemap) }}</ul>
+
+
+Using A Block Multiple Times
+============================
+
+Blocks have the small disadvantage that they work both ways which is a problem
+if you want to render a block two times on a page. Here a nice little
+workaround for this limitation:
+
+.. sourcecode:: html+jinja
+
+ <html>
+ <head>
+ <title>{% filter capture('title') %}{%
+ block title %}{% endblock %}{%
+ endfilter %}</title>
+ </head>
+ <body>
+ <div class="head">{{ title }}</div>
+ </body>
+ </html>
+
+Or if you use the `capture` filter in `clean` mode:
+
+.. sourcecode:: html+jinja
+
+ {% filter capture('title', True)|trim %}
+ {% block title %}{% endblock %}
+ {% endfilter %}
+ <html>
+ <head>
+ <title>{{ title }}</title>
+ </head>
+ <body>
+ <div class="head">{{ title }}</div>
+ </body>
+ </html>
return wrapped
-def do_capture(name='captured'):
+def do_trim(value):
+ """
+ Strip leading and trailing whitespace.
+ """
+ return value.strip()
+do_trim = stringfilter(do_trim)
+
+
+def do_capture(name='captured', clean=False):
"""
Store the value in a variable called ``captured`` or a variable
with the name provided. Useful for filter blocks:
.. sourcecode:: jinja
{% filter capture('foo') %}
- ....
+ ...
+ {% endfilter %}
+ {{ foo }}
+
+ This will output "..." two times. One time from the filter block
+ and one time from the variable. If you don't want the filter to
+ output something you can use it in `clean` mode:
+
+ .. sourcecode:: jinja
+
+ {% filter capture('foo', True) %}
+ ...
{% endfilter %}
{{ foo }}
"""
+ if not isinstance(name, unicode):
+ raise FilterArgumentError('You can only capture into variables')
def wrapped(env, context, value):
context[name] = value
+ if clean:
+ return Undefined
return value
return wrapped
'string': do_string,
'urlize': do_urlize,
'format': do_format,
- 'capture': do_capture
+ 'capture': do_capture,
+ 'trim': do_trim
}
jinja.plugin
~~~~~~~~~~~~
- Provide a bridge to buffet. Buffet is used by some frameworks (namely
- CherryPy, TurboGears and Pylons) to load templates.
+ This module proides a bridge to buffed so that you can use Jinja
+ in pylons. Note that this doesn't work with turbogears because their
+ buffet implementation is broken.
:copyright: 2007 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
extras_require = {'plugin': ['setuptools>=0.6a2']},
entry_points='''
[python.templating.engines]
- jinja = jinja.bakerplugin:JinjaPlugin[plugin]
+ jinja = jinja.plugin:JinjaPlugin[plugin]
'''
)
REVERSE = '''{{ "foobar"|reverse }}|{{ [1, 2, 3]|reverse }}'''
STRING = '''{{ range(10)|string }}'''
TITLE = '''{{ "foo bar"|title }}'''
+TRIM = '''{{ " foo "|trim }}'''
TRUNCATE = '''{{ data|truncate(15, true, ">>>") }}|\
{{ data|truncate(15, false, ">>>") }}|\
{{ smalldata|truncate(15) }}'''
assert tmpl.render() == "Foo Bar"
+def test_truncate(env):
+ tmpl = env.from_string(TRUNCATE)
+ assert tmpl.render() == 'foo'
+
+
def test_truncate(env):
tmpl = env.from_string(TRUNCATE)
out = tmpl.render(data='foobar baz bar' * 1000,