vendor/assets/javascripts/hogan.js in hogan_assets-1.0.0 vs vendor/assets/javascripts/hogan.js in hogan_assets-1.0.1
- old
+ new
@@ -11,66 +11,82 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-var HoganTemplate = (function () {
- function constructor(text) {
- this.text = text;
+
+var Hogan = {};
+
+(function (Hogan) {
+ Hogan.Template = function constructor(renderFunc, text, compiler) {
+ if (renderFunc) {
+ this.r = renderFunc;
+ }
+ this.c = compiler;
+ this.text = text || '';
}
- constructor.prototype = {
+ Hogan.Template.prototype = {
// render: replaced by generated code.
- r: function (context, partials) { return ''; },
+ r: function (context, partials, indent) { return ''; },
// variable escaping
v: hoganEscape,
- render: function render(context, partials) {
- return this.r(context, partials);
+ render: function render(context, partials, indent) {
+ return this.ri([context], partials || {}, indent);
},
+ // render internal -- a hook for overrides that catches partials too
+ ri: function (context, partials, indent) {
+ return this.r(context, partials, indent);
+ },
+
// tries to find a partial in the curent scope and render it
rp: function(name, context, partials, indent) {
var partial = partials[name];
if (!partial) {
return '';
}
- return partial.render(context, partials);
+ if (this.c && typeof partial == 'string') {
+ partial = this.c.compile(partial);
+ }
+
+ return partial.ri(context, partials, indent);
},
// render a section
rs: function(context, partials, section) {
var buf = '',
tail = context[context.length - 1];
if (!isArray(tail)) {
- buf = section(context, partials);
- return buf;
+ return buf = section(context, partials);
}
for (var i = 0; i < tail.length; i++) {
context.push(tail[i]);
buf += section(context, partials);
context.pop();
}
+
return buf;
},
// maybe start a section
- s: function(val, ctx, partials, inverted, start, end) {
+ s: function(val, ctx, partials, inverted, start, end, tags) {
var pass;
if (isArray(val) && val.length === 0) {
return false;
}
- if (!inverted && typeof val == 'function') {
- val = this.ls(val, ctx, partials, start, end);
+ if (typeof val == 'function') {
+ val = this.ls(val, ctx, partials, inverted, start, end, tags);
}
pass = (val === '') || !!val;
if (!inverted && pass && ctx) {
@@ -80,11 +96,10 @@
return pass;
},
// find values with dotted names
d: function(key, ctx, partials, returnFound) {
-
var names = key.split('.'),
val = this.f(names[0], ctx, partials, returnFound),
cx = null;
if (key === '.' && isArray(ctx[ctx.length - 2])) {
@@ -138,62 +153,92 @@
return val;
},
// higher order templates
- ho: function(val, cx, partials, text) {
+ ho: function(val, cx, partials, text, tags) {
+ var compiler = this.c;
var t = val.call(cx, text, function(t) {
- return Hogan.compile(t).render(cx);
+ return compiler.compile(t, {delimiters: tags}).render(cx, partials);
});
- var s = Hogan.compile(t.toString()).render(cx, partials);
+ var s = compiler.compile(t.toString(), {delimiters: tags}).render(cx, partials);
this.b = s;
return false;
},
// higher order template result buffer
b: '',
// lambda replace section
- ls: function(val, ctx, partials, start, end) {
+ ls: function(val, ctx, partials, inverted, start, end, tags) {
var cx = ctx[ctx.length - 1],
- t = val.call(cx);
+ t = null;
- if (val.length > 0) {
- return this.ho(val, cx, partials, this.text.substring(start, end));
+ if (!inverted && this.c && val.length > 0) {
+ return this.ho(val, cx, partials, this.text.substring(start, end), tags);
}
+ t = val.call(cx);
+
if (typeof t == 'function') {
- return this.ho(t, cx, partials, this.text.substring(start, end));
+ if (inverted) {
+ return true;
+ } else if (this.c) {
+ return this.ho(t, cx, partials, this.text.substring(start, end), tags);
+ }
}
+
return t;
},
// lambda replace variable
lv: function(val, ctx, partials) {
var cx = ctx[ctx.length - 1];
- return Hogan.compile(val.call(cx).toString()).render(cx, partials);
+ var result = val.call(cx);
+ if (typeof result == 'function') {
+ result = result.call(cx);
+ }
+ result = result.toString();
+
+ if (this.c && ~result.indexOf("{{")) {
+ return this.c.compile(result).render(cx, partials);
+ }
+
+ return result;
}
+
};
- var rAmp = /&/g, rLt = /</g, rGt = />/g, rApos =/\'/g,
- rQuot = /\"/g, hChars =/[&<>\"\']/;
+ var rAmp = /&/g,
+ rLt = /</g,
+ rGt = />/g,
+ rApos =/\'/g,
+ rQuot = /\"/g,
+ hChars =/[&<>\"\']/;
+
function hoganEscape(str) {
- var s = String(str === null ? '' : str);
- return hChars.test(s) ? s.replace(rAmp,'&')
- .replace(rLt,'<').replace(rGt,'>')
- .replace(rApos,''').replace(rQuot, '"') : s;
+ str = String((str === null || str === undefined) ? '' : str);
+ return hChars.test(str) ?
+ str
+ .replace(rAmp,'&')
+ .replace(rLt,'<')
+ .replace(rGt,'>')
+ .replace(rApos,''')
+ .replace(rQuot, '"') :
+ str;
}
var isArray = Array.isArray || function(a) {
return Object.prototype.toString.call(a) === '[object Array]';
};
- return constructor;
-})();
+})(typeof exports !== 'undefined' ? exports : Hogan);
-var Hogan = (function () {
+
+
+(function (Hogan) {
// Setup regex assignments
// remove whitespace according to Mustache spec
var rIsWhitespace = /\S/,
rQuot = /\"/g,
rNewline = /\n/g,
@@ -202,11 +247,11 @@
tagTypes = {
'#': 1, '^': 2, '/': 3, '!': 4, '>': 5,
'<': 6, '=': 7, '_v': 8, '{': 9, '&': 10
};
- function scan(text) {
+ Hogan.scan = function scan(text, delimiters) {
var len = text.length,
IN_TEXT = 0,
IN_TAG_TYPE = 1,
IN_TAG = 2,
state = IN_TEXT,
@@ -230,24 +275,29 @@
function lineIsWhitespace() {
var isAllWhitespace = true;
for (var j = lineStart; j < tokens.length; j++) {
isAllWhitespace =
(tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) ||
- (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null);
+ (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null);
if (!isAllWhitespace) {
return false;
}
}
return isAllWhitespace;
}
function filterLine(haveSeenTag, noNewLine) {
addBuf();
+
if (haveSeenTag && lineIsWhitespace()) {
- for (var j = lineStart; j < tokens.length; j++) {
+ for (var j = lineStart, next; j < tokens.length; j++) {
if (!tokens[j].tag) {
+ if ((next = tokens[j+1]) && next.tag == '>') {
+ // set indent to token value
+ next.indent = tokens[j].toString()
+ }
tokens.splice(j, 1);
}
}
} else if (!noNewLine) {
tokens.push({tag:'\n'});
@@ -258,17 +308,26 @@
}
function changeDelimiters(text, index) {
var close = '=' + ctag,
closeIndex = text.indexOf(close, index),
- delimiters = trim(text.substring(text.indexOf('=', index) + 1,
- closeIndex)).split(' ');
+ delimiters = trim(
+ text.substring(text.indexOf('=', index) + 1, closeIndex)
+ ).split(' ');
+
otag = delimiters[0];
ctag = delimiters[1];
+
return closeIndex + close.length - 1;
}
+ if (delimiters) {
+ delimiters = delimiters.split(' ');
+ otag = delimiters[0];
+ ctag = delimiters[1];
+ }
+
for (i = 0; i < len; i++) {
if (state == IN_TEXT) {
if (tagChange(otag, text, i)) {
--i;
addBuf();
@@ -282,29 +341,33 @@
}
} else if (state == IN_TAG_TYPE) {
i += otag.length - 1;
tag = tagTypes[text.charAt(i + 1)];
tagType = tag ? text.charAt(i + 1) : '_v';
- seenTag = i;
if (tagType == '=') {
i = changeDelimiters(text, i);
state = IN_TEXT;
} else {
if (tag) {
i++;
}
state = IN_TAG;
}
+ seenTag = i;
} else {
if (tagChange(ctag, text, i)) {
- i += ctag.length - 1;
- tokens.push({tag: tagType, n: trim(buf),
- i: (tagType == '/') ? seenTag - 1 : i + 1});
+ tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag,
+ i: (tagType == '/') ? seenTag - ctag.length : i + otag.length});
buf = '';
+ i += ctag.length - 1;
state = IN_TEXT;
if (tagType == '{') {
- i++;
+ if (ctag == '}}') {
+ i++;
+ } else {
+ cleanTripleStache(tokens[tokens.length - 1]);
+ }
}
} else {
buf += text.charAt(i);
}
}
@@ -313,10 +376,16 @@
filterLine(seenTag, true);
return tokens;
}
+ function cleanTripleStache(token) {
+ if (token.n.substr(token.n.length - 1) === '}') {
+ token.n = token.n.substring(0, token.n.length - 1);
+ }
+ }
+
function trim(s) {
if (s.trim) {
return s.trim();
}
@@ -342,12 +411,11 @@
opener = null,
token = null;
while (tokens.length > 0) {
token = tokens.shift();
- if (token.tag == '#' || token.tag == '^' ||
- isOpener(token, customTags)) {
+ if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) {
stack.push(token);
token.nodes = buildTree(tokens, token.tag, stack, customTags);
instructions.push(token);
} else if (token.tag == '/') {
if (stack.length === 0) {
@@ -386,20 +454,20 @@
return true;
}
}
}
- function generate(tree, text, options) {
- var code = 'var c = [cx];var b = "";var _ = this;' +
- walk(tree) + 'return b;';
+ function writeCode(tree) {
+ return 'i = i || "";var b = i + "";var _ = this;' + walk(tree) + 'return b;';
+ }
+
+ Hogan.generate = function (code, text, options) {
if (options.asString) {
- return 'function(cx,p){' + code + ';}';
+ return 'function(c,p,i){' + code + ';}';
}
- var template = new HoganTemplate(text);
- template.r = new Function('cx', 'p', code);
- return template;
+ return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan);
}
function esc(s) {
return s.replace(rSlash, '\\\\')
.replace(rQuot, '\\\"')
@@ -415,47 +483,47 @@
var code = '';
for (var i = 0, l = tree.length; i < l; i++) {
var tag = tree[i].tag;
if (tag == '#') {
code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n),
- tree[i].i, tree[i].end);
+ tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag);
} else if (tag == '^') {
code += invertedSection(tree[i].nodes, tree[i].n,
chooseMethod(tree[i].n));
} else if (tag == '<' || tag == '>') {
- code += partial(tree[i].n);
+ code += partial(tree[i]);
} else if (tag == '{' || tag == '&') {
code += tripleStache(tree[i].n, chooseMethod(tree[i].n));
} else if (tag == '\n') {
- code += text('\n');
+ code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i'));
} else if (tag == '_v') {
code += variable(tree[i].n, chooseMethod(tree[i].n));
} else if (tag === undefined) {
- code += text(tree[i]);
+ code += text('"' + esc(tree[i]) + '"');
}
}
return code;
}
- function section(nodes, id, method, start, end) {
+ function section(nodes, id, method, start, end, tags) {
return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' +
- 'c,p,0,' + start + ',' + end + ')){' +
+ 'c,p,0,' + start + ',' + end + ', "' + tags + '")){' +
'b += _.rs(c,p,' +
'function(c,p){ var b = "";' +
walk(nodes) +
'return b;});c.pop();}' +
'else{b += _.b; _.b = ""};';
}
function invertedSection(nodes, id, method) {
- return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0)){' +
+ return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' +
walk(nodes) +
'};';
}
- function partial(id) {
- return 'b += _.rp("' + esc(id) + '",c[c.length - 1],p);';
+ function partial(tok) {
+ return 'b += _.rp("' + esc(tok.n) + '",c,p,"' + (tok.indent || '') + '");';
}
function tripleStache(id, method) {
return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));';
}
@@ -463,52 +531,46 @@
function variable(id, method) {
return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));';
}
function text(id) {
- return 'b += "' + esc(id) + '";';
+ return 'b += ' + id + ';';
}
- return ({
- scan: scan,
+ Hogan.parse = function(tokens, options) {
+ options = options || {};
+ return buildTree(tokens, '', [], options.sectionTags || []);
+ },
- parse: function(tokens, options) {
- options = options || {};
- return buildTree(tokens, '', [], options.sectionTags || []);
- },
+ Hogan.cache = {};
- cache: {},
+ Hogan.compile = function(text, options) {
+ // options
+ //
+ // asString: false (default)
+ //
+ // sectionTags: [{o: '_foo', c: 'foo'}]
+ // An array of object with o and c fields that indicate names for custom
+ // section tags. The example above allows parsing of {{_foo}}{{/foo}}.
+ //
+ // delimiters: A string that overrides the default delimiters.
+ // Example: "<% %>"
+ //
+ options = options || {};
- compile: function(text, options) {
- // options
- //
- // asString: false (default)
- //
- // sectionTags: [{o: '_foo', c: 'foo'}]
- // An array of object with o and c fields that indicate names for custom
- // section tags. The example above allows parsing of {{_foo}}{{/foo}}.
- //
- options = options || {};
+ var key = text + '||' + !!options.asString;
- var t = this.cache[text];
- if (t) {
- return t;
- }
- t = generate(this.parse(scan(text), options), text, options);
- return this.cache[text] = t;
+ var t = this.cache[key];
+
+ if (t) {
+ return t;
}
- });
-})();
-// Export the hogan constructor for Node.js and CommonJS.
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = Hogan;
- module.exports.Template = HoganTemplate;
-} else if (typeof exports !== 'undefined') {
- exports.Hogan = Hogan;
- exports.HoganTemplate = HoganTemplate;
-}
+ t = this.generate(writeCode(this.parse(this.scan(text, options.delimiters), options)), text, options);
+ return this.cache[key] = t;
+ };
+})(typeof exports !== 'undefined' ? exports : Hogan);
-// Expose Hogan as an AMD module.
+
if (typeof define === 'function' && define.amd) {
- define(function () { return Hogan; });
+ define(Hogan);
}