mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
310 lines
8.8 KiB
Markdown
310 lines
8.8 KiB
Markdown
|
# JavaScript Templates
|
||
|
|
||
|
## Demo
|
||
|
[JavaScript Templates Demo](http://blueimp.github.com/JavaScript-Templates/)
|
||
|
|
||
|
## Usage
|
||
|
|
||
|
### Client-side
|
||
|
Include the (minified) JavaScript Templates script in your HTML markup:
|
||
|
|
||
|
```html
|
||
|
<script src="tmpl.min.js"></script>
|
||
|
```
|
||
|
|
||
|
Add a script section with type **"text/html"** and your template definition as content:
|
||
|
|
||
|
```html
|
||
|
<script type="text/html" id="tmpl-demo">
|
||
|
<h3>{%=o.title%}</h3>
|
||
|
<p>Released under the
|
||
|
<a href="{%=o.license.url%}">{%=o.license.name%}</a>.</p>
|
||
|
<h4>Features</h4>
|
||
|
<ul>
|
||
|
{% for (var i=0; i<o.features.length; i++) { %}
|
||
|
<li>{%=o.features[i]%}</li>
|
||
|
{% } %}
|
||
|
</ul>
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
**"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).
|
||
|
|
||
|
In your application code, create a JavaScript object to use as data for the template:
|
||
|
|
||
|
```js
|
||
|
var data = {
|
||
|
"title": "JavaScript Templates",
|
||
|
"license": {
|
||
|
"name": "MIT license",
|
||
|
"url": "http://www.opensource.org/licenses/MIT"
|
||
|
},
|
||
|
"features": [
|
||
|
"lightweight & fast",
|
||
|
"powerful",
|
||
|
"zero dependencies"
|
||
|
]
|
||
|
};
|
||
|
```
|
||
|
|
||
|
In a real application, this data could be the result of retrieving a [JSON](http://json.org/) resource.
|
||
|
|
||
|
Render the result by calling the **tmpl()** method with the id of the template and the data object as arguments:
|
||
|
|
||
|
```js
|
||
|
document.getElementById("result").innerHTML = tmpl("tmpl-demo", data);
|
||
|
```
|
||
|
|
||
|
### Server-side
|
||
|
|
||
|
The following is an example how to use the JavaScript Templates engine on the server-side with [node.js](http://nodejs.org/).
|
||
|
|
||
|
Create a new directory and add the **tmpl.js** file. Or alternatively, install the **blueimp-tmpl** package with [npm](http://npmjs.org/):
|
||
|
|
||
|
```sh
|
||
|
npm install blueimp-tmpl
|
||
|
```
|
||
|
|
||
|
Add a file **template.html** with the following content:
|
||
|
|
||
|
```html
|
||
|
<!DOCTYPE HTML>
|
||
|
<title>{%=o.title%}</title>
|
||
|
<h3><a href="{%=o.url%}">{%=o.title%}</a></h3>
|
||
|
<h4>Features</h4>
|
||
|
<ul>
|
||
|
{% for (var i=0; i<o.features.length; i++) { %}
|
||
|
<li>{%=o.features[i]%}</li>
|
||
|
{% } %}
|
||
|
</ul>
|
||
|
```
|
||
|
|
||
|
Add a file **server.js** with the following content:
|
||
|
|
||
|
```js
|
||
|
require("http").createServer(function (req, res) {
|
||
|
var fs = require("fs"),
|
||
|
// The tmpl module exports the tmpl() function:
|
||
|
tmpl = require("./tmpl").tmpl,
|
||
|
// Use the following version if you installed the package with npm:
|
||
|
// tmpl = require("blueimp-tmpl").tmpl,
|
||
|
// Sample data:
|
||
|
data = {
|
||
|
"title": "JavaScript Templates",
|
||
|
"url": "https://github.com/blueimp/JavaScript-Templates",
|
||
|
"features": [
|
||
|
"lightweight & fast",
|
||
|
"powerful",
|
||
|
"zero dependencies"
|
||
|
]
|
||
|
};
|
||
|
// Override the template loading method:
|
||
|
tmpl.load = function (id) {
|
||
|
var filename = id + ".html";
|
||
|
console.log("Loading " + filename);
|
||
|
return fs.readFileSync(filename, "utf8");
|
||
|
};
|
||
|
res.writeHead(200, {"Content-Type": "text/html"});
|
||
|
// Render the content:
|
||
|
res.end(tmpl("template", data));
|
||
|
}).listen(8080, "localhost");
|
||
|
console.log("Server running at http://localhost:8080/");
|
||
|
```
|
||
|
|
||
|
Run the application with the following command:
|
||
|
|
||
|
```sh
|
||
|
node server.js
|
||
|
```
|
||
|
|
||
|
## Requirements
|
||
|
The JavaScript Templates script has zero dependencies.
|
||
|
|
||
|
## API
|
||
|
|
||
|
### tmpl() function
|
||
|
The **tmpl()** function is added to the global **window** object and can be called as global function:
|
||
|
|
||
|
```js
|
||
|
var result = tmpl("tmpl-demo", data);
|
||
|
```
|
||
|
|
||
|
The **tmpl()** function can be called with the id of a template, or with a template string:
|
||
|
|
||
|
```js
|
||
|
var result = tmpl("<h3>{%=o.title%}</h3>", data);
|
||
|
```
|
||
|
|
||
|
If called without second argument, **tmpl()** returns a reusable template function:
|
||
|
|
||
|
```js
|
||
|
var func = tmpl("<h3>{%=o.title%}</h3>");
|
||
|
document.getElementById("result").innerHTML = func(data);
|
||
|
```
|
||
|
|
||
|
### Templates cache
|
||
|
Templates loaded by id are cached in the map **tmpl.cache**, which can be modified:
|
||
|
|
||
|
```js
|
||
|
var func = tmpl("tmpl-demo");
|
||
|
var cached = typeof tmpl.cache["tmpl-demo"] === "function"; // true
|
||
|
|
||
|
tmpl.cache["tmpl-demo"] = tmpl("<h3>{%=o.title%}</h3>");
|
||
|
var result = tmpl("tmpl-demo", {title: "JS"}); // Renders "<h3>JS</h3>"
|
||
|
```
|
||
|
|
||
|
### Output encoding
|
||
|
The method **tmpl.encode** is used to escape HTML special characters in template output:
|
||
|
|
||
|
```js
|
||
|
var output = tmpl.encode("<>&\"\x00"); // Renders "<>&""
|
||
|
```
|
||
|
|
||
|
**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:
|
||
|
|
||
|
```js
|
||
|
// Add single quotes to the encoding rules:
|
||
|
tmpl.encReg = /[<>&"'\x00]/g;
|
||
|
tmpl.encMap["'"] = "'";
|
||
|
|
||
|
var output = tmpl.encode("<>&\"'\x00"); // Renders "<>&"'"
|
||
|
```
|
||
|
|
||
|
### Local helper variables
|
||
|
The local variables available inside the templates are the following:
|
||
|
|
||
|
* **o**: The data object given as parameter to the template function (see the next section on how to modify the parameter name).
|
||
|
* **_s**: The string for the rendered result content.
|
||
|
* **_t**: A reference to the **tmpl** function object.
|
||
|
* **_e**: A reference to the **tmpl.encode** method.
|
||
|
* **print**: Function to add content to the rendered result string.
|
||
|
* **include**: Function to include the return value of a different template in the result.
|
||
|
|
||
|
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):
|
||
|
|
||
|
```js
|
||
|
tmpl.helper += ",log=function(){console.log.apply(console, arguments)}" +
|
||
|
",st='',stream=function(cb){var l=st.length;st=_s;cb( _s.slice(l));}";
|
||
|
```
|
||
|
|
||
|
Those new helper functions could be used to stream the template contents to the console output:
|
||
|
|
||
|
```html
|
||
|
<script type="text/html" id="tmpl-demo">
|
||
|
<h3>{%=o.title%}</h3>
|
||
|
{% stream(log); %}
|
||
|
<p>Released under the
|
||
|
<a href="{%=o.license.url%}">{%=o.license.name%}</a>.</p>
|
||
|
{% stream(log); %}
|
||
|
<h4>Features</h4>
|
||
|
<ul>
|
||
|
{% stream(log); %}
|
||
|
{% for (var i=0; i<o.features.length; i++) { %}
|
||
|
<li>{%=o.features[i]%}</li>
|
||
|
{% stream(log); %}
|
||
|
{% } %}
|
||
|
</ul>
|
||
|
{% stream(log); %}
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
### Template function argument
|
||
|
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).
|
||
|
|
||
|
The argument name can be modified by overriding **tmpl.arg**:
|
||
|
|
||
|
```js
|
||
|
tmpl.arg = "p";
|
||
|
|
||
|
// Renders "<h3>JavaScript Templates</h3>":
|
||
|
var result = tmpl("<h3>{%=p.title%}</h3>", {title: "JavaScript Templates"});
|
||
|
```
|
||
|
|
||
|
### Template parsing
|
||
|
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).
|
||
|
|
||
|
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 "**%\\]**":
|
||
|
|
||
|
```js
|
||
|
tmpl.regexp = /(\s+)|('|\\)(?![^%]*%\])|(?:\[%(=|#)(.+?)%\])|(\[%)|(%\])/g;
|
||
|
```
|
||
|
|
||
|
## Templates syntax
|
||
|
|
||
|
### Interpolation
|
||
|
Print variable with HTML special characters escaped:
|
||
|
|
||
|
```html
|
||
|
<h3>{%=o.title%}</h3>
|
||
|
```
|
||
|
|
||
|
Print variable without escaping:
|
||
|
|
||
|
```html
|
||
|
<h3>{%#o.user_id%}</h3>
|
||
|
```
|
||
|
|
||
|
Print output of function calls:
|
||
|
|
||
|
```html
|
||
|
<a href="{%=encodeURI(o.url)%}">Website</a>
|
||
|
```
|
||
|
|
||
|
Use dot notation to print nested properties:
|
||
|
|
||
|
```html
|
||
|
<strong>{%=o.author.name%}</strong>
|
||
|
```
|
||
|
|
||
|
Note that the JavaScript Templates engine prints **falsy** values as empty strings.
|
||
|
That is, **undefined**, **null**, **false**, **0** and **NaN** will all be converted to **''**.
|
||
|
To be able to print e.g. the number 0, convert it to a String before using it as an output variable:
|
||
|
|
||
|
```html
|
||
|
<h3>{%=0+''%}</h3>
|
||
|
```
|
||
|
|
||
|
### Evaluation
|
||
|
Use **print(str)** to add escaped content to the output:
|
||
|
|
||
|
```html
|
||
|
<span>Year: {% var d=new Date(); print(d.getFullYear()); %}</span>
|
||
|
```
|
||
|
|
||
|
Use **print(str, true)** to add unescaped content to the output:
|
||
|
|
||
|
```html
|
||
|
<span>{% print("Fast & powerful", true); %}</span>
|
||
|
```
|
||
|
|
||
|
Use **include(str, obj)** to include content from a different template:
|
||
|
|
||
|
```html
|
||
|
<div>
|
||
|
{% include('tmpl-link', {name: "Website", url: "http://example.org"}); %}
|
||
|
</div>
|
||
|
```
|
||
|
|
||
|
If else condition:
|
||
|
|
||
|
```html
|
||
|
{% if (o.author.url) { %}
|
||
|
<a href="{%=encodeURI(o.author.url)%}">{%=o.author.name%}</a>
|
||
|
{% } else { %}
|
||
|
<em>No author url.</em>
|
||
|
{% } %}
|
||
|
```
|
||
|
|
||
|
For loop:
|
||
|
|
||
|
```html
|
||
|
<ul>
|
||
|
{% for (var i=0; i<o.features.length; i++) { %}
|
||
|
<li>{%=o.features[i]%}</li>
|
||
|
{% } %}
|
||
|
</ul>
|
||
|
```
|
||
|
|
||
|
## License
|
||
|
The JavaScript Templates script is released under the [MIT license](http://www.opensource.org/licenses/MIT).
|