Edgewall Software

Changes between Initial Version and Version 1 of TracDev/ApiChanges/0.11


Ignore:
Timestamp:
Sep 13, 2006, 12:24:59 PM (18 years ago)
Author:
Christian Boos
Comment:

Migrating page templates from ClearSilver to Genshi

Legend:

Unmodified
Added
Removed
Modified
  • TracDev/ApiChanges/0.11

    v1 v1  
     1[[PageOutline(2-4)]]
     2= TracDev/ApiChanges/0.11 =
     3
     4'''Note: Development of Trac [milestone:0.11] has not yet "officially" started.
     5However, a good deal of work has already begun on the branches, and the information in this page will mostly be about what is quasi-certain to go in 0.11 at the time of writing. Nevertheless, you should have in mind that the information in this page corresponds to a ''work in progress''.'''
     6
     7== Migrating away from Clearsilver ==
     8
     9ClearSilver has proven a bit uncomfortable to work with, and search for better alternatives were done a few months ago. The [http://kid-templating.org/ Kid] templating language was unanimously found appealing, to the point cmlenz did a porting of Trac to Kid, during the DrProject fork. This in turn was found painful, and prompted Christopher to start his own, enhanced, version of Kid currently maturing as [http://genshi.edgewall.org/ Genshi].
     10
     11Migrating away from ClearSilver to use Genshi is scheduled for early [milestone:0.11], and is mostly complete in the source:sandbox/genshi branch at this point (r3728).
     12
     13The following documentation is by no means a replacement for the excellent documentation you'll find in the Genshi site.
     14You should go there for a more in-depth understanding of how Genshi actually works and should be used. Here we'll focus on the differences with Clearsilver.
     15
     16For migrating your own templates, a good way to start is to learn by example.
     17Compare the Clearsilver templates found in source:trunk/templates and their corresponding Genshi ones in source:sandbox/genshi/templates.
     18
     19Then, in the same way, compare the various web_ui.py controllers you'll find in both branches.
     20
     21=== Changes in the template syntax ===
     22
     23Most of the time, the porting is a straightforward operation.
     24==== expanding a variable ====
     25 - Clearsilver [[xml(<b><?cs var:the_variable ?></b>)]]
     26 - Genshi [[xml(<b>$the_variable</b>)]]
     27==== expand a simple computation ====
     28 - Clearsilver [[xml(<b><?cs var:the_variable+1 ?></b>)]]
     29 - Genshi [[xml(<b>${the_variable+1}</b>)]]
     30==== include another template ====
     31 - Clearsilver [[xml(<?cs include:the_file.cs ?>)]]
     32 - Genshi [[xml(<xi:include href="the_file.html"><xi:fallback/></xi:include>)]]
     33==== simple if...then (no else) ====
     34 - Clearsilver [[xml(<?cs if:flag ?><b>OK</b><?cs /if ?>)]]
     35 - Genshi [[xml(<py:if test="flag"><b>OK</b>)]] or simply [[xml(<b py:if="flag"><b>OK</b>)]]
     36==== if...then...else ====
     37 - Clearsilver
     38   {{{
     39#!xml
     40<?cs if:flag ?>
     41 <b>OK</b>
     42<?cs else ?>
     43 <i>!!!</i>
     44<?cs /if ?>
     45   }}}
     46 - Genshi
     47   {{{
     48#!xml
     49<py:choose test="flag">
     50  <py:when test="True>
     51    <b>OK</b>
     52  </py:when>
     53  <py:otherwise>
     54   <i>!!!</i>
     55  </py:otherwise>
     56</py:choose>
     57   }}}
     58   or simply:
     59   {{{
     60#!xml
     61<py:choose>
     62 <b py:when="flag">OK</b>
     63 <i py:otherwise="">!!!</i>
     64</py:choose>
     65   }}}
     66   The <py:choose>/<py:when>/<py:otherwise> is a bit heavy-weight for a simple if/else, but on the other hand, the construct is more general (think switch/case, or the equivalent choose/when/otherwise in XSLT).
     67
     68==== iterating ====
     69 - Clearsilver
     70   {{{
     71#!xml
     72<ul><?cs
     73 each:element = list ?>
     74  <li><?cs var:element ?></li><?cs
     75 /each ?>
     76</ul>
     77   }}}
     78 - Genshi
     79   {{{
     80#!xml
     81<ul>
     82  <py:for each="element in list">
     83    <li>$element</li>
     84  </py:for>
     85</ul>
     86   }}}
     87   or simply:
     88   {{{
     89#!xml
     90<ul>
     91  <li py:for="element in list">$element</li>
     92</ul>
     93   }}}
     94
     95
     96Let's take a full-contained example from the Trac source, the simple index.cs / index.html templates.
     97
     98[source:trunk/templates/index.cs@3725 index.cs]:
     99{{{
     100#!xml
     101<!DOCTYPE html
     102    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     103    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
     104<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
     105<head><title>Available Projects</title></head>
     106<body><h1>Available Projects</h1><ul><?cs
     107 each:project = projects ?><li><?cs
     108  if:project.href ?>
     109   <a href="<?cs var:project.href ?>" title="<?cs var:project.description ?>">
     110    <?cs var:project.name ?></a><?cs
     111  else ?>
     112   <small><?cs var:project.name ?>: <em>Error</em> <br />
     113   (<?cs var:project.description ?>)</small><?cs
     114  /if ?>
     115  </li><?cs
     116 /each ?></ul></body>
     117</html>
     118}}}
     119
     120[source:sandbox/genshi/templates/index.html@3728 index.html]:
     121{{{
     122#!xml
     123<!DOCTYPE html
     124    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     125    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
     126<html xmlns="http://www.w3.org/1999/xhtml"
     127  xmlns:py="http://genshi.edgewall.org/"
     128  xmlns:xi="http://www.w3.org/2001/XInclude">
     129
     130  <head><title>Available Projects</title></head>
     131
     132  <body>
     133    <h1>Available Projects</h1>
     134    <ul>
     135      <li py:for="project in projects" py:choose="">
     136        <a py:when="project.href" href="$project.href" title="$project.description">
     137          $project.name</a>
     138        <py:otherwise>
     139          <small>$project.name: <em>Error</em> <br />
     140           ($project.description)</small>
     141        </py:otherwise>
     142      </li>
     143    </ul>
     144  </body>
     145</html>
     146}}}
     147
     148Some remarks:
     149 - Note the possible use of multiple genshi attributes in the same element
     150   (in the above, the <li> element has a py:for and a py:choose attributes).
     151 - When there's only one element to output conditionally, one should use a genshi attribute
     152   (the py:for=project in projets" and the py:when="project.href" in the above).
     153   Otherwise, one should use a genshi element (here, the <py:otherwise>).
     154 - In this small example, there's no common Trac layout used (as the index is a bit special).
     155   For how a "normal" template looks like, see for example
     156   [source:sandbox/genshi/templates/diff_form.html diff_form.html], another small example.
     157
     158Note that a Genshi template can usually be rendered directly to have a taste of how it will look like:
     159----
     160{{{
     161#!html
     162    <h1>Available Projects</h1>
     163    <ul>
     164      <li py:for="project in projects" py:choose="">
     165        <a py:when="project.href" href="$project.href" title="$project.description">
     166          $project.name</a>
     167        <py:otherwise>
     168          <small>$project.name: <em>Error</em> <br />
     169           ($project.description)</small>
     170        </py:otherwise>
     171      </li>
     172    </ul>
     173}}}
     174----
     175This comes from an important property of Genshi templates: '''they must themselves be well-formed XML documents'''.
     176
     177That was not a constraint in Clearsilver, and sometimes the logic in those templates took "advantage" of that, e.g. by conditionally inserting end/start pairs of tags. Such templates are the hardest to port, because you actually have to think a bit... See for example the [source:sandbox/genshi/templates/query.html query.html] template.
     178Of course, the great benefit of this constraint is that you'll end up quite naturally with well-formed content, which was far from being a trivial achievement using Clearsilver templates. Granted, you could still insert directly some non well-formed `Markup` data in your template, but again, if you use the [http://genshi.edgewall.org/wiki/Documentation/builder.html genshi.builder] ''tag'' facility for this, that's hardly a risk.
     179
     180=== Changes in the controllers ===
     181
     182==== Implementing the `IRequestHandler` interface ====
     183Previously, all the data fed to a template had to be placed inside the `req.hdf` HDF wrapper object.
     184With Genshi, the data for the template is basically a `dict`, which has to be returned by `process_request`
     185at the same time as the template name. Check [source:sandbox/genshi/trac/wiki/web_ui.py trac.wiki.web_ui] for an example.
     186
     187==== Generating content ====
     188When one wants to directly render a template, the Chrome component facilities should be used.
     189Check the [source:sandbox/genshi/trac/web/chrome.py@3725#L424 Chrome.load_template]
     190and `render_method` methods. Note however that this API is still rapidly evolving.
     191
     192Usage examples:
     193 - Implementing [source:sandbox/genshi/trac/ticket/query.py@3725#L740 Ticket Query] macro (''table'' mode)
     194 - Sending [source:sandbox/genshi/trac/notification.py@3725#L99 notification] e-mails