These changes fixes an indentation bug introduced when partials was made to also be indented like its parent template. When partials are rendered inline, it should not be indented with the amount of indentation that the line already has. Fixes https://github.com/janl/mustache.js/issues/715 Refs https://github.com/janl/mustache.js/pull/705tags/v3.1.0
| @@ -122,7 +122,7 @@ | |||||
| function parseTemplate (template, tags) { | function parseTemplate (template, tags) { | ||||
| if (!template) | if (!template) | ||||
| return []; | return []; | ||||
| var lineHasNonSpace = false; | |||||
| 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; | ||||
| lineHasNonSpace = true; | |||||
| 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; | ||||
| lineHasNonSpace = false; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -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, lineHasNonSpace ]; | |||||
| } 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, lineHasNonSpace) { | |||||
| 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 || !lineHasNonSpace)) { | |||||
| 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 lineHasNonSpace = 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, lineHasNonSpace); | |||||
| } | } | ||||
| 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, false ] ], | |||||
| '{{> abc }}' : [ [ '>', 'abc', 0, 10, '', 0, false ] ], | |||||
| '{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0, false ] ], | |||||
| ' {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, false ] ], | |||||
| ' {{> abc }} {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, false ], [ '>', 'abc', 13, 23, ' ', 1, false ] ], | |||||
| '{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0, false ] ], | |||||
| '{{=<% %>=}}' : [ [ '=', '<% %>', 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':[]}]}; | ||||