KXStudio Website https://kx.studio/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

spec.html 24KB

9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  4. <head>
  5. <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
  6. <meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
  7. <title>Twig Template Engine Specification</title>
  8. <style type="text/css">
  9. /*
  10. :Author: David Goodger
  11. :Contact: goodger@users.sourceforge.net
  12. :Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $
  13. :Revision: $Revision: 4224 $
  14. :Copyright: This stylesheet has been placed in the public domain.
  15. Default cascading style sheet for the HTML output of Docutils.
  16. See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
  17. customize this style sheet.
  18. */
  19. /* used to remove borders from tables and images */
  20. .borderless, table.borderless td, table.borderless th {
  21. border: 0 }
  22. table.borderless td, table.borderless th {
  23. /* Override padding for "table.docutils td" with "! important".
  24. The right padding separates the table cells. */
  25. padding: 0 0.5em 0 0 ! important }
  26. .first {
  27. /* Override more specific margin styles with "! important". */
  28. margin-top: 0 ! important }
  29. .last, .with-subtitle {
  30. margin-bottom: 0 ! important }
  31. .hidden {
  32. display: none }
  33. a.toc-backref {
  34. text-decoration: none ;
  35. color: black }
  36. blockquote.epigraph {
  37. margin: 2em 5em ; }
  38. dl.docutils dd {
  39. margin-bottom: 0.5em }
  40. /* Uncomment (and remove this text!) to get bold-faced definition list terms
  41. dl.docutils dt {
  42. font-weight: bold }
  43. */
  44. div.abstract {
  45. margin: 2em 5em }
  46. div.abstract p.topic-title {
  47. font-weight: bold ;
  48. text-align: center }
  49. div.admonition, div.attention, div.caution, div.danger, div.error,
  50. div.hint, div.important, div.note, div.tip, div.warning {
  51. margin: 2em ;
  52. border: medium outset ;
  53. padding: 1em }
  54. div.admonition p.admonition-title, div.hint p.admonition-title,
  55. div.important p.admonition-title, div.note p.admonition-title,
  56. div.tip p.admonition-title {
  57. font-weight: bold ;
  58. font-family: sans-serif }
  59. div.attention p.admonition-title, div.caution p.admonition-title,
  60. div.danger p.admonition-title, div.error p.admonition-title,
  61. div.warning p.admonition-title {
  62. color: red ;
  63. font-weight: bold ;
  64. font-family: sans-serif }
  65. /* Uncomment (and remove this text!) to get reduced vertical space in
  66. compound paragraphs.
  67. div.compound .compound-first, div.compound .compound-middle {
  68. margin-bottom: 0.5em }
  69. div.compound .compound-last, div.compound .compound-middle {
  70. margin-top: 0.5em }
  71. */
  72. div.dedication {
  73. margin: 2em 5em ;
  74. text-align: center ;
  75. font-style: italic }
  76. div.dedication p.topic-title {
  77. font-weight: bold ;
  78. font-style: normal }
  79. div.figure {
  80. margin-left: 2em ;
  81. margin-right: 2em }
  82. div.footer, div.header {
  83. clear: both;
  84. font-size: smaller }
  85. div.line-block {
  86. display: block ;
  87. margin-top: 1em ;
  88. margin-bottom: 1em }
  89. div.line-block div.line-block {
  90. margin-top: 0 ;
  91. margin-bottom: 0 ;
  92. margin-left: 1.5em }
  93. div.sidebar {
  94. margin-left: 1em ;
  95. border: medium outset ;
  96. padding: 1em ;
  97. background-color: #ffffee ;
  98. width: 40% ;
  99. float: right ;
  100. clear: right }
  101. div.sidebar p.rubric {
  102. font-family: sans-serif ;
  103. font-size: medium }
  104. div.system-messages {
  105. margin: 5em }
  106. div.system-messages h1 {
  107. color: red }
  108. div.system-message {
  109. border: medium outset ;
  110. padding: 1em }
  111. div.system-message p.system-message-title {
  112. color: red ;
  113. font-weight: bold }
  114. div.topic {
  115. margin: 2em }
  116. h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
  117. h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
  118. margin-top: 0.4em }
  119. h1.title {
  120. text-align: center }
  121. h2.subtitle {
  122. text-align: center }
  123. hr.docutils {
  124. width: 75% }
  125. img.align-left {
  126. clear: left }
  127. img.align-right {
  128. clear: right }
  129. ol.simple, ul.simple {
  130. margin-bottom: 1em }
  131. ol.arabic {
  132. list-style: decimal }
  133. ol.loweralpha {
  134. list-style: lower-alpha }
  135. ol.upperalpha {
  136. list-style: upper-alpha }
  137. ol.lowerroman {
  138. list-style: lower-roman }
  139. ol.upperroman {
  140. list-style: upper-roman }
  141. p.attribution {
  142. text-align: right ;
  143. margin-left: 50% }
  144. p.caption {
  145. font-style: italic }
  146. p.credits {
  147. font-style: italic ;
  148. font-size: smaller }
  149. p.label {
  150. white-space: nowrap }
  151. p.rubric {
  152. font-weight: bold ;
  153. font-size: larger ;
  154. color: maroon ;
  155. text-align: center }
  156. p.sidebar-title {
  157. font-family: sans-serif ;
  158. font-weight: bold ;
  159. font-size: larger }
  160. p.sidebar-subtitle {
  161. font-family: sans-serif ;
  162. font-weight: bold }
  163. p.topic-title {
  164. font-weight: bold }
  165. pre.address {
  166. margin-bottom: 0 ;
  167. margin-top: 0 ;
  168. font-family: serif ;
  169. font-size: 100% }
  170. pre.literal-block, pre.doctest-block {
  171. margin-left: 2em ;
  172. margin-right: 2em ;
  173. background-color: #eeeeee }
  174. span.classifier {
  175. font-family: sans-serif ;
  176. font-style: oblique }
  177. span.classifier-delimiter {
  178. font-family: sans-serif ;
  179. font-weight: bold }
  180. span.interpreted {
  181. font-family: sans-serif }
  182. span.option {
  183. white-space: nowrap }
  184. span.pre {
  185. white-space: pre }
  186. span.problematic {
  187. color: red }
  188. span.section-subtitle {
  189. /* font-size relative to parent (h1..h6 element) */
  190. font-size: 80% }
  191. table.citation {
  192. border-left: solid 1px gray;
  193. margin-left: 1px }
  194. table.docinfo {
  195. margin: 2em 4em }
  196. table.docutils {
  197. margin-top: 0.5em ;
  198. margin-bottom: 0.5em }
  199. table.footnote {
  200. border-left: solid 1px black;
  201. margin-left: 1px }
  202. table.docutils td, table.docutils th,
  203. table.docinfo td, table.docinfo th {
  204. padding-left: 0.5em ;
  205. padding-right: 0.5em ;
  206. vertical-align: top }
  207. table.docutils th.field-name, table.docinfo th.docinfo-name {
  208. font-weight: bold ;
  209. text-align: left ;
  210. white-space: nowrap ;
  211. padding-left: 0 }
  212. h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
  213. h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
  214. font-size: 100% }
  215. tt.docutils {
  216. background-color: #eeeeee }
  217. ul.auto-toc {
  218. list-style-type: none }
  219. </style>
  220. </head>
  221. <body>
  222. <div class="document" id="twig-template-engine-specification">
  223. <h1 class="title">Twig Template Engine Specification</h1>
  224. <p>This specification specifies a simple cross-language template engine for at least
  225. PHP, Python and Ruby.</p>
  226. <div class="section">
  227. <h1><a id="purpose" name="purpose">Purpose</a></h1>
  228. <p>A language independent and simple template engine is useful for applications that
  229. use code which is written in more than one programming language. Good Examples
  230. are portal systems which use a blog written in Ruby, a forum software written in
  231. PHP and a planet system written in Python.</p>
  232. </div>
  233. <div class="section">
  234. <h1><a id="inspiration" name="inspiration">Inspiration</a></h1>
  235. <p>Twig uses a syntax similar to the Genshi text templates which in turn were
  236. inspired by django which also inspired Jinja (all three of them python template
  237. engines) which inspired the Twig runtime environment.</p>
  238. </div>
  239. <div class="section">
  240. <h1><a id="undefined-behavior" name="undefined-behavior">Undefined Behavior</a></h1>
  241. <p>To simplify porting the template language to different platforms in a couple of
  242. situations the behavior is undefined. Template authors may never take advantage
  243. of such a situation!</p>
  244. </div>
  245. <div class="section">
  246. <h1><a id="syntax" name="syntax">Syntax</a></h1>
  247. <p>I'm too lazy to write down the syntax as BNF diagram but the following snippet
  248. should explain the syntax elements:</p>
  249. <pre class="literal-block">
  250. &lt;!DOCTYPE HTML&gt;
  251. {# This is a comment #}
  252. &lt;title&gt;{% block title %}Page Title Goes Here{% endblock %}&lt;/title&gt;
  253. {% if show_navigation %}
  254. &lt;nav&gt;
  255. &lt;ul&gt;
  256. {% for item in navigation %}
  257. &lt;li&gt;&lt;a href=&quot;${item.href|e}&quot;&gt;$item.caption&lt;/a&gt;&lt;/li&gt;
  258. {% endfor %}
  259. &lt;/ul&gt;
  260. &lt;/nav&gt;
  261. {% endif %}
  262. &lt;article&gt;{% block body %}{% endblock %}&lt;/article&gt;
  263. </pre>
  264. <div class="section">
  265. <h2><a id="comments-and-whitespace" name="comments-and-whitespace">Comments and Whitespace</a></h2>
  266. <p>Everything between <tt class="docutils literal"><span class="pre">{#</span></tt> and <tt class="docutils literal"><span class="pre">#}</span></tt> is ignored by the lexer. Inside blocks and
  267. variable sections the Lexer has to remove whitespace too.</p>
  268. </div>
  269. <div class="section">
  270. <h2><a id="output-expressions" name="output-expressions">Output Expressions</a></h2>
  271. <p>To output expressions two syntaxes exist. Simple variable output or full
  272. expression output:</p>
  273. <pre class="literal-block">
  274. $this.is.a.variable.output
  275. ${ expression | goes | here }
  276. </pre>
  277. <p>The former is what we call a variable expression, the second a full expression.
  278. Variable expressions must not contain whitespace, whereas a full expression
  279. must print the output of the full wrapped expression.</p>
  280. </div>
  281. <div class="section">
  282. <h2><a id="expressions" name="expressions">Expressions</a></h2>
  283. <p>Expressions allow basic string manipulation and arithmetic calculations. It is
  284. an infix syntax with the following operators in this precedence:</p>
  285. <blockquote>
  286. <table border="1" class="docutils">
  287. <colgroup>
  288. <col width="15%" />
  289. <col width="85%" />
  290. </colgroup>
  291. <thead valign="bottom">
  292. <tr><th class="head">Operator</th>
  293. <th class="head">Description</th>
  294. </tr>
  295. </thead>
  296. <tbody valign="top">
  297. <tr><td><tt class="docutils literal"><span class="pre">+</span></tt></td>
  298. <td>Convert both arguments into a number and add them up.</td>
  299. </tr>
  300. <tr><td><tt class="docutils literal"><span class="pre">-</span></tt></td>
  301. <td>Convert both arguments into a number and substract them.</td>
  302. </tr>
  303. <tr><td><tt class="docutils literal"><span class="pre">*</span></tt></td>
  304. <td>Convert both arguments into a number and multiply them.</td>
  305. </tr>
  306. <tr><td><tt class="docutils literal"><span class="pre">/</span></tt></td>
  307. <td>Convert both arguments into a number and divide them.</td>
  308. </tr>
  309. <tr><td><tt class="docutils literal"><span class="pre">%</span></tt></td>
  310. <td>Convert both arguments into a number and calculate the rest
  311. of the integer division.</td>
  312. </tr>
  313. <tr><td><tt class="docutils literal"><span class="pre">~</span></tt></td>
  314. <td>Convert both arguments into a string and concatenate them.</td>
  315. </tr>
  316. <tr><td><tt class="docutils literal"><span class="pre">or</span></tt></td>
  317. <td>True if the left or the right expression is true.</td>
  318. </tr>
  319. <tr><td><tt class="docutils literal"><span class="pre">and</span></tt></td>
  320. <td>True if the left and the right expression is true.</td>
  321. </tr>
  322. <tr><td><tt class="docutils literal"><span class="pre">not</span></tt></td>
  323. <td>negate the expression</td>
  324. </tr>
  325. </tbody>
  326. </table>
  327. </blockquote>
  328. <p>All number conversions have an undefined precision but the implementations
  329. should try to select the best possible type. For example, if the implementation
  330. sees an integer and a float that looks like an integer it may convert the
  331. latter into a long and add them.</p>
  332. <p>Use parentheses to group expressions.</p>
  333. <p>If an object cannot be compared the implementation might raise an error or fail
  334. silently. Template authors may never apply mathematical operators to untrusted
  335. data. This is especially true for the php implementation where the following
  336. outputs <tt class="docutils literal"><span class="pre">42</span></tt>:</p>
  337. <pre class="literal-block">
  338. ${ &quot;foo41&quot; + 1 }
  339. </pre>
  340. <p>This is undefined behavior and will break on different implementations or
  341. return <tt class="docutils literal"><span class="pre">0</span></tt> as <tt class="docutils literal"><span class="pre">&quot;foo41&quot;</span></tt> is not a valid number.</p>
  342. <div class="section">
  343. <h3><a id="types" name="types">Types</a></h3>
  344. <p>The following types exist:</p>
  345. <blockquote>
  346. <table border="1" class="docutils">
  347. <colgroup>
  348. <col width="15%" />
  349. <col width="21%" />
  350. <col width="64%" />
  351. </colgroup>
  352. <thead valign="bottom">
  353. <tr><th class="head">Type</th>
  354. <th class="head">Literal</th>
  355. <th class="head">Description</th>
  356. </tr>
  357. </thead>
  358. <tbody valign="top">
  359. <tr><td><tt class="docutils literal"><span class="pre">integer</span></tt></td>
  360. <td><cite>d+</cite></td>
  361. <td>One of the two numeric types. Which of them
  362. is used and when is up to the implementation.</td>
  363. </tr>
  364. <tr><td><tt class="docutils literal"><span class="pre">float</span></tt></td>
  365. <td><cite>d+.d+</cite></td>
  366. <td>Floating point values.</td>
  367. </tr>
  368. <tr><td><tt class="docutils literal"><span class="pre">string</span></tt></td>
  369. <td>see below</td>
  370. <td>A unicode string. The PHP implementation has
  371. to use bytestrings here and may use mb_string.</td>
  372. </tr>
  373. <tr><td><tt class="docutils literal"><span class="pre">bool</span></tt></td>
  374. <td><cite>(true|false)</cite></td>
  375. <td>Represents boolean values.</td>
  376. </tr>
  377. <tr><td><tt class="docutils literal"><span class="pre">none</span></tt></td>
  378. <td><cite>none</cite></td>
  379. <td>This type is returned on missing variables or
  380. attributes.</td>
  381. </tr>
  382. </tbody>
  383. </table>
  384. </blockquote>
  385. <p>String regex:</p>
  386. <pre class="literal-block">
  387. (?:&quot;([^&quot;\\\\]*(?:\\\\.[^&quot;\\\\]*)*)&quot;|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')(?sm)
  388. </pre>
  389. </div>
  390. <div class="section">
  391. <h3><a id="attribute-lookup" name="attribute-lookup">Attribute Lookup</a></h3>
  392. <p>There are two ways to look up attributes on objects. The dot and the
  393. subscript syntax, both inspired by JavaScript. Basically the following
  394. expressions do the very same:</p>
  395. <pre class="literal-block">
  396. foo.name.0
  397. foo['name'][0]
  398. </pre>
  399. <p>This is useful to dynamically get attributes from objects:</p>
  400. <pre class="literal-block">
  401. foo[bar]
  402. </pre>
  403. <p>The underlaying implementation is free to specify on it's own what an attribute
  404. lookup means. The PHP reference implementation for example performs those
  405. actions on <tt class="docutils literal"><span class="pre">foo.bar</span></tt>:</p>
  406. <ul class="simple">
  407. <li>try <tt class="docutils literal"><span class="pre">$foo['bar']</span></tt></li>
  408. <li>try <tt class="docutils literal"><span class="pre">$foo-&gt;bar()</span></tt></li>
  409. <li>try <tt class="docutils literal"><span class="pre">$foo-&gt;bar</span></tt></li>
  410. <li>try <tt class="docutils literal"><span class="pre">$foo-&gt;getBar()</span></tt></li>
  411. </ul>
  412. <p>The first match returns the object, attribute access to nonexisting attributes
  413. returns <cite>none</cite>.</p>
  414. </div>
  415. <div class="section">
  416. <h3><a id="filtering" name="filtering">Filtering</a></h3>
  417. <p>The template language does not specify function calls, but filters can be used
  418. to further modify variables using functions the template engine provides.</p>
  419. <p>The following snippet shows how filters are translated to function calls:</p>
  420. <pre class="literal-block">
  421. ${ 42 | foo(1, 2) | bar | baz }
  422. -&gt; baz(bar(foo(42, 1, 2)))
  423. </pre>
  424. <p>The following filters must be provided by the implementation:</p>
  425. <blockquote>
  426. <table border="1" class="docutils">
  427. <colgroup>
  428. <col width="26%" />
  429. <col width="74%" />
  430. </colgroup>
  431. <thead valign="bottom">
  432. <tr><th class="head">Name</th>
  433. <th class="head">Description</th>
  434. </tr>
  435. </thead>
  436. <tbody valign="top">
  437. <tr><td><cite>date</cite></td>
  438. <td>Format the timestamp using the PHP date formatting
  439. rules. This may sound like a nonstandard way of
  440. formatting dates but it's a way very popular among
  441. template designers and also used by django.</td>
  442. </tr>
  443. <tr><td><cite>strftime</cite></td>
  444. <td>Format the timestamp using standard strftime rules.</td>
  445. </tr>
  446. <tr><td><cite>numberformat</cite></td>
  447. <td>Apply number formatting on the string. This may or
  448. may not use local specific rules.</td>
  449. </tr>
  450. <tr><td><cite>moneyformat</cite></td>
  451. <td>Like <cite>numberformat</cite> but for money.</td>
  452. </tr>
  453. <tr><td><cite>filesizeformat</cite></td>
  454. <td>Takes a number of bytes and displays it as KB/MB/GB</td>
  455. </tr>
  456. <tr><td><cite>format</cite></td>
  457. <td><dl class="first last docutils">
  458. <dt>Applies <cite>sprintf</cite> formatting on the string::</dt>
  459. <dd>${ &quot;%s %2f&quot; | format(string, float) }</dd>
  460. </dl>
  461. </td>
  462. </tr>
  463. <tr><td><cite>even</cite></td>
  464. <td>Is the number even?</td>
  465. </tr>
  466. <tr><td><cite>odd</cite></td>
  467. <td>Is the number odd?</td>
  468. </tr>
  469. <tr><td><cite>escape</cite></td>
  470. <td>Apply HTML escaping on a string. This also has to
  471. convert <cite>&quot;</cite> to <cite>&amp;quot; but leave `'</cite> unmodified.</td>
  472. </tr>
  473. <tr><td><cite>e</cite></td>
  474. <td>Alias for <cite>escape</cite>.</td>
  475. </tr>
  476. <tr><td><cite>urlencode</cite></td>
  477. <td>URL encode the string. If the second parameter is
  478. true this function should encode for path sections,
  479. otherwise for query strings.</td>
  480. </tr>
  481. <tr><td><cite>quotes</cite></td>
  482. <td>Escape quotes (', &quot;, etc.)</td>
  483. </tr>
  484. <tr><td><cite>title</cite></td>
  485. <td>Make the string lowercase and upper case the first
  486. characters of all words.</td>
  487. </tr>
  488. <tr><td><cite>capitalize</cite></td>
  489. <td>Like <cite>title</cite> but capitalizes only the first char of
  490. the whole string.</td>
  491. </tr>
  492. <tr><td><cite>upper</cite></td>
  493. <td>Convert the string to uppercase.</td>
  494. </tr>
  495. <tr><td><cite>lower</cite></td>
  496. <td>Convert the string to lowercase.</td>
  497. </tr>
  498. <tr><td><cite>strip</cite></td>
  499. <td>Trim leading and trailing whitespace.</td>
  500. </tr>
  501. <tr><td><cite>lstrip</cite></td>
  502. <td>Trim leading whitespace.</td>
  503. </tr>
  504. <tr><td><cite>rstrip</cite></td>
  505. <td>Trim trailing whitespace.</td>
  506. </tr>
  507. <tr><td><cite>translate</cite></td>
  508. <td>Translate the string using either the &quot;theme&quot; domain
  509. or the &quot;chyrp&quot; domain if in Admin. (Chyrp-specific)</td>
  510. </tr>
  511. <tr><td><cite>translate_plural</cite></td>
  512. <td>Translate the (singular) string, or the plural string
  513. if the number passed is not 1.</td>
  514. </tr>
  515. <tr><td><cite>normalize</cite></td>
  516. <td>Convert all excessive whitespace (including linebreaks)
  517. into a single space.</td>
  518. </tr>
  519. <tr><td><cite>truncate</cite></td>
  520. <td>Truncate a string, providing ellipsis, if it is longer
  521. than the passed length. Keeps words in tact by default,
  522. but with a second boolean parameter will be strict.</td>
  523. </tr>
  524. <tr><td><cite>replace</cite></td>
  525. <td>Replaces the occurrence of the first argument with the
  526. second argument in the string.</td>
  527. </tr>
  528. <tr><td><cite>linebreaks</cite></td>
  529. <td>Convert linebreaks to &lt;br /&gt;'s.</td>
  530. </tr>
  531. <tr><td><cite>camelize</cite></td>
  532. <td>Convert string to camelcase.</td>
  533. </tr>
  534. <tr><td><cite>strip_tags</cite></td>
  535. <td>Strip HTML from the string.</td>
  536. </tr>
  537. <tr><td><cite>pluralize</cite></td>
  538. <td>Return the pluralization of a string, or if a number
  539. is passed and it is 1, don't pluralize.</td>
  540. </tr>
  541. <tr><td><cite>sanitize</cite></td>
  542. <td>Remove special characters from a string.</td>
  543. </tr>
  544. <tr><td><cite>join</cite></td>
  545. <td>Concatenate the array items and join them with the
  546. string provided (or commas by default).</td>
  547. </tr>
  548. <tr><td><cite>split</cite></td>
  549. <td>Split a string into an array at the given breakpoints.</td>
  550. </tr>
  551. <tr><td><cite>first</cite></td>
  552. <td>First entry of an Array.</td>
  553. </tr>
  554. <tr><td><cite>offset</cite></td>
  555. <td>Entry at Array[offset].</td>
  556. </tr>
  557. <tr><td><cite>last</cite></td>
  558. <td>Last entry of an Array.</td>
  559. </tr>
  560. <tr><td><cite>reverse</cite></td>
  561. <td>Reverse the Array items.</td>
  562. </tr>
  563. <tr><td><cite>count</cite></td>
  564. <td>Count the number of items in an array or string
  565. characters.</td>
  566. </tr>
  567. <tr><td><cite>length</cite></td>
  568. <td>Alias for <cite>count</cite>.</td>
  569. </tr>
  570. <tr><td><cite>default</cite></td>
  571. <td>If the value is <cite>none</cite> the first argument is returned</td>
  572. </tr>
  573. <tr><td><cite>keys</cite></td>
  574. <td>Keys of an Array.</td>
  575. </tr>
  576. <tr><td><cite>items</cite></td>
  577. <td>Items of an Array.</td>
  578. </tr>
  579. <tr><td><cite>inspect</cite></td>
  580. <td>Dumps the variable or value.</td>
  581. </tr>
  582. <tr><td><cite>fallback</cite></td>
  583. <td>If the value is empty or <cite>none</cite>, return this value.</td>
  584. </tr>
  585. <tr><td><cite>selected</cite></td>
  586. <td>If the first argument is the same as the value, output
  587. <cite>class=&quot;selected&quot;</cite>, or <cite>selected</cite> if the second
  588. argument is <cite>true</cite>.</td>
  589. </tr>
  590. <tr><td><cite>option_selected</cite></td>
  591. <td>Same as <cite>selected</cite>, but for <cite>selected=&quot;selected&quot;</cite>.</td>
  592. </tr>
  593. <tr><td><cite>checked</cite></td>
  594. <td>Same as <cite>selected</cite>, but for <cite>checked=&quot;checked&quot;</cite>.</td>
  595. </tr>
  596. </tbody>
  597. </table>
  598. </blockquote>
  599. <p>Additionally, if a filter is missing (say, ${ foo | bar_filter }, in Chyrp it
  600. checks for an associated Trigger filter by that filter's name.</p>
  601. </div>
  602. </div>
  603. <div class="section">
  604. <h2><a id="for-loops" name="for-loops">For Loops</a></h2>
  605. <p>Iteration works via for loops. Loops work a bit like their Python counterparts,
  606. except that they don't support multilevel tuple unpacking and that they add a new
  607. layer to the context. Thus at the end of the iteration all the modifications on
  608. the context disappear. Additionally, inside loops you have access to a special
  609. <cite>loop</cite> object which provides runtime information:</p>
  610. <blockquote>
  611. <table border="1" class="docutils">
  612. <colgroup>
  613. <col width="30%" />
  614. <col width="70%" />
  615. </colgroup>
  616. <thead valign="bottom">
  617. <tr><th class="head">Variable</th>
  618. <th class="head">Description</th>
  619. </tr>
  620. </thead>
  621. <tbody valign="top">
  622. <tr><td><tt class="docutils literal"><span class="pre">loop.index</span></tt></td>
  623. <td>The current iteration of the loop (1-indexed)</td>
  624. </tr>
  625. <tr><td><tt class="docutils literal"><span class="pre">loop.index0</span></tt></td>
  626. <td>The current iteration of the loop (0-indexed)</td>
  627. </tr>
  628. <tr><td><tt class="docutils literal"><span class="pre">loop.revindex</span></tt></td>
  629. <td>The number of iterations from the end of the
  630. loop (1-indexed)</td>
  631. </tr>
  632. <tr><td><tt class="docutils literal"><span class="pre">loop.revindex0</span></tt></td>
  633. <td>The number of iterations from the end of the
  634. loop (0-indexed)</td>
  635. </tr>
  636. <tr><td><tt class="docutils literal"><span class="pre">loop.first</span></tt></td>
  637. <td>True if this is the first time through the loop</td>
  638. </tr>
  639. <tr><td><tt class="docutils literal"><span class="pre">loop.last</span></tt></td>
  640. <td>True if this is the last time through the loop</td>
  641. </tr>
  642. <tr><td><tt class="docutils literal"><span class="pre">loop.parent</span></tt></td>
  643. <td>For nested loops, this is the loop &quot;above&quot; the
  644. current one</td>
  645. </tr>
  646. </tbody>
  647. </table>
  648. </blockquote>
  649. <p>Additionally for loops can have an <cite>else</cite> section that is executed if no
  650. iteration took place.</p>
  651. <div class="section">
  652. <h3><a id="example" name="example">Example</a></h3>
  653. <pre class="literal-block">
  654. &lt;ul&gt;
  655. {% for user in users %}
  656. &lt;li&gt;&lt;a href=&quot;$user.href&quot;&gt;${ user.username | escape }&lt;/a&gt;&lt;/li&gt;
  657. {% else %}
  658. &lt;li&gt;&lt;em&gt;No users found!&lt;/em&gt;&lt;/li&gt;
  659. {% endfor %}
  660. &lt;/ul&gt;
  661. </pre>
  662. </div>
  663. <div class="section">
  664. <h3><a id="notes-on-iteration" name="notes-on-iteration">Notes on Iteration</a></h3>
  665. <p>Because we have to cope with PHP too, which has problematic arrays that are
  666. neither hashmaps nor lists, we have no support for associative array iteration
  667. at all. How do you iterate over associative arrays then? Using a filter:</p>
  668. <pre class="literal-block">
  669. {% for key, value in array | items %}
  670. ...
  671. {% endfor %}
  672. </pre>
  673. <p>To iterate over the keys only:</p>
  674. <pre class="literal-block">
  675. {% for key in array | keys %}
  676. ...
  677. {% endfor %}
  678. </pre>
  679. </div>
  680. </div>
  681. <div class="section">
  682. <h2><a id="if-conditions" name="if-conditions">If Conditions</a></h2>
  683. <p>If conditions work like like Ruby, PHP and Python, just that we use PHP
  684. keywords. Also, use <cite>elseif</cite> and not <cite>else if</cite>:</p>
  685. <pre class="literal-block">
  686. {% if expr1 %}
  687. ...
  688. {% elseif expr2 %}
  689. ...
  690. {% else %}
  691. ...
  692. {% endif %}
  693. </pre>
  694. </div>
  695. <div class="section">
  696. <h2><a id="inheritance" name="inheritance">Inheritance</a></h2>
  697. <p>Template inheritance allows you to build a base &quot;skeleton&quot; template that
  698. contains all the common elements of your site and defines <strong>blocks</strong> that
  699. child templates can override.</p>
  700. <p>Here a small template inheritance example:</p>
  701. <pre class="literal-block">
  702. &lt;!DOCTYPE HTML&gt;
  703. &lt;html lang=&quot;en&quot;&gt;
  704. &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
  705. &lt;title&gt;{% block title %}My site{% endblock %}&lt;/title&gt;
  706. &lt;div id=&quot;sidebar&quot;&gt;
  707. {% block sidebar %}
  708. &lt;ul&gt;
  709. &lt;li&gt;&lt;a href=&quot;/&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
  710. &lt;li&gt;&lt;a href=&quot;/blog/&quot;&gt;Blog&lt;/a&gt;&lt;/li&gt;
  711. &lt;/ul&gt;
  712. {% endblock %}
  713. &lt;/div&gt;
  714. &lt;div id=&quot;content&quot;&gt;
  715. {% block content %}{% endblock %}
  716. &lt;/div&gt;
  717. &lt;/html&gt;
  718. </pre>
  719. <p>If we call that template &quot;base.html&quot; a &quot;index.html&quot; template could override
  720. it and fill in the blocks:</p>
  721. <pre class="literal-block">
  722. {% extends &quot;base.html&quot; %}
  723. {% block title %}Foo &amp;mdash; {% super %}{% endblock %}
  724. {% block content %}
  725. This is the content
  726. {% endblock %}
  727. </pre>
  728. <p>By using <cite>{% super %}</cite> you can render the parent's block. The template
  729. filenames must be constant strings (we don't support dynamic inheritance
  730. for simplicity) and are relative to the loader folder, not the current
  731. template.</p>
  732. </div>
  733. </div>
  734. </div>
  735. </body>
  736. </html>