AutorÃa | Ultima modificación | Ver Log |
/*!* Copyright 2011 Twitter, Inc.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* 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 Hogan = {};(function (Hogan) {Hogan.Template = function (codeObj, text, compiler, options) {codeObj = codeObj || {};this.r = codeObj.code || this.r;this.c = compiler;this.options = options || {};this.text = text || '';this.partials = codeObj.partials || {};this.subs = codeObj.subs || {};this.buf = '';}Hogan.Template.prototype = {// render: replaced by generated code.r: function (context, partials, indent) { return ''; },// variable escapingv: hoganEscape,// triple stachet: coerceToString,render: function render(context, partials, indent) {return this.ri([context], partials || {}, indent);},// render internal -- a hook for overrides that catches partials toori: function (context, partials, indent) {return this.r(context, partials, indent);},// ensurePartialep: function(symbol, partials) {var partial = this.partials[symbol];// check to see that if we've instantiated this partial beforevar template = partials[partial.name];if (partial.instance && partial.base == template) {return partial.instance;}if (typeof template == 'string') {if (!this.c) {throw new Error("No compiler available.");}template = this.c.compile(template, this.options);}if (!template) {return null;}// We use this to check whether the partials dictionary has changedthis.partials[symbol].base = template;if (partial.subs) {// Make sure we consider parent template nowif (!partials.stackText) partials.stackText = {};for (key in partial.subs) {if (!partials.stackText[key]) {partials.stackText[key] = (this.activeSub !== undefined && partials.stackText[this.activeSub]) ? partials.stackText[this.activeSub] : this.text;}}template = createSpecializedPartial(template, partial.subs, partial.partials,this.stackSubs, this.stackPartials, partials.stackText);}this.partials[symbol].instance = template;return template;},// tries to find a partial in the current scope and render itrp: function(symbol, context, partials, indent) {var partial = this.ep(symbol, partials);if (!partial) {return '';}return partial.ri(context, partials, indent);},// render a sectionrs: function(context, partials, section) {var tail = context[context.length - 1];if (!isArray(tail)) {section(context, partials, this);return;}for (var i = 0; i < tail.length; i++) {context.push(tail[i]);section(context, partials, this);context.pop();}},// maybe start a sections: function(val, ctx, partials, inverted, start, end, tags) {var pass;if (isArray(val) && val.length === 0) {return false;}if (typeof val == 'function') {val = this.ms(val, ctx, partials, inverted, start, end, tags);}pass = !!val;if (!inverted && pass && ctx) {ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);}return pass;},// find values with dotted namesd: function(key, ctx, partials, returnFound) {var found,names = key.split('.'),val = this.f(names[0], ctx, partials, returnFound),doModelGet = this.options.modelGet,cx = null;if (key === '.' && isArray(ctx[ctx.length - 2])) {val = ctx[ctx.length - 1];} else {for (var i = 1; i < names.length; i++) {found = findInScope(names[i], val, doModelGet);if (found != null) {cx = val;val = found;} else {val = '';}}}if (returnFound && !val) {return false;}if (!returnFound && typeof val == 'function') {ctx.push(cx);val = this.mv(val, ctx, partials);ctx.pop();}return val;},// find values with normal namesf: function(key, ctx, partials, returnFound) {var val = false,v = null,found = false,doModelGet = this.options.modelGet;for (var i = ctx.length - 1; i >= 0; i--) {v = ctx[i];val = findInScope(key, v, doModelGet);if (val != null) {found = true;break;}}if (!found) {return (returnFound) ? false : "";}if (!returnFound && typeof val == 'function') {val = this.mv(val, ctx, partials);}return val;},// higher order templatesls: function(func, cx, partials, text, tags) {var oldTags = this.options.delimiters;this.options.delimiters = tags;this.b(this.ct(coerceToString(func.call(cx, text)), cx, partials));this.options.delimiters = oldTags;return false;},// compile textct: function(text, cx, partials) {if (this.options.disableLambda) {throw new Error('Lambda features disabled.');}return this.c.compile(text, this.options).render(cx, partials);},// template result bufferingb: function(s) { this.buf += s; },fl: function() { var r = this.buf; this.buf = ''; return r; },// method replace sectionms: function(func, ctx, partials, inverted, start, end, tags) {var textSource,cx = ctx[ctx.length - 1],result = func.call(cx);if (typeof result == 'function') {if (inverted) {return true;} else {textSource = (this.activeSub && this.subsText && this.subsText[this.activeSub]) ? this.subsText[this.activeSub] : this.text;return this.ls(result, cx, partials, textSource.substring(start, end), tags);}}return result;},// method replace variablemv: function(func, ctx, partials) {var cx = ctx[ctx.length - 1];var result = func.call(cx);if (typeof result == 'function') {return this.ct(coerceToString(result.call(cx)), cx, partials);}return result;},sub: function(name, context, partials, indent) {var f = this.subs[name];if (f) {this.activeSub = name;f(context, partials, this, indent);this.activeSub = false;}}};//Find a key in an objectfunction findInScope(key, scope, doModelGet) {var val, checkVal;if (scope && typeof scope == 'object') {if (scope[key] != null) {val = scope[key];// try lookup with get for backbone or similar model data} else if (doModelGet && scope.get && typeof scope.get == 'function') {val = scope.get(key);}}return val;}function createSpecializedPartial(instance, subs, partials, stackSubs, stackPartials, stackText) {function PartialTemplate() {};PartialTemplate.prototype = instance;function Substitutions() {};Substitutions.prototype = instance.subs;var key;var partial = new PartialTemplate();partial.subs = new Substitutions();partial.subsText = {}; //hehe. substext.partial.buf = '';stackSubs = stackSubs || {};partial.stackSubs = stackSubs;partial.subsText = stackText;for (key in subs) {if (!stackSubs[key]) stackSubs[key] = subs[key];}for (key in stackSubs) {partial.subs[key] = stackSubs[key];}stackPartials = stackPartials || {};partial.stackPartials = stackPartials;for (key in partials) {if (!stackPartials[key]) stackPartials[key] = partials[key];}for (key in stackPartials) {partial.partials[key] = stackPartials[key];}return partial;}var rAmp = /&/g,rLt = /</g,rGt = />/g,rApos = /\'/g,rQuot = /\"/g,hChars = /[&<>\"\']/;function coerceToString(val) {return String((val === null || val === undefined) ? '' : val);}function hoganEscape(str) {str = coerceToString(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]';};})(typeof exports !== 'undefined' ? exports : Hogan);(function (Hogan) {// Setup regex assignments// remove whitespace according to Mustache specvar rIsWhitespace = /\S/,rQuot = /\"/g,rNewline = /\n/g,rCr = /\r/g,rSlash = /\\/g;Hogan.tags = {'#': 1, '^': 2, '<': 3, '$': 4,'/': 5, '!': 6, '>': 7, '=': 8, '_v': 9,'{': 10, '&': 11, '_t': 12};Hogan.scan = function scan(text, delimiters) {var len = text.length,IN_TEXT = 0,IN_TAG_TYPE = 1,IN_TAG = 2,state = IN_TEXT,tagType = null,tag = null,buf = '',tokens = [],seenTag = false,i = 0,lineStart = 0,otag = '{{',ctag = '}}';function addBuf() {if (buf.length > 0) {tokens.push({tag: '_t', text: new String(buf)});buf = '';}}function lineIsWhitespace() {var isAllWhitespace = true;for (var j = lineStart; j < tokens.length; j++) {isAllWhitespace =(Hogan.tags[tokens[j].tag] < Hogan.tags['_v']) ||(tokens[j].tag == '_t' && tokens[j].text.match(rIsWhitespace) === null);if (!isAllWhitespace) {return false;}}return isAllWhitespace;}function filterLine(haveSeenTag, noNewLine) {addBuf();if (haveSeenTag && lineIsWhitespace()) {for (var j = lineStart, next; j < tokens.length; j++) {if (tokens[j].text) {if ((next = tokens[j+1]) && next.tag == '>') {// set indent to token valuenext.indent = tokens[j].text.toString()}tokens.splice(j, 1);}}} else if (!noNewLine) {tokens.push({tag:'\n'});}seenTag = false;lineStart = tokens.length;}function changeDelimiters(text, index) {var close = '=' + ctag,closeIndex = text.indexOf(close, index),delimiters = trim(text.substring(text.indexOf('=', index) + 1, closeIndex)).split(' ');otag = delimiters[0];ctag = delimiters[delimiters.length - 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();state = IN_TAG_TYPE;} else {if (text.charAt(i) == '\n') {filterLine(seenTag);} else {buf += text.charAt(i);}}} else if (state == IN_TAG_TYPE) {i += otag.length - 1;tag = Hogan.tags[text.charAt(i + 1)];tagType = tag ? text.charAt(i + 1) : '_v';if (tagType == '=') {i = changeDelimiters(text, i);state = IN_TEXT;} else {if (tag) {i++;}state = IN_TAG;}seenTag = i;} else {if (tagChange(ctag, text, i)) {tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag,i: (tagType == '/') ? seenTag - otag.length : i + ctag.length});buf = '';i += ctag.length - 1;state = IN_TEXT;if (tagType == '{') {if (ctag == '}}') {i++;} else {cleanTripleStache(tokens[tokens.length - 1]);}}} else {buf += text.charAt(i);}}}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();}return s.replace(/^\s*|\s*$/g, '');}function tagChange(tag, text, index) {if (text.charAt(index) != tag.charAt(0)) {return false;}for (var i = 1, l = tag.length; i < l; i++) {if (text.charAt(index + i) != tag.charAt(i)) {return false;}}return true;}// the tags allowed inside super templatesvar allowedInSuper = {'_t': true, '\n': true, '$': true, '/': true};function buildTree(tokens, kind, stack, customTags) {var instructions = [],opener = null,tail = null,token = null;tail = stack[stack.length - 1];while (tokens.length > 0) {token = tokens.shift();if (tail && tail.tag == '<' && !(token.tag in allowedInSuper)) {throw new Error('Illegal content in < super tag.');}if (Hogan.tags[token.tag] <= Hogan.tags['$'] || isOpener(token, customTags)) {stack.push(token);token.nodes = buildTree(tokens, token.tag, stack, customTags);} else if (token.tag == '/') {if (stack.length === 0) {throw new Error('Closing tag without opener: /' + token.n);}opener = stack.pop();if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) {throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n);}opener.end = token.i;return instructions;} else if (token.tag == '\n') {token.last = (tokens.length == 0) || (tokens[0].tag == '\n');}instructions.push(token);}if (stack.length > 0) {throw new Error('missing closing tag: ' + stack.pop().n);}return instructions;}function isOpener(token, tags) {for (var i = 0, l = tags.length; i < l; i++) {if (tags[i].o == token.n) {token.tag = '#';return true;}}}function isCloser(close, open, tags) {for (var i = 0, l = tags.length; i < l; i++) {if (tags[i].c == close && tags[i].o == open) {return true;}}}function stringifySubstitutions(obj) {var items = [];for (var key in obj) {items.push('"' + esc(key) + '": function(c,p,t,i) {' + obj[key] + '}');}return "{ " + items.join(",") + " }";}function stringifyPartials(codeObj) {var partials = [];for (var key in codeObj.partials) {partials.push('"' + esc(key) + '":{name:"' + esc(codeObj.partials[key].name) + '", ' + stringifyPartials(codeObj.partials[key]) + "}");}return "partials: {" + partials.join(",") + "}, subs: " + stringifySubstitutions(codeObj.subs);}Hogan.stringify = function(codeObj, text, options) {return "{code: function (c,p,i) { " + Hogan.wrapMain(codeObj.code) + " }," + stringifyPartials(codeObj) + "}";}var serialNo = 0;Hogan.generate = function(tree, text, options) {serialNo = 0;var context = { code: '', subs: {}, partials: {} };Hogan.walk(tree, context);if (options.asString) {return this.stringify(context, text, options);}return this.makeTemplate(context, text, options);}Hogan.wrapMain = function(code) {return 'var t=this;t.b(i=i||"");' + code + 'return t.fl();';}Hogan.template = Hogan.Template;Hogan.makeTemplate = function(codeObj, text, options) {var template = this.makePartials(codeObj);template.code = new Function('c', 'p', 'i', this.wrapMain(codeObj.code));return new this.template(template, text, this, options);}Hogan.makePartials = function(codeObj) {var key, template = {subs: {}, partials: codeObj.partials, name: codeObj.name};for (key in template.partials) {template.partials[key] = this.makePartials(template.partials[key]);}for (key in codeObj.subs) {template.subs[key] = new Function('c', 'p', 't', 'i', codeObj.subs[key]);}return template;}function esc(s) {return s.replace(rSlash, '\\\\').replace(rQuot, '\\\"').replace(rNewline, '\\n').replace(rCr, '\\r');}function chooseMethod(s) {return (~s.indexOf('.')) ? 'd' : 'f';}function createPartial(node, context) {var prefix = "<" + (context.prefix || "");var sym = prefix + node.n + serialNo++;context.partials[sym] = {name: node.n, partials: {}};context.code += 't.b(t.rp("' + esc(sym) + '",c,p,"' + (node.indent || '') + '"));';return sym;}Hogan.codegen = {'#': function(node, context) {context.code += 'if(t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),' +'c,p,0,' + node.i + ',' + node.end + ',"' + node.otag + " " + node.ctag + '")){' +'t.rs(c,p,' + 'function(c,p,t){';Hogan.walk(node.nodes, context);context.code += '});c.pop();}';},'^': function(node, context) {context.code += 'if(!t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),c,p,1,0,0,"")){';Hogan.walk(node.nodes, context);context.code += '};';},'>': createPartial,'<': function(node, context) {var ctx = {partials: {}, code: '', subs: {}, inPartial: true};Hogan.walk(node.nodes, ctx);var template = context.partials[createPartial(node, context)];template.subs = ctx.subs;template.partials = ctx.partials;},'$': function(node, context) {var ctx = {subs: {}, code: '', partials: context.partials, prefix: node.n};Hogan.walk(node.nodes, ctx);context.subs[node.n] = ctx.code;if (!context.inPartial) {context.code += 't.sub("' + esc(node.n) + '",c,p,i);';}},'\n': function(node, context) {context.code += write('"\\n"' + (node.last ? '' : ' + i'));},'_v': function(node, context) {context.code += 't.b(t.v(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));';},'_t': function(node, context) {context.code += write('"' + esc(node.text) + '"');},'{': tripleStache,'&': tripleStache}function tripleStache(node, context) {context.code += 't.b(t.t(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));';}function write(s) {return 't.b(' + s + ');';}Hogan.walk = function(nodelist, context) {var func;for (var i = 0, l = nodelist.length; i < l; i++) {func = Hogan.codegen[nodelist[i].tag];func && func(nodelist[i], context);}return context;}Hogan.parse = function(tokens, text, options) {options = options || {};return buildTree(tokens, '', [], options.sectionTags || []);}Hogan.cache = {};Hogan.cacheKey = function(text, options) {return [text, !!options.asString, !!options.disableLambda, options.delimiters, !!options.modelGet].join('||');}Hogan.compile = function(text, options) {options = options || {};var key = Hogan.cacheKey(text, options);var template = this.cache[key];if (template) {var partials = template.partials;for (var name in partials) {delete partials[name].instance;}return template;}template = this.generate(this.parse(this.scan(text, options.delimiters), text, options), text, options);return this.cache[key] = template;}})(typeof exports !== 'undefined' ? exports : Hogan);