UNPKG

todomvc

Version:

> Helping you select an MV\* framework

135 lines (113 loc) 3.37 kB
/*global define */ 'use strict'; // tmpl function scooped from underscore. // http://documentcloud.github.com/underscore/#template define(function () { var _ = {}; // List of HTML entities for escaping. var entityMap = { escape: { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', /*jshint quotmark:false */ "'": '&#x27;', '/': '&#x2F;' } }; var escapeKeys = '&<>"\'/'; var unescapeKeys = '&amp;|&lt;|&gt;|&quot;|&#x27;|&#x2F;'; // Regexes containing the keys and values listed immediately above. var entityRegexes = { escape: new RegExp('[' + escapeKeys + ']', 'g'), unescape: new RegExp('(' + unescapeKeys + ')', 'g') }; // Functions for escaping and unescaping strings to/from HTML interpolation. ['escape', 'unescape'].forEach(function (method) { _[method] = function (string) { if (string === null || string === undefined) { return ''; } return ('' + string).replace(entityRegexes[method], function (match) { return entityMap[method][match]; }); }; }); var settings = { evaluate: /<%([\s\S]+?)%>/g, interpolate: /<%=([\s\S]+?)%>/g, escape: /<%-([\s\S]+?)%>/g }; var noMatch = /(.)^/; var escapes = { /*jshint quotmark:false */ "'": "'", '\\': '\\', '\r': 'r', '\n': 'n', '\t': 't', '\u2028': 'u2028', '\u2029': 'u2029' }; var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; // JavaScript micro-templating, similar to John Resig's implementation. // Underscore templating handles arbitrary delimiters, preserves whitespace, // and correctly escapes quotes within interpolated code. var template = function (text, data) { var render; // Combine delimiters into one regular expression via alternation. var matcher = new RegExp([ (settings.escape || noMatch).source, (settings.interpolate || noMatch).source, (settings.evaluate || noMatch).source ].join('|') + '|$', 'g'); // Compile the template source, escaping string literals appropriately. var index = 0; var source = "__p+='"; text.replace(matcher, function (match, escape, interpolate, evaluate, offset) { source += text.slice(index, offset) .replace(escaper, function (match) { return '\\' + escapes[match]; }); if (escape) { source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; } if (interpolate) { source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; } if (evaluate) { source += "';\n" + evaluate + "\n__p+='"; } index = offset + match.length; return match; }); source += "';\n"; // If a variable is not specified, place data values in local scope. if (!settings.variable) { source = 'with(obj||{}){\n' + source + '}\n'; } source = "var __t,__p='',__j=Array.prototype.join," + "print=function(){__p+=__j.call(arguments,'');};\n" + source + "return __p;\n"; try { /*jshint evil:true */ render = new Function(settings.variable || 'obj', '_', source); } catch (err) { err.source = source; throw err; } if (data) { return render(data, _); } var template = function (data) { return render.call(this, data, _); }; // Provide the compiled function source as a convenience for precompilation. template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; return template; }; return { tmpl: template }; });