| 1 | [[PageOutline(2-4)]] |
| 2 | = TracDev/ApiChanges/0.11 = |
| 3 | |
| 4 | '''Note: Development of Trac [milestone:0.11] has not yet "officially" started. |
| 5 | However, 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 | |
| 9 | ClearSilver 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 | |
| 11 | Migrating 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 | |
| 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 and their corresponding Genshi ones in source:sandbox/genshi/templates. |
| 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 | ==== 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 | |
| 96 | Let'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 | |
| 148 | Some 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 | |
| 158 | Note 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 | ---- |
| 175 | This comes from an important property of Genshi templates: '''they must themselves be well-formed XML documents'''. |
| 176 | |
| 177 | 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 query.html] template. |
| 178 | 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. |
| 179 | |
| 180 | === Changes in the controllers === |
| 181 | |
| 182 | ==== Implementing the `IRequestHandler` interface ==== |
| 183 | Previously, all the data fed to a template had to be placed inside the `req.hdf` HDF wrapper object. |
| 184 | With Genshi, the data for the template is basically a `dict`, which has to be returned by `process_request` |
| 185 | at 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 ==== |
| 188 | When one wants to directly render a template, the Chrome component facilities should be used. |
| 189 | Check the [source:sandbox/genshi/trac/web/chrome.py@3725#L424 Chrome.load_template] |
| 190 | and `render_method` methods. Note however that this API is still rapidly evolving. |
| 191 | |
| 192 | Usage 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 |