Edgewall Software

Changes between Version 8 and Version 9 of TracDev/Proposals/Jinja


Ignore:
Timestamp:
Feb 5, 2016, 11:24:49 PM (8 years ago)
Author:
Christian Boos
Comment:

themeing part 2: #Jinja2theme

Legend:

Unmodified
Added
Removed
Modified
  • TracDev/Proposals/Jinja

    v8 v9  
    6161
    6262=== Themeing
    63 ==== Genshi thene
     63==== Genshi theme
    6464I'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 the following:
    6565
    66 Let's take the example of a simple "end user" page
    67 (e.g. [source:tags/trac-1.0.9/trac/search/templates/search.html search.html]):
     66Let's take the example of a simple "end user" page, the search.html page.
     67What happens is that:
     68 - search.html includes
     69   - layout.html, which includes
     70     - theme.html (as this is our default theme page)
     71
     72In more details, this is what happens with
     73[source:tags/trac-1.0.9/trac/search/templates/search.html search.html]:
    6874 - it starts by including the layout.html page:
    6975   {{{#!xml
     
    7985       - by default, this will be our
    8086         [source:tags/trac-1.0.9/trac/templates/theme.html theme.html]:
    81          - it simply defines a `<py:match>` filter on the `<body>` tag
     87         - it defines a `<py:match>` filter on the `<body>` tag
    8288           (the one that will be produced by the previously applied filters,
    8389           i.e. the output of the `<py:match>` from the layout.html)
     90           and it will **embed** that element into some predefined HTML
     91           structure (inside a div element), and
     92           it will prepend and append other divs around it:
     93           {{{#!xml
     94           <body>
     95             <div id="banner">
     96               ...
     97             </div>
     98             <div id="main">
     99               ...
     100               (here goes the content of the <body></body> produced by layout.html)
     101             </div>
     102             <div id="footer">
     103               ...
     104             </div>
     105           </body>
     106           }}}
    84107 - the search.html page then provide the `<head>` and `<body>` elements
    85108   specific to that search page; these elements will be processed by the
     
    115138An example of another theme page: [https://github.com/chevah/trac-bootstrap-theme/blob/master/templates/theme.html trac-bootstrap-theme's theme.html].
    116139
     140==== Jinja2 theme
     141
     142Fortunately Jinja2 can do dynamic includes (or extends in this case) as well,
     143so the same idea can be transposed: have the end user page extend the layout page,
     144then have the layout page extend whatever has been defined to be the theme page.
     145
     146The differences with Genshi are subtle: while in both case the control of the
     147output is delegated to the more generic page, with Jinja2 the parent only controls
     148what it puts around //blocks//. It can put some default content in these blocks,
     149but the end user page has the final say about what to do with this default content,
     150as it can reuse it inside its block (by calling `super()`) or not.
     151
     152So let's transpose the example.
     153For as long as we have both template engines coexisting,
     154we prefix the new Jinja2 templates with a `j`,
     155so we're now discussing:
     156 - jsearch.html, which extends
     157   - jlayout.html, which extends
     158     - jtheme.html (as this is our default theme page)
     159
     160In more details, we describe what happens with the
     161[source:cboos.git/trac/search/templates/jsearch.html jsearch.html] page:
     162 - it starts by //extending// the jlayout.html page:
     163   {{{#!jinja
     164   # extends 'jlayout.html'
     165   }}}
     166   - the [source:cboos.git/trac/templates/jlayout.html jlayout.html] page:
     167     - first **dynamically** //extends// in turn some "theme" page
     168       {{{#!jinja
     169       # extends ('j' + chrome.theme)
     170       }}}
     171       - by default, this will be our
     172         [source:cboos.git/trac/templates/jtheme.html jtheme.html] page:
     173         - it defines a `head` block inside of an otherwise empty `<head>` element;
     174           this means this a "slot" that will be filled by the content
     175           of the `head` block in the extending templates (in this case,
     176           jlayout.html)
     177         - it contains a `<body>` element;
     178           as we want to replicate what the original theme.html did,
     179           what we want to achieve here is to provide a ''slot''
     180           at the place where we want to substitute in the content
     181           produced by the jlayout.html template:
     182           {{{#!xml (shoud really be jinja+html...)
     183           <body>
     184             # block body
     185             <div id="banner">
     186               ...
     187             </div>
     188             <div id="main">
     189               ...
     190               # block content
     191               (here goes the content of the content block produced by layout.html)
     192               # endblock content
     193             </div>
     194             <div id="footer">
     195               ...
     196             </div>
     197             # block body
     198           </body>
     199           }}}
     200           I didn't name that inner block "body", as this could be confusing:
     201           we're not in control of the `<body>` element there, just of
     202           a fraction of it, the bottom part of the main div.
     203           //If// we want to be in complete control of the body in the extended
     204           template, we could (as opposed to what happens in Genshi),
     205           we would simply have to redefine the `body` block which contains
     206           all of the default structure (possibly reusing the content of that
     207           block by a call to `${ super() }`)
     208     - then the jlayout.html template defines the `head` and `content` blocks;
     209       it doesn't need to redefine the `body` block, as it's happy with what
     210       jtheme does with it;
     211       that `content` block is filled with some predefined, generic content,
     212       mostly the same stuff that could be found in the corresponding
     213       `<py:match>` filters in layout.html;
     214  - the end user template jsearch.html has to redefine the head and content
     215    blocks, and has to place a `${ super() }` expression in order to
     216    insert the default content proposed by the extended template at
     217    the right place
     218
     219Depending how one looks at it, it seems this approach is even more flexible than
     220what we had in Genshi, as the end user template can decide which bits of the
     221parent template it wants or not ("bottom-up" control), something that was not
     222readily doable with Genshi ("top-down" control).
     223
     224I omitted the discussion of the title block (not even implemented yet) and the
     225replacement for the `<xi:include href="site.html>` template
     226(`# include site_head.html` and `# include site_body.html`).