summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorKevin Decker <kpdecker@gmail.com>2015-08-23 23:45:17 -0500
committerKevin Decker <kpdecker@gmail.com>2015-08-23 23:45:17 -0500
commitc727e1f97c471ec6be26b54dcd7422fd521a2471 (patch)
tree0979b5f54c7e98b317545a573d43ec6e8566d576 /lib
parent2571dd8e8e43fd320672763564b16a5b3ae33966 (diff)
parent1c274088c1ea9969f7a676fd5bebd11698f73116 (diff)
downloadhandlebars.js-c727e1f97c471ec6be26b54dcd7422fd521a2471.zip
handlebars.js-c727e1f97c471ec6be26b54dcd7422fd521a2471.tar.gz
handlebars.js-c727e1f97c471ec6be26b54dcd7422fd521a2471.tar.bz2
Merge pull request #1076 from wycats/partial-block
Implement partial blocks
Diffstat (limited to 'lib')
-rw-r--r--lib/handlebars/compiler/compiler.js14
-rw-r--r--lib/handlebars/compiler/helpers.js38
-rw-r--r--lib/handlebars/compiler/printer.js16
-rw-r--r--lib/handlebars/compiler/visitor.js45
-rw-r--r--lib/handlebars/compiler/whitespace-control.js4
-rw-r--r--lib/handlebars/runtime.js15
6 files changed, 97 insertions, 35 deletions
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index ad6b861..a689e7d 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -1,3 +1,5 @@
+/* eslint-disable new-cap */
+
import Exception from '../exception';
import {isArray, indexOf} from '../utils';
import AST from './ast';
@@ -157,6 +159,11 @@ Compiler.prototype = {
PartialStatement: function(partial) {
this.usePartial = true;
+ let program = partial.program;
+ if (program) {
+ program = this.compileProgram(partial.program);
+ }
+
let params = partial.params;
if (params.length > 1) {
throw new Exception('Unsupported number of partial arguments: ' + params.length, partial);
@@ -170,7 +177,7 @@ Compiler.prototype = {
this.accept(partial.name);
}
- this.setupFullMustacheParams(partial, undefined, undefined, true);
+ this.setupFullMustacheParams(partial, program, undefined, true);
let indent = partial.indent || '';
if (this.options.preventIndent && indent) {
@@ -181,9 +188,12 @@ Compiler.prototype = {
this.opcode('invokePartial', isDynamic, partialName, indent);
this.opcode('append');
},
+ PartialBlockStatement: function(partialBlock) {
+ this.PartialStatement(partialBlock);
+ },
MustacheStatement: function(mustache) {
- this.SubExpression(mustache); // eslint-disable-line new-cap
+ this.SubExpression(mustache);
if (mustache.escaped && !this.options.noEscape) {
this.opcode('appendEscaped');
diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js
index bf72034..9c40f0d 100644
--- a/lib/handlebars/compiler/helpers.js
+++ b/lib/handlebars/compiler/helpers.js
@@ -1,5 +1,15 @@
import Exception from '../exception';
+function validateClose(open, close) {
+ close = close.path ? close.path.original : close;
+
+ if (open.path.original !== close) {
+ let errorNode = {loc: open.path.loc};
+
+ throw new Exception(open.path.original + " doesn't match " + close, errorNode);
+ }
+}
+
export function SourceLocation(source, locInfo) {
this.source = source;
this.start = {
@@ -86,11 +96,7 @@ export function prepareMustache(path, params, hash, open, strip, locInfo) {
}
export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
- if (openRawBlock.path.original !== close) {
- let errorNode = {loc: openRawBlock.path.loc};
-
- throw new Exception(openRawBlock.path.original + " doesn't match " + close, errorNode);
- }
+ validateClose(openRawBlock, close);
locInfo = this.locInfo(locInfo);
let program = {
@@ -114,11 +120,8 @@ export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
}
export function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
- // When we are chaining inverse calls, we will not have a close path
- if (close && close.path && openBlock.path.original !== close.path.original) {
- let errorNode = {loc: openBlock.path.loc};
-
- throw new Exception(openBlock.path.original + ' doesn\'t match ' + close.path.original, errorNode);
+ if (close && close.path) {
+ validateClose(openBlock, close);
}
program.blockParams = openBlock.blockParams;
@@ -185,3 +188,18 @@ export function prepareProgram(statements, loc) {
}
+export function preparePartialBlock(open, program, close, locInfo) {
+ validateClose(open, close);
+
+ return {
+ type: 'PartialBlockStatement',
+ name: open.path,
+ params: open.params,
+ hash: open.hash,
+ program,
+ openStrip: open.strip,
+ closeStrip: close && close.strip,
+ loc: this.locInfo(locInfo)
+ };
+}
+
diff --git a/lib/handlebars/compiler/printer.js b/lib/handlebars/compiler/printer.js
index 107d4b6..cf7aa48 100644
--- a/lib/handlebars/compiler/printer.js
+++ b/lib/handlebars/compiler/printer.js
@@ -84,6 +84,22 @@ PrintVisitor.prototype.PartialStatement = function(partial) {
}
return this.pad('{{> ' + content + ' }}');
};
+PrintVisitor.prototype.PartialBlockStatement = function(partial) {
+ let content = 'PARTIAL BLOCK:' + partial.name.original;
+ if (partial.params[0]) {
+ content += ' ' + this.accept(partial.params[0]);
+ }
+ if (partial.hash) {
+ content += ' ' + this.accept(partial.hash);
+ }
+
+ content += ' ' + this.pad('PROGRAM:');
+ this.padding++;
+ content += this.accept(partial.program);
+ this.padding--;
+
+ return this.pad('{{> ' + content + ' }}');
+};
PrintVisitor.prototype.ContentStatement = function(content) {
return this.pad("CONTENT[ '" + content.value + "' ]");
diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js
index 89dd632..cc54c53 100644
--- a/lib/handlebars/compiler/visitor.js
+++ b/lib/handlebars/compiler/visitor.js
@@ -75,35 +75,21 @@ Visitor.prototype = {
this.acceptArray(program.body);
},
- MustacheStatement: function(mustache) {
- this.acceptRequired(mustache, 'path');
- this.acceptArray(mustache.params);
- this.acceptKey(mustache, 'hash');
- },
+ MustacheStatement: visitSubExpression,
- BlockStatement: function(block) {
- this.acceptRequired(block, 'path');
- this.acceptArray(block.params);
- this.acceptKey(block, 'hash');
+ BlockStatement: visitBlock,
- this.acceptKey(block, 'program');
- this.acceptKey(block, 'inverse');
- },
+ PartialStatement: visitPartial,
+ PartialBlockStatement: function(partial) {
+ visitPartial.call(this, partial);
- PartialStatement: function(partial) {
- this.acceptRequired(partial, 'name');
- this.acceptArray(partial.params);
- this.acceptKey(partial, 'hash');
+ this.acceptKey(partial, 'program');
},
ContentStatement: function(/* content */) {},
CommentStatement: function(/* comment */) {},
- SubExpression: function(sexpr) {
- this.acceptRequired(sexpr, 'path');
- this.acceptArray(sexpr.params);
- this.acceptKey(sexpr, 'hash');
- },
+ SubExpression: visitSubExpression,
PathExpression: function(/* path */) {},
@@ -121,4 +107,21 @@ Visitor.prototype = {
}
};
+function visitSubExpression(mustache) {
+ this.acceptRequired(mustache, 'path');
+ this.acceptArray(mustache.params);
+ this.acceptKey(mustache, 'hash');
+}
+function visitBlock(block) {
+ visitSubExpression.call(this, block);
+
+ this.acceptKey(block, 'program');
+ this.acceptKey(block, 'inverse');
+}
+function visitPartial(partial) {
+ this.acceptRequired(partial, 'name');
+ this.acceptArray(partial.params);
+ this.acceptKey(partial, 'hash');
+}
+
export default Visitor;
diff --git a/lib/handlebars/compiler/whitespace-control.js b/lib/handlebars/compiler/whitespace-control.js
index d1b743d..6c8a986 100644
--- a/lib/handlebars/compiler/whitespace-control.js
+++ b/lib/handlebars/compiler/whitespace-control.js
@@ -61,7 +61,9 @@ WhitespaceControl.prototype.Program = function(program) {
return program;
};
-WhitespaceControl.prototype.BlockStatement = function(block) {
+
+WhitespaceControl.prototype.BlockStatement =
+WhitespaceControl.prototype.PartialBlockStatement = function(block) {
this.accept(block.program);
this.accept(block.inverse);
diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js
index fed72fb..de42752 100644
--- a/lib/handlebars/runtime.js
+++ b/lib/handlebars/runtime.js
@@ -194,7 +194,11 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa
export function resolvePartial(partial, context, options) {
if (!partial) {
- partial = options.partials[options.name];
+ if (options.name === '@partial-block') {
+ partial = options.data['partial-block'];
+ } else {
+ partial = options.partials[options.name];
+ }
} else if (!partial.call && !options.name) {
// This is a dynamic partial that returned a string
options.name = partial;
@@ -209,6 +213,15 @@ export function invokePartial(partial, context, options) {
options.data.contextPath = options.ids[0] || options.data.contextPath;
}
+ let partialBlock;
+ if (options.fn && options.fn !== noop) {
+ partialBlock = options.data['partial-block'] = options.fn;
+ }
+
+ if (partial === undefined && partialBlock) {
+ partial = partialBlock;
+ }
+
if (partial === undefined) {
throw new Exception('The partial ' + options.name + ' could not be found');
} else if (partial instanceof Function) {