Luke Blaney GitHub 1 год назад
Родитель
Сommit
53e429ba62
Не найден GPG ключ соответствующий данной подписи Идентификатор GPG ключа: B5690EEEBB952194
6 измененных файлов: 102 добавлений и 3 удалений
  1. +23
    -0
      README.md
  2. +29
    -2
      mustache.js
  3. +31
    -0
      test/mustache-spec-test.js
  4. +4
    -0
      test/parse-test.js
  5. +14
    -0
      test/partial-test.js
  6. +1
    -1
      test/spec

+ 23
- 0
README.md Просмотреть файл

@@ -419,6 +419,29 @@ Mustache.render(template, view, {
}); });
``` ```


Partials can have dynamic names, which begin with `*`. In this case, a value is read from the context and the partial with that value is used.

For example, this template and partial:

base.mustache:
<h2>Message of the Day</h2>
{{> *dayOfWeek}}

thursday.mustache:
<span>This must be Thursday. I never could get the hang of Thursdays.</span>

When loaded with the context:
```json
{
"dayOfWeek": "thursday"
}
```
will be expanded to:
```html
<h2>Message of the Day</h2>
<span>This must be Thursday. I never could get the hang of Thursdays.</span>
```

### Custom Delimiters ### Custom Delimiters


Custom delimiters can be used in place of `{{` and `}}` by setting the new values in JavaScript or in templates. Custom delimiters can be used in place of `{{` and `}}` by setting the new values in JavaScript or in templates.


+ 29
- 2
mustache.js Просмотреть файл

@@ -79,6 +79,7 @@ var spaceRe = /\s+/;
var equalsRe = /\s*=/; var equalsRe = /\s*=/;
var curlyRe = /\s*\}/; var curlyRe = /\s*\}/;
var tagRe = /#|\^|\/|>|\{|&|=|!/; var tagRe = /#|\^|\/|>|\{|&|=|!/;
var dynamicRe = /\*/;


/** /**
* Breaks up the given `template` string into a tree of tokens. If the `tags` * Breaks up the given `template` string into a tree of tokens. If the `tags`
@@ -202,6 +203,14 @@ function parseTemplate (template, tags) {
scanner.scan(curlyRe); scanner.scan(curlyRe);
scanner.scanUntil(closingTagRe); scanner.scanUntil(closingTagRe);
type = '&'; type = '&';
} else if (type === '>') {
if (scanner.scan(dynamicRe) === '') {
value = scanner.scanUntil(closingTagRe);
} else {
scanner.scan(whiteRe);
type = '>*';
value = scanner.scanUntil(closingTagRe);
}
} else { } else {
value = scanner.scanUntil(closingTagRe); value = scanner.scanUntil(closingTagRe);
} }
@@ -210,7 +219,7 @@ function parseTemplate (template, tags) {
if (!scanner.scan(closingTagRe)) if (!scanner.scan(closingTagRe))
throw new Error('Unclosed tag at ' + scanner.pos); throw new Error('Unclosed tag at ' + scanner.pos);


if (type == '>') {
if (type == '>' || type == '>*') {
token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ]; token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ];
} else { } else {
token = [ type, value, start, scanner.pos ]; token = [ type, value, start, scanner.pos ];
@@ -571,6 +580,7 @@ Writer.prototype.renderTokens = function renderTokens (tokens, context, partials
if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate, config); if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate, config);
else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate, config); else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate, config);
else if (symbol === '>') value = this.renderPartial(token, context, partials, config); else if (symbol === '>') value = this.renderPartial(token, context, partials, config);
else if (symbol === '>*') value = this.renderDynamicPartial(token, context, partials, config);
else if (symbol === '&') value = this.unescapedValue(token, context); else if (symbol === '&') value = this.unescapedValue(token, context);
else if (symbol === 'name') value = this.escapedValue(token, context, config); else if (symbol === 'name') value = this.escapedValue(token, context, config);
else if (symbol === 'text') value = this.rawValue(token); else if (symbol === 'text') value = this.rawValue(token);
@@ -636,10 +646,27 @@ Writer.prototype.indentPartial = function indentPartial (partial, indentation, l
return partialByNl.join('\n'); return partialByNl.join('\n');
}; };


Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) {
Writer.prototype.renderDynamicPartial = function renderPartial (token, context, partials, config) {
if (!partials) return; if (!partials) return;
var tags = this.getConfigTags(config); var tags = this.getConfigTags(config);
var name = context.lookup(token[1].trim());
var value = isFunction(partials) ? partials(name) : partials[name];
if (value != null) {
var lineHasNonSpace = token[6];
var tagIndex = token[5];
var indentation = token[4];
var indentedValue = value;
if (tagIndex == 0 && indentation) {
indentedValue = this.indentPartial(value, indentation, lineHasNonSpace);
}
var tokens = this.parse(indentedValue, tags);
return this.renderTokens(tokens, context, partials, indentedValue, config);
}
};


Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) {
if (!partials) return;
var tags = this.getConfigTags(config);
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 lineHasNonSpace = token[6];


+ 31
- 0
test/mustache-spec-test.js Просмотреть файл

@@ -14,6 +14,9 @@ var skipTests = {
inverted: [ inverted: [
'Standalone Without Newline' 'Standalone Without Newline'
], ],
interpolation: [
'Dotted Names - Context Precedence'
],
partials: [ partials: [
'Standalone Without Previous Line', 'Standalone Without Previous Line',
'Standalone Without Newline' 'Standalone Without Newline'
@@ -21,6 +24,34 @@ var skipTests = {
sections: [ sections: [
'Standalone Without Newline' 'Standalone Without Newline'
], ],
'~inheritance': [
'Default',
'Variable',
'Triple Mustache',
'Sections',
'Negative Sections',
'Mustache Injection',
'Inherit',
'Overridden content',
'Data does not override block',
'Data does not override block default',
'Overridden parent',
'Two overridden parents',
'Override parent with newlines',
'Inherit indentation',
'Only one override',
'Parent template',
'Recursion',
'Multi-level inheritance',
'Multi-level inheritance, no sub child',
'Text inside parent',
'Block scope',
'Standalone parent',
'Standalone block',
'Block reindentation',
'Intrinsic indentation',
'Nested block reindentation'
],
'~lambdas': [ '~lambdas': [
'Interpolation', 'Interpolation',
'Interpolation - Expansion', 'Interpolation - Expansion',


+ 4
- 0
test/parse-test.js Просмотреть файл

@@ -46,6 +46,10 @@ var expectations = {
' {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, false ] ], ' {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, false ] ],
' {{> abc }} {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, false ], [ '>', 'abc', 13, 23, ' ', 1, false ] ], ' {{> abc }} {{> abc }}\n' : [ [ '>', 'abc', 2, 12, ' ', 0, false ], [ '>', 'abc', 13, 23, ' ', 1, false ] ],
'{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0, false ] ], '{{ > abc }}' : [ [ '>', 'abc', 0, 11, '', 0, false ] ],
'{{>*abc}}' : [ [ '>*', 'abc', 0, 9, '', 0, false ] ],
'{{> *abc}}' : [ [ '>*', 'abc', 0, 10, '', 0, false ] ],
'{{>* abc}}' : [ [ '>*', 'abc', 0, 10, '', 0, false ] ],
'{{ > * abc }}' : [ [ '>*', 'abc', 0, 13, '', 0, false ] ],
'{{=<% %>=}}' : [ [ '=', '<% %>', 0, 11 ] ], '{{=<% %>=}}' : [ [ '=', '<% %>', 0, 11 ] ],
'{{= <% %> =}}' : [ [ '=', '<% %>', 0, 13 ] ], '{{= <% %> =}}' : [ [ '=', '<% %>', 0, 13 ] ],
'{{=<% %>=}}<%={{ }}=%>' : [ [ '=', '<% %>', 0, 11 ], [ '=', '{{ }}', 11, 22 ] ], '{{=<% %>=}}<%={{ }}=%>' : [ [ '=', '<% %>', 0, 11 ], [ '=', '{{ }}', 11, 22 ] ],


+ 14
- 0
test/partial-test.js Просмотреть файл

@@ -172,4 +172,18 @@ describe('Partials spec', function () {
var renderResult = Mustache.render(template, {}, partials, tags); var renderResult = Mustache.render(template, {}, partials, tags);
assert.equal(renderResult, expected); assert.equal(renderResult, expected);
}); });

describe('when rendering a dynamically named partial after already having rendered that partial with a different name value', function () {
it('returns different output for the latter render', function () {
var template = 'Place: {{>*place}}';
var partials = {
first: '1st',
second: '2nd',
};
var renderedFirst = Mustache.render(template, {place:'first'}, partials);
var renderedSecond = Mustache.render(template, {place:'second'}, partials);

assert.notEqual(renderedFirst, renderedSecond);
});
});
}); });

+ 1
- 1
test/spec

@@ -1 +1 @@
Subproject commit 72233f3ffda9e33915fd3022d0a9ebbcce265acd
Subproject commit 7138576e12ff0f05511de77807c2fb3959bb22e3

Загрузка…
Отмена
Сохранить