| @@ -122,7 +122,7 @@ | |||||
| function parseTemplate (template, tags) { | function parseTemplate (template, tags) { | ||||
| if (!template) | if (!template) | ||||
| return []; | return []; | ||||
| var firstNonSpace = true; | |||||
| var sections = []; // Stack to hold section tokens | var sections = []; // Stack to hold section tokens | ||||
| var tokens = []; // Buffer to hold the tokens | var tokens = []; // Buffer to hold the tokens | ||||
| var spaces = []; // Indices of whitespace tokens on the current line | var spaces = []; // Indices of whitespace tokens on the current line | ||||
| @@ -175,10 +175,11 @@ | |||||
| if (isWhitespace(chr)) { | if (isWhitespace(chr)) { | ||||
| spaces.push(tokens.length); | spaces.push(tokens.length); | ||||
| if (!nonSpace) | |||||
| indentation += chr; | |||||
| indentation += chr; | |||||
| } else { | } else { | ||||
| nonSpace = true; | nonSpace = true; | ||||
| firstNonSpace = false; | |||||
| indentation += ' '; | |||||
| } | } | ||||
| tokens.push([ 'text', chr, start, start + 1 ]); | tokens.push([ 'text', chr, start, start + 1 ]); | ||||
| @@ -189,6 +190,7 @@ | |||||
| stripSpace(); | stripSpace(); | ||||
| indentation = ''; | indentation = ''; | ||||
| tagIndex = 0; | tagIndex = 0; | ||||
| firstNonSpace = true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -222,7 +224,7 @@ | |||||
| throw new Error('Unclosed tag at ' + scanner.pos); | throw new Error('Unclosed tag at ' + scanner.pos); | ||||
| if (type == '>') { | if (type == '>') { | ||||
| token = [ type, value, start, scanner.pos, indentation, tagIndex ]; | |||||
| token = [ type, value, start, scanner.pos, indentation, tagIndex, firstNonSpace ]; | |||||
| } else { | } else { | ||||
| token = [ type, value, start, scanner.pos ]; | token = [ type, value, start, scanner.pos ]; | ||||
| } | } | ||||
| @@ -610,11 +612,11 @@ | |||||
| return this.renderTokens(token[4], context, partials, originalTemplate); | return this.renderTokens(token[4], context, partials, originalTemplate); | ||||
| }; | }; | ||||
| Writer.prototype.indentPartial = function indentPartial (partial, indentation) { | |||||
| Writer.prototype.indentPartial = function indentPartial (partial, indentation, firstNonSpace) { | |||||
| var filteredIndentation = indentation.replace(/[^ \t]/g, ''); | var filteredIndentation = indentation.replace(/[^ \t]/g, ''); | ||||
| var partialByNl = partial.split('\n'); | var partialByNl = partial.split('\n'); | ||||
| for (var i = 0; i < partialByNl.length; i++) { | for (var i = 0; i < partialByNl.length; i++) { | ||||
| if (partialByNl[i].length) { | |||||
| if (partialByNl[i].length && (i > 0 || firstNonSpace)) { | |||||
| partialByNl[i] = filteredIndentation + partialByNl[i]; | partialByNl[i] = filteredIndentation + partialByNl[i]; | ||||
| } | } | ||||
| } | } | ||||
| @@ -626,11 +628,12 @@ | |||||
| var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; | var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; | ||||
| if (value != null) { | if (value != null) { | ||||
| var firstNonSpace = token[6]; | |||||
| var tagIndex = token[5]; | var tagIndex = token[5]; | ||||
| var indentation = token[4]; | var indentation = token[4]; | ||||
| var indentedValue = value; | var indentedValue = value; | ||||
| if (tagIndex == 0 && indentation) { | if (tagIndex == 0 && indentation) { | ||||
| indentedValue = this.indentPartial(value, indentation); | |||||
| indentedValue = this.indentPartial(value, indentation, firstNonSpace); | |||||
| } | } | ||||
| return this.renderTokens(this.parse(indentedValue, tags), context, partials, indentedValue); | return this.renderTokens(this.parse(indentedValue, tags), context, partials, indentedValue); | ||||
| } | } | ||||
| @@ -40,12 +40,12 @@ var expectations = { | |||||
| 'a\n{{#a}}\n{{#b}}\n{{/b}}\n{{/a}}\nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 2, 8, [ [ '#', 'b', 9, 15, [], 16 ] ], 23 ], [ 'text', 'b', 30, 31 ] ], | 'a\n{{#a}}\n{{#b}}\n{{/b}}\n{{/a}}\nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 2, 8, [ [ '#', 'b', 9, 15, [], 16 ] ], 23 ], [ 'text', 'b', 30, 31 ] ], | ||||
| 'a\n {{#a}}\n{{#b}}\n{{/b}}\n{{/a}}\nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 3, 9, [ [ '#', 'b', 10, 16, [], 17 ] ], 24 ], [ 'text', 'b', 31, 32 ] ], | 'a\n {{#a}}\n{{#b}}\n{{/b}}\n{{/a}}\nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 3, 9, [ [ '#', 'b', 10, 16, [], 17 ] ], 24 ], [ 'text', 'b', 31, 32 ] ], | ||||
| 'a\n {{#a}}\n{{#b}}\n{{/b}}\n{{/a}} \nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 3, 9, [ [ '#', 'b', 10, 16, [], 17 ] ], 24 ], [ 'text', 'b', 32, 33 ] ], | 'a\n {{#a}}\n{{#b}}\n{{/b}}\n{{/a}} \nb' : [ [ 'text', 'a\n', 0, 2 ], [ '#', 'a', 3, 9, [ [ '#', 'b', 10, 16, [], 17 ] ], 24 ], [ 'text', 'b', 32, 33 ] ], | ||||
| '{{>abc}}' : [ [ '>', 'abc', 0, 8, '', 0 ] ], | |||||
| '{{> abc }}' : [ [ '>', 'abc', 0, 10, '', 0 ] ], | |||||
| '{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0 ] ], | |||||
| ' {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0 ] ], | |||||
| ' {{> abc }} {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0 ], [ '>', 'abc', 13, 23, ' ', 1 ] ], | |||||
| '{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0 ] ], | |||||
| '{{>abc}}' : [ [ '>', 'abc', 0, 8, '', 0, true ] ], | |||||
| '{{> abc }}' : [ [ '>', 'abc', 0, 10, '', 0, true ] ], | |||||
| '{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0, true ] ], | |||||
| ' {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, true ] ], | |||||
| ' {{> abc }} {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, true ], [ '>', 'abc', 13, 23, ' ', 1, true ] ], | |||||
| '{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0, true ] ], | |||||
| '{{=<% %>=}}' : [ [ '=', '<% %>', 0, 11 ] ], | '{{=<% %>=}}' : [ [ '=', '<% %>', 0, 11 ] ], | ||||
| '{{= <% %> =}}' : [ [ '=', '<% %>', 0, 13 ] ], | '{{= <% %> =}}' : [ [ '=', '<% %>', 0, 13 ] ], | ||||
| '{{=<% %>=}}<%={{ }}=%>' : [ [ '=', '<% %>', 0, 11 ], [ '=', '{{ }}', 11, 22 ] ], | '{{=<% %>=}}<%={{ }}=%>' : [ [ '=', '<% %>', 0, 11 ], [ '=', '{{ }}', 11, 22 ] ], | ||||
| @@ -31,6 +31,24 @@ describe('Partials spec', function () { | |||||
| var renderResult = Mustache.render(template, data, partials); | var renderResult = Mustache.render(template, data, partials); | ||||
| assert.equal(renderResult, expected); | assert.equal(renderResult, expected); | ||||
| }); | }); | ||||
| it('Inline partials should not be indented', function () { | |||||
| var template = ' <div>{{> partial}}</div>'; | |||||
| var data = {}; | |||||
| var partials = {'partial':'This is a partial.'}; | |||||
| var expected = ' <div>This is a partial.</div>'; | |||||
| var renderResult = Mustache.render(template, data, partials); | |||||
| assert.equal(renderResult, expected); | |||||
| }); | |||||
| it('Inline partials should not be indented (multiline)', function () { | |||||
| var template = ' <div>{{> partial}}</div>'; | |||||
| var data = {}; | |||||
| var partials = {'partial':'This is a\npartial.'}; | |||||
| var expected = ' <div>This is a\n partial.</div>'; | |||||
| var renderResult = Mustache.render(template, data, partials); | |||||
| assert.equal(renderResult, expected); | |||||
| }); | |||||
| it('The greater-than operator should properly recurse.', function () { | it('The greater-than operator should properly recurse.', function () { | ||||
| var template = '{{>node}}'; | var template = '{{>node}}'; | ||||
| var data = {'content':'X','nodes':[{'content':'Y','nodes':[]}]}; | var data = {'content':'X','nodes':[{'content':'Y','nodes':[]}]}; | ||||