Skip to content

Commit

Permalink
Merge branch 'master' into feature/multi-views
Browse files Browse the repository at this point in the history
* master:
  Fix more mistakes
  Fix Mistakes
  Add warning for ejs.render(dataAndOptions)
  Document JSDoc scripts in the README
  Clarify jsdocs for filename option
  Make suggested changes
  Fix typos
  Expand Client-side Support Section
  Clarify docs on the `client` option
  Add JSDocs for IncludeCallback
  Export the internal func for escaping XML
  Improve Documentation for <%_ and _%> Fixes mde#143 Also did some cleanup in the examples.
  Add documentation for renderFile() and filename
  fixed mocha test issue
  fixed unittest
  Update ejs.js
  Update index.html
  moved sample folder
  Fixed issue mde#119
  • Loading branch information
Marcello di Simone committed May 11, 2016
2 parents 5136cef + afa498e commit 21f71e9
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 37 deletions.
70 changes: 61 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,28 @@ template(data);

ejs.render(str, data, options);
// => Rendered HTML string

ejs.renderFile(filename, data, options, function(err, str){
// str => Rendered HTML string
});
```

You can also use the shortcut `ejs.render(dataAndOptions);` where you pass
It is also possible to use `ejs.render(dataAndOptions);` where you pass
everything in a single object. In that case, you'll end up with local variables
for all the passed options.
for all the passed options. However, be aware that your code could break if we
add an option with the same name as one of your data object's properties.
Therefore, we do not recommend using this shortcut.

## Options

- `cache` Compiled functions are cached, requires `filename`
- `filename` Used by `cache` to key caches, and for includes
- `filename` The name of the file being rendered. Not required if you
are using `renderFile()`. Used by `cache` to key caches, and for includes.
- `context` Function execution context
- `compileDebug` When `false` no debug instrumentation is compiled
- `client` Returns standalone compiled function
- `client` When `true`, compiles a function that can be rendered
in the browser without needing to load the EJS Runtime
([ejs.min.js](https://github.com/mde/ejs/releases/latest)).
- `delimiter` Character to use with angle brackets for open/close
- `debug` Output generated function body
- `strict` When set to `true`, generated function is in strict mode
Expand All @@ -65,6 +74,11 @@ for all the passed options.
slurping for all scriptlet tags (it does not strip new lines of tags in
the middle of a line).

This project uses [JSDoc](http://usejsdoc.org/). For the full public API
documentation, clone the repository and run `npm run doc`. This will run JSDoc
with the proper options and output the documentation to `out/`. If you want
the both the public & private API docs, run `npm run devdoc` instead.

## Tags

- `<%` 'Scriptlet' tag, for control-flow, no output
Expand All @@ -78,9 +92,12 @@ for all the passed options.
## Includes

Includes either have to be an absolute path, or, if not, are assumed as
relative to the template with the `include` call. (This requires the
`filename` option.) For example if you are including `./views/user/show.ejs`
from `./views/users.ejs` you would use `<%- include('user/show') %>`.
relative to the template with the `include` call. For example if you are
including `./views/user/show.ejs` from `./views/users.ejs` you would
use `<%- include('user/show') %>`.

You must specify the `filename` option for the template with the `include`
call unless you are using `renderFile()`.

You'll likely want to use the raw output tag (`<%-`) with your include to avoid
double-escaping the HTML output.
Expand Down Expand Up @@ -155,9 +172,44 @@ including headers and footers, like so:
## Client-side support

Go to the [Latest Release](https://github.com/mde/ejs/releases/latest), download
`./ejs.js` or `./ejs.min.js`.
`./ejs.js` or `./ejs.min.js`. Alternately, you can compile it yourself by cloning
the repository and running `jake build` (or `$(npm bin)/jake build` if jake is
not installed globally).

Include one of these files on your page, and `ejs` should be available globally.

### Example

```html
<div id="output"></div>
<script src="ejs.min.js"></script>
<script>
var people = ['geddy', 'neil', 'alex'],
html = ejs.render('<%= people.join(", "); %>', {people: people});
// With jQuery:
$('#output').html(html);
// Vanilla JS:
document.getElementById('output').innerHTML = html;
</script>
```

Include one of these on your page, and `ejs.render(str)`.
### Caveats

Most of EJS will work as expected; however, there are a few things to note:

1. Obviously, since you do not have access to the filesystem, `ejs.renderFile()` won't work.
2. For the same reason, `include`s do not work unless you use an `IncludeCallback`. Here is an example:
```javascript
var str = "Hello <%= include('file', {person: 'John'}); %>",
fn = ejs.compile(str, {client: true});

fn(data, null, function(path, d){ // IncludeCallback
// path -> 'file'
// d -> {person: 'John'}
// Put your code here
// Return the contents of file as a string
}); // returns rendered string
```

## Related projects

Expand Down
11 changes: 7 additions & 4 deletions docs/jsdoc/options.jsdoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@
* line).
*
* @property {Boolean} [client=false]
* Whether or not to compile functions that are to be included in the browser.
*
* Whether or not to compile a {@link ClientFunction} that can be rendered
* in the browser without depending on ejs.js. Otherwise, a {@link TemplateFunction}
* will be compiled.
*
* @property {EscapeCallback} [escape={@link module:utils.escapeXML}]
* The escaping function used with `<%=` construct. It is used in rendering
* and is `.toString()`ed in the generation of client functions.
*
* @property {String} [filename='undefined']
* The filename of the template. Used in inclusion, caching, and error
* reporting.
* The filename of the template. Required for inclusion and caching unless
* you are using {@link module:ejs.renderFile}. Also used for error reporting.
*
* @property {String} [delimiter='%']
* The delimiter used in template compilation.
*
Expand Down
19 changes: 15 additions & 4 deletions docs/jsdoc/template-functions.jsdoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@
* @global
*/

/**
* Escapes a string using HTML/XML escaping rules.
*
* @callback EscapeCallback
* @param {String} markup Input string
* @return {String} Escaped string
* @static
* @global
*/

/**
* This type of callback is used when {@link Options}`.compileDebug`
* is true, and an error in the template is thrown. By default it is used to
Expand All @@ -49,11 +59,12 @@
*/

/**
* Escapes a string using HTML/XML escaping rules.
* The callback called by {@link ClientFunction} to include files at runtime with `include()`
*
* @callback EscapeCallback
* @param {String} markup Input string
* @return {String} Escaped string
* @callback IncludeCallback
* @param {String} path Path to be included
* @param {Object} [data] Data passed to the template
* @return {String} Contents of the file requested
* @static
* @global
*/
90 changes: 70 additions & 20 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,24 @@ example below. You can trim it using the `-%>` ending tag.
##### EJS

```html
<p><%# comment %></p>
<div>
<%# comment %>
</div>

<div>
<%# comment -%>
</div>
```

##### HTML

```html
<p></p>
<div>

</div>

<div>
</div>
```

### `<%`: Scriptlets
Expand Down Expand Up @@ -236,7 +247,7 @@ The use of scriptlets might cause some useless whitespace, as illustrated by
the example below. You can trim it by

1. using the `-%>` ending tag, and
2. always starting the tag in the beginning of a line.
2. using the `<%_` starting tag or starting the tag in the beginning of a line.

#### Example

Expand Down Expand Up @@ -294,54 +305,93 @@ It does *not* mean that we recommend mixing coding styles in your own project.
</dl>
```

### `<%_` "Whitespace Slurping" Scriptlet

This tag is the same as a Scriptlet, except that it removes all whitespace before it.

#### Example

##### EJS

```html
<ul>
<% users.forEach(function(user, i, arr){ -%>
<li><%= user %></li>
<% }); -%>
</ul>

<ul>
<%_ users.forEach(function(user, i, arr){ -%>
<li><%= user %></li>
<%_ }); -%>
</ul>
```

##### HTML

```html
<ul>
<li>Anne</li>
<li>Bob</li>
</ul>

<ul>
<li>Anne</li>
<li>Bob</li>
</ul>
```

Ending tags
-----------

There are two flavors of ending tags: the regular one and the
whitespace-trimming one.
There are three flavors of ending tags: the regular one, the
newline-trimming one, and the whitespace-slurping one.

### `%>`: Regular ending tag

As used in all of the examples above, `%>` is the standard tag used to end an
EJS expression.

### `-%>`: Whitespace-trimming ending tag
### `-%>`: Newline-trimming ending tag

`-%>` trims all extra whitespace a scriptlet or a comment might cause. It does
`-%>` trims all extra newlines a scriptlet or a comment might cause. It does
not have any effect on output tags.

#### Example

This is the exact example from `<%` starting tag above, but with `%>`
substituted by `-%>`.

##### EJS

```js
```html
Beginning of template
<% 'this is a statement'
+ ' that is long'
+ ' and long'
+ ' and long' %>
This is indented so some spaces will still be left:
<% 'statement' -%>
See?
This is the proper way:
<% 'statement' -%>
End of template
---
Beginning of template
<% 'this is a statement'
+ ' that is long'
+ ' and long'
+ ' and long' -%>
End of template
```

##### Output

```
```html
Beginning of template

This is indented so some spaces will still be left:
See?
This is the proper way:
End of template
---
Beginning of template
End of template
```

### `_%>`: Whitespace-slurping ending tag

`_%>` removes all whitespace after it.

Literal tag
-----------

Expand Down
10 changes: 10 additions & 0 deletions lib/ejs.js
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,10 @@ Template.prototype = {
, d = this.opts.delimiter;

if (matches && matches.length) {
if (this.opts.compileDebug && this.opts.filename) {
this.source = ' ; __lines = ' + JSON.stringify(this.templateText) + '\n';
this.source += ' ; __filename = "' + this.opts.filename.replace(/\\/g, '/') + '"\n';
}
matches.forEach(function (line, index) {
var opening
, closing
Expand Down Expand Up @@ -729,6 +733,12 @@ Template.prototype = {
}
};

/*
* Export the internal function for escaping XML so people
* can use for manual escaping if needed
* */
exports.escapeXML = utils.escapeXML;

/**
* Express.js support.
*
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
},
"scripts": {
"test": "mocha",
"sample": "npm install express && node sample/index.js",
"coverage": "istanbul cover node_modules/mocha/bin/_mocha",
"doc": "rimraf out && jsdoc -c jsdoc.json lib/* docs/jsdoc/*",
"devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*"
Expand Down
2 changes: 2 additions & 0 deletions sample/body.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!-- Execute an exception -->
<p><%= this_variable_is_not_defined %></p>
3 changes: 3 additions & 0 deletions sample/header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<head>
<title><%= header %></title>
</head>
20 changes: 20 additions & 0 deletions sample/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<html>
<head>
<% include header.html %>
</head>
<body>
<!--
Without fix output is confusing
ReferenceError: ./ejs/test/sample/index.html:2
1| <html>
>> 2| <head>
3| <% include header.html %>
4| </head>
5| <body>
this_variable_is_not_defined is not defined
-->
<% include body.html %>
</body>
</html>
11 changes: 11 additions & 0 deletions sample/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
var express = require('express'),
ejs = require('../lib/ejs.js');
var app = express();
app.engine('.html', ejs.__express);
app.set('view engine', 'ejs');
app.get('/', function(req, res) {
res.render(__dirname + '/index.html', {header: 'Hello EJS'});
});
var server = app.listen(3000, function () {
console.log('Example app listening at http://localhost:3000');
});

0 comments on commit 21f71e9

Please sign in to comment.