116 | ```
117 |
118 | Add a file **server.js** with the following content:
119 |
120 | ```js
121 | require('http')
122 | .createServer(function (req, res) {
123 | var fs = require('fs'),
124 | // The tmpl module exports the tmpl() function:
125 | tmpl = require('./tmpl'),
126 | // Use the following version if you installed the package with npm:
127 | // tmpl = require("blueimp-tmpl"),
128 | // Sample data:
129 | data = {
130 | title: 'JavaScript Templates',
131 | url: 'https://github.com/blueimp/JavaScript-Templates',
132 | features: ['lightweight & fast', 'powerful', 'zero dependencies']
133 | }
134 | // Override the template loading method:
135 | tmpl.load = function (id) {
136 | var filename = id + '.html'
137 | console.log('Loading ' + filename)
138 | return fs.readFileSync(filename, 'utf8')
139 | }
140 | res.writeHead(200, { 'Content-Type': 'text/x-tmpl' })
141 | // Render the content:
142 | res.end(tmpl('template', data))
143 | })
144 | .listen(8080, 'localhost')
145 | console.log('Server running at http://localhost:8080/')
146 | ```
147 |
148 | Run the application with the following command:
149 |
150 | ```sh
151 | node server.js
152 | ```
153 |
154 | ## Requirements
155 |
156 | The JavaScript Templates script has zero dependencies.
157 |
158 | ## API
159 |
160 | ### tmpl() function
161 |
162 | The **tmpl()** function is added to the global **window** object and can be
163 | called as global function:
164 |
165 | ```js
166 | var result = tmpl('tmpl-demo', data)
167 | ```
168 |
169 | The **tmpl()** function can be called with the id of a template, or with a
170 | template string:
171 |
172 | ```js
173 | var result = tmpl('
{%=o.title%}
', data)
174 | ```
175 |
176 | If called without second argument, **tmpl()** returns a reusable template
177 | function:
178 |
179 | ```js
180 | var func = tmpl('
{%=o.title%}
')
181 | document.getElementById('result').innerHTML = func(data)
182 | ```
183 |
184 | ### Templates cache
185 |
186 | Templates loaded by id are cached in the map **tmpl.cache**:
187 |
188 | ```js
189 | var func = tmpl('tmpl-demo'), // Loads and parses the template
190 | cached = typeof tmpl.cache['tmpl-demo'] === 'function', // true
191 | result = tmpl('tmpl-demo', data) // Uses cached template function
192 |
193 | tmpl.cache['tmpl-demo'] = null
194 | result = tmpl('tmpl-demo', data) // Loads and parses the template again
195 | ```
196 |
197 | ### Output encoding
198 |
199 | The method **tmpl.encode** is used to escape HTML special characters in the
200 | template output:
201 |
202 | ```js
203 | var output = tmpl.encode('<>&"\'\x00') // Renders "<>&"'"
204 | ```
205 |
206 | **tmpl.encode** makes use of the regular expression **tmpl.encReg** and the
207 | encoding map **tmpl.encMap** to match and replace special characters, which can
208 | be modified to change the behavior of the output encoding.
209 | Strings matched by the regular expression, but not found in the encoding map are
210 | removed from the output. This allows for example to automatically trim input
211 | values (removing whitespace from the start and end of the string):
212 |
213 | ```js
214 | tmpl.encReg = /(^\s+)|(\s+$)|[<>&"'\x00]/g
215 | var output = tmpl.encode(' Banana! ') // Renders "Banana" (without whitespace)
216 | ```
217 |
218 | ### Local helper variables
219 |
220 | The local variables available inside the templates are the following:
221 |
222 | - **o**: The data object given as parameter to the template function (see the
223 | next section on how to modify the parameter name).
224 | - **tmpl**: A reference to the **tmpl** function object.
225 | - **\_s**: The string for the rendered result content.
226 | - **\_e**: A reference to the **tmpl.encode** method.
227 | - **print**: Helper function to add content to the rendered result string.
228 | - **include**: Helper function to include the return value of a different
229 | template in the result.
230 |
231 | To introduce additional local helper variables, the string **tmpl.helper** can
232 | be extended. The following adds a convenience function for _console.log_ and a
233 | streaming function, that streams the template rendering result back to the
234 | callback argument (note the comma at the beginning of each variable
235 | declaration):
236 |
237 | ```js
238 | tmpl.helper +=
239 | ',log=function(){console.log.apply(console, arguments)}' +
240 | ",st='',stream=function(cb){var l=st.length;st=_s;cb( _s.slice(l));}"
241 | ```
242 |
243 | Those new helper functions could be used to stream the template contents to the
244 | console output:
245 |
246 | ```html
247 |
263 | ```
264 |
265 | ### Template function argument
266 |
267 | The generated template functions accept one argument, which is the data object
268 | given to the **tmpl(id, data)** function. This argument is available inside the
269 | template definitions as parameter **o** (the lowercase letter).
270 |
271 | The argument name can be modified by overriding **tmpl.arg**:
272 |
273 | ```js
274 | tmpl.arg = 'p'
275 |
276 | // Renders "
JavaScript Templates
":
277 | var result = tmpl('
{%=p.title%}
', { title: 'JavaScript Templates' })
278 | ```
279 |
280 | ### Template parsing
281 |
282 | The template contents are matched and replaced using the regular expression
283 | **tmpl.regexp** and the replacement function **tmpl.func**. The replacement
284 | function operates based on the
285 | [parenthesized submatch strings](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_function_as_a_parameter).
286 |
287 | To use different tags for the template syntax, override **tmpl.regexp** with a
288 | modified regular expression, by exchanging all occurrences of "{%" and "%}",
289 | e.g. with "[%" and "%]":
290 |
291 | ```js
292 | tmpl.regexp = /([\s'\\])(?!(?:[^[]|\[(?!%))*%\])|(?:\[%(=|#)([\s\S]+?)%\])|(\[%)|(%\])/g
293 | ```
294 |
295 | By default, the plugin preserves whitespace (newlines, carriage returns, tabs
296 | and spaces). To strip unnecessary whitespace, you can override the **tmpl.func**
297 | function, e.g. with the following code:
298 |
299 | ```js
300 | var originalFunc = tmpl.func
301 | tmpl.func = function (s, p1, p2, p3, p4, p5, offset, str) {
302 | if (p1 && /\s/.test(p1)) {
303 | if (
304 | !offset ||
305 | /\s/.test(str.charAt(offset - 1)) ||
306 | /^\s+$/g.test(str.slice(offset))
307 | ) {
308 | return ''
309 | }
310 | return ' '
311 | }
312 | return originalFunc.apply(tmpl, arguments)
313 | }
314 | ```
315 |
316 | ## Templates syntax
317 |
318 | ### Interpolation
319 |
320 | Print variable with HTML special characters escaped:
321 |
322 | ```html
323 |
384 | ```
385 |
386 | ## Compiled templates
387 |
388 | The JavaScript Templates project comes with a compilation script, that allows
389 | you to compile your templates into JavaScript code and combine them with a
390 | minimal Templates runtime into one combined JavaScript file.
391 |
392 | The compilation script is built for [Node.js](https://nodejs.org/).
393 | To use it, first install the JavaScript Templates project via
394 | [NPM](https://www.npmjs.org/):
395 |
396 | ```sh
397 | npm install blueimp-tmpl
398 | ```
399 |
400 | This will put the executable **tmpl.js** into the folder **node_modules/.bin**.
401 | It will also make it available on your PATH if you install the package globally
402 | (by adding the **-g** flag to the install command).
403 |
404 | The **tmpl.js** executable accepts the paths to one or multiple template files
405 | as command line arguments and prints the generated JavaScript code to the
406 | console output. The following command line shows you how to store the generated
407 | code in a new JavaScript file that can be included in your project:
408 |
409 | ```sh
410 | tmpl.js index.html > tmpl.js
411 | ```
412 |
413 | The files given as command line arguments to **tmpl.js** can either be pure
414 | template files or HTML documents with embedded template script sections. For the
415 | pure template files, the file names (without extension) serve as template ids.
416 | The generated file can be included in your project as a replacement for the
417 | original **tmpl.js** runtime. It provides you with the same API and provides a
418 | **tmpl(id, data)** function that accepts the id of one of your templates as
419 | first and a data object as optional second parameter.
420 |
421 | ## Tests
422 |
423 | The JavaScript Templates project comes with
424 | [Unit Tests](https://en.wikipedia.org/wiki/Unit_testing).
425 | There are two different ways to run the tests:
426 |
427 | - Open test/index.html in your browser or
428 | - run `npm test` in the Terminal in the root path of the repository package.
429 |
430 | The first one tests the browser integration, the second one the
431 | [Node.js](https://nodejs.org/) integration.
432 |
433 | ## License
434 |
435 | The JavaScript Templates script is released under the
436 | [MIT license](https://opensource.org/licenses/MIT).
437 |
--------------------------------------------------------------------------------
/bin/sync-vendor-libs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd "$(dirname "$0")/.."
3 | cp node_modules/chai/chai.js test/vendor/
4 | cp node_modules/mocha/mocha.js test/vendor/
5 | cp node_modules/mocha/mocha.css test/vendor/
6 |
--------------------------------------------------------------------------------
/css/demo.css:
--------------------------------------------------------------------------------
1 | /*
2 | * JavaScript Templates Demo CSS
3 | * https://github.com/blueimp/JavaScript-Templates
4 | *
5 | * Copyright 2013, Sebastian Tschan
6 | * https://blueimp.net
7 | *
8 | * Licensed under the MIT license:
9 | * https://opensource.org/licenses/MIT
10 | */
11 |
12 | body {
13 | max-width: 990px;
14 | margin: 0 auto;
15 | padding: 1em;
16 | font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue',
17 | Arial, sans-serif;
18 | -webkit-text-size-adjust: 100%;
19 | line-height: 1.4;
20 | background: #212121;
21 | color: #dedede;
22 | }
23 | a {
24 | color: #61afef;
25 | text-decoration: none;
26 | }
27 | a:visited {
28 | color: #56b6c2;
29 | }
30 | a:hover {
31 | color: #98c379;
32 | }
33 | h1,
34 | h2,
35 | h3,
36 | h4,
37 | h5,
38 | h6 {
39 | margin-top: 1.5em;
40 | margin-bottom: 0.5em;
41 | }
42 | h1 {
43 | margin-top: 0.5em;
44 | }
45 | label {
46 | display: inline-block;
47 | margin-bottom: 0.25em;
48 | }
49 | button,
50 | select,
51 | input,
52 | textarea,
53 | div.result {
54 | -webkit-appearance: none;
55 | box-sizing: border-box;
56 | margin: 0;
57 | padding: 0.5em 0.75em;
58 | font-family: inherit;
59 | font-size: 100%;
60 | line-height: 1.4;
61 | background: #414141;
62 | color: #dedede;
63 | border: 1px solid #363636;
64 | border-radius: 5px;
65 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.07);
66 | }
67 | input,
68 | textarea,
69 | div.result {
70 | width: 100%;
71 | box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.07);
72 | }
73 | textarea {
74 | display: block;
75 | overflow: auto;
76 | }
77 | button {
78 | background: #3c76a7;
79 | background: linear-gradient(180deg, #3c76a7, #225c8d);
80 | border-color: #225c8d;
81 | color: #fff;
82 | }
83 | button[type='submit'] {
84 | background: #6fa349;
85 | background: linear-gradient(180deg, #6fa349, #568a30);
86 | border-color: #568a30;
87 | }
88 | button[type='reset'] {
89 | background: #d79435;
90 | background: linear-gradient(180deg, #d79435, #be7b1c);
91 | border-color: #be7b1c;
92 | }
93 | button:active {
94 | box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5);
95 | }
96 |
97 | pre,
98 | textarea.code {
99 | font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
100 | }
101 |
102 | @media (prefers-color-scheme: light) {
103 | body {
104 | background: #ececec;
105 | color: #212121;
106 | }
107 | a {
108 | color: #225c8d;
109 | }
110 | a:visited {
111 | color: #378f9a;
112 | }
113 | a:hover {
114 | color: #6fa349;
115 | }
116 | input,
117 | textarea,
118 | div.result {
119 | background: #fff;
120 | border-color: #d1d1d1;
121 | color: #212121;
122 | }
123 | }
124 |
125 | @media (min-width: 540px) {
126 | #navigation {
127 | list-style: none;
128 | padding: 0;
129 | }
130 | #navigation li {
131 | display: inline-block;
132 | }
133 | #navigation li:not(:first-child)::before {
134 | content: ' | ';
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
19 |
20 | JavaScript Templates Demo
21 |
25 |
26 |
27 |
28 |
29 |
JavaScript Templates Demo
30 |
31 | 1KB lightweight, fast & powerful
32 | JavaScript
33 | templating engine with zero dependencies.
34 | Compatible with server-side environments like
35 | Node.js, module loaders like
36 | RequireJS or
37 | webpack and all web browsers.
38 |