Add support for dynamic partial names

Uses the subexpression syntax to allow for dynamic partial lookups. Ex:

```
{{> (helper) }}
```

Fixes #933
This commit is contained in:
kpdecker
2015-01-18 13:23:45 -06:00
parent b0b522b4f8
commit cb51b82b8e
9 changed files with 92 additions and 9 deletions
+9
View File
@@ -63,6 +63,15 @@ var AST = {
this.hash = hash;
},
PartialExpression: function(name, params, hash, locInfo) {
this.loc = locInfo;
this.type = 'PartialExpression';
this.name = name;
this.params = params || [];
this.hash = hash;
},
PathExpression: function(data, depth, parts, original, locInfo) {
this.loc = locInfo;
this.type = 'PathExpression';
+8 -2
View File
@@ -145,7 +145,6 @@ Compiler.prototype = {
},
PartialStatement: function(partial) {
var partialName = partial.sexpr.path.original;
this.usePartial = true;
var params = partial.sexpr.params;
@@ -155,6 +154,12 @@ Compiler.prototype = {
params.push({type: 'PathExpression', parts: [], depth: 0});
}
var partialName = partial.sexpr.name.original,
isDynamic = partial.sexpr.name.type === 'SubExpression';
if (isDynamic) {
this.accept(partial.sexpr.name);
}
this.setupFullMustacheParams(partial.sexpr, undefined, undefined, true);
var indent = partial.indent || '';
@@ -162,7 +167,8 @@ Compiler.prototype = {
this.opcode('appendContent', indent);
indent = '';
}
this.opcode('invokePartial', partialName, indent);
this.opcode('invokePartial', isDynamic, partialName, indent);
this.opcode('append');
},
+11 -2
View File
@@ -644,17 +644,26 @@ JavaScriptCompiler.prototype = {
//
// This operation pops off a context, invokes a partial with that context,
// and pushes the result of the invocation back.
invokePartial: function(name, indent) {
invokePartial: function(isDynamic, name, indent) {
var params = [],
options = this.setupParams(name, 1, params, false);
if (isDynamic) {
name = this.popStack();
delete options.name;
}
if (indent) {
options.indent = JSON.stringify(indent);
}
options.helpers = 'helpers';
options.partials = 'partials';
params.unshift(this.nameLookup('partials', name, 'partial'));
if (!isDynamic) {
params.unshift(this.nameLookup('partials', name, 'partial'));
} else {
params.unshift(name);
}
if (this.options.compat) {
options.depths = 'depths';
+1 -1
View File
@@ -75,7 +75,7 @@ PrintVisitor.prototype.BlockStatement = function(block) {
PrintVisitor.prototype.PartialStatement = function(partial) {
var sexpr = partial.sexpr,
content = 'PARTIAL:' + sexpr.path.original;
content = 'PARTIAL:' + sexpr.name.original;
if(sexpr.params[0]) {
content += ' ' + this.accept(sexpr.params[0]);
}
+5
View File
@@ -92,6 +92,11 @@ Visitor.prototype = {
this.acceptArray(sexpr.params);
this.acceptKey(sexpr, 'hash');
},
PartialExpression: function(partial) {
this.acceptRequired(partial, 'name');
this.acceptArray(partial.params);
this.acceptKey(partial, 'hash');
},
PathExpression: function(/* path */) {},
+12 -3
View File
@@ -39,10 +39,8 @@ export function template(templateSpec, env) {
if (options.hash) {
context = Utils.extend({}, context, options.hash);
}
if (!partial) {
partial = options.partials[options.name];
}
partial = env.VM.resolvePartial.call(this, partial, context, options);
var result = env.VM.invokePartial.call(this, partial, context, options);
if (result == null && env.compile) {
@@ -187,6 +185,17 @@ export function program(container, i, fn, data, declaredBlockParams, blockParams
return prog;
}
export function resolvePartial(partial, context, options) {
if (!partial) {
partial = options.partials[options.name];
} else if (!partial.call && !options.name) {
// This is a dynamic partial that returned a string
options.name = partial;
partial = options.partials[partial];
}
return partial;
}
export function invokePartial(partial, context, options) {
options.partial = true;