|
| 1 | +# JavaScript Templates |
| 2 | + |
| 3 | +## Demo |
| 4 | +[JavaScript Templates Demo](http://blueimp.github.com/JavaScript-Templates/) |
| 5 | + |
| 6 | +## Usage |
| 7 | + |
| 8 | +### Client-side |
| 9 | +Include the (minified) JavaScript Templates script in your HTML markup: |
| 10 | + |
| 11 | +```html |
| 12 | +<script src="tmpl.min.js"></script> |
| 13 | +``` |
| 14 | + |
| 15 | +Add a script section with type **"text/html"** and your template definition as content: |
| 16 | + |
| 17 | +```html |
| 18 | +<script type="text/html" id="tmpl-demo"> |
| 19 | +<h3>{%=o.title%}</h3> |
| 20 | +<p>Released under the |
| 21 | +<a href="{%=o.license.url%}">{%=o.license.name%}</a>.</p> |
| 22 | +<h4>Features</h4> |
| 23 | +<ul> |
| 24 | +{% for (var i=0; i<o.features.length; i++) { %} |
| 25 | + <li>{%=o.features[i]%}</li> |
| 26 | +{% } %} |
| 27 | +</ul> |
| 28 | +</script> |
| 29 | +``` |
| 30 | + |
| 31 | +**"o"** (the lowercase letter) is a reference to the data parameter of the template function (see the API section on how to modify this identifier). |
| 32 | + |
| 33 | +In your application code, create a JavaScript object to use as data for the template: |
| 34 | + |
| 35 | +```js |
| 36 | +var data = { |
| 37 | + "title": "JavaScript Templates", |
| 38 | + "license": { |
| 39 | + "name": "MIT license", |
| 40 | + "url": "http://creativecommons.org/licenses/MIT/" |
| 41 | + }, |
| 42 | + "features": [ |
| 43 | + "lightweight & fast", |
| 44 | + "powerful", |
| 45 | + "zero dependencies" |
| 46 | + ] |
| 47 | +}; |
| 48 | +``` |
| 49 | + |
| 50 | +In a real application, this data could be the result of retrieving a [JSON](http://json.org/) resource. |
| 51 | + |
| 52 | +Render the result by calling the **tmpl()** method with the id of the template and the data object as arguments: |
| 53 | + |
| 54 | +```js |
| 55 | +document.getElementById("result").innerHTML = tmpl("tmpl-demo", data); |
| 56 | +``` |
| 57 | + |
| 58 | +### Server-side |
| 59 | + |
| 60 | +The following is an example how to use the JavaScript Templates engine on the server-side with [node.js](http://nodejs.org/). |
| 61 | + |
| 62 | +Create a new directory and add the **tmpl.js** file. Or alternatively, install the **blueimp-tmpl** package with [npm](http://npmjs.org/): |
| 63 | + |
| 64 | +```sh |
| 65 | +npm install blueimp-tmpl |
| 66 | +``` |
| 67 | + |
| 68 | +Add a file **template.html** with the following content: |
| 69 | + |
| 70 | +```html |
| 71 | +<!DOCTYPE HTML> |
| 72 | +<title>{%=o.title%}</title> |
| 73 | +<h3><a href="{%=o.url%}">{%=o.title%}</a></h3> |
| 74 | +<h4>Features</h4> |
| 75 | +<ul> |
| 76 | +{% for (var i=0; i<o.features.length; i++) { %} |
| 77 | + <li>{%=o.features[i]%}</li> |
| 78 | +{% } %} |
| 79 | +</ul> |
| 80 | +``` |
| 81 | + |
| 82 | +Add a file **server.js** with the following content: |
| 83 | + |
| 84 | +```js |
| 85 | +require("http").createServer(function (req, res) { |
| 86 | + var fs = require("fs"), |
| 87 | + // The tmpl module exports the tmpl() function: |
| 88 | + tmpl = require("./tmpl").tmpl, |
| 89 | + // Use the following version if you installed the package with npm: |
| 90 | + // tmpl = require("blueimp-tmpl").tmpl, |
| 91 | + // Sample data: |
| 92 | + data = { |
| 93 | + "title": "JavaScript Templates", |
| 94 | + "url": "https://github.com/blueimp/JavaScript-Templates", |
| 95 | + "features": [ |
| 96 | + "lightweight & fast", |
| 97 | + "powerful", |
| 98 | + "zero dependencies" |
| 99 | + ] |
| 100 | + }; |
| 101 | + // Override the template loading method: |
| 102 | + tmpl.load = function (id) { |
| 103 | + var filename = id + ".html"; |
| 104 | + console.log("Loading " + filename); |
| 105 | + return fs.readFileSync(filename, "utf8"); |
| 106 | + }; |
| 107 | + res.writeHead(200, {"Content-Type": "text/html"}); |
| 108 | + // Render the content: |
| 109 | + res.end(tmpl("template", data)); |
| 110 | +}).listen(8080, "localhost"); |
| 111 | +console.log("Server running at http://localhost:8080/"); |
| 112 | +``` |
| 113 | + |
| 114 | +Run the application with the following command: |
| 115 | + |
| 116 | +```sh |
| 117 | +node server.js |
| 118 | +``` |
| 119 | + |
| 120 | +## Requirements |
| 121 | +The JavaScript Templates script has zero dependencies. |
| 122 | + |
| 123 | +## API |
| 124 | + |
| 125 | +### tmpl() function |
| 126 | +The **tmpl()** function is added to the global **window** object and can be called as global function: |
| 127 | + |
| 128 | +```js |
| 129 | +var result = tmpl("tmpl-demo", data); |
| 130 | +``` |
| 131 | + |
| 132 | +The **tmpl()** function can be called with the id of a template, or with a template string: |
| 133 | + |
| 134 | +```js |
| 135 | +var result = tmpl("<h3>{%=o.title%}</h3>", data); |
| 136 | +``` |
| 137 | + |
| 138 | +If called without second argument, **tmpl()** returns a reusable template function: |
| 139 | + |
| 140 | +```js |
| 141 | +var func = tmpl("<h3>{%=o.title%}</h3>"); |
| 142 | +document.getElementById("result").innerHTML = func(data); |
| 143 | +``` |
| 144 | + |
| 145 | +### Templates cache |
| 146 | +Templates loaded by id are cached in the map **tmpl.cache**, which can be modified: |
| 147 | + |
| 148 | +```js |
| 149 | +var func = tmpl("tmpl-demo"); |
| 150 | +var cached = typeof tmpl.cache["tmpl-demo"] === "function"; // true |
| 151 | + |
| 152 | +tmpl.cache["tmpl-demo"] = tmpl("<h3>{%=o.title%}</h3>"); |
| 153 | +var result = tmpl("tmpl-demo", {title: "JS"}); // Renders "<h3>JS</h3>" |
| 154 | +``` |
| 155 | + |
| 156 | +### Output encoding |
| 157 | +The method **tmpl.encode** is used to escape HTML special characters in template output: |
| 158 | + |
| 159 | +```js |
| 160 | +var output = tmpl.encode("<>&\"\x00"); // Renders "<>&"" |
| 161 | +``` |
| 162 | + |
| 163 | +**tmpl.encode** makes use of the regular expression **tmpl.encReg** and the encoding map **tmpl.encMap** to match and replace special characters, which can be modified to change the behavior of the output encoding: |
| 164 | + |
| 165 | +```js |
| 166 | +// Add single quotes to the encoding rules: |
| 167 | +tmpl.encReg = /[<>&"'\x00]/g; |
| 168 | +tmpl.encMap["'"] = "'"; |
| 169 | + |
| 170 | +var output = tmpl.encode("<>&\"'\x00"); // Renders "<>&"'" |
| 171 | +``` |
| 172 | + |
| 173 | +### Local helper variables |
| 174 | +The local variables available inside the templates are the following: |
| 175 | + |
| 176 | +* **o**: The data object given as parameter to the template function (see the next section on how to modify the parameter name). |
| 177 | +* **_s**: The string for the rendered result content. |
| 178 | +* **_t**: A reference to the **tmpl** function object. |
| 179 | +* **_e**: A reference to the **tmpl.encode** method. |
| 180 | +* **print**: Function to add content to the rendered result string. |
| 181 | +* **include**: Function to include the return value of a different template in the result. |
| 182 | + |
| 183 | +To introduce additional local helper variables, the string **tmpl.helper** can be extended. The following adds a convenience function for *console.log* and a streaming function, that streams the template rendering result back to the callback argument (note the comma at the beginning of each variable declaration): |
| 184 | + |
| 185 | +```js |
| 186 | +tmpl.helper += ",log=function(){console.log.apply(console, arguments)}" + |
| 187 | + ",st='',stream=function(cb){var l=st.length;st=_s;cb( _s.slice(l));}"; |
| 188 | +``` |
| 189 | + |
| 190 | +Those new helper functions could be used to stream the template contents to the console output: |
| 191 | + |
| 192 | +```html |
| 193 | +<script type="text/html" id="tmpl-demo"> |
| 194 | +<h3>{%=o.title%}</h3> |
| 195 | +{% stream(log); %} |
| 196 | +<p>Released under the |
| 197 | +<a href="{%=o.license.url%}">{%=o.license.name%}</a>.</p> |
| 198 | +{% stream(log); %} |
| 199 | +<h4>Features</h4> |
| 200 | +<ul> |
| 201 | +{% stream(log); %} |
| 202 | +{% for (var i=0; i<o.features.length; i++) { %} |
| 203 | + <li>{%=o.features[i]%}</li> |
| 204 | + {% stream(log); %} |
| 205 | +{% } %} |
| 206 | +</ul> |
| 207 | +{% stream(log); %} |
| 208 | +</script> |
| 209 | +``` |
| 210 | + |
| 211 | +### Template function argument |
| 212 | +The generated template functions accept one argument, which is the data object given to the **tmpl(id, data)** function. This argument is available inside the template definitions as parameter **o** (the lowercase letter). |
| 213 | + |
| 214 | +The argument name can be modified by overriding **tmpl.arg**: |
| 215 | + |
| 216 | +```js |
| 217 | +tmpl.arg = "p"; |
| 218 | + |
| 219 | +// Renders "<h3>JavaScript Templates</h3>": |
| 220 | +var result = tmpl("<h3>{%=p.title%}</h3>", {title: "JavaScript Templates"}); |
| 221 | +``` |
| 222 | + |
| 223 | +### Template parsing |
| 224 | +The template contents are matched and replaced using the regular expression **tmpl.regexp** and the replacement function **tmpl.func**. The replacement function operates based on the [parenthesized submatch strings](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_function_as_a_parameter). |
| 225 | + |
| 226 | +To use different tags for the template syntax, override **tmpl.regexp** with a modified regular expression, by exchanging all occurrences of "**\\{%**" and "**%\\}**", e.g. with "**\\[%**" and "**%\\]**": |
| 227 | + |
| 228 | +```js |
| 229 | +tmpl.regexp = /(\s+)|('|\\)(?![^%]*%\])|(?:\[%(=|!)(.+?)%\])|(\[%)|(%\])/g; |
| 230 | +``` |
| 231 | + |
| 232 | +## Templates syntax |
| 233 | + |
| 234 | +### Interpolation |
| 235 | +Print variable with HTML special characters escaped: |
| 236 | + |
| 237 | +```html |
| 238 | +<h3>{%=o.title%}</h3> |
| 239 | +``` |
| 240 | + |
| 241 | +Print variable without escaping: |
| 242 | + |
| 243 | +```html |
| 244 | +<h3>{%!o.user_id%}</h3> |
| 245 | +``` |
| 246 | + |
| 247 | +Print output of function calls: |
| 248 | + |
| 249 | +```html |
| 250 | +<a href="{%=encodeURI(o.url)%}">Website</a> |
| 251 | +``` |
| 252 | + |
| 253 | +Use dot notation to print nested properties: |
| 254 | + |
| 255 | +```html |
| 256 | +<strong>{%=o.author.name%}</strong> |
| 257 | +``` |
| 258 | + |
| 259 | +### Evaluation |
| 260 | +Use **print(str)** to add escaped content to the output: |
| 261 | + |
| 262 | +```html |
| 263 | +<span>Year: {% var d=new Date(); print(d.getFullYear()); %}</span> |
| 264 | +``` |
| 265 | + |
| 266 | +Use **print(str, true)** to add unescaped content to the output: |
| 267 | + |
| 268 | +```html |
| 269 | +<span>{% print("Fast & powerful", true); %}</span> |
| 270 | +``` |
| 271 | + |
| 272 | +Use **include(str, obj)** to include content from a different template: |
| 273 | + |
| 274 | +```html |
| 275 | +<div> |
| 276 | +{% include('tmpl-link', {name: "Website", url: "http://example.org"}); %} |
| 277 | +</div> |
| 278 | +``` |
| 279 | + |
| 280 | +If else condition: |
| 281 | + |
| 282 | +```html |
| 283 | +{% if (o.author.url) { %} |
| 284 | + <a href="{%=encodeURI(o.author.url)%}">{%=o.author.name%}</a> |
| 285 | +{% } else { %} |
| 286 | + <em>No author url.</em> |
| 287 | +{% } %} |
| 288 | +``` |
| 289 | + |
| 290 | +For loop: |
| 291 | + |
| 292 | +```html |
| 293 | +<ul> |
| 294 | +{% for (var i=0; i<o.features.length; i++) { %} |
| 295 | + <li>{%=o.features[i]%}</li> |
| 296 | +{% } %} |
| 297 | +</ul> |
| 298 | +``` |
| 299 | + |
| 300 | +## License |
| 301 | +The JavaScript Templates script is released under the [MIT license](http://creativecommons.org/licenses/MIT/). |
0 commit comments