Skip to content

Commit 7cdf8e0

Browse files
Added ability to pass arbitrary values into extend and embed via attributes. Resolves #14.
1 parent 5d9fb5a commit 7cdf8e0

File tree

8 files changed

+160
-16
lines changed

8 files changed

+160
-16
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
coverage/
33
docs/
44
node_modules/
5+
test/actual/
56

67
*.log
78
.*.swp

README.md

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ With [Bower](http://bower.io):
1616

1717
## Helpers
1818

19-
### `{{#extend [partial]}}`
19+
### `{{#extend [partial] [key=value ...]}}`
2020

2121
- `partial` `String` - Name of partial to render.
22+
- `attributes` `Object` _(Optional)_ - Arbitrary values that will be added to the context passed to the partial.
2223

2324
Loads a layout partial of a given name and defines block content.
2425

25-
```html
26-
{{#extend "layout"}}
26+
```handlebars
27+
{{#extend "layout" keywords="handlebars,hbs,layout"}}
2728
{{#content "title" mode="prepend"}}Example - {{/content}}
2829
{{/extend}}
2930
```
@@ -38,13 +39,14 @@ class Page extends Layout {
3839
}
3940
```
4041

41-
### `{{#embed [partial]}}`
42+
### `{{#embed [partial] [key=value ...]}}`
4243

4344
- `partial` `String` - Name of partial to render.
45+
- `attributes` `Object` _(Optional)_ - Arbitrary values that will be added to the context passed to the partial.
4446

4547
Allows you to load a partial which itself extends from a layout. Blocks defined in embedded partials will not conflict with those in the primary layout.
4648

47-
```html
49+
```handlebars
4850
{{#extend "layout"}}
4951
5052
{{#content "body"}}
@@ -55,7 +57,7 @@ Allows you to load a partial which itself extends from a layout. Blocks defined
5557
{{/content}}
5658
{{/embed}}
5759
58-
{{#embed "modal"}}
60+
{{#embed "modal" foo="bar" name=user.fullName}}
5961
{{#content "title" mode="prepend"}}Image 1 - {{/content}}
6062
{{#content "body"}}<img src="1.png" alt="" />{{/content}}
6163
{{/embed}}
@@ -71,11 +73,11 @@ class Page extends Layout {
7173
body() {
7274
var gallery = new Gallery();
7375
gallery.replaceBody('<img src="1.png" alt="" />\n<img src="2.png" alt="" />');
74-
76+
7577
var modal = new Modal();
7678
modal.prependTitle('Image 1 - ');
7779
modal.replaceBody('<img src="1.png" alt="" />');
78-
80+
7981
return gallery.toString() + modal.toString();
8082
}
8183
}
@@ -87,7 +89,7 @@ class Page extends Layout {
8789

8890
Defines a named block, with optional default content. Blocks may have content appended, prepended, or replaced entirely when extending or embedding. You may append and prepend to the same block multiple times.
8991

90-
```html
92+
```handlebars
9193
{{#block "header"}}
9294
<h1>Hello World</h1>
9395
{{/block}}
@@ -101,6 +103,13 @@ Defines a named block, with optional default content. Blocks may have content ap
101103
{{/block}}
102104
```
103105

106+
Default block content is optional, and may be omitted.
107+
108+
```handlebars
109+
<h1>{{{block "title"}}}</h1>
110+
<p>{{{block "description"}}}</p>
111+
```
112+
104113
### `{{#content [name] mode="(append|prepend|replace)"}}`
105114

106115
- `name` `String` - Identifier of the block to modify.
@@ -110,7 +119,7 @@ Sets block content, optionally appending or prepending using the `mode` attribut
110119

111120
Layout:
112121

113-
```html
122+
```handlebars
114123
<html>
115124
...
116125
<body>
@@ -131,7 +140,7 @@ Layout:
131140

132141
Page:
133142

134-
```html
143+
```handlebars
135144
{{#extend "layout"}}
136145
137146
{{#content "header"}}
@@ -151,7 +160,7 @@ Page:
151160

152161
Output:
153162

154-
```html
163+
```handlebars
155164
<html>
156165
...
157166
<body>
@@ -166,6 +175,12 @@ Output:
166175
</html>
167176
```
168177

178+
Content is optional, and may be omitted. This will cause the `main` block to be replaced with an empty string, clearing out any default content.
179+
180+
```handlebars
181+
{{{content "main"}}}
182+
```
183+
169184
## Api
170185

171186
Helpers are registered by passing in your instance of Handlebars. This allows
@@ -209,7 +224,7 @@ grunt.initConfig({
209224

210225
### Layout Partial
211226

212-
```html
227+
```handlebars
213228
<!doctype html>
214229
<html lang="en-us">
215230
<head>
@@ -249,7 +264,7 @@ grunt.initConfig({
249264

250265
### Template
251266

252-
```html
267+
```handlebars
253268
{{#extend "layout"}}
254269
{{#content "head" mode="append"}}
255270
<link rel="stylesheet" href="assets/css/home.css" />
@@ -301,7 +316,7 @@ console.log(output);
301316

302317
### Output (prettified for readability)
303318

304-
```html
319+
```handlebars
305320
<!doctype html>
306321
<html lang="en-us">
307322
<head>

dist/handlebars-layouts.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,29 @@ function applyAction(val, action) {
5454
}
5555
}
5656

57+
function mixin(target) {
58+
var arg, key,
59+
len = arguments.length,
60+
i = 1;
61+
62+
for (; i < len; i++) {
63+
arg = arguments[i];
64+
65+
if (!arg) {
66+
continue;
67+
}
68+
69+
for (key in arg) {
70+
/* istanbul ignore else */
71+
if (arg.hasOwnProperty(key)) {
72+
target[key] = arg[key];
73+
}
74+
}
75+
}
76+
77+
return target;
78+
}
79+
5780
/**
5881
* Registers layout helpers on an instance of Handlebars.
5982
*
@@ -68,6 +91,7 @@ function layouts(handlebars) {
6891
* @param {String} name
6992
* @param {Object} options
7093
* @param {Function(Object)} options.fn
94+
* @param {Object} options.hash
7195
* @return {String} Rendered partial.
7296
*/
7397
extend: function (name, options) {
@@ -77,6 +101,9 @@ function layouts(handlebars) {
77101
context = Object.create(this || {}),
78102
template = handlebars.partials[name];
79103

104+
// Mix attributes into context
105+
mixin(context, options.hash);
106+
80107
// Partial template required
81108
if (template == null) {
82109
throw new Error('Missing partial: \'' + name + '\'');

index.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,29 @@ function applyAction(val, action) {
5353
}
5454
}
5555

56+
function mixin(target) {
57+
var arg, key,
58+
len = arguments.length,
59+
i = 1;
60+
61+
for (; i < len; i++) {
62+
arg = arguments[i];
63+
64+
if (!arg) {
65+
continue;
66+
}
67+
68+
for (key in arg) {
69+
/* istanbul ignore else */
70+
if (arg.hasOwnProperty(key)) {
71+
target[key] = arg[key];
72+
}
73+
}
74+
}
75+
76+
return target;
77+
}
78+
5679
/**
5780
* Registers layout helpers on an instance of Handlebars.
5881
*
@@ -67,6 +90,7 @@ function layouts(handlebars) {
6790
* @param {String} name
6891
* @param {Object} options
6992
* @param {Function(Object)} options.fn
93+
* @param {Object} options.hash
7094
* @return {String} Rendered partial.
7195
*/
7296
extend: function (name, options) {
@@ -76,6 +100,9 @@ function layouts(handlebars) {
76100
context = Object.create(this || {}),
77101
template = handlebars.partials[name];
78102

103+
// Mix attributes into context
104+
mixin(context, options.hash);
105+
79106
// Partial template required
80107
if (template == null) {
81108
throw new Error('Missing partial: \'' + name + '\'');

test/expected/hash.html

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!doctype html>
2+
<html lang="en-us">
3+
<head>
4+
<title>Users</title>
5+
6+
<link rel="stylesheet" href="assets/css/screen.css" />
7+
</head>
8+
<body>
9+
<div class="site">
10+
<div class="site-hd" role="banner">
11+
<h1>Users</h1>
12+
</div>
13+
14+
<div class="site-bd" role="main">
15+
<div class="user">
16+
17+
<p>Monica Curtis</p>
18+
19+
</div>
20+
<div class="user">
21+
22+
<p>Sheppard Williams</p>
23+
24+
</div>
25+
<div class="user">
26+
27+
<p>Freida Bartlett</p>
28+
29+
</div>
30+
<div class="user">
31+
32+
<p>Bette Holden</p>
33+
34+
</div>
35+
<div class="user">
36+
<p>User is active.</p>
37+
38+
<p>Lora Cote</p>
39+
40+
</div>
41+
<div class="user">
42+
<p>User is active.</p>
43+
44+
<p>Dickerson Parsons</p>
45+
46+
</div>
47+
</div>
48+
49+
<div class="site-ft" role="contentinfo">
50+
<small>&copy; 1984</small>
51+
</div>
52+
</div>
53+
54+
<script src="assets/js/controllers/home.js"></script>
55+
</body>
56+
</html>

test/fixtures/hash.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{{#extend "layout"}}
2+
{{#content "body"}}
3+
{{#each users}}
4+
{{#embed "user" showBanner=isActive status="active"}}
5+
{{#content "body"}}
6+
<p>{{../../name.first}} {{../../name.last}}</p>
7+
{{/content}}
8+
{{/embed}}
9+
{{/each}}
10+
{{/content}}
11+
{{/extend}}

test/fixtures/partials/media.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
{{#block "image"}}{{/block}}
44
</div>
55
<div class="media-bd">
6-
{{#block "body"}}{{/block}}
6+
{{{block "body"}}}
77
</div>
88
</div>

test/fixtures/partials/user.hbs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div class="user">
2+
{{#if showBanner}}
3+
<p>User is {{status}}.</p>
4+
{{/if}}
5+
6+
{{{block "body"}}}
7+
</div>

0 commit comments

Comments
 (0)