Edgewall Software

Changes between Version 9 and Version 10 of TracDev/ApiChanges/0.11


Ignore:
Timestamp:
Dec 9, 2006, 5:13:18 PM (17 years ago)
Author:
Christian Boos
Comment:

Moved the ClearSilver to Genshi guide to its own page (TracDev/PortingFromClearSilverToGenshi)

Legend:

Unmodified
Added
Removed
Modified
  • TracDev/ApiChanges/0.11

    v9 v10  
    11[[PageOutline(2-4)]]
    2 = TracDev/ApiChanges/0.11 =
     2= !TracDev/ApiChanges/0.11 =
    33
    44'''Note: Development of Trac [milestone:0.11] has started with r3804 and the trunk now uses ''[http://genshi.edgewall.org/ Genshi]'' instead of ClearSilver, for its template engine.
     
    1111The migration from ClearSilver to Genshi was done on trunk in r3832.
    1212
    13 The following documentation is by no means a replacement for the excellent documentation you'll find in the Genshi site.
    14 You 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 
    16 For migrating your own templates, a good way to start is to learn by example.
    17 Compare the Clearsilver templates found in source:trunk/templates@3831 and their corresponding Genshi ones in source:sandbox/genshi/templates@3831.
    18 
    19 Then, 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 
    23 Most of the time, the porting is a straightforward operation.
    24 ==== expand 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></py:if>)]] or simply [[xml(<b py:if="flag">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 ==== iterate over a collection ====
    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 ==== define a macro ====
    96  - Clearsilver
    97    {{{
    98 #!xml
    99 <?cs def:entry(key, val)?>
    100  <dt><?cs var:key ?></dt><dd><?cs var:val ?></dd>
    101 <?cs /def ?>
    102    }}}
    103  - Genshi
    104    {{{
    105 #!xml
    106 <py:def function="entry(key, val='--')">
    107  <dt>$key</dt><dd>$val</dd>
    108 </py:def>
    109    }}}
    110    As you can see, with Genshi it's also easy to specify default values for the macro arguments.
    111 
    112 ==== set a variable ====
    113  - Clearsilver
    114    {{{
    115 #!xml
    116 <?cs set:count = len(collection) ?>
    117 We have <?cs if:count > 10 ?>too much<?cs else ?><?cs var:count ?><?cs /if ?> elements.
    118    }}}
    119  - Genshi
    120    {{{
    121 #!xml
    122 <py:with vars="count = len(collection)">
    123 We have ${count &gt; 10 and 'too much' or count} elements.
    124 </py:with>
    125    }}}
    126    Note that we had to use `&gt;` in Genshi, instead of directly `>` as in Clearsilver.
    127 
    128 ==== Examples ====
    129 Let's first take a simple full-contained example from the Trac source, the simple index.cs / index.html templates.
    130 
    131  - Clearsilver [source:trunk/templates/index.cs@3725 index.cs]:
    132    {{{
    133 #!xml
    134 <!DOCTYPE html
    135     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    136     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    137 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    138 <head><title>Available Projects</title></head>
    139 <body><h1>Available Projects</h1><ul><?cs
    140  each:project = projects ?><li><?cs
    141   if:project.href ?>
    142    <a href="<?cs var:project.href ?>" title="<?cs var:project.description ?>">
    143     <?cs var:project.name ?></a><?cs
    144   else ?>
    145    <small><?cs var:project.name ?>: <em>Error</em> <br />
    146    (<?cs var:project.description ?>)</small><?cs
    147   /if ?>
    148   </li><?cs
    149  /each ?></ul></body>
    150 </html>
    151    }}}
    152  - Genshi [source:sandbox/genshi/templates/index.html@3728 index.html]:
    153    {{{
    154 #!xml
    155 <!DOCTYPE html
    156     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    157     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    158 <html xmlns="http://www.w3.org/1999/xhtml"
    159   xmlns:py="http://genshi.edgewall.org/"
    160   xmlns:xi="http://www.w3.org/2001/XInclude">
    161 
    162   <head><title>Available Projects</title></head>
    163 
    164   <body>
    165     <h1>Available Projects</h1>
    166     <ul>
    167       <li py:for="project in projects" py:choose="">
    168         <a py:when="project.href" href="$project.href" title="$project.description">
    169           $project.name</a>
    170         <py:otherwise>
    171           <small>$project.name: <em>Error</em> <br />
    172            ($project.description)</small>
    173         </py:otherwise>
    174       </li>
    175     </ul>
    176   </body>
    177 </html>
    178    }}}
    179 
    180 Some remarks:
    181  - Note the possible use of multiple genshi attributes in the same element
    182    (in the above, the `<li>` element has a `py:for` and a `py:choose` attribute).
    183  - When there's only one element to output conditionally, one should use a genshi attribute
    184    (the `py:for="project in projets"` and the `py:when="project.href"` in the above).
    185    Otherwise, one should use a genshi element (here, the `<py:otherwise>`).
    186  - In this small example, there's no common Trac layout used (as the index is a bit special).
    187    For how a "normal" template looks like, see for example
    188    [source:sandbox/genshi/templates/diff_form.html@3831 diff_form.html], another small template.
    189 
    190 Note that a Genshi template can usually be rendered directly to have a taste of how it will look like:
    191 ----
    192 {{{
    193 #!html
    194     <h1>Available Projects</h1>
    195     <ul>
    196       <li py:for="project in projects" py:choose="">
    197         <a py:when="project.href" href="$project.href" title="$project.description">
    198           $project.name</a>
    199         <py:otherwise>
    200           <small>$project.name: <em>Error</em> <br />
    201            ($project.description)</small>
    202         </py:otherwise>
    203       </li>
    204     </ul>
    205 }}}
    206 ----
    207 This comes from an important property of Genshi templates: '''they must themselves be well-formed XML documents'''.
    208 
    209 That 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@3831 query.html] template.
    210 Of 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.
    211 
    212 
    213 Another example from Trac, a bit more complex.
    214 This illustrates how to use `<py:def>` and `<py:with>`, to convert a Clearsilver macro using `<?cs def: ?>` and `<?cs set: ?>`.
    215 
    216  - Clearsilver
    217    {{{
    218 #!xml
    219 def:browser_path_links(path, file) ?><?cs
    220 <?cs set:first = #1 ?><?cs
    221   each:part = path ?><?cs
    222    set:last = name(part) == len(path) - #1 ?><a<?cs
    223    if:first ?> class="first" title="Go to root directory"<?cs
    224     set:first = #0 ?><?cs
    225    else ?> title="View <?cs var:part.name ?>"<?cs
    226    /if ?> href="<?cs var:part.href ?>"><?cs var:part.name ?></a><?cs
    227    if:!last ?><span class="sep">/</span><?cs /if ?><?cs
    228  /each ?><?cs
    229 /def ?><?cs
    230    }}}
    231  - Genshi
    232    {{{
    233 #!xml
    234   <py:def function="browser_path_links(path_links)">
    235     <py:for each="idx, part in enumerate(path_links)">
    236       <py:with vars="first = (idx == 0); last = (idx == len(path_links) - 1)">
    237         <a class="${first and 'first' or None}"
    238           title="${first and 'Go to root directory' or 'View ' + part.name}"
    239           href="$part.href">$part.name</a>
    240         <py:if test="not last"><span class="sep">/</span></py:if>
    241       </py:with>
    242     </py:for>
    243   </py:def>
    244    }}}
    245 
    246 
    247 === Changes in the controllers ===
    248 
    249 ==== Implementing the `IRequestHandler` interface ====
    250 Previously, all the data fed to a template had to be placed inside the `req.hdf` HDF wrapper object.
    251 With Genshi, the data for the template is basically a `dict`, which has to be returned by `process_request`
    252 at the same time as the template name. Check [source:sandbox/genshi/trac/wiki/web_ui.py@3831 trac.wiki.web_ui] for an example.
    253 
    254 ==== Generating content ====
    255 When one wants to directly render a template, the Chrome component facilities should be used.
    256 Check the [source:sandbox/genshi/trac/web/chrome.py@3730#L422 Chrome.load_template]
    257 and `render_method` methods. Note however that this API is still rapidly evolving.
    258 
    259 Usage examples:
    260  - Implementing [source:sandbox/genshi/trac/ticket/query.py@3725#L740 Ticket Query] macro (''table'' mode)
    261  - Sending [source:sandbox/genshi/trac/notification.py@3725#L99 notification] e-mails
     13You can start porting your plugins [TracDev/PortingFromClearSilverToGenshi from Clearsilver to Genshi].
    26214
    26315== Date and Time Manipulations ==