blob: 91464c592994eed3fab0c5c3bff086b155617937 [file] [log] [blame]
Brian Silverman70325d62015-09-20 17:00:43 -04001<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2<html>
3<head>
4<title>Template Examples</title>
5
6<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
7<link href="designstyle.css" type="text/css" rel="stylesheet">
8<style type="text/css">
9 ol.bluelist li {
10 color: #3366ff;
11 font-family: sans-serif;
12 }
13 ol.bluelist li p {
14 color: #000;
15 font-family: "Times Roman", times, serif;
16 }
17 ul.blacklist li {
18 color: #000;
19 font-family: "Times Roman", times, serif;
20 }
21</style>
22</head>
23
24<body>
25
26<h1>Template Examples</h1>
27
28
29<h2> Simple Example </h2>
30
31<p>One reason this example is so simple is that it doesn't even
32require a separate template file, but instead uses
33<code>StringToTemplateCache()</code>. It also doesn't use sections or
34template-includes.</p>
35
36<pre class=example>
37
38int main() {
39 static const char template_text[] =
40 "ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}: {{ERROR_MESSAGE}}\n";
41 ctemplate::StringToTemplateCache("mytpl", template_text, ctemplate::DO_NOT_STRIP);
42 FILE* fp = fopen(argv[1], "r");
43 if (fp == NULL) {
44 int err_no = errno; // squirrel this away
45 ctemplate::TemplateDictionary dict("error_msg: fopen()");
46 dict.SetValue("FUNCTION", "fopen");
47 dict.SetValue("ARGS", argv[1]);
48 dict.SetIntValue("ERROR_CODE", err_no);
49 dict.SetValue("ERROR_MESSAGE", strerror(err_no));
50
51 string error_text;
52 ctemplate::ExpandTemplate("mytpl", ctemplate::DO_NOT_STRIP, &dict, &error_text);
53 puts(error_text.c_str());
54 }
55}
56
57</pre>
58
59Note: If this template was intended to run in a web application, you can
60leverage the functionality provided by the auto-escape mode. Simply add
61the AUTOESCAPE pragma directive at the top of the template text and your
62variables will be automatically escaped for the context you specify.
63
64For example, if your template is returned in an HTML context,
65change the <code>template_text</code> declaration as follows:
66
67<pre class=example>
68 static const char template_text[] =
69 "{{%AUTOESCAPE context=\"HTML\"}}"
70 "ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}: {{ERROR_MESSAGE}}\n";
71</pre>
72
73<p>This example is only slightly more complicated: we only print the
74": &lt;error message&gt;" part when the error message isn't the empty
75string.</p>
76
77<pre class=example>
78
79int main() {
80 static const char template_text[] =
81 "ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}"
82 "{{#MSG_SECTION}}: {{ERROR_MESSAGE}}{{/MSG_SECTION}}\n";
83 ctemplate::StringToTemplateCache("mytpl", template_text, ctemplate::DO_NOT_STRIP);
84 FILE* fp = fopen(argv[1], "r");
85 if (fp == NULL) {
86 int err_no = errno; // squirrel this away
87 ctemplate::TemplateDictionary dict("file_error_message");
88 dict.SetValue("FUNCTION", "fopen");
89 dict.SetValue("ARGS", argv[1]);
90 dict.SetIntValue("ERROR_CODE", err_no);
91 if (err_no > 0)
92 dict.SetValueAndShowSection("ERROR_MESSAGE", strerror(err_no),
93 "MSG_SECTION");
94
95 string error_text;
96 ctemplate::ExpandTemplate("mytpl", ctemplate::DO_NOT_STRIP, &dict, &error_text);
97 puts(error_text.c_str());
98 }
99 delete tpl;
100}
101
102</pre>
103
104<p>This maybe-show-text functionality is one way the template
105machinery is more powerful than just using <code>printf</code>.
106Another nice property of templates is you can reuse the same variable
107multiple times in your template string. You can also define the
108variable values in any order.</p>
109
110
111<h2> Search Results Page </h2>
112
113<p>Here is an example template that could be used to format a Google
114search results page:</p>
115
116<pre class=example>
117
118{{>HEADER}}
119&lt;body bgcolor=white>
120
121{{>PAGE_HEADING}}{{!The following div must be on the same line}}&lt;div>
122
123{{!The ONE_RESULT section displays a single search item}}
124{{#ONE_RESULT}}
125 {{! Note: there are two SUBITEM_SECTIONs. They both show or hide together}}
126 {{#SUBITEM_SECTION}}&lt;blockquote>{{/SUBITEM_SECTION}}
127 {{! LEAD_LINE is received HTML-escaped from the backend.}}
128 &lt;p>&lt;a href="{{JUMP_TO_URL:html_escape}}" target=nw>{{LEAD_LINE}}&lt;/a>&lt;font size=-1>
129
130 {{! SNIPPET1, SNIPPET2 are HTML-escaped in the snippet generator.}}
131 {{#SNIPPET1_SECTION}}
132 &lt;br>{{SNIPPET1}}
133 {{/SNIPPET1_SECTION}}
134
135 {{#SNIPPET2_SECTION}}
136 &lt;br>{{SNIPPET2}}
137 {{/SNIPPET2_SECTION}}
138
139 {{#DESCRIPTION_SECTION}}
140 {{! DESC is received HTML-escaped from the backend.}}
141 &lt;br>&lt;span class=f>Description:&lt;/span> {{DESC}}
142 {{/DESCRIPTION_SECTION}}
143
144 {{#CATEGORY_SECTION}}
145 &lt;br>&lt;span class=f>Category:&lt;/span> &lt;a href="{{CAT_URL:html_escape}}" class=f>
146 {{CATEGORY:html_escape}}&lt;/a>
147 {{/CATEGORY_SECTION}}
148
149 {{#LASTLINE_SECTION}}
150 &lt;br>&lt;font color="{{ALT_TEXT_COLOR:h}}">{{URL:h}}
151 {{#KS_SECTION}}} - {{KSIZE:h}}{{/KS_SECTION}}}
152 {{#CACHE_SECTION}}} - &lt;a href="{{CACHE_URL:h}}" class=f>Cached&lt;/A>
153 {{/CACHE_SECTION}}}
154 {{#SIM_SECTION}}} - &lt;a href="{{SIM_PAGES_URL:h}}" class=f>Similar pages&lt;/A>
155 {{/SIM_SECTION}}}
156
157 {{#STOCK_SECTION}}
158 - &lt;a href="{{STOCK_URL:h}}" class=f>Stock quotes: {{STOCK_SYMBOL:h}}&lt;/a>
159 {{/STOCK_SECTION}}
160 &lt;/font>
161 {{/LASTLINE_SECTION}}
162
163 {{#MORE_SECTION}}
164 &lt;br>[ &lt;a href="{{MORE_URL:h}}" class=f>More results from {{MORE_LABEL:h}}&lt;/a> ]
165 {{/MORE_SECTION}}
166
167 &lt;/font>&lt;br>
168 {{! Note: there are two SUBITEM_SECTIONs. They both show or hide together}}
169 {{#SUBITEM_SECTION}}&lt;/blockquote>{{/SUBITEM_SECTION}}
170{{/ONE_RESULT}}
171&lt;/div> {{! this /div closes the div at the top of this file}}
172{{>PAGE_FOOTING}}
173
174</pre>
175
176<p> Here is a sample procedure that could populate a dictionary for
177expanding that template. The "one procedure" entry point is
178<code>fill_search_results_dictionary</code>. The
179<code>SetTemplateValues</code> function is a separate entry point for
180initializing each top-level template with some standard values.</p>
181
182<pre class=example>
183#include "template.h"
184
185RegisterTemplateFilename(SEARCH_RESULTS_FN, "search_results.tpl");
186#include "search_results.tpl.varnames.h" // defines ksr_HEADER, etc.
187
188using ctemplate::TemplateDictionary;
189using ctemplate::ExpandTemplate;
190using ctemplate::STRIP_WHITESPACE;
191
192// IsEmpty
193// A simple utility function
194static bool IsEmpty(const string &amp;str) {
195 return str.empty();
196}
197
198// SetTemplateValues
199// Use the TemplateDictionary object to set template-wide values that
200// may be used in the top-level template and all its sub-sections
201// and included templates. The template-wide values are all
202// colors from the Palette object
203void SetTemplateValues(TemplateDictionary *dictionary, const Palette* colors) {
204 // better would be to use ksr_LINK_COLOR, etc, assuming those are
205 // defined in search_results.tpl.varnames.h. But using literal
206 // text, as here, is legal as well.
207 dictionary->SetValue("LINK_COLOR", colors->link_color);
208 dictionary->SetValue("BAR_TEXT_COLOR", colors->bar_text_color);
209 dictionary->SetValue("TEXT_COLOR", colors->text_color);
210 dictionary->SetValue("FAINT_COLOR", colors->faint_color);
211 dictionary->SetValue("IMPORTANT_COLOR", colors->important_color);
212 dictionary->SetValue("BAR_COLOR", colors->bar_color);
213 dictionary->SetValue("ALT_TEXT_COLOR", colors->alt_text_color);
214 dictionary->SetValue("ALINK_COLOR", colors->alink_color);
215 dictionary->SetValue("VLINK_COLOR", colors->vlink_color);
216}
217
218// fill_search_results_dictionary
219// Iterates through all the QueryResults contained in the Query object.
220// For each one, it sets corresponding template dictionary values
221// (or hides sections containing their variables, if appropriate) in
222// a sub-dictionary and then adds that dictionary to the parent
223void fill_search_results_dictionary(TemplateDictionary *dictionary,
224 const Query *query) {
225 dictionary->SetFilename(SEARCH_RESULTS_FN);
226
227 // These two functions are defined elsewhere
228 fill_header_dictionary(dictionary->AddIncludeDictionary(ksr_HEADER));
229 fill_page_heading_dictionary(dictionary->AddIncludeDictionary(ksr_PAGE_HEADING),
230 query);
231
232 ResultsList *results = query->GetResults();
233 int resCount = 0;
234
235 for (ResultsList::const_iterator iter = results->begin();
236 iter != results->end();
237 ++iter) {
238 QueryResult *qr = (*iter);
239
240 // Create a new sub-dictionary named "Result Dict &lt;n>" for this entry
241
242 ++resCount;
243
244 TemplateDictionary *result_dictionary =
245 dictionary->AddSectionDictionary(ksr_ONE_RESULT);
246
247 result_dictionary->SetValue(ksr_JUMP_TO_URL, qr->GetUrl());
248
249 if (qr->IsSubItem()) {
250 result_dictionary->ShowSection(ksr_SUBITEM_SECTION);
251 }
252
253 result_dictionary->SetValue(ksr_LEAD_LINE, qr->GetLeadLine());
254
255 result_dictionary->SetValueAndShowSection(ksr_SNIPPET1, qr->GetSnippet1(),
256 ksr_SNIPPET1_SECTION);
257
258 result_dictionary->SetValueAndShowSection(ksr_SNIPPET2, qr->GetSnippet2(),
259 ksr_SNIPPET2_SECTION);
260
261 result_dictionary->SetValueAndShowSection(ksr_DESC, qr->GetDescription(),
262 ksr_DESCRIPTION_SECTION);
263
264 result_dictionary->SetValueAndShowSection(ksr_CAT_URL, qr->GetCategoryUrl(),
265 ksr_CATEGORY_SECTION);
266
267 result_dictionary->SetValueAndShowSection("CATEGORY", qr->GetCategoryName(),
268 "CATEGORY_SECTION");
269
270
271 if (IsEmpty(qr->GetDisplayUrl()) &amp;&amp;
272 IsEmpty(qr->GetPageSize()) &amp;&amp;
273 IsEmpty(qr->GetCachedUrl()) &amp;&amp;
274 IsEmpty(qr->GetSimilarPagesUrl()) &amp;&amp;
275 (IsEmpty(qr->GetStockUrl()) ||
276 IsEmpty(qr->GetStockSymbol())) ) {
277 // there is nothing on the last line, so hide it altogether
278 } else {
279 result_dictionary->ShowSection("LASTLINE_SECTION");
280
281 result_dictionary->SetValue(ksr_URL, qr->GetDisplayUrl());
282
283 result_dictionary->SetValueAndShowSection(ksr_KSIZE, qr->GetPageSize(),
284 ksr_KS_SECTION);
285
286 result_dictionary->SetValueAndShowSection(ksr_CACHE_URL, qr->GetCachedUrl(),
287 ksr_CACHE_SECTION);
288
289 result_dictionary->SetValueAndShowSection(ksr_SIM_PAGES_URL,
290 qr->GetSimilarPagesUrl(),
291 ksr_SIM_SECTION);
292
293 result_dictionary->SetValueAndShowSection(ksr_STOCK_URL, qr->GetStockUrl(),
294 ksr_STOCK_SECTION);
295
296 result_dictionary->SetValueAndShowSection(ksr_STOCK_SYMBOL,
297 qr->GetStockSymbol(),
298 ksr_STOCK_SECTION);
299 }
300
301 result_dictionary->SetValueAndShowSection(ksr_MORE_URL, qr->GetMoreUrl(),
302 ksr_MORE_SECTION);
303
304 result_dictionary->SetValueAndShowSection(ksr_MORE_LABEL, qr->GetMoreLabel(),
305 ksr_MORE_SECTION);
306
307 }
308
309 fill_page_footing_dictionary(dictionary->AddIncludeDictionary(ksr_PAGE_FOOTING),
310 query);
311}
312
313void output_page(const Query* query) {
314 TemplateDictionary dict("search-results dict");
315 string output;
316 fill_search_results_dictionary(&amp;dict, query);
317 ctemplate::ExpandTemplate(SEARCH_RESULTS_FN, STRIP_WHITESPACE, &amp;dict, &amp;output);
318 // output now holds the expanded template
319}
320
321</pre>
322
323
324<hr>
325<ul>
326 <li> <A HREF="guide.html">User's Guide</A> </li>
327 <li> <A HREF="reference.html">Reference Manual</A> </li>
328 <li> <A HREF="auto_escape.html">Auto Escape</A> </li>
329 <li> <A HREF="tips.html">Tips</A> </li>
330<!--
331 <li> <A HREF="example.html">Example</A> </li>
332-->
333</ul>
334
335<hr>
336<address>
337Craig Silverstein<br>
338<script type=text/javascript>
339 var lm = new Date(document.lastModified);
340 document.write(lm.toDateString());
341</script>
342</address>
343
344</body>
345</html>