+// The MIT License
+//
+// Copyright (c) 2009 Chris Wanstrath (Ruby)
+// Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)
+// Copyright (c) 2010-2015 The mustache.js community
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+// Description of import into Moodle:
+// Checkout from https://github.com/moodle/custom-mustache.js
+// Rebase onto latest release tag from https://github.com/janl/mustache.js
+// Copy mustache.js into lib/amd/src/ in Moodle folder.
+// Add the license as a comment to the file and these instructions.
+// Add jshint tags so this file is not linted.
+// Remove the "global define:" comment (hint for linter)
+// Make sure that you have not removed the custom code for '$' and '<'.
+
/*!
* mustache.js - Logic-less {{mustache}} templates with JavaScript
* http://github.com/janl/mustache.js
*/
-/*global define: false Mustache: true*/
+/* jshint ignore:start */
(function defineMustache (global, factory) {
if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') {
var spaceRe = /\s+/;
var equalsRe = /\s*=/;
var curlyRe = /\s*\}/;
- var tagRe = /#|\^|\/|>|\{|&|=|!/;
+ var tagRe = /#|\^|\/|>|\{|&|=|!|\$|</;
/**
* Breaks up the given `template` string into a tree of tokens. If the `tags`
token = [ type, value, start, scanner.pos ];
tokens.push(token);
- if (type === '#' || type === '^') {
+ if (type === '#' || type === '^' || type === '$' || type === '<') {
sections.push(token);
} else if (type === '/') {
// Check section nesting.
token = tokens[i];
switch (token[0]) {
+ case '$':
+ case '<':
case '#':
case '^':
collector.push(token);
*/
function Context (view, parentContext) {
this.view = view;
+ this.blocks = {};
this.cache = { '.': this.view };
this.parent = parentContext;
}
return new Context(view, this);
};
+ /**
+ * Set a value in the current block context.
+ */
+ Context.prototype.setBlockVar = function set (name, value) {
+ var blocks = this.blocks;
+
+ blocks[name] = value;
+
+ return value;
+ };
+
+ /**
+ * Clear all current block vars.
+ */
+ Context.prototype.clearBlockVars = function clearBlockVars () {
+ this.blocks = {};
+ };
+
+ /**
+ * Get a value only from the current block context.
+ */
+ Context.prototype.getBlockVar = function getBlockVar (name) {
+ var blocks = this.blocks;
+
+ var value;
+ if (blocks.hasOwnProperty(name)) {
+ value = blocks[name];
+ } else {
+ if (this.parent) {
+ value = this.parent.getBlockVar(name);
+ }
+ }
+ // Can return undefined.
+ return value;
+ };
+
/**
* Returns the value of the given name in this context, traversing
* up the context hierarchy if the value is absent in this context's view.
if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate);
else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate);
else if (symbol === '>') value = this.renderPartial(token, context, partials, originalTemplate);
+ else if (symbol === '<') value = this.renderBlock(token, context, partials, originalTemplate);
+ else if (symbol === '$') value = this.renderBlockVariable(token, context, partials, originalTemplate);
else if (symbol === '&') value = this.unescapedValue(token, context);
else if (symbol === 'name') value = this.escapedValue(token, context);
else if (symbol === 'text') value = this.rawValue(token);
return this.renderTokens(this.parse(value), context, partials, value);
};
+ Writer.prototype.renderBlock = function renderBlock (token, context, partials, originalTemplate) {
+ if (!partials) return;
+
+ var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
+ if (value != null)
+ // Ignore any wrongly set block vars before we started.
+ context.clearBlockVars();
+ // We are only rendering to record the default block variables.
+ this.renderTokens(token[4], context, partials, originalTemplate);
+ // Now we render and return the result.
+ var result = this.renderTokens(this.parse(value), context, partials, value);
+ // Don't leak the block variables outside this include.
+ context.clearBlockVars();
+ return result;
+ };
+
+ Writer.prototype.renderBlockVariable = function renderBlockVariable (token, context, partials, originalTemplate) {
+ var value = token[1];
+
+ var exists = context.getBlockVar(value);
+ if (!exists) {
+ context.setBlockVar(value, originalTemplate.slice(token[3], token[5]));
+ return this.renderTokens(token[4], context, partials, originalTemplate);
+ } else {
+ return this.renderTokens(this.parse(exists), context, partials, exists);
+ }
+ };
+
Writer.prototype.unescapedValue = function unescapedValue (token, context) {
var value = context.lookup(token[1]);
if (value != null)
return mustache;
}));
+/* jshint ignore:end */