forked from twigkit/tempo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
766 lines (666 loc) · 34.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>Tempo :: The Intuitive JavaScript Template Engine by Twigkit</title>
<link rel="stylesheet" href="css/tempo.css" type="text/css" media="screen">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
<script type="text/javascript" src="tempo.js"></script>
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<style>
ol#tweets {
margin: 0;
}
ol#tweets li {
overflow: hidden;
list-style: none outside none;
}
ol#tweets li img {
float: left;
margin-right: 10px;
width: 48px;
height: 48px;
}
ol#tweets li h3 {
margin: 0;
font-size: 0.9em;
font-family: Helvetica;
font-weight: bold;
}
ol#tweets li p span {
font-size: 0.8em;
}
ol#tweets li p {
font-size: 0.9em;
color: #666;
}
ol#tweets li:last-child p {
margin-bottom: 0;
}
</style>
<script>
$(document).ready(function() {
// jQuery example
var twitter = Tempo.prepare('tweets');
$.getJSON("http://search.twitter.com/search.json?q='groucho marx'&rpp=2&callback=?", function(data) {
twitter.render(data.results);
});
});
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-10163369-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<!-- AdPacks.com Ad Code -->
<script type="text/javascript">
(function(){
var bsa = document.createElement('script');
bsa.type = 'text/javascript';
bsa.async = true;
bsa.src = '//s3.buysellads.com/ac/bsa.js';
(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(bsa);
})();
</script>
<!-- End AdPacks.com Ad Code -->
<div id="top"> </div>
<header id="overview">
<section id="hero">
<h1>Tempo <span class="version" style="font-size: 0.5em;">2.0</span></h1>
<p>Tempo is an easy, intuitive JavaScript rendering engine that enables you to craft data templates in pure HTML.</p>
<nav id="actions">
<ul>
<li class="download"><a href="https://github.com/twigkit/tempo/archive/2.0.zip">Download</a></li>
<li><a href="examples/twitter/">Twitter Example</a></li>
<li><a href="examples/solr/">Solr Example</a></li>
<!-- <li><a href="examples/cloudsearch">CloudSearch Example</a></li> -->
<li><a href="https://github.com/twigkit/tempo">GitHub</a></li>
</ul>
</nav>
<h3>Why use Tempo?</h3>
<ul id="why">
<li>Clear separation of concerns: no HTML in your JavaScript files, and no JavaScript in your HTML</li>
<li>Makes working with AJAX/JSON content a piece of cake</li>
<li>Works in Safari, Chrome, FireFox, Opera, and Internet Explorer 6+</li>
</ul>
<h3>Key Features</h3>
<ul id="features">
<li>Itty-bitty footprint, lightning-fast rendering!</li>
<li>No dependencies - Use with or without jQuery</li>
<li>Supports <a href="#partial-templates">partial</a>, <a href="#nested-templates">nested</a> and <a href="#conditional-templates">conditional</a> templates</li>
<li>Support for <a href="#preprocessing">pre-processing</a>, <a href="#filter-functions">filter and formatting</a> functions and safe <a href="#attribute-setters">attribute setters</a></li>
<li>Variable <a href="#inline-injection">injection</a> for inline JavaScript expressions</li>
<li>Degrades <a href="#template-fallback">gracefully</a> if JavaScript is not enabled</li>
<li>Configurable <a href="#configurable-syntax">syntax</a> for greater compatibility</li>
</ul>
</section>
<aside id="example">
<h3><span>1.</span> Include the Tempo script</h3>
<pre>
<script src="<em>js/tempo.js</em>" type="text/javascript"></script>
<span><script></span>Tempo.<em>prepare</em>("tweets").<em>render</em>(data);<span></script></span>
</pre>
<h3><span>2.</span> Compose the data template inline in HTML</h3>
<pre>
<ol id="tweets">
<li <em>data-template</em>>
<img <em>src</em>="default.png" <em>data-src</em>="<em>{{profile_image_url}}</em>" />
<h3><em>{{from_user}}</em></h3>
<p><em>{{text}}</em><span><em>, {{created_at|date 'HH:mm on EEEE'}}</em></span></p>
</li>
<li <em>data-template-fallback</em>>Sorry, JavaScript required!</li>
</ol>
</pre>
<h3><span>3.</span> Booyah!</h3>
<div class="example">
<ol id="tweets">
<li data-template style="display: none;">
<img src="examples/images/tweeter.png" data-src="{{profile_image_url}}" />
<h3>{{from_user}}</h3>
<p>{{text}}<span>, {{created_at | date 'HH:mm on EEEE'}}</span></p>
</li>
<li data-template-fallback>Sorry, JavaScript required!</li>
</ol>
</div>
</aside>
</header>
<article id="usage">
<header>
<div>
<section>
<h2>Usage</h2>
<nav>
<ul>
<li><a href="#json">JSON</a></li>
<li><a href="#javascript">JavaScript</a></li>
<li><a href="#html">HTML</a></li>
<li><a href="#preprocessing">Pre-processing and Event Handling</a></li>
<li><a href="#jquery">jQuery</a></li>
<li><a href="#advanced">Advanced Topics</a></li>
</ul>
</nav>
</section>
</div>
</header>
<div class="usage">
<section class="usage">
<a id="json"></a>
<h3>JSON</h3>
<p>Tempo takes information encoded as JSON and renders it according to an HTML template. Below is a sample array of JSON data.</p>
<pre>
var data = [
{'name':{'first':'Leonard','last':'Marx'},'nickname':'Chico','born':'March 21, 1887','actor': true,'solo_endeavours':[{'title':'Papa Romani'}]},
{'name':{'first':'Adolph','last':'Marx'},'nickname':'Harpo','born':'November 23, 1888','actor':true,'solo_endeavours':[{'title':'Too Many Kisses','rating':'favourite'},{'title':'Stage Door Canteen'}]},
{'name':{'first':'Julius Henry','last':'Marx'},'nickname':'Groucho','born': 'October 2, 1890','actor':true,'solo_endeavours':[{'title':'Copacabana'},{'title':'Mr. Music','rating':'favourite'},{'title':'Double Dynamite'}]},
{'name':{'first':'Milton','last':'Marx'},'nickname':'Gummo','born':'October 23, 1892'},
{'name':{'first':'Herbert','last':'Marx'},'nickname':'Zeppo','born':'February 25, 1901','actor':true,'solo_endeavours':[{'title':'A Kiss in the Dark'}]}
];
</pre>
<a id="javascript"></a>
<h3>JavaScript</h3>
<h4>Include script</h4>
<p>You only need to include one little script.</p>
<pre>
<script src="<em>js/tempo.js</em>" type="text/javascript"></script>
</pre>
<h4>Tempo.prepare(element)</h4>
<p>To initialize Tempo, run the <code>prepare()</code> function to scan an HTML container for data templates, cache them in memory, and remove the data template HTML elements from the page. <code>Tempo.prepare(element)</code> returns an instance of a renderer that knows how to layout the data you provide to it.</p>
<h5>element</h5>
<p class="h5">The <strong>ID</strong> of the HTML element (or the element itself) containing your data template. If you're using jQuery, you may pass in a jQuery object instead.</p>
<p>If the container does not contain a default (that is without conditions and not nested) <code>data-template</code> the entire contents of the container will be considered to represent the template.</p>
<h4>template.render()</h4>
<p>The Tempo.prepare() function returns an instance of a template ready for rendering. Once the JSON data is available, run the <code>render(data)</code> function to add the data to the page.</p>
<h5>data</h5>
<p class="h5">The JSON <strong>data</strong> to be rendered. You'll first need to perform an AJAX call to the JSON data source (see below).</p>
<pre>
Tempo.prepare( <em>element</em> ).render( <em>data</em> );
</pre>
<pre>
Tempo.prepare('marx-brothers').render(data);
</pre>
<h4>template.append()</h4>
<p>Renderer methods all return an instance of the renderer (a la fluent) so you can chain calls to it. The <code>append(data)</code> function will render the data you pass in and append it to the container.</p>
<h5>data</h5>
<p class="h5">The JSON <strong>data</strong> to append.</p>
<pre>
Tempo.prepare('marx-brothers').render( data )<em>.append( more_brothers )</em>;
</pre>
<h4>template.prepend()</h4>
<p>The <code>prepend(data)</code> function will render the data you pass in and insert it before others in the container.</p>
<h5>data</h5>
<p class="h5">The JSON <strong>data</strong> to prepend.</p>
<pre>
Tempo.prepare('marx-brothers').render( data )<em>.prepend( brothers_we_didnt_know_about )</em>;
</pre>
<h4>template.clear()</h4>
<p>The <code>clear()</code> function will empty the container, allowing you to render the data again.</p>
<pre>
Tempo.prepare('marx-brothers').render( data )<em>.clear()</em>;
</pre>
<h4>template.errors(errorHandler)</h4>
<p>Tempo will attempt to deal with errors and failures silently but you can pass in your own handler for exceptions:</p>
<h5>errorHandler</h5>
<p class="h5">A function which will be called with the error object from the <code>try/catch</code> block.</p>
<pre>
Tempo.prepare('list').errors(function (err) {
console.log('Whoa! something happened!');
console.log(err);
}).render(data);
</pre>
<h4>template.into(container)</h4>
<p>The <code>into(element)</code> function will allow you to render the original template to one or more different containers specified. The method will return a new template on which you can call the other template methods such as <code>render()</code> or <code>append()</code>.</p>
<h5>container</h5>
<p class="h5">The container to render the template to.</p>
<h6>Render to different container:</h6>
<pre>
Tempo.prepare('marx-brothers')<em>.into('alternative-container')</em>.render( data );
</pre>
<h6>Reuse template for multiple different containers:</h6>
<pre>
var template = Tempo.prepare('marx-brothers');
template<em>.into('alternative-container')</em>.render( data_1 );
template<em>.into('yet-another-alternative-container')</em>.render( data_2 );
</pre>
<a id="html"></a>
<h3>HTML</h3>
<h4>data-template</h4>
<p>Any tag with the <code>data-template</code> attribute will be flagged as a data template.</p>
<p>For compliance the full (non-minimized) form is also supported: <code>data-template="data-template"</code>.</p>
<h4>{{fields}}</h4>
<p>Any field represented in the JSON data may be retrieved by referencing the field name inside double brackets.</p>
<pre>
<ol id="marx-brothers">
<li <em>data-template</em>><em>{{nickname}}</em> <em>{{name.last}}</em></li>
</ol>
</pre>
<p>The above example would be rendered as:</p>
<div class="example">
<ol id="marx-brothers">
<li data-template="">Chico Marx</li>
<li data-template="">Harpo Marx</li>
<li data-template="">Groucho Marx</li>
<li data-template="">Gummo Marx</li>
<li data-template="">Zeppo Marx</li>
</ol>
</div>
<p>You can reference the object being iterated with <em>{{.}}</em>:
<div class="example">
var data = [
'Leonard Marx',
'Adolph Marx',
'Julius Henry Marx',
'Milton Marx',
'Herbert Marx'
];
</div>
<pre>
<ol id="marx-brothers">
<li <em>data-template</em>><em>{{.}}</em></li>
</ol>
</pre>
<p>If the JSON data represents an array of arrays (which can not be referenced by field/member name) for example:</p>
<div class="example">
var data = [
['Leonard','Marx'],
['Adolph','Marx'],
['Julius Henry','Marx'],
['Milton','Marx'],
['Herbert','Marx']
];
</div>
<p>You can reference array elements with the following notation:</p>
<pre>
<ol id="marx-brothers">
<li <em>data-template</em>><em>{{[0]}}</em> <em>{{[1]}}</em></li>
</ol>
</pre>
<p>Both examples above would be rendered as:</p>
<div class="example">
<ol id="marx-brothers_from_array">
<li data-template="">Leonard Marx</li>
<li data-template="">Adolph Marx</li>
<li data-template="">Julius Henry Marx</li>
<li data-template="">Milton Marx</li>
<li data-template="">Herbert Marx</li>
</ol>
</div>
<a id="data-from-map"></a>
<h4>Using data from associative arrays (objects)</h4>
<p>Normally data being iterated is represented as an array of objects. In some cases however the data is a series of objects in a map:</p>
<pre>
var data = {
'leonard': 'Leonard Marx',
'adolph': 'Adolph Marx',
'julius': 'Julius Henry Marx',
'milton': 'Milton Marx',
'herbert': Herbert Marx'
};
</pre>
<p>In this case you can iterate all the elements using the <code>data-from-map</code> attribute where the key name can be accessed with <code>{{key}}</code> and the value object via <code>{{value}}</code>:</p>
<pre>
<ol id="list">
<li data-template <em>data-from-map</em>>{{<em>value</em>}} - {{<em>key</em> | append '@marx.com'}}</li>
</ol>
</pre>
<h4>Values are escaped by default</h4>
<p>All values are escaped by default. To disable automatic escaping pass in the <code>'escape': false</code> parameter:</p>
<pre>
Tempo.prepare('marx-brothers', <em>{'escape': false}</em>).render(data);
</pre>
<p>If you disable escaping you can control this at individual value level using the <code><a href="#filter-functions">escape</a></code> and <code><a href="#filter-functions">encodeURI</a></code> filters.</p>
<a id="nested-templates"></a>
<h4>Nested data-templates</h4>
<p>Data templates can even be nested within other data templates. Multiple nested templates are supported.</p>
<pre>
<li <em>data-template</em>>
<em>{{nickname}}</em> <em>{{name.last}}</em>
<ul>
<li <em>data-template-for</em>="solo_endeavours"><em>{{title}}</em></li>
</ul>
</li>
</pre>
<div class="example">
<ol id="marx-brothers_nested">
<li>Chico Marx
<ul>
<li>Papa Romani</li>
</ul>
</li>
<li>Harpo Marx
<ul>
<li>Too Many Kisses</li>
<li>Stage Door Canteen</li>
</ul>
</li>
<li>Groucho Marx
<ul>
<li>Copacabana</li>
<li>Mr. Music</li>
<li>Double Dynamite </li>
</ul>
</li>
<li>Gummo Marx</li>
<li>Zeppo Marx
<ul>
<li>A Kiss in the Dark</li>
</ul>
</li>
</ol>
</div>
<p>You can (recursively) refer to parent objects within a nested template using the <code>_parent</code> variable.</p>
<pre>
<li <em>data-template-for</em>="solo_endeavours">{{<em>_parent</em>.name.first}} acted in {{title}}</li>
</pre>
<a id="partial-templates"></a>
<h4>Nested Templates as Partial Template Files</h4>
<p>Tempo supports separating more complex nested templates in to master and partial template files. Partials templates are loaded on demand from the server and do require you to use the alternative asynchronous pattern:</p>
<h6>JavaScript:</h6>
<pre>
Tempo.prepare('marx-brothers'<em>, <a href="#configurable-syntax">{}</a>, function(template)</em> {
<em>template.render(data);</em>
});
</pre>
<h6>Template:</h6>
<pre>
<li data-template>
{{name.first}} {{name.last}}
<ol>
<li data-template-for="solo_endeavours" <em>data-template-file=</em>"partials/movie.html"></li>
</ol>
</li>
</pre>
<h6>Partial ('partials/movie.html'):</h6>
<pre>
{{title}}
</pre>
<div class="example">
<ol id="marx-brothers_partial">
<li>Chico Marx
<ul>
<li>Papa Romani</li>
</ul>
</li>
<li>Harpo Marx
<ul>
<li>Too Many Kisses</li>
<li>Stage Door Canteen</li>
</ul>
</li>
<li>Groucho Marx
<ul>
<li>Copacabana</li>
<li>Mr. Music</li>
<li>Double Dynamite </li>
</ul>
</li>
<li>Gummo Marx</li>
<li>Zeppo Marx
<ul>
<li>A Kiss in the Dark</li>
</ul>
</li>
</ol>
</div>
<a id="conditional-templates"></a>
<h4>Conditional Templates</h4>
<p>Tempo provides boolean and value-based conditionals, as well as the ability to define multiple data templates per container (the first matching template wins).</p>
<pre>
<ul id="marx-brothers3">
<li <em>data-template</em> <em>data-if-nickname</em>="Groucho""><em>{{nickname}}</em> (aka <em>{{name.first}}</em>) was grumpy!</li>
<li <em>data-template</em> <em>data-if-actor</em>><em>{{name.first}}</em>, nicknamed '<i><em>{{nickname}}</em> <em>{{name.last}}</em></i>' was born on <em>{{born}}</em></li>
<!-- Default template -->
<li <em>data-template</em>><em>{{name.first}}</em> <em>{{name.last}}</em> was not in any movies!</li>
</ul>
</pre>
<div class="example">
<ul id="marx-brothers4">
<li>Leonard, nicknamed '<i>Chico Marx</i>' was born on March 21, 1887</li>
<li>Adolph, nicknamed '<i>Harpo Marx</i>' was born on November 23, 1888</li>
<li>Groucho (aka Julius Henry) was grumpy!</li>
<li>Milton Marx was not in any movies!</li>
<li>Herbert, nicknamed '<i>Zeppo Marx</i>' was born on February 25, 1901</li>
</ul>
</div>
<p>You can define templates based on data member existence as well:</p>
<pre>
<li data-template <em>data-has=</em>"friend">{{friend}}></li>
</pre>
<a id="template-fallback"></a>
<h4>Fallback Template</h4>
<p>Use the <code>data-template-fallback</code> attribute to identify HTML containers you would like to show if JavaScript is disabled.</p>
<p>To ensure that your data template is not visible before being rendered (either because of JavaScript being disabled or due to latency retrieving the data), it's best practice to hide your templates with CSS. If you add an inline rule of <code>style="display: none;"</code> Tempo will simply remove the inline rule once the data has been rendered.</p>
<pre>
<ul id="marx-brothers">
<li <em>data-template style="display: none;"</em>>{{nickname}} {{name.last}}</li>
<li <em>data-template-fallback</em>>Sorry, JavaScript required!</li>
</ul>
</pre>
<p>If JavaScript is disabled in the browser the above example would be rendered as:</p>
<div class="example">
<ul id="marx-brothers_with_fallback">
<li data-template-fallback>Sorry, JavaScript required!</li>
</ul>
</div>
<a id="template-before-after"></a>
<h4>Preserving other elements in the template container</h4>
<p>If the template container contains other elements that should be preserved or ignored you can mark these with the <code>data-before-template</code> and <code>data-after-template</code> attributes:</p>
<pre>
<ol id="marx-brothers">
<li <em>data-before-template</em>>...</li>
<li data-template>{{name.first}} {{name.last}}</em></li>
<li <em>data-after-template</em>>...</li>
</ol>
</pre>
<a id="filter-functions"></a>
<h4>Filter and Formatting Functions</h4>
<p>Tempo supports a number of filter functions to modify individual values before they are rendered. Filters can be chained to apply multiple ones to the same value.</p>
<h5><code>{{ field | <em>escape</em> }}</code></h5>
<p class="h5">Escape HTML characters before rendering to page.</p>
<h5><code>{{ field | <em>encodeURI</em> }}</code></h5>
<p class="h5">Encodes a Uniform Resource Identifier (URI) by replacing certain characters with escape sequences representing the UTF-8 encoding of the character.</p>
<h5><code>{{ field | <em>decodeURI</em> }}</code></h5>
<p class="h5">Replaces each escape sequence in an encoded URI with the character that it represents.</p>
<h5><code>{{ field | <em>truncate 25</em>[, 'optional_suffix'] }}</code></h5>
<p class="h5">If the value of this field is longer than 25 characters, then truncate to the length provided. If a second argument is provided then it is used as the suffix instead of the default ellipsis (...).</p>
<h5><code>{{ field | <em>format[, numberOfDecimals]</em> }}</code></h5>
<p class="h5">Currently only formats numbers like 100000.25 by adding commas: 100,000.25. You can optionally specify the number of decimals to use.</p>
<h5><code>{{ field | <em>default 'default value'</em> }}</code></h5>
<p class="h5">If the field is undefined, or null, then show the default value specified.</p>
<h5><code>{{ field | <em>date 'preset or pattern like HH:mm, DD-MM-YYYY'[, 'UTC']</em> }}</code></h5>
<p class="h5">Creates a date object from the field value, and formats according to presets, or using a date pattern. Available presets are <code>localedate</code>, <code>localetime</code>, <code>date</code> and <code>time</code>. The following pattern elements are supported:</p>
<ul class="h5">
<li><code>YYYY or YY</code>: year as 4 or 2 digits.</li>
<li><code>MMMM, MMM, MM or M</code>: month of the year as either full name (September), abbreviated (Sep), padded two digit number or simple integer.</li>
<li><code>DD or D</code>: day of the month.</li>
<li><code>EEEE, EEE or E</code>: day of the week as either full (Tuesday), abbreviated (Tue) or number.</li>
<li><code>HH, H or h</code>: hour of the day.</li>
<li><code>mm or m</code>: minutes of the hour.</li>
<li><code>ss or s</code>: seconds.</li>
<li><code>SSS or S</code>: milliseconds.</li>
<li><code>a</code>: AM/PM.</li>
</ul>
<p class="h5">If you would like to use any of the format characters verbatim in the pattern then use <code>\</code> to escape: <code>{{ some_date | date '\at HH:mm' }}</code>. In this case the <code>a</code> is not replaced with AM/PM. Additionally you can specify whether dates should be handled as UTC.</p>
<h5><code>{{ field | <em>replace 'regex_pattern', 'replacement'</em> }}</code></h5>
<p class="h5">Replace all occurrences of the pattern (supports regular expressions) with the replacement. Replacement string can contain backreferences. See <a href="examples/twitter/">Twitter code sample</a> for an example.</p>
<h5><code>{{ field | <em>trim</em> }}</code></h5>
<p class="h5">Trim any white space at the beginning or end of the value.</p>
<h5><code>{{ field | <em>upper</em> }}</code></h5>
<p class="h5">Change any lower case characters in the value to upper case.</p>
<h5><code>{{ field | <em>lower</em> }}</code></h5>
<p class="h5">Change any upper case characters in the value to lower case.</p>
<h5><code>{{ field | <em>titlecase[, 'and for the']</em> }}</code></h5>
<p class="h5">Format strings to title case, with an optional blacklist of words that should not be titled (unless first in string e.g. 'the last of the mohicans' to 'The Last of the Mohicans'). See <a href="http://jsfiddle.net/gh/get/jquery/1.8/twigkit/tempo/tree/dev-2.0/examples/fiddles/filters/titlecase/" target="_blank">example</a>.</p>
<h5><code>{{ field | <em>append '&nbsp;some suffix'</em> }}</code></h5>
<p class="h5">If the field value is not empty, then append the string to the value. Helpful if you don't want the suffix to show up in the template if the field is undefined or null. Use &nbsp; if you need before or after the suffix.</p>
<h5><code>{{ field | <em>prepend 'some prefix&nbsp;'</em> }}</code></h5>
<p class="h5">If the field value is not empty, then prepend the string to the value. Helpful if you don't want the prefix to show up in the template if the field is undefined or null. Use &nbsp; if you need before or after the prefix.</p>
<h5><code>{{ field | <em>join 'separator'</em> }}</code></h5>
<p class="h5">If the field is an array joins the elements into a string using the supplied separator.</p>
<a id="attribute-setters"></a>
<h4>Attribute Setters</h4>
<p>If an HTML element attribute in a template is immediately followed by a second attribute with the same name, prefixed with <code>data-</code>, then as long as the second one is not empty will the value of the original be replaced with the value of the latter.</p>
<p>In the following example, will the reference to <code>default_image.png</code> be replaced by an actual field value if one exists. Notice here that the <code>.png</code> suffix is only added if the field is not empty.</p>
<pre>
<img <em>src</em>="<em>default_image.png</em>" <em>data-src</em>="<em>{{actual_image_if_exists | append '.png'}}</em>" ... />
</pre>
<h4>Template Tags</h4>
<p>Tempo also supports tag blocks.</p>
<h5><code>{% if <i>javascript-expression</i> %} ... {% else %} ... {% endif %}</code></h5>
<p class="h5">The body of the tag will only be rendered if the JavaScript expression evaluates to true. The <code>{% else %}</code> is optional.</p>
<a id="inline-injection"></a>
<h4>Variable injection for inline scripts</h4>
<p>If you're using scripts inline in your template, you can access JSON object members. You reference these via the <code>__</code> variable.</p>
<pre>
<a href="#" onclick="alert(<em>__.nickname</em>); return false;">{{name.last}}</a>
</pre>
<p>Similarly you can reference array elements (shorthand for for <em>__.this[0]</em>):</p>
<pre>
<a href="#" onclick="alert(<em>__[0]</em>); return false;">{{[0]}}</a>
</pre>
<p>You can refer to the object being iterated with <em>__.this</em>. You can use normal dot notation to access members of that object.:</p>
<pre>
<a href="#" onclick="alert(<em>__.this</em>); return false;">{{.}}</a>
</pre>
<p>At render time the accessor variable will be replaced by the object it references. If the object is a <string>string</string> then its value will be wrapped in single quotes, otherwise type is preserved.</p>
<a id="preprocessing"></a>
<h3>Pre-processing and Event Handling</h3>
<h4>template.when(type, handler)</h4>
<p>After preparing a template you can register one or more event listeners by providing a callback function to be notified of events in the lifecycle.</p>
<h5>type</h5>
<p class="h5">The <strong>type</strong> of the event. Constant values are defined in <code>TempoEvent.Types</code>.</p>
<ul class="h5">
<li><code>TempoEvent.Types.RENDER_STARTING</code>: Indicates that rendering has started, or been manually triggered by calling <code>starting()</code> on the renderer object.</li>
<li><code>TempoEvent.Types.ITEM_RENDER_STARTING</code>: Indicates that the rendering of a given individual item is starting.</li>
<li><code>TempoEvent.Types.ITEM_RENDER_COMPLETE</code>: Indicates that the rendering of a given individual item has completed.</li>
<li><code>TempoEvent.Types.RENDER_COMPLETE</code>: Indicates that the rendering of all items is completed.</li>
<li><code>TempoEvent.Types.BEFORE_CLEAR</code>: Fires before the container is cleared of all elements.</li>
<li><code>TempoEvent.Types.AFTER_CLEAR</code>: Fires after the container is cleared of all elements.</li>
</ul>
<h5>handler</h5>
<p class="h5">The <strong>handler</strong> function to call when the specified event fires.</p>
<p>The event listener will be called with a single argument, a <code>TempoEvent</code> which has the following properties:</p>
<h5>type</h5>
<p class="h5">The <strong>type</strong> of the event. Constant values are defined in <code>TempoEvent.Types</code>.</p>
<h5>item</h5>
<p class="h5">The <strong>item</strong> being rendered. This is only available for the <code>ITEM_RENDER_STARTING</code> and <code>ITEM_RENDER_COMPLETE</code> events.</p>
<h5>element</h5>
<p class="h5">The HTML <strong>element</strong> or template being used for rendering. This is only available for the <code>ITEM_RENDER_STARTING</code> and <code>ITEM_RENDER_COMPLETE</code> events.</p>
<pre>
Tempo.prepare('tweets')<em>.when(TempoEvent.Types.RENDER_STARTING, function (event)</em> {
$('#tweets').addClass('loading');
})<em>.when(TempoEvent.Types.RENDER_COMPLETE, function (event)</em> {
$('#tweets').removeClass('loading');
}).render(data);
</pre>
<p>Even though it's possible to modify the DOM via event handlers it's worth keeping in mind that Tempo is built on the premise of keeping the templates as semantic and readable as possible. We would therefore advise that you limit the use or pre-processing to data cleansing and restructuring as opposed to template modifications.</p>
<h4>starting()</h4>
<p>In some cases you prepare the templates ahead of calling render. In those cases if you would like to e.g. set loader graphics, call the renderer's <code>starting()</code> method just prior to issuing e.g. a jQuery request. This will fire the <code>ITEM_RENDER_STARTING</code> event.</p>
<p>The following example demonstrates use of both methods above. In this case we prepare the templates, and register our event handler function. The event handler is then notified that the jQuery request is about to be issued (when we manually fire <code>RENDER_STARTING</code> with a call to <code>starting()</code>) adding a CSS class to the container. We are then notified that rendering is complete so we can remove the CSS class.
<pre>
var twitter = Tempo.prepare('tweets')<em>.when(TempoEvent.Types.RENDER_STARTING, function (event)</em> {
$('#tweets').addClass('loading');
})<em>.when(TempoEvent.Types.RENDER_COMPLETE, function (event)</em> {
$('#tweets').removeClass('loading');
});
twitter.<em>starting</em>();
$.getJSON(url, function(data) {
twitter.render(data.results);
});
</pre>
<a id="jquery"></a>
<h3>Using Tempo with jQuery</h3>
<p>jQuery's <a href="http://api.jquery.com/jQuery.getJSON/">getJSON()</a> method provides an easy means of loading JSON-encoded data from the server using a GET HTTP request.</p>
<pre>
var twitter = Tempo.<em>prepare</em>('tweets');
$.getJSON("http://search.twitter.com/search.json?q='marx brothers'&callback=?", function(data) {
twitter.<em>render</em>(data.results);
});
</pre>
<h4>Binding event handlers</h4>
<p>
Note that if you've bound event listeners to elements in your template, these will <b>not</b> be cloned when the template is used. In order to do this you have two options. <br/>
</p>
<p>
You can either leave binding until the data has been rendered, e.g. by registering a <code>TempoEvent.Types.RENDER_COMPLETE</code> listener and doing the binding when that fires, or you can use jQuery <a href="http://api.jquery.com/live/">live</a> which attaches a handler to elements even though they haven't been created.
</p>
<p>
The following example shows how to make a template clickable (assuming an <code>'ol li'</code> selector provides a reference to a template element) and how to obtain a reference to the clicked element:
</p>
<pre>
$('ol li').live('click', function() {
// Do something with the clicked element
alert(this);
});
</pre>
<a id="advanced"></a>
<h3>Advanced Topics</h3>
<a id="configurable-syntax"></a>
<h4>Configuring the surrounding brace syntax</h4>
<p>
In order to make it easier to use Tempo with other frameworks such as Django, you can configure Tempo to use surrounding braces other than the default <code>{{ ... }}</code> and <code>{% ... %}</code>.
</p>
<p>
To do this you pass the <code>var_braces</code> and <code>tag_braces</code> parameters to the <code>Tempo.prepare</code> function. These will be split down the middle to form the left and right braces.
</p>
<pre>
Tempo.prepare('marx-brothers', <em>{'var_braces' : '\\[\\[\\]\\]', 'tag_braces' : '\\[\\?\\?\\]'}</em>);
</pre>
<p>You can now use this template syntax instead:</p>
<pre>
<ol id="marx-brothers">
<li data-template><em>[[nickname]]</em> is <em>[? if nickname == 'Groucho' ?]</em>grouchy<em>[? else ?]</em>happy<em>[? endif ?]</em>!</li>
</ol>
</pre>
<h4>Tempo Renderer Information - the <code>_tempo</code> variable</h4>
<p>You can access information about the rendering process via the <code>_tempo</code> variable.</p>
<h5>_tempo.index</h5>
<p class="h5">The <code>index</code> variable tells you how many iterations of a given template have been carried out. This is a zero (0) based index. Nested templates have a separate counter.
<p>The following example adds the iteration count to the <code>class</code> attribute, prefixed with '<code>item-</code>':</p>
<pre>
<ol id="marx-brothers" class="item-<em>{{_tempo.index}}</em>">
<li data-template>{{nickname}} {{name.last}}</li>
</ol>
</pre>
<p>This example shows how to access the iteration counter using inline JavaScript injection:</p>
<pre>
<a href="#" onclick="alert(<em>__._tempo.index</em>); return false;">{{name.last}}</a>
</pre>
<h5>_tempo.first</h5>
<p class="h5">True if the item being iterated is the first one in the collection.</p>
<h5>_tempo.last</h5>
<p class="h5">True if the item being iterated is the last one in the collection.</p>
</section>
<aside id="advert">
<div class="ad">
<!-- AdPacks.com Zone Code -->
<div id="bsap_1259205" class="bsarocks bsap_25779f8aebf23dd2e6c5b30743833cb3"></div>
<a href="http://adpacks.com" id="bsap_aplink">via Ad Packs</a>
<!-- End AdPacks.com Zone Code -->
</div>
</aside>
</div>
</article>
<nav id="actions2">
<ul>
<li class="download"><a href="https://github.com/twigkit/tempo/archive/2.0.zip">Download</a></li>
<li><a href="examples/twitter/">Twitter Example</a></li>
<li><a href="examples/solr/">Solr Example</a></li>
<li><a href="https://github.com/twigkit/tempo">View on GitHub</a></li>
</ul>
</nav>
<footer id="bottom">
<section>
<p>Brought to you by the friendly guys at <a href="http://twigkit.com/">Twigkit</a>. Follow <a href="http://twitter.com/mrolafsson">Stefan Olafsson</a> on Twitter.</p>
</section>
</footer>
</body>
</html>