| @@ -203,13 +203,19 @@ | |||||
| return fn; | return fn; | ||||
| }; | }; | ||||
| Writer.prototype.getPartial = function (name) { | |||||
| if (!(name in this._partialCache) && this._loadPartial) { | |||||
| this.compilePartial(name, this._loadPartial(name)); | |||||
| } | |||||
| return this._partialCache[name]; | |||||
| }; | |||||
| Writer.prototype.compileTokens = function (tokens, template) { | Writer.prototype.compileTokens = function (tokens, template) { | ||||
| var fn = compileTokens(tokens); | |||||
| var self = this; | var self = this; | ||||
| return function (view, partials) { | return function (view, partials) { | ||||
| if (partials) { | if (partials) { | ||||
| if (typeof partials === "function") { | |||||
| if (typeof partials === 'function') { | |||||
| self._loadPartial = partials; | self._loadPartial = partials; | ||||
| } else { | } else { | ||||
| for (var name in partials) { | for (var name in partials) { | ||||
| @@ -218,7 +224,7 @@ | |||||
| } | } | ||||
| } | } | ||||
| return fn(self, Context.make(view), template); | |||||
| return renderTokens(tokens, self, Context.make(view), template); | |||||
| }; | }; | ||||
| }; | }; | ||||
| @@ -226,122 +232,72 @@ | |||||
| return this.compile(template)(view, partials); | return this.compile(template)(view, partials); | ||||
| }; | }; | ||||
| Writer.prototype._section = function (token, context, template, callback) { | |||||
| var name = token[1]; | |||||
| var value = context.lookup(name); | |||||
| switch (typeof value) { | |||||
| case "object": | |||||
| if (isArray(value)) { | |||||
| var buffer = ''; | |||||
| for (var i = 0, len = value.length; i < len; ++i) { | |||||
| buffer += callback(this, context.push(value[i])); | |||||
| } | |||||
| return buffer; | |||||
| } | |||||
| return value ? callback(this, context.push(value)) : ""; | |||||
| case "function": | |||||
| var text = template == null ? null : template.slice(token[3], token[5]); | |||||
| var self = this; | |||||
| var scopedRender = function (template) { | |||||
| return self.render(template, context); | |||||
| }; | |||||
| var result = value.call(context.view, text, scopedRender); | |||||
| return result == null ? '' : result; | |||||
| default: | |||||
| if (value) { | |||||
| return callback(this, context); | |||||
| } | |||||
| } | |||||
| return ''; | |||||
| }; | |||||
| Writer.prototype._inverted = function (token, context, callback) { | |||||
| var value = context.lookup(token[1]); | |||||
| // Use JavaScript's definition of falsy. Include empty arrays. | |||||
| // See https://github.com/janl/mustache.js/issues/186 | |||||
| if (!value || (isArray(value) && value.length === 0)) { | |||||
| return callback(this, context); | |||||
| } | |||||
| return ''; | |||||
| }; | |||||
| Writer.prototype._partial = function (token, context) { | |||||
| var name = token[1]; | |||||
| /** | |||||
| * Low-level function that renders the given `tokens` using the given `writer` | |||||
| * and `context`. The `template` string is only needed for templates that use | |||||
| * higher-order sections to extract the portion of the original template that | |||||
| * was contained in that section. | |||||
| */ | |||||
| function renderTokens(tokens, writer, context, template) { | |||||
| var buffer = ''; | |||||
| if (!(name in this._partialCache) && this._loadPartial) { | |||||
| this.compilePartial(name, this._loadPartial(name)); | |||||
| } | |||||
| var token, tokenValue, value; | |||||
| for (var i = 0, len = tokens.length; i < len; ++i) { | |||||
| token = tokens[i]; | |||||
| tokenValue = token[1]; | |||||
| var fn = this._partialCache[name]; | |||||
| switch (token[0]) { | |||||
| case '#': | |||||
| value = context.lookup(tokenValue); | |||||
| return fn ? fn(context) : ''; | |||||
| }; | |||||
| if (typeof value === 'object') { | |||||
| if (isArray(value)) { | |||||
| for (var j = 0, jlen = value.length; j < jlen; ++j) { | |||||
| buffer += renderTokens(token[4], writer, context.push(value[j]), template); | |||||
| } | |||||
| } else if (value) { | |||||
| buffer += renderTokens(token[4], writer, context.push(value), template); | |||||
| } | |||||
| } else if (typeof value === 'function') { | |||||
| var text = template == null ? null : template.slice(token[3], token[5]); | |||||
| var result = value.call(context.view, text, function (template) { | |||||
| return writer.render(template, context); | |||||
| }); | |||||
| if (result != null) buffer += result; | |||||
| } else if (value) { | |||||
| buffer += renderTokens(token[4], writer, context, template); | |||||
| } | |||||
| Writer.prototype._name = function (token, context) { | |||||
| var value = context.lookup(token[1]); | |||||
| return value == null ? '' : value; | |||||
| }; | |||||
| break; | |||||
| case '^': | |||||
| value = context.lookup(tokenValue); | |||||
| Writer.prototype._escaped = function (token, context) { | |||||
| return exports.escape(this._name(token, context)); | |||||
| }; | |||||
| // Use JavaScript's definition of falsy. Include empty arrays. | |||||
| // See https://github.com/janl/mustache.js/issues/186 | |||||
| if (!value || (isArray(value) && value.length === 0)) { | |||||
| buffer += renderTokens(token[4], writer, context, template); | |||||
| } | |||||
| /** | |||||
| * Low-level function that compiles the given `tokens` into a function | |||||
| * that accepts three arguments: a Writer, a Context, and the template. | |||||
| */ | |||||
| function compileTokens(tokens) { | |||||
| var subRenders = {}; | |||||
| function subRender(i, tokens, template) { | |||||
| if (!subRenders[i]) { | |||||
| var fn = compileTokens(tokens); | |||||
| subRenders[i] = function (writer, context) { | |||||
| return fn(writer, context, template); | |||||
| }; | |||||
| break; | |||||
| case '>': | |||||
| value = writer.getPartial(tokenValue); | |||||
| if (typeof value === 'function') buffer += value(context); | |||||
| break; | |||||
| case '&': | |||||
| value = context.lookup(tokenValue); | |||||
| if (value != null) buffer += value; | |||||
| break; | |||||
| case 'name': | |||||
| value = context.lookup(tokenValue); | |||||
| if (value != null) buffer += exports.escape(value); | |||||
| break; | |||||
| case 'text': | |||||
| buffer += tokenValue; | |||||
| break; | |||||
| } | } | ||||
| return subRenders[i]; | |||||
| } | } | ||||
| return function (writer, context, template) { | |||||
| var buffer = ''; | |||||
| var token; | |||||
| for (var i = 0, len = tokens.length; i < len; ++i) { | |||||
| token = tokens[i]; | |||||
| switch (token[0]) { | |||||
| case "#": | |||||
| buffer += writer._section(token, context, template, subRender(i, token[4], template)); | |||||
| break; | |||||
| case "^": | |||||
| buffer += writer._inverted(token, context, subRender(i, token[4], template)); | |||||
| break; | |||||
| case ">": | |||||
| buffer += writer._partial(token, context); | |||||
| break; | |||||
| case "&": | |||||
| buffer += writer._name(token, context); | |||||
| break; | |||||
| case "name": | |||||
| buffer += writer._escaped(token, context); | |||||
| break; | |||||
| case "text": | |||||
| buffer += token[1]; | |||||
| break; | |||||
| } | |||||
| } | |||||
| return buffer; | |||||
| }; | |||||
| return buffer; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -544,8 +500,7 @@ | |||||
| return nestTokens(squashTokens(tokens)); | return nestTokens(squashTokens(tokens)); | ||||
| }; | }; | ||||
| // The high-level clearCache, compile, compilePartial, and render functions | |||||
| // use this default writer. | |||||
| // All Mustache.* functions use this writer. | |||||
| var _writer = new Writer(); | var _writer = new Writer(); | ||||
| /** | /** | ||||