define("handlebars/base", ["./utils","./exception","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; var Utils = __dependency1__; var Exception = __dependency2__["default"]; var VERSION = "1.3.0"; __exports__.VERSION = VERSION;var COMPILER_REVISION = 4; __exports__.COMPILER_REVISION = COMPILER_REVISION; var REVISION_CHANGES = { 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 2: '== 1.0.0-rc.3', 3: '== 1.0.0-rc.4', 4: '>= 1.0.0' }; __exports__.REVISION_CHANGES = REVISION_CHANGES; var isArray = Utils.isArray, isFunction = Utils.isFunction, toString = Utils.toString, objectType = '[object Object]'; function HandlebarsEnvironment(helpers, partials) { this.helpers = helpers || {}; this.partials = partials || {}; registerDefaultHelpers(this); } __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { constructor: HandlebarsEnvironment, logger: logger, log: log, registerHelper: function(name, fn, inverse) { if (toString.call(name) === objectType) { if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); } Utils.extend(this.helpers, name); } else { if (inverse) { fn.not = inverse; } this.helpers[name] = fn; } }, registerPartial: function(name, str) { if (toString.call(name) === objectType) { Utils.extend(this.partials, name); } else { this.partials[name] = str; } } }; function registerDefaultHelpers(instance) { instance.registerHelper('helperMissing', function(arg) { if(arguments.length === 2) { return undefined; } else { throw new Exception("Missing helper: '" + arg + "'"); } }); instance.registerHelper('blockHelperMissing', function(context, options) { var inverse = options.inverse || function() {}, fn = options.fn; if (isFunction(context)) { context = context.call(this); } if(context === true) { return fn(this); } else if(context === false || context == null) { return inverse(this); } else if (isArray(context)) { if(context.length > 0) { return instance.helpers.each(context, options); } else { return inverse(this); } } else { return fn(context); } }); instance.registerHelper('each', function(context, options) { var fn = options.fn, inverse = options.inverse; var i = 0, ret = "", data; if (isFunction(context)) { context = context.call(this); } if (options.data) { data = createFrame(options.data); } if(context && typeof context === 'object') { if (isArray(context)) { for(var j = context.length; i 0) { throw new Exception("Invalid path: " + original, this); } else if (part === "..") { depth++; } else { this.isScoped = true; } } else { dig.push(part); } } this.original = original; this.parts = dig; this.string = dig.join('.'); this.depth = depth; // an ID is simple if it only has one part, and that part is not // `..` or `this`. this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; this.stringModeValue = this.string; }, PartialNameNode: function(name, locInfo) { LocationInfo.call(this, locInfo); this.type = "PARTIAL_NAME"; this.name = name.original; }, DataNode: function(id, locInfo) { LocationInfo.call(this, locInfo); this.type = "DATA"; this.id = id; }, StringNode: function(string, locInfo) { LocationInfo.call(this, locInfo); this.type = "STRING"; this.original = this.string = this.stringModeValue = string; }, IntegerNode: function(integer, locInfo) { LocationInfo.call(this, locInfo); this.type = "INTEGER"; this.original = this.integer = integer; this.stringModeValue = Number(integer); }, BooleanNode: function(bool, locInfo) { LocationInfo.call(this, locInfo); this.type = "BOOLEAN"; this.bool = bool; this.stringModeValue = bool === "true"; }, CommentNode: function(comment, locInfo) { LocationInfo.call(this, locInfo); this.type = "comment"; this.comment = comment; } }; // Must be exported as an object rather than the root of the module as the jison lexer // most modify the object to operate properly. __exports__["default"] = AST; }); define("handlebars/compiler/base", ["./parser","./ast","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; var parser = __dependency1__["default"]; var AST = __dependency2__["default"]; __exports__.parser = parser; function parse(input) { // Just return if an already-compile AST was passed in. if(input.constructor === AST.ProgramNode) { return input; } parser.yy = AST; return parser.parse(input); } __exports__.parse = parse; }); define("handlebars/compiler/compiler", ["../exception","exports"], function(__dependency1__, __exports__) { "use strict"; var Exception = __dependency1__["default"]; function Compiler() {} __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a // function in a context. This is necessary for mustache compatibility, which // requires that context functions in blocks are evaluated by blockHelperMissing, // and then proceed as if the resulting value was provided to blockHelperMissing. Compiler.prototype = { compiler: Compiler, disassemble: function() { var opcodes = this.opcodes, opcode, out = [], params, param; for (var i=0, l=opcodes.length; i 0) { this.source[1] = this.source[1] + ", " + locals.join(", "); } // Generate minimizer alias mappings if (!this.isChild) { for (var alias in this.context.aliases) { if (this.context.aliases.hasOwnProperty(alias)) { this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; } } } if (this.source[1]) { this.source[1] = "var " + this.source[1].substring(2) + ";"; } // Merge children if (!this.isChild) { this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; } if (!this.environment.isSimple) { this.pushSource("return buffer;"); } var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; for(var i=0, l=this.environment.depths.list.length; i this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } return this.topStackName(); }, topStackName: function() { return "stack" + this.stackSlot; }, flushInline: function() { var inlineStack = this.inlineStack; if (inlineStack.length) { this.inlineStack = []; for (var i = 0, len = inlineStack.length; i < len; i++) { var entry = inlineStack[i]; if (entry instanceof Literal) { this.compileStack.push(entry); } else { this.pushStack(entry); } } } }, isInline: function() { return this.inlineStack.length; }, popStack: function(wrapped) { var inline = this.isInline(), item = (inline ? this.inlineStack : this.compileStack).pop(); if (!wrapped && (item instanceof Literal)) { return item.value; } else { if (!inline) { if (!this.stackSlot) { throw new Exception('Invalid stack pop'); } this.stackSlot--; } return item; } }, topStack: function(wrapped) { var stack = (this.isInline() ? this.inlineStack : this.compileStack), item = stack[stack.length - 1]; if (!wrapped && (item instanceof Literal)) { return item.value; } else { return item; } }, quotedString: function(str) { return '"' + str .replace(/\\/g, '\\\\') .replace(/"/g, '\\"') .replace(/\n/g, '\\n') .replace(/\r/g, '\\r') .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 .replace(/\u2029/g, '\\u2029') + '"'; }, setupHelper: function(paramSize, name, missingParams) { var params = [], paramsInit = this.setupParams(paramSize, params, missingParams); var foundHelper = this.nameLookup('helpers', name, 'helper'); return { params: params, paramsInit: paramsInit, name: foundHelper, callParams: ["depth0"].concat(params).join(", "), helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") }; }, setupOptions: function(paramSize, params) { var options = [], contexts = [], types = [], param, inverse, program; options.push("hash:" + this.popStack()); if (this.options.stringParams) { options.push("hashTypes:" + this.popStack()); options.push("hashContexts:" + this.popStack()); } inverse = this.popStack(); program = this.popStack(); // Avoid setting fn and inverse if neither are set. This allows // helpers to do a check for `if (options.fn)` if (program || inverse) { if (!program) { this.context.aliases.self = "this"; program = "self.noop"; } if (!inverse) { this.context.aliases.self = "this"; inverse = "self.noop"; } options.push("inverse:" + inverse); options.push("fn:" + program); } for(var i=0; i 2) { expected.push("'" + this.terminals_[p] + "'"); } if (this.lexer.showPosition) { errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; } else { errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); } this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); } } if (action[0] instanceof Array && action.length > 1) { throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); } switch (action[0]) { case 1: stack.push(symbol); vstack.push(this.lexer.yytext); lstack.push(this.lexer.yylloc); stack.push(action[1]); symbol = null; if (!preErrorSymbol) { yyleng = this.lexer.yyleng; yytext = this.lexer.yytext; yylineno = this.lexer.yylineno; yyloc = this.lexer.yylloc; if (recovering > 0) recovering--; } else { symbol = preErrorSymbol; preErrorSymbol = null; } break; case 2: len = this.productions_[action[1]][1]; yyval.$ = vstack[vstack.length - len]; yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; if (ranges) { yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; } r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); if (typeof r !== "undefined") { return r; } if (len) { stack = stack.slice(0, -1 * len * 2); vstack = vstack.slice(0, -1 * len); lstack = lstack.slice(0, -1 * len); } stack.push(this.productions_[action[1]][0]); vstack.push(yyval.$); lstack.push(yyval._$); newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; stack.push(newState); break; case 3: return true; } } return true; } }; function stripFlags(open, close) { return { left: open.charAt(2) === '~', right: close.charAt(0) === '~' || close.charAt(1) === '~' }; } /* Jison generated lexer */ var lexer = (function(){ var lexer = ({EOF:1, parseError:function parseError(str, hash) { if (this.yy.parser) { this.yy.parser.parseError(str, hash); } else { throw new Error(str); } }, setInput:function (input) { this._input = input; this._more = this._less = this.done = false; this.yylineno = this.yyleng = 0; this.yytext = this.matched = this.match = ''; this.conditionStack = ['INITIAL']; this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; if (this.options.ranges) this.yylloc.range = [0,0]; this.offset = 0; return this; }, input:function () { var ch = this._input[0]; this.yytext += ch; this.yyleng++; this.offset++; this.match += ch; this.matched += ch; var lines = ch.match(/(?:\r\n?|\n).*/g); if (lines) { this.yylineno++; this.yylloc.last_line++; } else { this.yylloc.last_column++; } if (this.options.ranges) this.yylloc.range[1]++; this._input = this._input.slice(1); return ch; }, unput:function (ch) { var len = ch.length; var lines = ch.split(/(?:\r\n?|\n)/g); this._input = ch + this._input; this.yytext = this.yytext.substr(0, this.yytext.length-len-1); //this.yyleng -= len; this.offset -= len; var oldLines = this.match.split(/(?:\r\n?|\n)/g); this.match = this.match.substr(0, this.match.length-1); this.matched = this.matched.substr(0, this.matched.length-1); if (lines.length-1) this.yylineno -= lines.length-1; var r = this.yylloc.range; this.yylloc = {first_line: this.yylloc.first_line, last_line: this.yylineno+1, first_column: this.yylloc.first_column, last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length: this.yylloc.first_column - len }; if (this.options.ranges) { this.yylloc.range = [r[0], r[0] + this.yyleng - len]; } return this; }, more:function () { this._more = true; return this; }, less:function (n) { this.unput(this.match.slice(n)); }, pastInput:function () { var past = this.matched.substr(0, this.matched.length - this.match.length); return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); }, upcomingInput:function () { var next = this.match; if (next.length < 20) { next += this._input.substr(0, 20-next.length); } return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); }, showPosition:function () { var pre = this.pastInput(); var c = new Array(pre.length + 1).join("-"); return pre + this.upcomingInput() + "\n" + c+"^"; }, next:function () { if (this.done) { return this.EOF; } if (!this._input) this.done = true; var token, match, tempMatch, index, col, lines; if (!this._more) { this.yytext = ''; this.match = ''; } var rules = this._currentRules(); for (var i=0;i < rules.length; i++) { tempMatch = this._input.match(this.rules[rules[i]]); if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { match = tempMatch; index = i; if (!this.options.flex) break; } } if (match) { lines = match[0].match(/(?:\r\n?|\n).*/g); if (lines) this.yylineno += lines.length; this.yylloc = {first_line: this.yylloc.last_line, last_line: this.yylineno+1, first_column: this.yylloc.last_column, last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length}; this.yytext += match[0]; this.match += match[0]; this.matches = match; this.yyleng = this.yytext.length; if (this.options.ranges) { this.yylloc.range = [this.offset, this.offset += this.yyleng]; } this._more = false; this._input = this._input.slice(match[0].length); this.matched += match[0]; token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); if (this.done && this._input) this.done = false; if (token) return token; else return; } if (this._input === "") { return this.EOF; } else { return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), {text: "", token: null, line: this.yylineno}); } }, lex:function lex() { var r = this.next(); if (typeof r !== 'undefined') { return r; } else { return this.lex(); } }, begin:function begin(condition) { this.conditionStack.push(condition); }, popState:function popState() { return this.conditionStack.pop(); }, _currentRules:function _currentRules() { return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; }, topState:function () { return this.conditionStack[this.conditionStack.length-2]; }, pushState:function begin(condition) { this.begin(condition); }}); lexer.options = {}; lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { function strip(start, end) { return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng-end); } var YYSTATE=YY_START switch($avoiding_name_collisions) { case 0: if(yy_.yytext.slice(-2) === "\\\\") { strip(0,1); this.begin("mu"); } else if(yy_.yytext.slice(-1) === "\\") { strip(0,1); this.begin("emu"); } else { this.begin("mu"); } if(yy_.yytext) return 14; break; case 1:return 14; break; case 2: this.popState(); return 14; break; case 3:strip(0,4); this.popState(); return 15; break; case 4:return 35; break; case 5:return 36; break; case 6:return 25; break; case 7:return 16; break; case 8:return 20; break; case 9:return 19; break; case 10:return 19; break; case 11:return 23; break; case 12:return 22; break; case 13:this.popState(); this.begin('com'); break; case 14:strip(3,5); this.popState(); return 15; break; case 15:return 22; break; case 16:return 41; break; case 17:return 40; break; case 18:return 40; break; case 19:return 44; break; case 20:// ignore whitespace break; case 21:this.popState(); return 24; break; case 22:this.popState(); return 18; break; case 23:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 32; break; case 24:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 32; break; case 25:return 42; break; case 26:return 34; break; case 27:return 34; break; case 28:return 33; break; case 29:return 40; break; case 30:yy_.yytext = strip(1,2); return 40; break; case 31:return 'INVALID'; break; case 32:return 5; break; } }; lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; lexer.conditions = {"mu":{"rules":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"INITIAL":{"rules":[0,1,32],"inclusive":true}}; return lexer;})() parser.lexer = lexer; function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; return new Parser; })();__exports__["default"] = handlebars; /* jshint ignore:end */ }); define("handlebars/compiler/printer", ["./visitor","exports"], function(__dependency1__, __exports__) { "use strict"; var Visitor = __dependency1__["default"]; function print(ast) { return new PrintVisitor().accept(ast); } __exports__.print = print;function PrintVisitor() { this.padding = 0; } __exports__.PrintVisitor = PrintVisitor;PrintVisitor.prototype = new Visitor(); PrintVisitor.prototype.pad = function(string, newline) { var out = ""; for(var i=0,l=this.padding; i " + content + " }}"); }; PrintVisitor.prototype.hash = function(hash) { var pairs = hash.pairs; var joinedPairs = [], left, right; for(var i=0, l=pairs.length; i 1) { return "PATH:" + path; } else { return "ID:" + path; } }; PrintVisitor.prototype.PARTIAL_NAME = function(partialName) { return "PARTIAL:" + partialName.name; }; PrintVisitor.prototype.DATA = function(data) { return "@" + this.accept(data.id); }; PrintVisitor.prototype.content = function(content) { return this.pad("CONTENT[ '" + content.string + "' ]"); }; PrintVisitor.prototype.comment = function(comment) { return this.pad("{{! '" + comment.comment + "' }}"); }; }); define("handlebars/compiler/visitor", ["exports"], function(__exports__) { "use strict"; function Visitor() {} Visitor.prototype = { constructor: Visitor, accept: function(object) { return this[object.type](object); } }; __exports__["default"] = Visitor; }); define("handlebars/exception", ["exports"], function(__exports__) { "use strict"; var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; function Exception(message, node) { var line; if (node && node.firstLine) { line = node.firstLine; message += ' - ' + line + ':' + node.firstColumn; } var tmp = Error.prototype.constructor.call(this, message); // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. for (var idx = 0; idx < errorProps.length; idx++) { this[errorProps[idx]] = tmp[errorProps[idx]]; } if (line) { this.lineNumber = line; this.column = node.firstColumn; } } Exception.prototype = new Error(); __exports__["default"] = Exception; }); define("handlebars/runtime", ["./utils","./exception","./base","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; var Utils = __dependency1__; var Exception = __dependency2__["default"]; var COMPILER_REVISION = __dependency3__.COMPILER_REVISION; var REVISION_CHANGES = __dependency3__.REVISION_CHANGES; function checkRevision(compilerInfo) { var compilerRevision = compilerInfo && compilerInfo[0] || 1, currentRevision = COMPILER_REVISION; if (compilerRevision !== currentRevision) { if (compilerRevision < currentRevision) { var runtimeVersions = REVISION_CHANGES[currentRevision], compilerVersions = REVISION_CHANGES[compilerRevision]; throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+ "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."); } else { // Use the embedded version info since the runtime doesn't know about this revision yet throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+ "Please update your runtime to a newer version ("+compilerInfo[1]+")."); } } } __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial function template(templateSpec, env) { if (!env) { throw new Exception("No environment passed to template"); } // Note: Using env.VM references rather than local var references throughout this section to allow // for external users to override these as psuedo-supported APIs. var invokePartialWrapper = function(partial, name, context, helpers, partials, data) { var result = env.VM.invokePartial.apply(this, arguments); if (result != null) { return result; } if (env.compile) { var options = { helpers: helpers, partials: partials, data: data }; partials[name] = env.compile(partial, { data: data !== undefined }, env); return partials[name](context, options); } else { throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); } }; // Just add water var container = { escapeExpression: Utils.escapeExpression, invokePartial: invokePartialWrapper, programs: [], program: function(i, fn, data) { var programWrapper = this.programs[i]; if(data) { programWrapper = program(i, fn, data); } else if (!programWrapper) { programWrapper = this.programs[i] = program(i, fn); } return programWrapper; }, merge: function(param, common) { var ret = param || common; if (param && common && (param !== common)) { ret = {}; Utils.extend(ret, common); Utils.extend(ret, param); } return ret; }, programWithDepth: env.VM.programWithDepth, noop: env.VM.noop, compilerInfo: null }; return function(context, options) { options = options || {}; var namespace = options.partial ? options : env, helpers, partials; if (!options.partial) { helpers = options.helpers; partials = options.partials; } var result = templateSpec.call( container, namespace, context, helpers, partials, options.data); if (!options.partial) { env.VM.checkRevision(container.compilerInfo); } return result; }; } __exports__.template = template;function programWithDepth(i, fn, data /*, $depth */) { var args = Array.prototype.slice.call(arguments, 3); var prog = function(context, options) { options = options || {}; return fn.apply(this, [context, options.data || data].concat(args)); }; prog.program = i; prog.depth = args.length; return prog; } __exports__.programWithDepth = programWithDepth;function program(i, fn, data) { var prog = function(context, options) { options = options || {}; return fn(context, options.data || data); }; prog.program = i; prog.depth = 0; return prog; } __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data) { var options = { partial: true, helpers: helpers, partials: partials, data: data }; if(partial === undefined) { throw new Exception("The partial " + name + " could not be found"); } else if(partial instanceof Function) { return partial(context, options); } } __exports__.invokePartial = invokePartial;function noop() { return ""; } __exports__.noop = noop; }); define("handlebars/safe-string", ["exports"], function(__exports__) { "use strict"; // Build out our basic SafeString type function SafeString(string) { this.string = string; } SafeString.prototype.toString = function() { return "" + this.string; }; __exports__["default"] = SafeString; }); define("handlebars/utils", ["./safe-string","exports"], function(__dependency1__, __exports__) { "use strict"; /*jshint -W004 */ var SafeString = __dependency1__["default"]; var escape = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "`": "`" }; var badChars = /[&<>"'`]/g; var possible = /[&<>"'`]/; function escapeChar(chr) { return escape[chr] || "&"; } function extend(obj, value) { for(var key in value) { if(Object.prototype.hasOwnProperty.call(value, key)) { obj[key] = value[key]; } } } __exports__.extend = extend;var toString = Object.prototype.toString; __exports__.toString = toString; // Sourced from lodash // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt var isFunction = function(value) { return typeof value === 'function'; }; // fallback for older versions of Chrome and Safari if (isFunction(/x/)) { isFunction = function(value) { return typeof value === 'function' && toString.call(value) === '[object Function]'; }; } var isFunction; __exports__.isFunction = isFunction; var isArray = Array.isArray || function(value) { return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; }; __exports__.isArray = isArray; function escapeExpression(string) { // don't escape SafeStrings, since they're already safe if (string instanceof SafeString) { return string.toString(); } else if (!string && string !== 0) { return ""; } // Force a string conversion as this will be done by the append regardless and // the regex test will do this transparently behind the scenes, causing issues if // an object's to string has escaped characters in it. string = "" + string; if(!possible.test(string)) { return string; } return string.replace(badChars, escapeChar); } __exports__.escapeExpression = escapeExpression;function isEmpty(value) { if (!value && value !== 0) { return true; } else if (isArray(value) && value.length === 0) { return true; } else { return false; } } __exports__.isEmpty = isEmpty; }); define("htmlbars-compiler", ["./htmlbars-compiler/compiler","exports"], function(__dependency1__, __exports__) { "use strict"; var compilerSpec = __dependency1__.compilerSpec; var compilerSpec; __exports__.compilerSpec = compilerSpec; }); define("htmlbars-compiler/ast", ["../handlebars/compiler/ast","exports"], function(__dependency1__, __exports__) { "use strict"; var AST = __dependency1__["default"]; var MustacheNode = AST.MustacheNode; __exports__.MustacheNode = MustacheNode;var SexprNode = AST.SexprNode; __exports__.SexprNode = SexprNode;var HashNode = AST.HashNode; __exports__.HashNode = HashNode;var IdNode = AST.IdNode; __exports__.IdNode = IdNode;var StringNode = AST.StringNode; __exports__.StringNode = StringNode; function ProgramNode(statements, strip) { this.type = 'program'; this.statements = statements; this.strip = strip; } __exports__.ProgramNode = ProgramNode;function BlockNode(mustache, program, inverse, strip) { this.type = 'block'; this.mustache = mustache; this.program = program; this.inverse = inverse; this.strip = strip; } __exports__.BlockNode = BlockNode;function ComponentNode(tag, attributes, program) { this.type = 'component'; this.tag = tag; this.attributes = attributes; this.program = program; } __exports__.ComponentNode = ComponentNode;function ElementNode(tag, attributes, helpers, children) { this.type = 'element'; this.tag = tag; this.attributes = attributes; this.helpers = helpers; this.children = children; } __exports__.ElementNode = ElementNode;function PartialNode(name) { this.id = {}; this.id.string = this.name = 'partial'; this.type = 'mustache'; this.params = [name]; this.program = null; this.inverse = null; this.hash = undefined; this.escaped = true; this.isHelper = true; } __exports__.PartialNode = PartialNode;function AttrNode(name, value) { this.type = 'attr'; this.name = name; this.value = value; } __exports__.AttrNode = AttrNode;function TextNode(chars) { this.type = 'text'; this.chars = chars; } __exports__.TextNode = TextNode;function childrenFor(node) { if (node.type === 'program') return node.statements; if (node.type === 'element') return node.children; } __exports__.childrenFor = childrenFor;function usesMorph(node) { return node.type === 'mustache' || node.type === 'block' || node.type === 'component'; } __exports__.usesMorph = usesMorph;function appendChild(parent, node) { var children = childrenFor(parent); var len = children.length, last; if (len > 0) { last = children[len-1]; if (usesMorph(last) && usesMorph(node)) { children.push(new TextNode('')); } } children.push(node); } __exports__.appendChild = appendChild; }); define("htmlbars-compiler/compiler", ["./parser","./compiler/template","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; /*jshint evil:true*/ var preprocess = __dependency1__.preprocess; var TemplateCompiler = __dependency2__.TemplateCompiler; /* * Compile a string into a template rendering function * * Example usage: * * // Template is the hydration portion of the compiled template * var template = compile("Howdy {{name}}"); * * // Template accepts three arguments: * // * // 1. A context object * // 2. An env object * // 3. A contextualElement (optional, document.body is the default) * // * // The env object *must* have at least these two properties: * // * // 1. `hooks` - Basic hooks for rendering a template * // 2. `dom` - An instance of DOMHelper * // * import {hooks} from 'htmlbars-runtime'; * import {DOMHelper} from 'morph'; * var context = {name: 'whatever'}, * env = {hooks: hooks, dom: new DOMHelper()}, * contextualElement = document.body; * var domFragment = template(context, env, contextualElement); * * @method compile * @param {String} string An htmlbars template string * @return {Function} A function for rendering the template */ function compile(string) { var program = compileSpec(string); return new Function("return " + program)(); } __exports__.compile = compile;/* * Compile a string into a template spec string. The template spec is a string * representation of a template. Usually, you would use compileSpec for * pre-compilation of a template on the server. * * Example usage: * * var templateSpec = compileSpec("Howdy {{name}}"); * // This next step is basically what plain compile does * var template = new Function("return " + templateSpec)(); * * @method compileSpec * @param {String} string An htmlbars template string * @return {Function} A template spec string */ function compileSpec(string) { var ast = preprocess(string); var compiler = new TemplateCompiler(); var program = compiler.compile(ast); return program; } __exports__.compileSpec = compileSpec; }); define("htmlbars-compiler/compiler/fragment", ["./utils","./quoting","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; var processOpcodes = __dependency1__.processOpcodes; var string = __dependency2__.string; function FragmentCompiler() { this.source = []; this.depth = -1; } __exports__.FragmentCompiler = FragmentCompiler;FragmentCompiler.prototype.compile = function(opcodes, options) { this.source.length = 0; this.depth = -1; this.indent = (options && options.indent) || ""; this.source.push(this.indent+'function build(dom) {\n'); processOpcodes(this, opcodes); this.source.push(this.indent+'}\n'); return this.source.join(''); }; FragmentCompiler.prototype.createFragment = function() { var el = 'el'+(++this.depth); this.source.push(this.indent+' var '+el+' = dom.createDocumentFragment();\n'); }; FragmentCompiler.prototype.createElement = function(tagName) { var el = 'el'+(++this.depth); this.source.push(this.indent+' var '+el+' = dom.createElement('+string(tagName)+');\n'); }; FragmentCompiler.prototype.createText = function(str) { var el = 'el'+(++this.depth); this.source.push(this.indent+' var '+el+' = dom.createTextNode('+string(str)+');\n'); }; FragmentCompiler.prototype.returnNode = function() { var el = 'el'+this.depth; this.source.push(this.indent+' return '+el+';\n'); }; FragmentCompiler.prototype.setAttribute = function(name, value) { var el = 'el'+this.depth; this.source.push(this.indent+' dom.setAttribute('+el+','+string(name)+','+string(value)+');\n'); }; FragmentCompiler.prototype.appendChild = function() { var child = 'el'+(this.depth--); var el = 'el'+this.depth; this.source.push(this.indent+' dom.appendChild('+el+', '+child+');\n'); }; FragmentCompiler.prototype.setNamespace = function(namespace) { this.source.push(this.indent+' dom.setNamespace('+(namespace ? string(namespace) : 'null')+');\n'); }; }); define("htmlbars-compiler/compiler/fragment_opcode", ["./template_visitor","./utils","../utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; var TemplateVisitor = __dependency1__["default"]; var processOpcodes = __dependency2__.processOpcodes; var forEach = __dependency3__.forEach; function FragmentOpcodeCompiler() { this.opcodes = []; } FragmentOpcodeCompiler.prototype.compile = function(ast) { var templateVisitor = new TemplateVisitor(); templateVisitor.visit(ast); processOpcodes(this, templateVisitor.actions); return this.opcodes; }; FragmentOpcodeCompiler.prototype.opcode = function(type, params) { this.opcodes.push([type, params]); }; FragmentOpcodeCompiler.prototype.text = function(text, childIndex, childCount, isSingleRoot) { this.opcode('createText', [text.chars]); if (!isSingleRoot) { this.opcode('appendChild'); } }; FragmentOpcodeCompiler.prototype.openElement = function(element) { this.opcode('createElement', [element.tag]); forEach(element.attributes, this.attribute, this); }; FragmentOpcodeCompiler.prototype.closeElement = function(element, childIndex, childCount, isSingleRoot) { if (!isSingleRoot) { this.opcode('appendChild'); } }; FragmentOpcodeCompiler.prototype.startProgram = function(program) { this.opcodes.length = 0; if (program.statements.length !== 1) { this.opcode('createFragment'); } }; FragmentOpcodeCompiler.prototype.endProgram = function(program) { this.opcode('returnNode'); }; FragmentOpcodeCompiler.prototype.mustache = function () {}; FragmentOpcodeCompiler.prototype.component = function () {}; FragmentOpcodeCompiler.prototype.block = function () {}; FragmentOpcodeCompiler.prototype.attribute = function(attr) { if (attr.value.type === 'text') { this.opcode('setAttribute', [attr.name, attr.value.chars]); } }; FragmentOpcodeCompiler.prototype.setNamespace = function(namespace) { this.opcode('setNamespace', [namespace]); }; __exports__.FragmentOpcodeCompiler = FragmentOpcodeCompiler; }); define("htmlbars-compiler/compiler/helpers", ["./quoting","exports"], function(__dependency1__, __exports__) { "use strict"; var array = __dependency1__.array; var hash = __dependency1__.hash; var string = __dependency1__.string; function prepareHelper(stack, size) { var args = [], types = [], hashPairs = [], hashTypes = [], keyName, i; var hashSize = stack.pop(); for (i=0; i 0){ this.opcode( 'repairClonedNode', blankChildTextNodes ); } }; HydrationOpcodeCompiler.prototype.endProgram = function(program) { distributeMorphs(this.morphs, this.opcodes); }; HydrationOpcodeCompiler.prototype.text = function(string, pos, len) { ++this.currentDOMChildIndex; }; HydrationOpcodeCompiler.prototype.openElement = function(element, pos, len, isSingleRoot, mustacheCount, blankChildTextNodes) { distributeMorphs(this.morphs, this.opcodes); ++this.currentDOMChildIndex; this.element = this.currentDOMChildIndex; if (!isSingleRoot) { this.opcode('consumeParent', this.currentDOMChildIndex); // If our parent referance will be used more than once, cache its referance. if (mustacheCount > 1) { this.opcode('element', ++this.elementNum); this.element = null; // Set element to null so we don't cache it twice } } var isElementChecked = detectIsElementChecked(element); if (blankChildTextNodes.length > 0 || isElementChecked) { this.opcode( 'repairClonedNode', blankChildTextNodes, isElementChecked ); } this.paths.push(this.currentDOMChildIndex); this.currentDOMChildIndex = -1; forEach(element.attributes, this.attribute, this); forEach(element.helpers, this.nodeHelper, this); }; HydrationOpcodeCompiler.prototype.closeElement = function(element, pos, len, isSingleRoot) { distributeMorphs(this.morphs, this.opcodes); if (!isSingleRoot) { this.opcode('popParent'); } this.currentDOMChildIndex = this.paths.pop(); }; HydrationOpcodeCompiler.prototype.block = function(block, childIndex, childrenLength) { var currentDOMChildIndex = this.currentDOMChildIndex, mustache = block.mustache; var start = (currentDOMChildIndex < 0 ? null : currentDOMChildIndex), end = (childIndex === childrenLength - 1 ? null : currentDOMChildIndex + 1); var morphNum = this.morphNum++; this.morphs.push([morphNum, this.paths.slice(), start, end]); this.opcode('program', this.templateId++, block.inverse === null ? null : this.templateId++); processParams(this, mustache.params); processHash(this, mustache.hash); this.opcode('helper', mustache.id.string, mustache.params.length, mustache.escaped, morphNum); }; HydrationOpcodeCompiler.prototype.component = function(component, childIndex, childrenLength) { var currentDOMChildIndex = this.currentDOMChildIndex; var start = (currentDOMChildIndex < 0 ? null : currentDOMChildIndex), end = (childIndex === childrenLength - 1 ? null : currentDOMChildIndex + 1); var morphNum = this.morphNum++; this.morphs.push([morphNum, this.paths.slice(), start, end]); this.opcode('program', this.templateId++, null); processHash(this, buildHashFromAttributes(component.attributes)); this.opcode('component', component.tag, morphNum); }; HydrationOpcodeCompiler.prototype.opcode = function(type) { var params = [].slice.call(arguments, 1); this.opcodes.push([type, params]); }; HydrationOpcodeCompiler.prototype.attribute = function(attr) { if (attr.value.type === 'text') return; // We treat attribute like a attribute helper evaluated by the element hook. //

// Unwrapped any mustaches to just be their internal sexprs. this.nodeHelper({ params: [attr.name, attr.value.sexpr], hash: null, id: { string: 'attribute' } }); }; HydrationOpcodeCompiler.prototype.nodeHelper = function(mustache) { this.opcode('program', null, null); processParams(this, mustache.params); processHash(this, mustache.hash); // If we have a helper in a node, and this element has not been cached, cache it if(this.element !== null){ this.opcode('element', ++this.elementNum); this.element = null; // Reset element so we don't cache it more than once } this.opcode('nodeHelper', mustache.id.string, mustache.params.length, this.elementNum); }; HydrationOpcodeCompiler.prototype.mustache = function(mustache, childIndex, childrenLength) { var currentDOMChildIndex = this.currentDOMChildIndex; var start = currentDOMChildIndex, end = (childIndex === childrenLength - 1 ? -1 : currentDOMChildIndex + 1); var morphNum = this.morphNum++; this.morphs.push([morphNum, this.paths.slice(), start, end]); if (mustache.isHelper) { this.opcode('program', null, null); processParams(this, mustache.params); processHash(this, mustache.hash); this.opcode('helper', mustache.id.string, mustache.params.length, mustache.escaped, morphNum); } else { this.opcode('ambiguous', mustache.id.string, mustache.escaped, morphNum); } }; HydrationOpcodeCompiler.prototype.sexpr = function(sexpr) { this.string('sexpr'); this.opcode('program', null, null); processParams(this, sexpr.params); processHash(this, sexpr.hash); this.opcode('sexpr', sexpr.id.string, sexpr.params.length); }; HydrationOpcodeCompiler.prototype.string = function(str) { this.opcode('string', str); }; HydrationOpcodeCompiler.prototype.mustacheInAttr = function(mustache) { if (mustache.isHelper) { this.opcode('program', null, null); processParams(this, mustache.params); processHash(this, mustache.hash); this.opcode('helperAttr', mustache.id.string, mustache.params.length, mustache.escaped); } else { this.opcode('ambiguousAttr', mustache.id.string, mustache.escaped); } }; HydrationOpcodeCompiler.prototype.ID = function(id) { this.opcode('id', id.parts); }; HydrationOpcodeCompiler.prototype.STRING = function(string) { this.opcode('stringLiteral', string.stringModeValue); }; HydrationOpcodeCompiler.prototype.BOOLEAN = function(boolean) { this.opcode('literal', boolean.stringModeValue); }; HydrationOpcodeCompiler.prototype.INTEGER = function(integer) { this.opcode('literal', integer.stringModeValue); }; function processParams(compiler, params) { forEach(params, function(param) { if (param.type === 'text') { compiler.STRING({ stringModeValue: param.chars }); } else if (param.type) { compiler[param.type](param); } else { compiler.STRING({ stringModeValue: param }); } }); } function processHash(compiler, hash) { if (hash) { forEach(hash.pairs, function(pair) { var name = pair[0], param = pair[1]; compiler[param.type](param); compiler.opcode('stackLiteral', name); }); compiler.opcode('stackLiteral', hash.pairs.length); } else { compiler.opcode('stackLiteral', 0); } } function distributeMorphs(morphs, opcodes) { if (morphs.length === 0) { return; } // Splice morphs after the most recent shareParent/consumeParent. var o; for (o = opcodes.length - 1; o >= 0; --o) { var opcode = opcodes[o][0]; if (opcode === 'element' || opcode === 'consumeParent' || opcode === 'popParent') { break; } } var spliceArgs = [o + 1, 0]; for (var i = 0; i < morphs.length; ++i) { var p = morphs[i]; spliceArgs.push(['morph', [p[0], p[1], p[2], p[3]]]); } opcodes.splice.apply(opcodes, spliceArgs); morphs.length = 0; } __exports__.HydrationOpcodeCompiler = HydrationOpcodeCompiler; }); define("htmlbars-compiler/compiler/quoting", ["exports"], function(__exports__) { "use strict"; function escapeString(str) { return str.replace(/"/g, '\\"').replace(/\n/g, "\\n"); } __exports__.escapeString = escapeString; function string(str) { return '"' + escapeString(str) + '"'; } __exports__.string = string; function array(a) { return "[" + a + "]"; } __exports__.array = array; function quotedArray(list) { return array(list.map(string).join(", ")); } __exports__.quotedArray = quotedArray;function hash(pairs) { return "{" + pairs.join(",") + "}"; } __exports__.hash = hash;function repeat(chars, times) { var str = ""; while (times--) { str += chars; } return str; } __exports__.repeat = repeat; }); define("htmlbars-compiler/compiler/template", ["./fragment_opcode","./fragment","./hydration_opcode","./hydration","./template_visitor","./utils","./quoting","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { "use strict"; var FragmentOpcodeCompiler = __dependency1__.FragmentOpcodeCompiler; var FragmentCompiler = __dependency2__.FragmentCompiler; var HydrationOpcodeCompiler = __dependency3__.HydrationOpcodeCompiler; var HydrationCompiler = __dependency4__.HydrationCompiler; var TemplateVisitor = __dependency5__["default"]; var processOpcodes = __dependency6__.processOpcodes; var string = __dependency7__.string; var repeat = __dependency7__.repeat; function TemplateCompiler() { this.fragmentOpcodeCompiler = new FragmentOpcodeCompiler(); this.fragmentCompiler = new FragmentCompiler(); this.hydrationOpcodeCompiler = new HydrationOpcodeCompiler(); this.hydrationCompiler = new HydrationCompiler(); this.templates = []; this.childTemplates = []; } __exports__.TemplateCompiler = TemplateCompiler;TemplateCompiler.prototype.compile = function(ast) { var templateVisitor = new TemplateVisitor(); templateVisitor.visit(ast); processOpcodes(this, templateVisitor.actions); return this.templates.pop(); }; TemplateCompiler.prototype.startProgram = function(program, childTemplateCount, blankChildTextNodes) { this.fragmentOpcodeCompiler.startProgram(program, childTemplateCount, blankChildTextNodes); this.hydrationOpcodeCompiler.startProgram(program, childTemplateCount, blankChildTextNodes); this.childTemplates.length = 0; while(childTemplateCount--) { this.childTemplates.push(this.templates.pop()); } }; TemplateCompiler.prototype.endProgram = function(program, programDepth) { this.fragmentOpcodeCompiler.endProgram(program); this.hydrationOpcodeCompiler.endProgram(program); var indent = repeat(" ", programDepth); var options = { indent: indent + " " }; // function build(dom) { return fragment; } var fragmentProgram = this.fragmentCompiler.compile( this.fragmentOpcodeCompiler.opcodes, options ); // function hydrate(fragment) { return mustaches; } var hydrationProgram = this.hydrationCompiler.compile( this.hydrationOpcodeCompiler.opcodes, options ); var childTemplateVars = ""; for (var i=0, l=this.childTemplates.length; ibaz * * produces the actions * * [['startProgram', [programNode, 0]], * ['text', [textNode, 0, 3]], * ['mustache', [mustacheNode, 1, 3]], * ['openElement', [elementNode, 2, 3, 0]], * ['text', [textNode, 0, 1]], * ['closeElement', [elementNode, 2, 3], * ['endProgram', [programNode]]] * * This visitor walks the AST depth first and backwards. As * a result the bottom-most child template will appear at the * top of the actions list whereas the root template will appear * at the bottom of the list. For example, * *
{{#if}}foo{{else}}bar{{/if}}
* * produces the actions * * [['startProgram', [programNode, 0]], * ['text', [textNode, 0, 2, 0]], * ['openElement', [elementNode, 1, 2, 0]], * ['closeElement', [elementNode, 1, 2]], * ['endProgram', [programNode]], * ['startProgram', [programNode, 0]], * ['text', [textNode, 0, 1]], * ['endProgram', [programNode]], * ['startProgram', [programNode, 2]], * ['openElement', [elementNode, 0, 1, 1]], * ['block', [blockNode, 0, 1]], * ['closeElement', [elementNode, 0, 1]], * ['endProgram', [programNode]]] * * The state of the traversal is maintained by a stack of frames. * Whenever a node with children is entered (either a ProgramNode * or an ElementNode) a frame is pushed onto the stack. The frame * contains information about the state of the traversal of that * node. For example, * * - index of the current child node being visited * - the number of mustaches contained within its child nodes * - the list of actions generated by its child nodes */ function TemplateVisitor() { this.frameStack = []; this.actions = []; this.programDepth = -1; } // Traversal methods TemplateVisitor.prototype.visit = function(node) { this[node.type](node); }; TemplateVisitor.prototype.program = function(program) { this.programDepth++; var parentFrame = this.getCurrentFrame(); var programFrame = this.pushFrame(); programFrame.parentNode = program; programFrame.children = program.statements; programFrame.childCount = program.statements.length; programFrame.blankChildTextNodes = []; programFrame.actions.push(['endProgram', [program, this.programDepth]]); for (var i = program.statements.length - 1; i >= 0; i--) { programFrame.childIndex = i; this.visit(program.statements[i]); } programFrame.actions.push(['startProgram', [ program, programFrame.childTemplateCount, programFrame.blankChildTextNodes.reverse() ]]); this.popFrame(); this.programDepth--; // Push the completed template into the global actions list if (parentFrame) { parentFrame.childTemplateCount++; } push.apply(this.actions, programFrame.actions.reverse()); }; TemplateVisitor.prototype.element = function(element) { var parentFrame = this.getCurrentFrame(); var elementFrame = this.pushFrame(); var parentNode = parentFrame.parentNode; elementFrame.parentNode = element; elementFrame.children = element.children; elementFrame.childCount = element.children.length; elementFrame.mustacheCount += element.helpers.length; elementFrame.blankChildTextNodes = []; var actionArgs = [ element, parentFrame.childIndex, parentFrame.childCount, parentNode.type === 'program' && parentFrame.childCount === 1 ]; var lastNode = parentFrame.childIndex === parentFrame.childCount-1, introducesNamespace = elementIntroducesNamespace(element, parentFrame.parentNode); if ( !lastNode && introducesNamespace ) { elementFrame.actions.push(['setNamespace', [parentNode.namespaceURI]]); } elementFrame.actions.push(['closeElement', actionArgs]); if ( !lastNode && element.isHTMLIntergrationPoint ) { elementFrame.actions.push(['setNamespace', []]); } for (var i = element.attributes.length - 1; i >= 0; i--) { this.visit(element.attributes[i]); } for (i = element.children.length - 1; i >= 0; i--) { elementFrame.childIndex = i; this.visit(element.children[i]); } if ( element.isHTMLIntergrationPoint ) { elementFrame.actions.push(['setNamespace', []]); } elementFrame.actions.push(['openElement', actionArgs.concat([ elementFrame.mustacheCount, elementFrame.blankChildTextNodes.reverse() ])]); if ( introducesNamespace ) { elementFrame.actions.push(['setNamespace', [element.namespaceURI]]); } this.popFrame(); // Propagate the element's frame state to the parent frame if (elementFrame.mustacheCount > 0) { parentFrame.mustacheCount++; } parentFrame.childTemplateCount += elementFrame.childTemplateCount; push.apply(parentFrame.actions, elementFrame.actions); }; TemplateVisitor.prototype.attr = function(attr) { if (attr.value.type === 'mustache') { this.getCurrentFrame().mustacheCount++; } }; TemplateVisitor.prototype.block = function(node) { var frame = this.getCurrentFrame(); var parentNode = frame.parentNode; frame.mustacheCount++; frame.actions.push([node.type, [node, frame.childIndex, frame.childCount]]); if (node.inverse) { this.visit(node.inverse); } if (node.program) { this.visit(node.program); } }; TemplateVisitor.prototype.partial = function(node) { var frame = this.getCurrentFrame(); frame.mustacheCount++; frame.actions.push(['mustache', [node, frame.childIndex, frame.childCount]]); }; TemplateVisitor.prototype.component = TemplateVisitor.prototype.block; TemplateVisitor.prototype.text = function(text) { var frame = this.getCurrentFrame(); var isSingleRoot = frame.parentNode.type === 'program' && frame.childCount === 1; if (text.chars === '') { frame.blankChildTextNodes.push(domIndexOf(frame.children, text)); } frame.actions.push(['text', [text, frame.childIndex, frame.childCount, isSingleRoot]]); }; TemplateVisitor.prototype.mustache = function(mustache) { var frame = this.getCurrentFrame(); frame.mustacheCount++; frame.actions.push(['mustache', [mustache, frame.childIndex, frame.childCount]]); }; // Frame helpers TemplateVisitor.prototype.getCurrentFrame = function() { return this.frameStack[this.frameStack.length - 1]; }; TemplateVisitor.prototype.pushFrame = function() { var frame = new Frame(); this.frameStack.push(frame); return frame; }; TemplateVisitor.prototype.popFrame = function() { return this.frameStack.pop(); }; __exports__["default"] = TemplateVisitor; // Returns the index of `domNode` in the `nodes` array, skipping // over any nodes which do not represent DOM nodes. function domIndexOf(nodes, domNode) { var index = -1; for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; if (node.type !== 'text' && node.type !== 'element') { continue; } else { index++; } if (node === domNode) { return index; } } return -1; } }); define("htmlbars-compiler/compiler/utils", ["exports"], function(__exports__) { "use strict"; function processOpcodes(compiler, opcodes) { for (var i=0, l=opcodes.length; i 0 && statements[i-1].strip && statements[i-1].strip.right) || (i === 0 && program.strip.left)) { statement.chars = statement.chars.replace(/^\s+/, ''); } if ((i < l-1 && statements[i+1].strip && statements[i+1].strip.left) || (i === l-1 && program.strip.right)) { statement.chars = statement.chars.replace(/\s+$/, ''); } // Remove unnecessary text nodes if (statement.chars.length === 0) { if ((i > 0 && statements[i-1].type === 'element') || (i < l-1 && statements[i+1].type === 'element')) { statements.splice(i, 1); i--; l--; } } } } __exports__.postprocessProgram = postprocessProgram; }); define("htmlbars-compiler/html-parser/node-handlers", ["../ast","../html-parser/helpers","../html-parser/tokens","../utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var BlockNode = __dependency1__.BlockNode; var ProgramNode = __dependency1__.ProgramNode; var TextNode = __dependency1__.TextNode; var PartialNode = __dependency1__.PartialNode; var appendChild = __dependency1__.appendChild; var usesMorph = __dependency1__.usesMorph; var postprocessProgram = __dependency2__.postprocessProgram; var Chars = __dependency3__.Chars; var forEach = __dependency4__.forEach; var nodeHandlers = { program: function(program) { var statements = []; var node = new ProgramNode(statements, program.strip); var i, l = program.statements.length; this.elementStack.push(node); if (l === 0) { return this.elementStack.pop(); } for (i = 0; i < l; i++) { this.acceptNode(program.statements[i]); } this.acceptToken(this.tokenizer.tokenizeEOF()); postprocessProgram(node); // Ensure that that the element stack is balanced properly. var poppedNode = this.elementStack.pop(); if (poppedNode !== node) { throw new Error("Unclosed element: " + poppedNode.tag); } return node; }, block: function(block) { switchToHandlebars(this); this.acceptToken(block); var mustache = block.mustache; var program = this.acceptNode(block.program); var inverse = block.inverse ? this.acceptNode(block.inverse) : null; var strip = block.strip; // Normalize inverse's strip if (inverse && !inverse.strip.left) { inverse.strip.left = false; } var node = new BlockNode(mustache, program, inverse, strip); var parentProgram = this.currentElement(); appendChild(parentProgram, node); }, content: function(content) { var tokens = this.tokenizer.tokenizePart(content.string); return forEach(tokens, this.acceptToken, this); }, mustache: function(mustache) { switchToHandlebars(this); this.acceptToken(mustache); }, comment: function(comment) { return; }, partial: function(partial) { var node = new PartialNode(partial.partialName.name); appendChild(this.currentElement(), node); return; } }; function switchToHandlebars(processor) { var token = processor.tokenizer.token; // TODO: Monkey patch Chars.addChar like attributes if (token instanceof Chars) { processor.acceptToken(token); processor.tokenizer.token = null; } } __exports__["default"] = nodeHandlers; }); define("htmlbars-compiler/html-parser/token-handlers", ["../ast","./helpers","../utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; var ProgramNode = __dependency1__.ProgramNode; var ComponentNode = __dependency1__.ComponentNode; var ElementNode = __dependency1__.ElementNode; var TextNode = __dependency1__.TextNode; var appendChild = __dependency1__.appendChild; var postprocessProgram = __dependency2__.postprocessProgram; var forEach = __dependency3__.forEach; // This table maps from the state names in the tokenizer to a smaller // number of states that control how mustaches are handled var states = { "beforeAttributeValue": "before-attr", "attributeValueDoubleQuoted": "attr", "attributeValueSingleQuoted": "attr", "attributeValueUnquoted": "attr", "beforeAttributeName": "in-tag" }; // The HTML elements in this list are speced by // http://www.w3.org/TR/html-markup/syntax.html#syntax-elements, // and will be forced to close regardless of if they have a // self-closing /> at the end. var voidTagNames = "area base br col command embed hr img input keygen link meta param source track wbr"; var voidMap = {}; forEach(voidTagNames.split(" "), function(tagName) { voidMap[tagName] = true; }); var svgNamespace = "http://www.w3.org/2000/svg", // http://www.w3.org/html/wg/drafts/html/master/syntax.html#html-integration-point svgHTMLIntegrationPoints = {'foreignObject':true, 'desc':true, 'title':true}; function applyNamespace(tag, element, currentElement){ if (tag.tagName === 'svg') { element.namespaceURI = svgNamespace; } else if ( currentElement.type === 'element' && currentElement.namespaceURI && !currentElement.isHTMLIntegrationPoint ) { element.namespaceURI = currentElement.namespaceURI; } } function applyHTMLIntegrationPoint(tag, element){ if (svgHTMLIntegrationPoints[tag.tagName]) { element.isHTMLIntegrationPoint = true; } } // Except for `mustache`, all tokens are only allowed outside of // a start or end tag. var tokenHandlers = { Chars: function(token) { var current = this.currentElement(); var text = new TextNode(token.chars); appendChild(current, text); }, StartTag: function(tag) { var element = new ElementNode(tag.tagName, tag.attributes, tag.helpers || [], []); applyNamespace(tag, element, this.currentElement()); applyHTMLIntegrationPoint(tag, element); this.elementStack.push(element); if (voidMap.hasOwnProperty(tag.tagName) || tag.selfClosing) { tokenHandlers.EndTag.call(this, tag); } }, block: function(block) { if (this.tokenizer.state !== 'data') { throw new Error("A block may only be used inside an HTML element or another block."); } }, mustache: function(mustache) { var state = this.tokenizer.state; var token = this.tokenizer.token; switch(states[state]) { case "before-attr": this.tokenizer.state = 'attributeValueUnquoted'; token.addToAttributeValue(mustache); return; case "attr": token.addToAttributeValue(mustache); return; case "in-tag": token.addTagHelper(mustache); return; default: appendChild(this.currentElement(), mustache); } }, EndTag: function(tag) { var element = this.elementStack.pop(); var parent = this.currentElement(); if (element.tag !== tag.tagName) { throw new Error("Closing tag " + tag.tagName + " did not match last open tag " + element.tag); } if (element.tag.indexOf("-") === -1) { appendChild(parent, element); } else { var program = new ProgramNode(element.children, { left: false, right: false }); postprocessProgram(program); var component = new ComponentNode(element.tag, element.attributes, program); appendChild(parent, component); } } }; __exports__["default"] = tokenHandlers; }); define("htmlbars-compiler/html-parser/tokens", ["../../simple-html-tokenizer","../ast","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; var Chars = __dependency1__.Chars; var StartTag = __dependency1__.StartTag; var EndTag = __dependency1__.EndTag; var AttrNode = __dependency2__.AttrNode; var TextNode = __dependency2__.TextNode; var MustacheNode = __dependency2__.MustacheNode; var StringNode = __dependency2__.StringNode; var IdNode = __dependency2__.IdNode; StartTag.prototype.startAttribute = function(char) { this.finalizeAttributeValue(); this.currentAttribute = new AttrNode(char.toLowerCase(), []); this.attributes.push(this.currentAttribute); }; StartTag.prototype.addToAttributeName = function(char) { this.currentAttribute.name += char; }; StartTag.prototype.addToAttributeValue = function(char) { var value = this.currentAttribute.value; if (char.type === 'mustache') { value.push(char); } else { if (value.length > 0 && value[value.length - 1].type === 'text') { value[value.length - 1].chars += char; } else { value.push(new TextNode(char)); } } }; StartTag.prototype.finalize = function() { this.finalizeAttributeValue(); delete this.currentAttribute; return this; }; StartTag.prototype.finalizeAttributeValue = function() { var attr = this.currentAttribute; if (!attr) return; if (attr.value.length === 1) { // Unwrap a single TextNode or MustacheNode attr.value = attr.value[0]; } else { // If the attr value has multiple parts combine them into // a single MustacheNode with the concat helper var params = [ new IdNode([{ part: 'concat' }]) ]; for (var i = 0; i < attr.value.length; i++) { var part = attr.value[i]; if (part.type === 'text') { params.push(new StringNode(part.chars)); } else if (part.type === 'mustache') { var sexpr = part.sexpr; delete sexpr.isRoot; if (sexpr.isHelper) { sexpr.isHelper = true; } params.push(sexpr); } } attr.value = new MustacheNode(params, undefined, true, { left: false, right: false }); } }; StartTag.prototype.addTagHelper = function(helper) { var helpers = this.helpers = this.helpers || []; helpers.push(helper); }; __exports__.Chars = Chars; __exports__.StartTag = StartTag; __exports__.EndTag = EndTag; }); define("htmlbars-compiler/parser", ["../handlebars/compiler/base","../simple-html-tokenizer","./html-parser/node-handlers","./html-parser/token-handlers","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var parse = __dependency1__.parse; var Tokenizer = __dependency2__.Tokenizer; var nodeHandlers = __dependency3__["default"]; var tokenHandlers = __dependency4__["default"]; function preprocess(html, options) { var ast = parse(html); var combined = new HTMLProcessor().acceptNode(ast); return combined; } __exports__.preprocess = preprocess;function HTMLProcessor() { this.elementStack = []; this.tokenizer = new Tokenizer(''); this.nodeHandlers = nodeHandlers; this.tokenHandlers = tokenHandlers; } HTMLProcessor.prototype.acceptNode = function(node) { return this.nodeHandlers[node.type].call(this, node); }; HTMLProcessor.prototype.acceptToken = function(token) { if (token) { return this.tokenHandlers[token.type].call(this, token); } }; HTMLProcessor.prototype.currentElement = function() { return this.elementStack[this.elementStack.length - 1]; }; }); define("htmlbars-compiler/utils", ["exports"], function(__exports__) { "use strict"; function forEach(array, callback, binding) { var i, l; if (binding === undefined) { for (i=0, l=array.length; i // // // // The tbody may be omitted, and the browser will accept and render: // // // // // However, the omitted start tag will still be added to the DOM. Here // we test the string and context to see if the browser is about to // perform this cleanup. // // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags // describes which tags are omittable. The spec for tbody and colgroup // explains this behavior: // // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element // var omittedStartTagChildTest = /<([\w:]+)/; function detectOmittedStartTag(string, contextualElement){ // Omitted start tags are only inside table tags. if (contextualElement.tagName === 'TABLE') { var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); if (omittedStartTagChildMatch) { var omittedStartTagChild = omittedStartTagChildMatch[1]; // It is already asserted that the contextual element is a table // and not the proper start tag. Just see if a tag was omitted. return omittedStartTagChild === 'tr' || omittedStartTagChild === 'col'; } } } function buildSVGDOM(html, dom){ var div = dom.document.createElement('div'); div.innerHTML = ''+html+''; return div.firstChild.childNodes; } /* * A class wrapping DOM functions to address environment compatibility, * namespaces, contextual elements for morph un-escaped content * insertion. * * When entering a template, a DOMHelper should be passed: * * template(context, { hooks: hooks, dom: new DOMHelper() }); * * TODO: support foreignObject as a passed contextual element. It has * a namespace (svg) that does not match its internal namespace * (xhtml). * * @class DOMHelper * @constructor * @param {HTMLDocument} _document The document DOM methods are proxied to */ function DOMHelper(_document){ this.document = _document || window.document; this.namespace = null; } var prototype = DOMHelper.prototype; prototype.constructor = DOMHelper; prototype.insertBefore = function(element, childElement, referenceChild) { return element.insertBefore(childElement, referenceChild); }; prototype.appendChild = function(element, childElement) { return element.appendChild(childElement); }; prototype.appendText = function(element, text) { return element.appendChild(this.document.createTextNode(text)); }; prototype.setAttribute = function(element, name, value) { element.setAttribute(name, value); }; if (document.createElementNS) { // Only opt into namespace detection if a contextualElement // is passed. prototype.createElement = function(tagName, contextualElement) { var namespace = this.namespace; if (contextualElement) { if (tagName === 'svg') { namespace = svgNamespace; } else { namespace = interiorNamespace(contextualElement); } } if (namespace) { return this.document.createElementNS(namespace, tagName); } else { return this.document.createElement(tagName); } }; } else { prototype.createElement = function(tagName) { return this.document.createElement(tagName); }; } prototype.setNamespace = function(ns) { this.namespace = ns; }; prototype.detectNamespace = function(element) { this.namespace = interiorNamespace(element); }; prototype.createDocumentFragment = function(){ return this.document.createDocumentFragment(); }; prototype.createTextNode = function(text){ return this.document.createTextNode(text); }; prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; var endTag = ''; var wrappedHTML = [startTag, html, endTag]; var i = wrappingTags.length; var wrappedDepth = 1 + i; while(i--) { wrappedHTML.unshift('<'+wrappingTags[i]+'>'); wrappedHTML.push(''); } var wrapper = document.createElement('div'); scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); var element = wrapper; while (wrappedDepth--) { element = element.firstChild; while (element && element.nodeType !== 1) { element = element.nextSibling; } } while (element && element.tagName !== tagName) { element = element.nextSibling; } return element ? element.childNodes : []; } var buildDOM; if (needsShy) { buildDOM = function buildDOM(html, contextualElement, dom){ contextualElement = dom.cloneNode(contextualElement, false); scriptSafeInnerHTML(contextualElement, html); return contextualElement.childNodes; }; } else { buildDOM = function buildDOM(html, contextualElement, dom){ contextualElement = dom.cloneNode(contextualElement, false); contextualElement.innerHTML = html; return contextualElement.childNodes; }; } var buildIESafeDOM; if (tagNamesRequiringInnerHTMLFix.length > 0 || movesWhitespace) { buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { // Make a list of the leading text on script nodes. Include // script tags without any whitespace for easier processing later. var spacesBefore = []; var spacesAfter = []; html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { spacesAfter.push(spaces); return tag; }); // Fetch nodes var nodes; if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { // buildDOMWithFix uses string wrappers for problematic innerHTML. nodes = buildDOMWithFix(html, contextualElement); } else { nodes = buildDOM(html, contextualElement, dom); } // Build a list of script tags, the nodes themselves will be // mutated as we add test nodes. var i, j, node, nodeScriptNodes; var scriptNodes = []; for (i=0;node=nodes[i];i++) { if (node.nodeType !== 1) { continue; } if (node.tagName === 'SCRIPT') { scriptNodes.push(node); } else { nodeScriptNodes = node.getElementsByTagName('script'); for (j=0;j 0) { textNode = dom.document.createTextNode(spaceBefore); scriptNode.parentNode.insertBefore(textNode, scriptNode); } spaceAfter = spacesAfter[i]; if (spaceAfter && spaceAfter.length > 0) { textNode = dom.document.createTextNode(spaceAfter); scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); } } return nodes; }; } else { buildIESafeDOM = buildDOM; } var buildHTMLDOM; if (needsIntegrationPointFix) { buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ if (svgHTMLIntegrationPoints[contextualElement.tagName]) { return buildIESafeDOM(html, document.createElement('div'), dom); } else { return buildIESafeDOM(html, contextualElement, dom); } }; } else { buildHTMLDOM = buildIESafeDOM; } __exports__.buildHTMLDOM = buildHTMLDOM; }); define("morph/morph", ["exports"], function(__exports__) { "use strict"; var splice = Array.prototype.splice; function ensureStartEnd(start, end) { if (start === null || end === null) { throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); } } function ensureContext(contextualElement) { if (!contextualElement || contextualElement.nodeType !== 1) { throw new Error('An element node must be provided for a contextualElement, you provided ' + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); } } // TODO: this is an internal API, this should be an assert function Morph(parent, start, end, domHelper, contextualElement) { if (parent.nodeType === 11) { ensureStartEnd(start, end); this.element = null; } else { this.element = parent; } this._parent = parent; this.start = start; this.end = end; this.domHelper = domHelper; ensureContext(contextualElement); this.contextualElement = contextualElement; this.reset(); } Morph.prototype.reset = function() { this.text = null; this.owner = null; this.morphs = null; this.before = null; this.after = null; this.escaped = true; }; Morph.prototype.parent = function () { if (!this.element) { var parent = this.start.parentNode; if (this._parent !== parent) { this.element = this._parent = parent; } } return this._parent; }; Morph.prototype.destroy = function () { if (this.owner) { this.owner.removeMorph(this); } else { clear(this.element || this.parent(), this.start, this.end); } }; Morph.prototype.removeMorph = function (morph) { var morphs = this.morphs; for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; var after = index < morphs.length ? morphs[index] : null; var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); morph.owner = this; morph._update(parent, node); if (before !== null) { morph.before = before; before.end = start.nextSibling; before.after = morph; } if (after !== null) { morph.after = after; after.before = morph; after.start = end.previousSibling; } this.morphs.splice(index, 0, morph); return morph; }; Morph.prototype.replace = function (index, removedLength, addedNodes) { if (this.morphs === null) this.morphs = []; var parent = this.element || this.parent(); var morphs = this.morphs; var before = index > 0 ? morphs[index-1] : null; var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); var addedLength = addedNodes === undefined ? 0 : addedNodes.length; var args, i, current; if (removedLength > 0) { clear(parent, start, end); } if (addedLength === 0) { if (before !== null) { before.after = after; before.end = end; } if (after !== null) { after.before = before; after.start = start; } morphs.splice(index, removedLength); return; } args = new Array(addedLength+2); if (addedLength > 0) { for (i=0; i") { return this.emitToken(); } else { this.addToComment(char); this.state = 'comment'; } }, commentStartDash: function(char) { if (char === "-") { this.state = 'commentEnd'; } else if (char === ">") { return this.emitToken(); } else { this.addToComment("-"); this.state = 'comment'; } }, comment: function(char) { if (char === "-") { this.state = 'commentEndDash'; } else { this.addToComment(char); } }, commentEndDash: function(char) { if (char === "-") { this.state = 'commentEnd'; } else { this.addToComment("-" + char); this.state = 'comment'; } }, commentEnd: function(char) { if (char === ">") { return this.emitToken(); } else { this.addToComment("--" + char); this.state = 'comment'; } }, tagName: function(char) { if (isSpace(char)) { this.state = 'beforeAttributeName'; } else if (char === "/") { this.state = 'selfClosingStartTag'; } else if (char === ">") { return this.emitToken(); } else { this.token.addToTagName(char); } }, beforeAttributeName: function(char) { if (isSpace(char)) { return; } else if (char === "/") { this.state = 'selfClosingStartTag'; } else if (char === ">") { return this.emitToken(); } else { this.attribute(char); } }, attributeName: function(char) { if (isSpace(char)) { this.state = 'afterAttributeName'; } else if (char === "/") { this.state = 'selfClosingStartTag'; } else if (char === "=") { this.state = 'beforeAttributeValue'; } else if (char === ">") { return this.emitToken(); } else { this.addToAttributeName(char); } }, afterAttributeName: function(char) { if (isSpace(char)) { return; } else if (char === "/") { this.state = 'selfClosingStartTag'; } else if (char === "=") { this.state = 'beforeAttributeValue'; } else if (char === ">") { return this.emitToken(); } else { this.attribute(char); } }, beforeAttributeValue: function(char) { if (isSpace(char)) { return; } else if (char === '"') { this.state = 'attributeValueDoubleQuoted'; } else if (char === "'") { this.state = 'attributeValueSingleQuoted'; } else if (char === ">") { return this.emitToken(); } else { this.state = 'attributeValueUnquoted'; this.addToAttributeValue(char); } }, attributeValueDoubleQuoted: function(char) { if (char === '"') { this.state = 'afterAttributeValueQuoted'; } else if (char === "&") { this.addToAttributeValue(this.consumeCharRef('"') || "&"); } else { this.addToAttributeValue(char); } }, attributeValueSingleQuoted: function(char) { if (char === "'") { this.state = 'afterAttributeValueQuoted'; } else if (char === "&") { this.addToAttributeValue(this.consumeCharRef("'") || "&"); } else { this.addToAttributeValue(char); } }, attributeValueUnquoted: function(char) { if (isSpace(char)) { this.state = 'beforeAttributeName'; } else if (char === "&") { this.addToAttributeValue(this.consumeCharRef(">") || "&"); } else if (char === ">") { return this.emitToken(); } else { this.addToAttributeValue(char); } }, afterAttributeValueQuoted: function(char) { if (isSpace(char)) { this.state = 'beforeAttributeName'; } else if (char === "/") { this.state = 'selfClosingStartTag'; } else if (char === ">") { return this.emitToken(); } else { this.char--; this.state = 'beforeAttributeName'; } }, selfClosingStartTag: function(char) { if (char === ">") { this.selfClosing(); return this.emitToken(); } else { this.char--; this.state = 'beforeAttributeName'; } }, endTagOpen: function(char) { if (isAlpha(char)) { this.tag(EndTag, char.toLowerCase()); } } } }; function Tag(tagName, attributes, options) { this.tagName = tagName || ""; this.attributes = attributes || []; this.selfClosing = options ? options.selfClosing : false; } Tag.prototype = { constructor: Tag, addToTagName: function(char) { this.tagName += char; }, startAttribute: function(char) { this.currentAttribute = [char.toLowerCase(), null]; this.attributes.push(this.currentAttribute); }, addToAttributeName: function(char) { this.currentAttribute[0] += char; }, addToAttributeValue: function(char) { this.currentAttribute[1] = this.currentAttribute[1] || ""; this.currentAttribute[1] += char; }, finalize: function() { delete this.currentAttribute; return this; } }; function StartTag() { Tag.apply(this, arguments); } StartTag.prototype = objectCreate(Tag.prototype); StartTag.prototype.type = 'StartTag'; StartTag.prototype.constructor = StartTag; StartTag.prototype.toHTML = function() { return config.generateTag(this); }; function generateTag(tag) { var out = "<"; out += tag.tagName; if (tag.attributes.length) { out += " " + config.generateAttributes(tag.attributes); } out += ">"; return out; } function generateAttributes(attributes) { var out = [], attribute, attrString, value; for (var i=0, l=attributes.length; i"; } }; function tokenize(input) { var tokenizer = new Tokenizer(input); return tokenizer.tokenize(); } function generate(tokens) { var output = ""; for (var i=0, l=tokens.length; i