`).
An example of another theme page: [https://github.com/chevah/trac-bootstrap-theme/blob/master/templates/theme.html trac-bootstrap-theme's theme.html].
Note that this scheme can be extended to additional intermediate levels,
for example see what we do with the admin panels.
One such panel is
[source:tags/trac-1.0.9/trac/admin/templates/admin_basics.html admin_basics.html]:
{{{#!html+genshi
Basics
...
}}}
- it starts by including the admin.html page
- then it provides the `` and `` elements specific to that panel
The [source:tags/trac-1.0.9/trac/admin/templates/admin.html admin.html] page
is similar to the search.html page in that it includes the layout.html, but
it also first contains its own `
` templates to organize the content of
the admin panel which included it:
{{{#!html+genshi
Administration: ${select('title/text()')}
${select("*[local-name() != 'title']")}
Administration
}}}
- defines `
` filters for `` and `` (of the including panel page),
which in turn will produce modified `` and `` elements
- it then includes the layout.html page (see above)
Feel free to brush up your Genshi craft by reading ([G:GenshiTutorial#AddingaLayoutTemplate]),
as I just did ;-)
== Jinja2 architecture
Jinja2 can do dynamic includes as well, or more precisely, dynamic ''extends''.
Therefore the Genshi approach can be transposed to Jinja: have the end user page extend the layout page,
then have the layout page extend whatever has been defined to be the theme page.
The differences with Genshi are subtle: while in both case the control of the
output is delegated to the more generic page, with Jinja2 the parent only controls
what it puts around //blocks//. It can put some default content in these blocks,
but the end user page has the final say about what to do with this default content,
as it can reuse it inside its block (by calling `super()`) or not.
Let's transpose the previous example of the search.html template.
For as long as we'll have both template engines coexisting,
we'll prefix the new Jinja2 templates with a `j`.
So we're now discussing:
- jsearch.html, which extends
- jlayout.html, which extends
- jtheme.html (as this is our default theme page)
A template which extends another can redefine the content of the //named blocks// defined in the extended template. This redefinition may or may not refer to the original content of the block in the extended template (`${ super() }`).
We first give an overview of the three templates and how their content will be combined in the generated output.
|--------------------------------------------------------------------------
|| __jtheme.html__ || \
|| __jlayout.html__ \\ //# extends jtheme.html// || \
|| __jsearch.html__ \\ //# extends jlayout.html// ||
|--------------------------------------------------------------------------
{{{#!td style="vertical-align:top"
{{{#!html
<html>
<head>
# block head
# endblock head
</head>
<body>
# block body
… banner + metanav + mainnav + contextnav + warnings + notices …
# block content
# endblock content
… footer …
# endblock body
</body>
</html>
}}}
\\
(//head// and //content// blocks \\
have no default content)
}}}
{{{#!td style="vertical-align:top"
{{{#!html
<html>
<head>
# block head
<title>
# block title
- Trac
# endblock title
</title>
… meta + link + script …
# endblock head
</head>
<body>
# block content
… alternate formats …
# endblock content
</body>
</html>
}}}
\\
(//head// and //content// blocks \\
have default content)
}}}
{{{#!td style="vertical-align:top"
{{{#!html
<html>
<head>
<title>
# block title
Search
${ super() }
# endblock title
</title>
# block head
${ super() }
… meta …
# endblock head
</head>
<body>
# block content
<div class="content">
… Search Results …
</div>
${ super() }
# endblock content
</body>
</html>
}}}
}}}
|--------------------------------------------------------------------------
{{{#!td colspan=3 style="vertical-align:top"
generated output:
{{{#!html
<html>
<head>
<title>
Search
- Trac
</title>
… meta + link + script …
… meta …
</head>
<body>
… banner + metanav + mainnav + contextnav + warnings + notices …
<div class="content">
… Search Results …
</div>
… alternate formats …
… footer …
</body>
</html>
}}}
}}}
Let's have a closer look at the content of each template, starting with the
most specific template, in our example the
[source:cboos.git/trac/search/templates/jsearch.html jsearch.html] page:
{{{#!html+jinja
# extends 'jlayout.html'
# block title
${_("Search")} ${ super() }
# endblock title
# block head
${ super() }
...
# endblock head
# block content
${_("Search")}
...
}}}
- it starts by //extending// the jlayout.html page (`# extends 'jlayout.html')
- then it redefines the ''title'', ''head'' and ''content'' blocks,
and has to place a `${ super() }` expression in order to insert the default
content proposed by the extended template at the right place;
note that the presence of the ``, `` and `` tags here
is strictly "decorative", it will be ignored in the final output. As we're
in a template extending another, only what's in the redefined blocks matters.
These blocks are first defined in the extended template, jlayout.html.
The [source:cboos.git/trac/templates/jlayout.html jlayout.html] page looks like this:
{{{#!html+jinja
# extends ('j' + chrome.theme)
# block head
# block title
– ${project.name or 'Trac'}
# endblock title
...
# endblock head
# block content
# endblock content
...
...
}}}
- first **dynamically** //extends// in turn some "theme" page (`# extends ('j' + chrome.theme)`)
- then the jlayout.html template defines a few blocks:
- the ''head'' block and its ''title'' sub-block; here we understand why we've put
the ''title'' block **outside** of the ''head'' block in the jsearch.html template:
the jlayout.html's ''head'' block contains among other things a `` element,
and we're reusing that default content in the inheriting ''head'' block; if in
jsearch.html we had defined the element in the ''head'' block as well,
we would have had two of these elements in that block
- the ''content'' block which is filled with some predefined, generic content,
mostly the same stuff that could be found in the corresponding layout.html,
in `` filters
By default, this theme template will be our
[source:cboos.git/trac/templates/jtheme.html jtheme.html] page:
{{{#!html+jinja
# block head
# endblock head
# block body
...
...
# block content
(here goes the content of the content block produced by layout.html)
# endblock content
# block body
}}}
- it defines a ''head'' block inside an otherwise empty `` element;
this means this is simply a "slot" that will be filled by the content
of the `head` block in the extending templates (in this case, jlayout.html)
- it contains a `` element;
as we want to replicate what the original theme.html did,
what we want to achieve here is to provide a ''slot''
at the place where we want to insert the content
produced by the jlayout.html template;
I didn't name that inner block "body", as this could be confusing:
we're not in control of the `` element there, just of
a fraction of it, the bottom part of the main div.
Note that //if// we wanted to be in full control of the body in the extending
template, we could (as opposed to what you can do in Genshi): we would simply
have to redefine the ''body'' block which contains all of the default structure
(possibly reusing the content of that block by a call to `${ super() }`).
In our case, neither jsearch.html nor jlayout.html redefine the `body` block,
as they're happy with what jtheme does with it.
Depending how one looks at it, it seems this approach is even more flexible than
what we had in Genshi, as the end user template can decide which bits of the
parent template it wants or not ("bottom-up" control), something that was not
readily doable with Genshi ("top-down" control).
Like what we did with Genshi, this scheme can be extended to support additional intermediate levels. We did that for the admin and the preference panels.
Let's take for example the Logging admin panel, [source:cboos.git/trac/admin/templates/jadmin_logging.html jadmin_logging.html]:
{{{#!html+jinja
# extends "jadmin.html"
# block admintitle
Logging
# endblock admintitle
# block adminpanel
...
# block adminpanel
}}}
- it starts by extending the jadmin.html page
- then it provides the `` and `` elements specific to that panel,
more precisely the //admintitle// and //adminpanel// blocks (if some JavaScript
or other resources are needed, the //head// could be redefined as well)
The [source:cboos.git/trac/admin/templates/jadmin.html@jinja2 jadmin.html] page
is similar to the jsearch.html page in that it extends the jlayout.html:
{{{#!html+jinja
# extends "jlayout.html"
# block title
Administration:
# block admintitle
# endblock admintitle
${ super() }
# endblock
# block content
Administration
# block adminpanel
# endblock adminpanel
# endblock content
}}}
//See [1df4e05c/cboos.git] for the full conversion of admin.html -> jadmin.html and admin_logging.html -> jadmin_logging.html.//
I omitted the discussion of the
replacement for the `