= Architecture of the HTML templates Here we explain the current template page architecture in Trac which is used since the adoption of the Genshi template engine, i.e. since Trac 0.11. We also describe the future template page architecture which will be used when we switch to the Jinja2 template engine (see Proposals/Jinja). For now this architecture closely follows the Genshi one. == Genshi architecture The Genshi template page architecture in Trac follows two key ideas: - all pages focus on providing the content which is unique to them, and the common parts and look and feel is obtained by //including// a "base" template, //layout.html// - the layout.html includes a dynamic template which takes care of the common look and feel and can be substituted through the configuration; this is how "themes" are handled, and the default dynamic inclusion is the //theme.html// template I've never really tried the TH:ThemeEnginePlugin plugin, or alternatives, so I can't be sure if I got it right, but from what I can see in Trac's code base itself, the idea with Genshi-based themeing (and page architecture in general) was to have a dynamically loaded "theme" template page that would primarily be in charge of the main structure of all HTML pages. === The search.html template Let's take the example of a simple "end user" page, the search.html page. What happens is that: - search.html includes - layout.html, which includes - $chrome.theme (typically "theme.html", the default theme page that ships with Trac) In more details, the [source:tags/trac-1.0.9/trac/search/templates/search.html search.html] is structured like this: {{{#!html+genshi Search ... }}} - it starts by including the layout.html page (``) - it then provides the `` and `` elements specific to that search page; these elements will be processed by the ``es filters defined so far, in the order in which they have been included The [source:tags/trac-1.0.9/trac/templates/layout.html layout.html] page in turn is structured like this: {{{#!html+genshi ${title} – ${project.name or 'Trac'} <!-- e.g. "Search - Trac" --> ... ${select("*[local-name() != 'title']|text()|comment()")} ${select('*|text()|comment()')} ... }}} - it defines `` filters for transforming the content provided in `` and `` elements in the including template (search.html); the head filter adds some content to the `` and prepends some content in the <head>, the body filter appends some content in the <body> - it then **dynamically** includes some "theme" page, `$chrome.theme` By default, this theme page will be our [source:tags/trac-1.0.9/trac/templates/theme.html theme.html] template: {{{#!xml <html> <body> <div id="banner"> ... </div> <div id="main"> ... ${select('*|text()|comment()')} <!-- e.g. "<h1>Search</h1>" ... <div id="altlinks" ... </div> --> </div> <div id="footer"> ... </div> </body> </html> }}} - it defines a `<py:match>` filter on the `<body>` tag (the one that will be produced by the previously applied filters, i.e. the output of the `<py:match>` from the layout.html) and it will **embed** that element into some predefined HTML structure (inside a div element), and it will prepend and append other divs around it: So this dynamic theme template has the last say, and can theoretically re-order the content generated by the previous filters any way it likes, although in practice it simply inserts the body content produced by previous steps inside a predefined structure (the `<div id="main">`). An example of another theme page: [https://github.com/chevah/trac-bootstrap-theme/blob/master/templates/theme.html trac-bootstrap-theme's theme.html]. === The admin.html template as container for other templates 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 <html> <xi:include href="admin.html" /> <head> <title>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

${select("*|text()")}
}}} - 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. === The search.html template Let's transpose the previous example of the search.html template. So we're now discussing: - [source:cboos.git/trac/search/templates/search.html@jinja2-trunk-r15341 search.html], which extends - [source:cboos.git/trac/templates/layout.html@jinja2-trunk-r15341 layout.html], which extends - [source:cboos.git/trac/templates/theme.html@jinja2-trunk-r15341 theme.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 include 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. |-------------------------------------------------------------------------- || __theme.html__ || \ || __layout.html__ \\ //# extends theme.html// || \ || __search.html__ \\ //# extends layout.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/search.html@jinja2-trunk-r15341 search.html] page: {{{#!html+jinja # extends 'layout.html' # block title ${_("Search")} ${ super() } # endblock title # block head ${ super() } ... # endblock head # block content }}} - it starts by //extending// the layout.html page (`# extends 'layout.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", they will be ignored in the final output. As we're in a template extending another, **only what's in the redefined blocks matters**. This is especially important to remember, as this can be a source of error: for example, no matter that you added your `