Implement parser for else chaining of helpers
Allows users to chain multiple helpers together using their inverse callbacks. I.e.
```
{{#if foo}}
{{else if bar}}
{{else}}
{{/if}}
```
The control flow here effectively causes the helpers to be nested. The above is actually syntactic sugar for this:
```
{{#if foo}}
{{else}}
{{#if bar}}
{{else}}
{{/if}}
{{/if}}
```
Any helper may be used in this manner, the only requirement is they support normal calls and inverse calls.
Introduces a breaking change in that `{{else foo}}` may no longer be used as a root level operator. Instead `{{^foo}}` must be used.
Fixes #72.
This commit is contained in:
@@ -10,11 +10,29 @@ export function stripFlags(open, close) {
|
||||
|
||||
export function prepareBlock(mustache, program, inverseAndProgram, close, inverted, locInfo) {
|
||||
/*jshint -W040 */
|
||||
if (mustache.sexpr.id.original !== close.path.original) {
|
||||
// When we are chaining inverse calls, we will not have a close path
|
||||
if (close && close.path && (mustache.sexpr.id.original !== close.path.original)) {
|
||||
throw new Exception(mustache.sexpr.id.original + ' doesn\'t match ' + close.path.original, mustache);
|
||||
}
|
||||
|
||||
var inverse = inverseAndProgram && inverseAndProgram.program;
|
||||
// Safely handle a chained inverse that does not have a non-conditional inverse
|
||||
// (i.e. both inverseAndProgram AND close are undefined)
|
||||
if (!close) {
|
||||
close = {strip: {}};
|
||||
}
|
||||
|
||||
// Find the inverse program that is involed with whitespace stripping.
|
||||
var inverse = inverseAndProgram && inverseAndProgram.program,
|
||||
firstInverse = inverse,
|
||||
lastInverse = inverse;
|
||||
if (inverse && inverse.inverse) {
|
||||
firstInverse = inverse.statements[0].program;
|
||||
|
||||
// Walk the inverse chain to find the last inverse that is actually in the chain.
|
||||
while (lastInverse.inverse) {
|
||||
lastInverse = lastInverse.statements[lastInverse.statements.length-1].program;
|
||||
}
|
||||
}
|
||||
|
||||
var strip = {
|
||||
left: mustache.strip.left,
|
||||
@@ -23,7 +41,7 @@ export function prepareBlock(mustache, program, inverseAndProgram, close, invert
|
||||
// Determine the standalone candiacy. Basically flag our content as being possibly standalone
|
||||
// so our parent can determine if we actually are standalone
|
||||
openStandalone: isNextWhitespace(program.statements),
|
||||
closeStandalone: isPrevWhitespace((inverse || program).statements)
|
||||
closeStandalone: isPrevWhitespace((firstInverse || program).statements)
|
||||
};
|
||||
|
||||
if (mustache.strip.right) {
|
||||
@@ -36,19 +54,20 @@ export function prepareBlock(mustache, program, inverseAndProgram, close, invert
|
||||
if (inverseStrip.left) {
|
||||
omitLeft(program.statements, null, true);
|
||||
}
|
||||
|
||||
if (inverseStrip.right) {
|
||||
omitRight(inverse.statements, null, true);
|
||||
omitRight(firstInverse.statements, null, true);
|
||||
}
|
||||
if (close.strip.left) {
|
||||
omitLeft(inverse.statements, null, true);
|
||||
omitLeft(lastInverse.statements, null, true);
|
||||
}
|
||||
|
||||
// Find standalone else statments
|
||||
if (isPrevWhitespace(program.statements)
|
||||
&& isNextWhitespace(inverse.statements)) {
|
||||
&& isNextWhitespace(firstInverse.statements)) {
|
||||
|
||||
omitLeft(program.statements);
|
||||
omitRight(inverse.statements);
|
||||
omitRight(firstInverse.statements);
|
||||
}
|
||||
} else {
|
||||
if (close.strip.left) {
|
||||
|
||||
Reference in New Issue
Block a user