Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add contentFor #31

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Express 3.x `layout`, `partial` and `block` template functions for the EJS template engine.

Forked to support contentFor('name')

Previously also offered `include` but you should use EJS 0.8.x's own method for that now.

## Installation
Expand All @@ -24,6 +26,13 @@ Given a template, `index.ejs`:
<% block('header', "<p>I'm in the header.</p>") -%>
<% block('footer', "<p>I'm in the footer.</p>") -%>

<%- contentFor('contentBlock') -%>
<h2>This is the contentBlock</h2>

<%- contentFor('contentBlock with space') -%>
<h2>This is the contentBlock with space</h2>


And a layout, `boilerplate.ejs`:

<!DOCTYPE html>
Expand All @@ -39,6 +48,10 @@ And a layout, `boilerplate.ejs`:
</header>
<section>
<%-body -%>

<%- contentFor.contentBlock -%>
<%- contentFor["contentBlock with space"] -%>

</section>
<footer>
<%-blocks.footer%>
Expand Down Expand Up @@ -80,6 +93,10 @@ You get the following result:
</header>
<section>
<h1>I am the best template</h1>

<h2>This is the contentBlock</h2>
<h2>This is the contentBlock with space</h2>

</section>
<footer>
<p>I'm in the footer.</p>
Expand Down Expand Up @@ -108,6 +125,10 @@ When called anywhere inside a template, adds the given html to the named block.

Since this relies on javascript strings, and bypasses EJS's default escaping, you should be very careful if you use this function with user-submitted data.

### `contentFor(name)`
`block()` would be convenient for shorter text, but if you want to define a larger block of code (that can potentially includes other partials), you can use `<%- contentFor('name') -%> your html to follow` to define the new contentFor block inside the view. Then to render the code in the layout, use `<%- contentFor.name -%>`. If you contentFor block's name has a space, use `<%- contentFor["block name"] -%>`. The contentFor block will be end when followed by another `contentFor("name")`, or to the end of the page.


### `script(src,type)`

A convenience function for `block('scripts', '<script src="src.js"></script>')` with optional type. When called anywhere inside a template, adds a script tag with the given src/type to the scripts block. In the layout you can then do `<%-scripts%> to output the scripts from all the child templates.
Expand All @@ -117,6 +138,7 @@ A convenience function for `block('scripts', '<script src="src.js"></script>')`
A convenience function for `block('stylesheets', '<link rel="stylesheet" href="href.css" />')` with optional media type. When called anywhere inside a template, adds a link tag for the stylesheet with the given href/media to the stylesheets block. In the layout you can then do `<%-stylesheets%> to output the links from all the child templates.



## Template Support

- `ejs` (actually hard coded right now, but feel free to __fork and help!__)
Expand Down
42 changes: 41 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,36 @@ var ejs = require('ejs')
, join = path.join
, basename = path.basename;


/* from ejs-layout */
var contentPattern = '&&<>&&'

function contentFor(contentName) {
return contentPattern + contentName + contentPattern;
}

function parseContents(options) {
if (!options.locals.body) return;

var locals = options.locals;
var str = locals.body;
var regex = new RegExp('\n?' + contentPattern + '.+?' + contentPattern + '\n?', 'g')
var split = str.split(regex)
var matches = str.match(regex)

locals.body = split[0]
var i = 1;

if (matches != null) {
matches.forEach(function(match) {
var name = match.split(contentPattern)[1]
options.contentFor[name] = split[i];
i++;
});
}
}


/**
* Express 3.x Layout & Partial support for EJS.
*
Expand Down Expand Up @@ -68,6 +98,12 @@ var renderFile = module.exports = function(file, options, fn){
options.locals = {};
}


// make contentFor available in the view
if(!options.contentFor)
options.contentFor = contentFor;


if (!options.locals.blocks) {
// one set of blocks no matter how often we recurse
var blocks = { scripts: new Block(), stylesheets: new Block() };
Expand All @@ -82,6 +118,9 @@ var renderFile = module.exports = function(file, options, fn){
options.locals.layout = layout.bind(options);
options.locals.partial = partial.bind(options);

// should extract the contentFor stuff here
parseContents(options)

ejs.renderFile(file, options, function(err, html) {

if (err) {
Expand Down Expand Up @@ -137,6 +176,7 @@ var renderFile = module.exports = function(file, options, fn){

};


/**
* Memory cache for resolved object names.
*/
Expand Down Expand Up @@ -299,6 +339,7 @@ function partial(view, options){
for(var k in this)
options[k] = options[k] || this[k];


// extract object name from view
name = options.as || resolveObjectName(view);

Expand Down Expand Up @@ -453,4 +494,3 @@ function stylesheet(path, media) {
}
return this;
}