1 |
|
2 | Templates
|
3 | =========
|
4 |
|
5 | View templates in Shunter are written in [Dust](http://www.dustjs.com/) and live in the `view` folder by default.
|
6 |
|
7 | - [Specifying a Template](#specifying-a-template)
|
8 | - [Dust Basics](#dust-basics)
|
9 | - [Using partials](#using-partials)
|
10 | - [Using layouts](#using-layouts)
|
11 | - [Built-In Dust Extensions](#built-in-dust-extensions)
|
12 | - [Writing Dust Extensions](#writing-dust-extensions)
|
13 |
|
14 |
|
15 | Specifying a Template
|
16 | ---------------------
|
17 |
|
18 | When a JSON response is received from the back end with the (configured trigger header)[configuration-reference.md#trigger-parameter] (default: `Content-Type: application/x-shunter+json`), Shunter will look for a `layout.template` property and attempt to render the matching Dust file. So with the following JSON:
|
19 |
|
20 | ```json
|
21 | {
|
22 | "layout": {
|
23 | "template": "foo"
|
24 | }
|
25 | }
|
26 | ```
|
27 |
|
28 | Shunter will attempt to render the file `view/foo.dust`. This allows your back end application to decide which template to render for a given page.
|
29 |
|
30 | Templates cannot contain "/" characters in Shunter, instead if you need to reference a template in a subdirectory you should use double underscores. So with the following JSON:
|
31 |
|
32 | ```json
|
33 | {
|
34 | "layout": {
|
35 | "template": "foo__bar"
|
36 | }
|
37 | }
|
38 | ```
|
39 |
|
40 | Shunter will attempt to render the file `view/foo/bar.dust`.
|
41 |
|
42 | If a JSON response is received without the (configured trigger header)[configuration-reference.md#trigger-parameter] then Shunter will simply pass it through unmodified as it would any other resource.
|
43 |
|
44 |
|
45 | Dust Basics
|
46 | -----------
|
47 |
|
48 | Dust has all of the features you'd expect from a good templating language. We'll cover some basics here, but you should read the [Dust documentation](http://www.dustjs.com/) for more information.
|
49 |
|
50 | ### References
|
51 |
|
52 | You can output properties from the back end JSON simply by surrounding the property name in curly braces. So with the following JSON and Dust template:
|
53 |
|
54 | ```json
|
55 | {
|
56 | "thing": "World"
|
57 | }
|
58 | ```
|
59 |
|
60 | ```html
|
61 | <p>Hello {thing}!</p>
|
62 | ```
|
63 |
|
64 | Dust will render:
|
65 |
|
66 | ```html
|
67 | <p>Hello World!</p>
|
68 | ```
|
69 |
|
70 | ### Conditionals
|
71 |
|
72 | You can conditionally output HTML based on the values of JSON properties. So with the following JSON and Dust template:
|
73 |
|
74 | ```json
|
75 | {
|
76 | "show_html": true
|
77 | }
|
78 | ```
|
79 |
|
80 | ```html
|
81 | {?show_html}
|
82 | <p>Hello World!</p>
|
83 | {/show_html}
|
84 | ```
|
85 |
|
86 | Dust will render:
|
87 |
|
88 | ```html
|
89 | <p>Hello World!</p>
|
90 | ```
|
91 |
|
92 | ### Loops
|
93 |
|
94 | You can loop over arrays in the JSON with Dust and generate output for each item in the array. So with the following JSON and Dust template:
|
95 |
|
96 | ```json
|
97 | {
|
98 | "list": [
|
99 | "foo",
|
100 | "bar",
|
101 | "baz"
|
102 | ]
|
103 | }
|
104 | ```
|
105 |
|
106 | ```html
|
107 | <ul>
|
108 | {#list}
|
109 | <li>{.}</li>
|
110 | {/list}
|
111 | </ul>
|
112 | ```
|
113 |
|
114 | Dust will render:
|
115 |
|
116 | ```html
|
117 | <ul>
|
118 | <li>foo</li>
|
119 | <li>bar</li>
|
120 | <li>baz</li>
|
121 | </ul>
|
122 | ```
|
123 |
|
124 | For more information on Dust, refer to the [Dust getting started documentation](http://www.dustjs.com/guides/getting-started/).
|
125 |
|
126 |
|
127 | Using Partials
|
128 | --------------
|
129 |
|
130 | Partials in Dust allow you to insert other Dust files into your template to create a page. This encourages code reuse, and smaller more maintainable templates.
|
131 |
|
132 | Partials are subject to the same naming rules as templates when they're references in Dust files. You'll need to replace slashes with double underscores in order for Shunter to find them.
|
133 |
|
134 | So with the following Dust templates:
|
135 |
|
136 | ```html
|
137 | <!-- view/foo/bar.dust -->
|
138 | Hello World!
|
139 | ```
|
140 |
|
141 | ```html
|
142 | <!-- view/foo.dust -->
|
143 | <p>{>foo__bar/}</p>
|
144 | ```
|
145 |
|
146 | When `view/foo.dust` is rendered, it will produce the following output:
|
147 |
|
148 | ```html
|
149 | <p>Hello World!</p>
|
150 | ```
|
151 |
|
152 | Partials can also be referenced by using JSON properties. This is very powerful if you'd like your back end to have more control over the presentation. So with the following JSON and Dust template:
|
153 |
|
154 | ```json
|
155 | {
|
156 | "foo": "bar"
|
157 | }
|
158 | ```
|
159 |
|
160 | ```html
|
161 | {>"{foo}"/}
|
162 | ```
|
163 |
|
164 | The `view/bar.dust` partial will be rendered.
|
165 |
|
166 | For more information on partials in Dust partials, refer to the [Dust Partials documentation](http://www.dustjs.com/guides/partials/).
|
167 |
|
168 |
|
169 | Using Layouts
|
170 | -------------
|
171 |
|
172 | There are several ways to implement layouts in Shunter, either by allowing your JSON to configure them or by using Dust's built-in Blocks.
|
173 |
|
174 | ### Layouts In JSON
|
175 |
|
176 | Because partials can be referenced using JSON properties, you could create layouts by using a single `layout` view and injecting a second template into the body of it.
|
177 |
|
178 | For example, given the following JSON and Dust templates:
|
179 |
|
180 | ```json
|
181 | {
|
182 | "layout": {
|
183 | "template": "layout",
|
184 | "page_template": "home"
|
185 | },
|
186 | "title": "Hello World!"
|
187 | }
|
188 | ```
|
189 |
|
190 | ```html
|
191 | <!-- view/layout.dust -->
|
192 | <!DOCTYPE html>
|
193 | <html lang="en">
|
194 | <head>
|
195 | <title>{title}</title>
|
196 | </head>
|
197 | <body>
|
198 | {>"{layout.page_template}"/}
|
199 | </body>
|
200 | </html>
|
201 | ```
|
202 |
|
203 | ```html
|
204 | <!-- view/home.dust -->
|
205 | <p>This is the home page!</p>
|
206 | ```
|
207 |
|
208 | Dust will combine the templates and render:
|
209 |
|
210 | ```html
|
211 | <!DOCTYPE html>
|
212 | <html lang="en">
|
213 | <head>
|
214 | <title>Hello World!</title>
|
215 | </head>
|
216 | <body>
|
217 | <p>This is the home page!</p>
|
218 | </body>
|
219 | </html>
|
220 | ```
|
221 |
|
222 | ### Layouts With Dust Blocks
|
223 |
|
224 | Dust has a feature called [Blocks and Inline Partials](http://www.dustjs.com/guides/blocks/) which is very powerful. It allows you to create templates which extend each other, and inject content into templates further up the chain.
|
225 |
|
226 | We can utilise this for layouts quite easily, and without any need to add extra layout properties to the JSON.
|
227 |
|
228 | For example, given the following JSON and Dust templates:
|
229 |
|
230 | ```json
|
231 | {
|
232 | "layout": {
|
233 | "template": "home"
|
234 | },
|
235 | "title": "Hello World!"
|
236 | }
|
237 | ```
|
238 |
|
239 | ```html
|
240 | <!-- view/layout.dust -->
|
241 | <!DOCTYPE html>
|
242 | <html lang="en">
|
243 | <head>
|
244 | <title>{title}</title>
|
245 | </head>
|
246 | <body>
|
247 | {+bodyContent/}
|
248 | </body>
|
249 | </html>
|
250 | ```
|
251 |
|
252 | ```html
|
253 | <!-- view/home.dust -->
|
254 | {>"layout"/}
|
255 |
|
256 | {<bodyContent}
|
257 | <p>This is the home page!</p>
|
258 | {/bodyContent}
|
259 | ```
|
260 |
|
261 | Dust will combine the templates and render:
|
262 |
|
263 | ```html
|
264 | <!DOCTYPE html>
|
265 | <html lang="en">
|
266 | <head>
|
267 | <title>Hello World!</title>
|
268 | </head>
|
269 | <body>
|
270 | <p>This is the home page!</p>
|
271 | </body>
|
272 | </html>
|
273 | ```
|
274 |
|
275 |
|
276 | Built-In Dust Extensions
|
277 | ------------------------
|
278 |
|
279 | For when basic logic isn't enough, you can use helpers and filters to extend Dust. Although templates should ideally contain as little logic as possible, sometimes you can't get away from it.
|
280 |
|
281 | Dust helpers can run on a block of HTML:
|
282 |
|
283 | ```html
|
284 | {@helper}HTML to run the helper on{/helper}
|
285 | ```
|
286 |
|
287 | Or by themselves to output content:
|
288 |
|
289 | ```html
|
290 | {@helper/}
|
291 | ```
|
292 |
|
293 | They are also configurable with parameters:
|
294 |
|
295 | ```html
|
296 | {@helper param="value"/}
|
297 | ```
|
298 |
|
299 | Filters are different – they operate on existing values:
|
300 |
|
301 | ```html
|
302 | {myProperty|filter}
|
303 | ```
|
304 |
|
305 | Filters are chainable:
|
306 |
|
307 | ```html
|
308 | {myProperty|filter1|filter2}
|
309 | ```
|
310 |
|
311 | Shunter includes the full set of [officially supported Dust helpers](http://www.dustjs.com/guides/dust-helpers/). These add a lot of power to the language.
|
312 |
|
313 | As well as including the official helpers and filters, Shunter comes bundled with some additional ones:
|
314 |
|
315 | ### The `assetPath` Helper
|
316 |
|
317 | The `assetPath` helper is used to output the correct paths to MD5-fingerprinted assets. It's required for your application to run in production.
|
318 |
|
319 | `assetPath` accepts a `src` parameter which should be set to the non-fingerprinted path:
|
320 |
|
321 | ```html
|
322 | <link rel="stylesheet" href="{@assetPath src="main.css"/}"/>
|
323 | ```
|
324 |
|
325 | ### The `and` Helper
|
326 |
|
327 | The `and` helper is used to check whether several properties are all truthy. It accepts a `keys` parameter which should be a pipe-separated list of properties to check. If all of them are truthy, the helper block will be output:
|
328 |
|
329 | ```html
|
330 | {@and keys="foo|bar"}
|
331 | Output if `foo` and `bar` are both truthy
|
332 | {/and}
|
333 | ```
|
334 |
|
335 | The `and` helper supports an `{:else}` block:
|
336 |
|
337 | ```html
|
338 | {@and keys="foo|bar"}
|
339 | Output if `foo` and `bar` are both truthy
|
340 | {:else}
|
341 | Output if either `foo` or `bar` are falsy
|
342 | {/and}
|
343 | ```
|
344 |
|
345 | Also if the `not` parameter is `true`, the behaviour of the helper is inverted:
|
346 |
|
347 | ```html
|
348 | {@and keys="foo|bar" not=true}
|
349 | Output if `foo` and `bar` are both falsy
|
350 | {/and}
|
351 | ```
|
352 |
|
353 | ### The `or` Helper
|
354 |
|
355 | The `or` helper is used to check whether one of the given properties are truthy. It accepts a `keys` parameter which should be a pipe-separated list of properties to check. If at least one of them is truthy, the helper block will be output:
|
356 |
|
357 | ```html
|
358 | {@or keys="foo|bar"}
|
359 | Output if either `foo` or `bar` are truthy
|
360 | {/or}
|
361 | ```
|
362 |
|
363 | The `or` helper supports an `{:else}` block:
|
364 |
|
365 | ```html
|
366 | {@or keys="foo|bar"}
|
367 | Output if either `foo` or `bar` are truthy
|
368 | {:else}
|
369 | Output if `foo` and `bar` are both falsy
|
370 | {/or}
|
371 | ```
|
372 |
|
373 | Also if the `not` parameter is `true`, the `or` helper will render the block if at least one of the properties is _falsy_:
|
374 |
|
375 | ```html
|
376 | {@or keys="foo|bar" not=true}
|
377 | Output if either `foo` or `bar` are falsy
|
378 | {/or}
|
379 | ```
|
380 |
|
381 | ### The `dateFormat` Helper
|
382 |
|
383 | The `dateFormat` helper is used to format dates. It accepts two parameters: `date` and `format`. The `date` parameter expects a date string, and the `format` should be a formatting string supported by the [node-dateformat library](https://github.com/felixge/node-dateformat):
|
384 |
|
385 | ```html
|
386 | {@dateFormat date="2015-09-14" format="dd mmmm yyyy"/}
|
387 | <!-- Outputs: "14 September 2015" -->
|
388 | ```
|
389 |
|
390 | ### The `numberFormat` Helper
|
391 |
|
392 | The `numberFormat` helper is used to format numbers. It accepts a single parameter (`num`) and outputs the given number with thousands seperators:
|
393 |
|
394 | ```html
|
395 | {@numberFormat num="1000000"/}
|
396 | <!-- Outputs: "1,000,000" -->
|
397 | ```
|
398 |
|
399 | ### The `lower` Filter
|
400 |
|
401 | The `lower` filter takes a property and lowercases the value. If `foo` is `Hello World`:
|
402 |
|
403 | ```html
|
404 | {foo|lower}
|
405 | <!-- Outputs: "hello world" -->
|
406 | ```
|
407 |
|
408 | ### The `upper` Filter
|
409 |
|
410 | The `upper` filter takes a property and uppercases the value. If `foo` is `Hello World`:
|
411 |
|
412 | ```html
|
413 | {foo|upper}
|
414 | <!-- Outputs: "HELLO WORLD" -->
|
415 | ```
|
416 |
|
417 | ### The `title` Filter
|
418 |
|
419 | The `title` filter takes a property and titlecases the value. If `foo` is `hello world`:
|
420 |
|
421 | ```html
|
422 | {foo|title}
|
423 | <!-- Outputs: "Hello World" -->
|
424 | ```
|
425 |
|
426 | ### The `trim` Filter
|
427 |
|
428 | The `trim` filter takes a property and strips leading and trailing whitespace from the value. If `foo` is `\r\n \thello world\n`:
|
429 |
|
430 | ```html
|
431 | {foo|trim}
|
432 | <!-- Outputs: "hello world" -->
|
433 | ```
|
434 |
|
435 | ### The `amp` Filter
|
436 |
|
437 | The `amp` filter replaces ampersands in a property with HTML entities, but ignores ampersands that are the opening for an existing entity. If `foo` is `Hello World & Everyone…`:
|
438 |
|
439 | ```html
|
440 | {foo|amp}
|
441 | <!-- Outputs: "Hello World & Everyone…" -->
|
442 | ```
|
443 |
|
444 | Note that the `…` has not been touched.
|
445 |
|
446 | ### The `stripTags` Filter
|
447 |
|
448 | The `stripTags` filter strips HTML open/close tags from a string. If `foo` is `<p>Hello <i>World</i></p>`:
|
449 |
|
450 | ```html
|
451 | {foo|stripTags}
|
452 | <!-- Outputs: "Hello World" -->
|
453 | ```
|
454 |
|
455 | ### The `html` Filter
|
456 |
|
457 | The `html` filter encodes HTML special characters `<>&"'` as HTML entities. It will also ignore ampersands that are the opening for an existing entity, in the same way as the `amp` filter. If `foo` is `Hello <i>World</i> & "Everyone"`:
|
458 |
|
459 | ```html
|
460 | {foo|html}
|
461 | <!-- Outputs: "Hello <i>World</i> & "Everyone"" -->
|
462 | ```
|
463 |
|
464 |
|
465 | Writing Dust Extensions
|
466 | -----------------------
|
467 |
|
468 | It's also possible to write your own Dust helpers and filters to use in your Shunter application. Dust extensions live in the `dust` directory of your application and must export a single function:
|
469 |
|
470 | ```js
|
471 | module.exports = function(dust) {
|
472 | // `dust.helpers` = an object to add helpers to
|
473 | // `dust.filters` = an object to add filters to
|
474 | };
|
475 | ```
|
476 |
|
477 | An example helper might look like the following, which outputs the current year:
|
478 |
|
479 | ```js
|
480 | // <app>/dust/current-year.js
|
481 | module.exports = function(dust) {
|
482 | dust.helpers.currentYear = function(chunk) {
|
483 | var date = new Date();
|
484 | return chunk.write(date.getFullYear());
|
485 | };
|
486 | };
|
487 | ```
|
488 |
|
489 | An example filter might look like the following, which reverses a string and outputs it:
|
490 |
|
491 | ```js
|
492 | // <app>/dust/reverse.js
|
493 | module.exports = function(dust) {
|
494 | dust.filters.reverse = function(value) {
|
495 | return value.split('').reverse().join('');
|
496 | };
|
497 | };
|
498 | ```
|
499 |
|
500 | Dust helpers and filters can also access the Shunter renderer and config objects by accepting more arguments in the exported function:
|
501 |
|
502 | ```js
|
503 | module.exports = function(dust, renderer, config) {
|
504 | // `renderer` = the Shunter renderer object
|
505 | // `config` = the Shunter application configuration
|
506 | };
|
507 | ```
|
508 |
|
509 | Dust has excellent documentation on how to write both [helpers](http://www.dustjs.com/docs/helper-api/) and [filters](http://www.dustjs.com/docs/filter-api/). You should follow these guides if you want to learn how to write helpers that leverage parameters and blocks.
|
510 |
|
511 |
|
512 | ---
|
513 |
|
514 | Related:
|
515 |
|
516 | - [Full API Documentation](index.md)
|