Skip to content

Commit fdc71a3

Browse files
author
Damyon Wiese
committed
Pull request janl#473
Add template inheritance feature.
1 parent b0a6d6c commit fdc71a3

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

mustache.js

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
var spaceRe = /\s+/;
7777
var equalsRe = /\s*=/;
7878
var curlyRe = /\s*\}/;
79-
var tagRe = /#|\^|\/|>|\{|&|=|!/;
79+
var tagRe = /#|\^|\/|>|\{|&|=|!|\$|</;
8080

8181
/**
8282
* Breaks up the given `template` string into a tree of tokens. If the `tags`
@@ -198,7 +198,7 @@
198198
token = [ type, value, start, scanner.pos ];
199199
tokens.push(token);
200200

201-
if (type === '#' || type === '^') {
201+
if (type === '#' || type === '^' || type === '$' || type === '<') {
202202
sections.push(token);
203203
} else if (type === '/') {
204204
// Check section nesting.
@@ -267,6 +267,8 @@
267267
token = tokens[i];
268268

269269
switch (token[0]) {
270+
case '$':
271+
case '<':
270272
case '#':
271273
case '^':
272274
collector.push(token);
@@ -352,6 +354,7 @@
352354
*/
353355
function Context (view, parentContext) {
354356
this.view = view;
357+
this.blocks = {};
355358
this.cache = { '.': this.view };
356359
this.parent = parentContext;
357360
}
@@ -364,6 +367,42 @@
364367
return new Context(view, this);
365368
};
366369

370+
/**
371+
* Set a value in the current block context.
372+
*/
373+
Context.prototype.setBlockVar = function set (name, value) {
374+
var blocks = this.blocks;
375+
376+
blocks[name] = value;
377+
378+
return value;
379+
};
380+
381+
/**
382+
* Clear all current block vars.
383+
*/
384+
Context.prototype.clearBlockVars = function clearBlockVars () {
385+
this.blocks = {};
386+
};
387+
388+
/**
389+
* Get a value only from the current block context.
390+
*/
391+
Context.prototype.getBlockVar = function getBlockVar (name) {
392+
var blocks = this.blocks;
393+
394+
var value;
395+
if (blocks.hasOwnProperty(name)) {
396+
value = blocks[name];
397+
} else {
398+
if (this.parent) {
399+
value = this.parent.getBlockVar(name);
400+
}
401+
}
402+
// Can return undefined.
403+
return value;
404+
};
405+
367406
/**
368407
* Returns the value of the given name in this context, traversing
369408
* up the context hierarchy if the value is absent in this context's view.
@@ -486,6 +525,8 @@
486525
if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate);
487526
else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate);
488527
else if (symbol === '>') value = this.renderPartial(token, context, partials, originalTemplate);
528+
else if (symbol === '<') value = this.renderBlock(token, context, partials, originalTemplate);
529+
else if (symbol === '$') value = this.renderBlockVariable(token, context, partials, originalTemplate);
489530
else if (symbol === '&') value = this.unescapedValue(token, context);
490531
else if (symbol === 'name') value = this.escapedValue(token, context);
491532
else if (symbol === 'text') value = this.rawValue(token);
@@ -548,6 +589,34 @@
548589
return this.renderTokens(this.parse(value), context, partials, value);
549590
};
550591

592+
Writer.prototype.renderBlock = function renderBlock (token, context, partials, originalTemplate) {
593+
if (!partials) return;
594+
595+
var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
596+
if (value != null)
597+
// Ignore any wrongly set block vars before we started.
598+
context.clearBlockVars();
599+
// We are only rendering to record the default block variables.
600+
this.renderTokens(token[4], context, partials, originalTemplate);
601+
// Now we render and return the result.
602+
var result = this.renderTokens(this.parse(value), context, partials, value);
603+
// Don't leak the block variables outside this include.
604+
context.clearBlockVars();
605+
return result;
606+
};
607+
608+
Writer.prototype.renderBlockVariable = function renderBlockVariable (token, context, partials, originalTemplate) {
609+
var value = token[1];
610+
611+
var exists = context.getBlockVar(value);
612+
if (!exists) {
613+
context.setBlockVar(value, originalTemplate.slice(token[3], token[5]));
614+
return this.renderTokens(token[4], context, partials, originalTemplate);
615+
} else {
616+
return this.renderTokens(this.parse(exists), context, partials, exists);
617+
}
618+
};
619+
551620
Writer.prototype.unescapedValue = function unescapedValue (token, context) {
552621
var value = context.lookup(token[1]);
553622
if (value != null)

0 commit comments

Comments
 (0)