From 18271e3b7a55c879c70830a35ba1c4a06111c60b Mon Sep 17 00:00:00 2001 From: tomhuda Date: Fri, 18 Jan 2013 14:44:31 -0800 Subject: [PATCH 1/7] Empty object proxies are not truthy in {{#if}} This addresses at least one issue in #1812 --- .../ember-handlebars/lib/helpers/binding.js | 3 ++ .../tests/helpers/if_unless_test.js | 30 ++++++++++++++++++- .../ember-runtime/lib/system/object_proxy.js | 4 +++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/ember-handlebars/lib/helpers/binding.js b/packages/ember-handlebars/lib/helpers/binding.js index ff41ecb98d8..f4134006102 100644 --- a/packages/ember-handlebars/lib/helpers/binding.js +++ b/packages/ember-handlebars/lib/helpers/binding.js @@ -228,6 +228,9 @@ EmberHandlebars.registerHelper('bind', function(property, options) { EmberHandlebars.registerHelper('boundIf', function(property, fn) { var context = (fn.contexts && fn.contexts[0]) || this; var func = function(result) { + var truthy = result && get(result, 'isTruthy'); + if (typeof truthy === 'boolean') { return truthy; } + if (Ember.typeOf(result) === 'array') { return get(result, 'length') !== 0; } else { diff --git a/packages/ember-handlebars/tests/helpers/if_unless_test.js b/packages/ember-handlebars/tests/helpers/if_unless_test.js index 229581640d7..7d6ceb22944 100644 --- a/packages/ember-handlebars/tests/helpers/if_unless_test.js +++ b/packages/ember-handlebars/tests/helpers/if_unless_test.js @@ -2,6 +2,8 @@ var appendView = function(view) { Ember.run(function() { view.appendTo('#qunit-fixture'); }); }; +var compile = Ember.Handlebars.compile; + var view; module("Handlebars {{#if}} and {{#unless}} helpers", { @@ -18,10 +20,36 @@ test("unless should keep the current context (#784)", function() { view = Ember.View.create({ o: Ember.Object.create({foo: '42'}), - template: Ember.Handlebars.compile('{{#with view.o}}{{#view Ember.View}}{{#unless view.doesNotExist}}foo: {{foo}}{{/unless}}{{/view}}{{/with}}') + template: compile('{{#with view.o}}{{#view Ember.View}}{{#unless view.doesNotExist}}foo: {{foo}}{{/unless}}{{/view}}{{/with}}') }); appendView(view); equal(view.$().text(), 'foo: 42'); }); + +test("The `if` helper tests for `isTruthy` if available", function() { + view = Ember.View.create({ + truthy: Ember.Object.create({ isTruthy: true }), + falsy: Ember.Object.create({ isTruthy: false }), + + template: compile('{{#if view.truthy}}Yep{{/if}}{{#if view.falsy}}Nope{{/if}}') + }); + + appendView(view); + + equal(view.$().text(), 'Yep'); +}); + +test("The `if` helper does not print the contents for an object proxy without content", function() { + view = Ember.View.create({ + truthy: Ember.ObjectProxy.create({ content: {} }), + falsy: Ember.ObjectProxy.create({ content: null }), + + template: compile('{{#if view.truthy}}Yep{{/if}}{{#if view.falsy}}Nope{{/if}}') + }); + + appendView(view); + + equal(view.$().text(), 'Yep'); +}); diff --git a/packages/ember-runtime/lib/system/object_proxy.js b/packages/ember-runtime/lib/system/object_proxy.js index 869147de9e6..7f124d60db5 100644 --- a/packages/ember-runtime/lib/system/object_proxy.js +++ b/packages/ember-runtime/lib/system/object_proxy.js @@ -108,6 +108,10 @@ Ember.ObjectProxy = Ember.Object.extend( Ember.assert("Can't set ObjectProxy's content to itself", this.get('content') !== this); }, 'content'), + isTruthy: Ember.computed(function() { + return !!get(this, 'content'); + }).property('content'), + willWatchProperty: function (key) { var contentKey = 'content.' + key; addBeforeObserver(this, contentKey, null, contentPropertyWillChange); From e0b94231299e34b39dacbf315219ae342ba65056 Mon Sep 17 00:00:00 2001 From: tomhuda Date: Fri, 18 Jan 2013 17:32:20 -0800 Subject: [PATCH 2/7] Allow {{action}} to support string literal params --- ...ars-1.0.rc.1.js => handlebars-1.0.rc.2.js} | 380 +++++++++++------- .../ember-handlebars-compiler/lib/main.js | 2 +- packages/ember-handlebars/lib/ext.js | 37 +- .../ember-handlebars/tests/lookup_test.js | 113 ++++++ packages/ember-routing/lib/helpers/action.js | 18 +- .../tests/helpers/action_test.js | 23 ++ packages/handlebars/lib/main.js | 327 ++++++++------- tests/index.html | 8 - 8 files changed, 601 insertions(+), 307 deletions(-) rename lib/{handlebars-1.0.rc.1.js => handlebars-1.0.rc.2.js} (79%) create mode 100644 packages/ember-handlebars/tests/lookup_test.js diff --git a/lib/handlebars-1.0.rc.1.js b/lib/handlebars-1.0.rc.2.js similarity index 79% rename from lib/handlebars-1.0.rc.1.js rename to lib/handlebars-1.0.rc.2.js index 05346370a20..247a3fdff11 100644 --- a/lib/handlebars-1.0.rc.1.js +++ b/lib/handlebars-1.0.rc.2.js @@ -5,7 +5,7 @@ this.Handlebars = {}; (function(Handlebars) { -Handlebars.VERSION = "1.0.rc.1"; +Handlebars.VERSION = "1.0.rc.2"; Handlebars.helpers = {}; Handlebars.partials = {}; @@ -62,22 +62,53 @@ Handlebars.createFrame = Object.create || function(object) { return obj; }; +Handlebars.logger = { + DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, + + methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'}, + + // can be overridden in the host environment + log: function(level, obj) { + if (Handlebars.logger.level <= level) { + var method = Handlebars.logger.methodMap[level]; + if (typeof console !== 'undefined' && console[method]) { + console[method].call(console, obj); + } + } + } +}; + +Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); }; + Handlebars.registerHelper('each', function(context, options) { var fn = options.fn, inverse = options.inverse; - var ret = "", data; + var i = 0, ret = "", data; if (options.data) { data = Handlebars.createFrame(options.data); } - if(context && context.length > 0) { - for(var i=0, j=context.length; i)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; -lexer.conditions = {"mu":{"rules":[3,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],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,28],"inclusive":true}}; +lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/]; +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,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"par":{"rules":[30,31],"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; -})(); -if (typeof require !== 'undefined' && typeof exports !== 'undefined') { -exports.parser = handlebars; -exports.Parser = handlebars.Parser; -exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); } -exports.main = function commonjsMain(args) { - if (!args[1]) - throw new Error('Usage: '+args[0]+' FILE'); - var source, cwd; - if (typeof process !== 'undefined') { - source = require('fs').readFileSync(require('path').resolve(args[1]), "utf8"); - } else { - source = require("file").path(require("file").cwd()).join(args[1]).read({charset: "utf-8"}); - } - return exports.parser.parse(source); -} -if (typeof module !== 'undefined' && require.main === module) { - exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); -} -}; -; +})();; // lib/handlebars/compiler/base.js Handlebars.Parser = handlebars; @@ -597,17 +625,7 @@ Handlebars.parse = function(string) { Handlebars.print = function(ast) { return new Handlebars.PrintVisitor().accept(ast); -}; - -Handlebars.logger = { - DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, - - // override in the host environment - log: function(level, str) {} -}; - -Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; -; +};; // lib/handlebars/compiler/ast.js (function() { @@ -641,13 +659,10 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; // pass or at runtime. }; - Handlebars.AST.PartialNode = function(id, context) { - this.type = "partial"; - - // TODO: disallow complex IDs - - this.id = id; - this.context = context; + Handlebars.AST.PartialNode = function(partialName, context) { + this.type = "partial"; + this.partialName = partialName; + this.context = context; }; var verifyMatch = function(open, close) { @@ -699,6 +714,13 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; // 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; + }; + + Handlebars.AST.PartialNameNode = function(name) { + this.type = "PARTIAL_NAME"; + this.name = name; }; Handlebars.AST.DataNode = function(id) { @@ -709,16 +731,19 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; Handlebars.AST.StringNode = function(string) { this.type = "STRING"; this.string = string; + this.stringModeValue = string; }; Handlebars.AST.IntegerNode = function(integer) { this.type = "INTEGER"; this.integer = integer; + this.stringModeValue = Number(integer); }; Handlebars.AST.BooleanNode = function(bool) { this.type = "BOOLEAN"; this.bool = bool; + this.stringModeValue = bool === "true"; }; Handlebars.AST.CommentNode = function(comment) { @@ -728,14 +753,16 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; })();; // lib/handlebars/utils.js + +var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + Handlebars.Exception = function(message) { var tmp = Error.prototype.constructor.apply(this, arguments); - for (var p in tmp) { - if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; } + // 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]]; } - - this.message = tmp.message; }; Handlebars.Exception.prototype = new Error(); @@ -778,11 +805,7 @@ Handlebars.SafeString.prototype.toString = function() { }, isEmpty: function(value) { - if (typeof value === "undefined") { - return true; - } else if (value === null) { - return true; - } else if (value === false) { + if (!value && value !== 0) { return true; } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) { return true; @@ -921,7 +944,7 @@ Handlebars.JavaScriptCompiler = function() {}; // evaluate it by executing `blockHelperMissing` this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); - this.opcode('pushLiteral', '{}'); + this.opcode('pushHash'); this.opcode('blockValue'); } else { this.ambiguousMustache(mustache, program, inverse); @@ -930,7 +953,7 @@ Handlebars.JavaScriptCompiler = function() {}; // evaluate it by executing `blockHelperMissing` this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); - this.opcode('pushLiteral', '{}'); + this.opcode('pushHash'); this.opcode('ambiguousBlockValue'); } @@ -940,19 +963,24 @@ Handlebars.JavaScriptCompiler = function() {}; hash: function(hash) { var pairs = hash.pairs, pair, val; - this.opcode('push', '{}'); + this.opcode('pushHash'); for(var i=0, l=pairs.length; iedit') + }); + + appendView(); + + view.$('button').trigger('click'); + + deepEqual(passedParams, ["herp", model], "the action was called with the passed contexts"); +}); + var namespace = { "Component": { toString: function() { return "Component"; }, diff --git a/packages/handlebars/lib/main.js b/packages/handlebars/lib/main.js index cc87141c3ad..247a3fdff11 100644 --- a/packages/handlebars/lib/main.js +++ b/packages/handlebars/lib/main.js @@ -5,7 +5,7 @@ this.Handlebars = {}; (function(Handlebars) { -Handlebars.VERSION = "1.0.rc.1"; +Handlebars.VERSION = "1.0.rc.2"; Handlebars.helpers = {}; Handlebars.partials = {}; @@ -62,6 +62,24 @@ Handlebars.createFrame = Object.create || function(object) { return obj; }; +Handlebars.logger = { + DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, + + methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'}, + + // can be overridden in the host environment + log: function(level, obj) { + if (Handlebars.logger.level <= level) { + var method = Handlebars.logger.methodMap[level]; + if (typeof console !== 'undefined' && console[method]) { + console[method].call(console, obj); + } + } + } +}; + +Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); }; + Handlebars.registerHelper('each', function(context, options) { var fn = options.fn, inverse = options.inverse; var i = 0, ret = "", data; @@ -117,8 +135,9 @@ Handlebars.registerHelper('with', function(context, options) { return options.fn(context); }); -Handlebars.registerHelper('log', function(context) { - Handlebars.log(context); +Handlebars.registerHelper('log', function(context, options) { + var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; + Handlebars.log(level, context); }); }(this.Handlebars)); @@ -128,103 +147,111 @@ Handlebars.registerHelper('log', function(context) { var handlebars = (function(){ var parser = {trace: function trace() { }, yy: {}, -symbols_: {"error":2,"root":3,"program":4,"EOF":5,"statements":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"OPEN_PARTIAL":24,"params":25,"hash":26,"DATA":27,"param":28,"STRING":29,"INTEGER":30,"BOOLEAN":31,"hashSegments":32,"hashSegment":33,"ID":34,"EQUALS":35,"pathSegments":36,"SEP":37,"$accept":0,"$end":1}, -terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",27:"DATA",29:"STRING",30:"INTEGER",31:"BOOLEAN",34:"ID",35:"EQUALS",37:"SEP"}, -productions_: [0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[17,1],[25,2],[25,1],[28,1],[28,1],[28,1],[28,1],[28,1],[26,1],[32,2],[32,1],[33,3],[33,3],[33,3],[33,3],[33,3],[21,1],[36,3],[36,1]], +symbols_: {"error":2,"root":3,"program":4,"EOF":5,"simpleInverse":6,"statements":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"OPEN_PARTIAL":24,"partialName":25,"params":26,"hash":27,"DATA":28,"param":29,"STRING":30,"INTEGER":31,"BOOLEAN":32,"hashSegments":33,"hashSegment":34,"ID":35,"EQUALS":36,"PARTIAL_NAME":37,"pathSegments":38,"SEP":39,"$accept":0,"$end":1}, +terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",28:"DATA",30:"STRING",31:"INTEGER",32:"BOOLEAN",35:"ID",36:"EQUALS",37:"PARTIAL_NAME",39:"SEP"}, +productions_: [0,[3,2],[4,2],[4,3],[4,2],[4,1],[4,1],[4,0],[7,1],[7,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[6,2],[17,3],[17,2],[17,2],[17,1],[17,1],[26,2],[26,1],[29,1],[29,1],[29,1],[29,1],[29,1],[27,1],[33,2],[33,1],[34,3],[34,3],[34,3],[34,3],[34,3],[25,1],[21,1],[38,3],[38,1]], performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { var $0 = $$.length - 1; switch (yystate) { case 1: return $$[$0-1]; break; -case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]); +case 2: this.$ = new yy.ProgramNode([], $$[$0]); break; -case 3: this.$ = new yy.ProgramNode($$[$0]); +case 3: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]); break; -case 4: this.$ = new yy.ProgramNode([]); +case 4: this.$ = new yy.ProgramNode($$[$0-1], []); break; -case 5: this.$ = [$$[$0]]; +case 5: this.$ = new yy.ProgramNode($$[$0]); break; -case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; +case 6: this.$ = new yy.ProgramNode([], []); break; -case 7: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]); +case 7: this.$ = new yy.ProgramNode([]); break; -case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]); +case 8: this.$ = [$$[$0]]; break; -case 9: this.$ = $$[$0]; +case 9: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; break; -case 10: this.$ = $$[$0]; +case 10: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]); break; -case 11: this.$ = new yy.ContentNode($$[$0]); +case 11: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]); break; -case 12: this.$ = new yy.CommentNode($$[$0]); +case 12: this.$ = $$[$0]; break; -case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); +case 13: this.$ = $$[$0]; break; -case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); +case 14: this.$ = new yy.ContentNode($$[$0]); break; -case 15: this.$ = $$[$0-1]; +case 15: this.$ = new yy.CommentNode($$[$0]); break; case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); break; -case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true); +case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); +break; +case 18: this.$ = $$[$0-1]; +break; +case 19: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); +break; +case 20: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true); +break; +case 21: this.$ = new yy.PartialNode($$[$0-1]); break; -case 18: this.$ = new yy.PartialNode($$[$0-1]); +case 22: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]); break; -case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]); +case 23: break; -case 20: +case 24: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]]; break; -case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]]; +case 25: this.$ = [[$$[$0-1]].concat($$[$0]), null]; break; -case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null]; +case 26: this.$ = [[$$[$0-1]], $$[$0]]; break; -case 23: this.$ = [[$$[$0-1]], $$[$0]]; +case 27: this.$ = [[$$[$0]], null]; break; -case 24: this.$ = [[$$[$0]], null]; +case 28: this.$ = [[new yy.DataNode($$[$0])], null]; break; -case 25: this.$ = [[new yy.DataNode($$[$0])], null]; +case 29: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; break; -case 26: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; +case 30: this.$ = [$$[$0]]; break; -case 27: this.$ = [$$[$0]]; +case 31: this.$ = $$[$0]; break; -case 28: this.$ = $$[$0]; +case 32: this.$ = new yy.StringNode($$[$0]); break; -case 29: this.$ = new yy.StringNode($$[$0]); +case 33: this.$ = new yy.IntegerNode($$[$0]); break; -case 30: this.$ = new yy.IntegerNode($$[$0]); +case 34: this.$ = new yy.BooleanNode($$[$0]); break; -case 31: this.$ = new yy.BooleanNode($$[$0]); +case 35: this.$ = new yy.DataNode($$[$0]); break; -case 32: this.$ = new yy.DataNode($$[$0]); +case 36: this.$ = new yy.HashNode($$[$0]); break; -case 33: this.$ = new yy.HashNode($$[$0]); +case 37: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; break; -case 34: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; +case 38: this.$ = [$$[$0]]; break; -case 35: this.$ = [$$[$0]]; +case 39: this.$ = [$$[$0-2], $$[$0]]; break; -case 36: this.$ = [$$[$0-2], $$[$0]]; +case 40: this.$ = [$$[$0-2], new yy.StringNode($$[$0])]; break; -case 37: this.$ = [$$[$0-2], new yy.StringNode($$[$0])]; +case 41: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])]; break; -case 38: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])]; +case 42: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])]; break; -case 39: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])]; +case 43: this.$ = [$$[$0-2], new yy.DataNode($$[$0])]; break; -case 40: this.$ = [$$[$0-2], new yy.DataNode($$[$0])]; +case 44: this.$ = new yy.PartialNameNode($$[$0]); break; -case 41: this.$ = new yy.IdNode($$[$0]); +case 45: this.$ = new yy.IdNode($$[$0]); break; -case 42: $$[$0-2].push($$[$0]); this.$ = $$[$0-2]; +case 46: $$[$0-2].push($$[$0]); this.$ = $$[$0-2]; break; -case 43: this.$ = [$$[$0]]; +case 47: this.$ = [$$[$0]]; break; } }, -table: [{3:1,4:2,5:[2,4],6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{1:[3]},{5:[1,16]},{5:[2,3],7:17,8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,19],20:[2,3],22:[1,13],23:[1,14],24:[1,15]},{5:[2,5],14:[2,5],15:[2,5],16:[2,5],19:[2,5],20:[2,5],22:[2,5],23:[2,5],24:[2,5]},{4:20,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{4:21,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{17:22,21:23,27:[1,24],34:[1,26],36:25},{17:27,21:23,27:[1,24],34:[1,26],36:25},{17:28,21:23,27:[1,24],34:[1,26],36:25},{17:29,21:23,27:[1,24],34:[1,26],36:25},{21:30,34:[1,26],36:25},{1:[2,1]},{6:31,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{5:[2,6],14:[2,6],15:[2,6],16:[2,6],19:[2,6],20:[2,6],22:[2,6],23:[2,6],24:[2,6]},{17:22,18:[1,32],21:23,27:[1,24],34:[1,26],36:25},{10:33,20:[1,34]},{10:35,20:[1,34]},{18:[1,36]},{18:[2,24],21:41,25:37,26:38,27:[1,45],28:39,29:[1,42],30:[1,43],31:[1,44],32:40,33:46,34:[1,47],36:25},{18:[2,25]},{18:[2,41],27:[2,41],29:[2,41],30:[2,41],31:[2,41],34:[2,41],37:[1,48]},{18:[2,43],27:[2,43],29:[2,43],30:[2,43],31:[2,43],34:[2,43],37:[2,43]},{18:[1,49]},{18:[1,50]},{18:[1,51]},{18:[1,52],21:53,34:[1,26],36:25},{5:[2,2],8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,2],22:[1,13],23:[1,14],24:[1,15]},{14:[2,20],15:[2,20],16:[2,20],19:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,7],14:[2,7],15:[2,7],16:[2,7],19:[2,7],20:[2,7],22:[2,7],23:[2,7],24:[2,7]},{21:54,34:[1,26],36:25},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],24:[2,8]},{14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{18:[2,22],21:41,26:55,27:[1,45],28:56,29:[1,42],30:[1,43],31:[1,44],32:40,33:46,34:[1,47],36:25},{18:[2,23]},{18:[2,27],27:[2,27],29:[2,27],30:[2,27],31:[2,27],34:[2,27]},{18:[2,33],33:57,34:[1,58]},{18:[2,28],27:[2,28],29:[2,28],30:[2,28],31:[2,28],34:[2,28]},{18:[2,29],27:[2,29],29:[2,29],30:[2,29],31:[2,29],34:[2,29]},{18:[2,30],27:[2,30],29:[2,30],30:[2,30],31:[2,30],34:[2,30]},{18:[2,31],27:[2,31],29:[2,31],30:[2,31],31:[2,31],34:[2,31]},{18:[2,32],27:[2,32],29:[2,32],30:[2,32],31:[2,32],34:[2,32]},{18:[2,35],34:[2,35]},{18:[2,43],27:[2,43],29:[2,43],30:[2,43],31:[2,43],34:[2,43],35:[1,59],37:[2,43]},{34:[1,60]},{14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],24:[2,13]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],24:[2,16]},{5:[2,17],14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],24:[2,18]},{18:[1,61]},{18:[1,62]},{18:[2,21]},{18:[2,26],27:[2,26],29:[2,26],30:[2,26],31:[2,26],34:[2,26]},{18:[2,34],34:[2,34]},{35:[1,59]},{21:63,27:[1,67],29:[1,64],30:[1,65],31:[1,66],34:[1,26],36:25},{18:[2,42],27:[2,42],29:[2,42],30:[2,42],31:[2,42],34:[2,42],37:[2,42]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],24:[2,19]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],24:[2,15]},{18:[2,36],34:[2,36]},{18:[2,37],34:[2,37]},{18:[2,38],34:[2,38]},{18:[2,39],34:[2,39]},{18:[2,40],34:[2,40]}], -defaultActions: {16:[2,1],24:[2,25],38:[2,23],55:[2,21]}, +table: [{3:1,4:2,5:[2,7],6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],22:[1,14],23:[1,15],24:[1,16]},{1:[3]},{5:[1,17]},{5:[2,6],7:18,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,6],22:[1,14],23:[1,15],24:[1,16]},{5:[2,5],6:20,8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,5],22:[1,14],23:[1,15],24:[1,16]},{17:23,18:[1,22],21:24,28:[1,25],35:[1,27],38:26},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],24:[2,8]},{4:28,6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,7],22:[1,14],23:[1,15],24:[1,16]},{4:29,6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,7],22:[1,14],23:[1,15],24:[1,16]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{5:[2,13],14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],24:[2,13]},{5:[2,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],24:[2,15]},{17:30,21:24,28:[1,25],35:[1,27],38:26},{17:31,21:24,28:[1,25],35:[1,27],38:26},{17:32,21:24,28:[1,25],35:[1,27],38:26},{25:33,37:[1,34]},{1:[2,1]},{5:[2,2],8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,2],22:[1,14],23:[1,15],24:[1,16]},{17:23,21:24,28:[1,25],35:[1,27],38:26},{5:[2,4],7:35,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,4],22:[1,14],23:[1,15],24:[1,16]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,23],14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],24:[2,23]},{18:[1,36]},{18:[2,27],21:41,26:37,27:38,28:[1,45],29:39,30:[1,42],31:[1,43],32:[1,44],33:40,34:46,35:[1,47],38:26},{18:[2,28]},{18:[2,45],28:[2,45],30:[2,45],31:[2,45],32:[2,45],35:[2,45],39:[1,48]},{18:[2,47],28:[2,47],30:[2,47],31:[2,47],32:[2,47],35:[2,47],39:[2,47]},{10:49,20:[1,50]},{10:51,20:[1,50]},{18:[1,52]},{18:[1,53]},{18:[1,54]},{18:[1,55],21:56,35:[1,27],38:26},{18:[2,44],35:[2,44]},{5:[2,3],8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,3],22:[1,14],23:[1,15],24:[1,16]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{18:[2,25],21:41,27:57,28:[1,45],29:58,30:[1,42],31:[1,43],32:[1,44],33:40,34:46,35:[1,47],38:26},{18:[2,26]},{18:[2,30],28:[2,30],30:[2,30],31:[2,30],32:[2,30],35:[2,30]},{18:[2,36],34:59,35:[1,60]},{18:[2,31],28:[2,31],30:[2,31],31:[2,31],32:[2,31],35:[2,31]},{18:[2,32],28:[2,32],30:[2,32],31:[2,32],32:[2,32],35:[2,32]},{18:[2,33],28:[2,33],30:[2,33],31:[2,33],32:[2,33],35:[2,33]},{18:[2,34],28:[2,34],30:[2,34],31:[2,34],32:[2,34],35:[2,34]},{18:[2,35],28:[2,35],30:[2,35],31:[2,35],32:[2,35],35:[2,35]},{18:[2,38],35:[2,38]},{18:[2,47],28:[2,47],30:[2,47],31:[2,47],32:[2,47],35:[2,47],36:[1,61],39:[2,47]},{35:[1,62]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{21:63,35:[1,27],38:26},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],24:[2,16]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],24:[2,19]},{5:[2,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],24:[2,21]},{18:[1,64]},{18:[2,24]},{18:[2,29],28:[2,29],30:[2,29],31:[2,29],32:[2,29],35:[2,29]},{18:[2,37],35:[2,37]},{36:[1,61]},{21:65,28:[1,69],30:[1,66],31:[1,67],32:[1,68],35:[1,27],38:26},{18:[2,46],28:[2,46],30:[2,46],31:[2,46],32:[2,46],35:[2,46],39:[2,46]},{18:[1,70]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],24:[2,22]},{18:[2,39],35:[2,39]},{18:[2,40],35:[2,40]},{18:[2,41],35:[2,41]},{18:[2,42],35:[2,42]},{18:[2,43],35:[2,43]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],24:[2,18]}], +defaultActions: {17:[2,1],25:[2,28],38:[2,26],57:[2,24]}, parseError: function parseError(str, hash) { throw new Error(str); }, @@ -521,7 +548,7 @@ case 2: break; case 3: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15; break; -case 4: return 24; +case 4: this.begin("par"); return 24; break; case 5: return 16; break; @@ -541,13 +568,13 @@ case 12: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return break; case 13: return 22; break; -case 14: return 35; +case 14: return 36; break; -case 15: return 34; +case 15: return 35; break; -case 16: return 34; +case 16: return 35; break; -case 17: return 37; +case 17: return 39; break; case 18: /*ignore whitespace*/ break; @@ -555,55 +582,39 @@ case 19: this.popState(); return 18; break; case 20: this.popState(); return 18; break; -case 21: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 29; +case 21: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30; break; -case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 29; +case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30; break; -case 23: yy_.yytext = yy_.yytext.substr(1); return 27; +case 23: yy_.yytext = yy_.yytext.substr(1); return 28; break; -case 24: return 31; +case 24: return 32; break; -case 25: return 31; +case 25: return 32; break; -case 26: return 30; +case 26: return 31; break; -case 27: return 34; +case 27: return 35; break; -case 28: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 34; +case 28: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35; break; case 29: return 'INVALID'; break; -case 30: return 5; +case 30: /*ignore whitespace*/ +break; +case 31: this.popState(); return 37; +break; +case 32: return 5; break; } }; -lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\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],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"INITIAL":{"rules":[0,1,30],"inclusive":true}}; +lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[} ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-/]+)/,/^(?:$)/]; +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,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"par":{"rules":[30,31],"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; -})(); -if (typeof require !== 'undefined' && typeof exports !== 'undefined') { -exports.parser = handlebars; -exports.Parser = handlebars.Parser; -exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); } -exports.main = function commonjsMain(args) { - if (!args[1]) - throw new Error('Usage: '+args[0]+' FILE'); - var source, cwd; - if (typeof process !== 'undefined') { - source = require('fs').readFileSync(require('path').resolve(args[1]), "utf8"); - } else { - source = require("file").path(require("file").cwd()).join(args[1]).read({charset: "utf-8"}); - } - return exports.parser.parse(source); -} -if (typeof module !== 'undefined' && require.main === module) { - exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); -} -}; -; +})();; // lib/handlebars/compiler/base.js Handlebars.Parser = handlebars; @@ -614,17 +625,7 @@ Handlebars.parse = function(string) { Handlebars.print = function(ast) { return new Handlebars.PrintVisitor().accept(ast); -}; - -Handlebars.logger = { - DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, - - // override in the host environment - log: function(level, str) {} -}; - -Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; -; +};; // lib/handlebars/compiler/ast.js (function() { @@ -658,13 +659,10 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; // pass or at runtime. }; - Handlebars.AST.PartialNode = function(id, context) { - this.type = "partial"; - - // TODO: disallow complex IDs - - this.id = id; - this.context = context; + Handlebars.AST.PartialNode = function(partialName, context) { + this.type = "partial"; + this.partialName = partialName; + this.context = context; }; var verifyMatch = function(open, close) { @@ -716,6 +714,13 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; // 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; + }; + + Handlebars.AST.PartialNameNode = function(name) { + this.type = "PARTIAL_NAME"; + this.name = name; }; Handlebars.AST.DataNode = function(id) { @@ -726,16 +731,19 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; Handlebars.AST.StringNode = function(string) { this.type = "STRING"; this.string = string; + this.stringModeValue = string; }; Handlebars.AST.IntegerNode = function(integer) { this.type = "INTEGER"; this.integer = integer; + this.stringModeValue = Number(integer); }; Handlebars.AST.BooleanNode = function(bool) { this.type = "BOOLEAN"; this.bool = bool; + this.stringModeValue = bool === "true"; }; Handlebars.AST.CommentNode = function(comment) { @@ -745,14 +753,16 @@ Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; })();; // lib/handlebars/utils.js + +var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + Handlebars.Exception = function(message) { var tmp = Error.prototype.constructor.apply(this, arguments); - for (var p in tmp) { - if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; } + // 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]]; } - - this.message = tmp.message; }; Handlebars.Exception.prototype = new Error(); @@ -795,11 +805,7 @@ Handlebars.SafeString.prototype.toString = function() { }, isEmpty: function(value) { - if (typeof value === "undefined") { - return true; - } else if (value === null) { - return true; - } else if (value === false) { + if (!value && value !== 0) { return true; } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) { return true; @@ -938,7 +944,7 @@ Handlebars.JavaScriptCompiler = function() {}; // evaluate it by executing `blockHelperMissing` this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); - this.opcode('pushLiteral', '{}'); + this.opcode('pushHash'); this.opcode('blockValue'); } else { this.ambiguousMustache(mustache, program, inverse); @@ -947,7 +953,7 @@ Handlebars.JavaScriptCompiler = function() {}; // evaluate it by executing `blockHelperMissing` this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); - this.opcode('pushLiteral', '{}'); + this.opcode('pushHash'); this.opcode('ambiguousBlockValue'); } @@ -957,19 +963,24 @@ Handlebars.JavaScriptCompiler = function() {}; hash: function(hash) { var pairs = hash.pairs, pair, val; - this.opcode('push', '{}'); + this.opcode('pushHash'); for(var i=0, l=pairs.length; i - From 361c2f2035de93131d42f27c5d98599e8ea41455 Mon Sep 17 00:00:00 2001 From: Michael Reinsch Date: Sun, 20 Jan 2013 13:17:31 +0900 Subject: [PATCH 4/7] set default_external for ruby 1.9 --- Assetfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Assetfile b/Assetfile index 06cb57c40d5..ebef910692e 100644 --- a/Assetfile +++ b/Assetfile @@ -1,3 +1,5 @@ +Encoding.default_external = "UTF-8" if defined?(Encoding) + require "rake-pipeline-web-filters" require "json" require "uglifier" From 80ed23f665ccb707aea558f6676f7d99d84361cd Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sun, 20 Jan 2013 16:30:08 -0800 Subject: [PATCH 5/7] Abstract clearing observers on willClearRender --- packages/ember-handlebars/lib/ext.js | 18 ++++---------- .../ember-handlebars/lib/helpers/binding.js | 24 ++++--------------- packages/ember-views/lib/views/view.js | 20 ++++++++-------- 3 files changed, 18 insertions(+), 44 deletions(-) diff --git a/packages/ember-handlebars/lib/ext.js b/packages/ember-handlebars/lib/ext.js index 1a261f1143c..f3ec9a5c2eb 100644 --- a/packages/ember-handlebars/lib/ext.js +++ b/packages/ember-handlebars/lib/ext.js @@ -227,21 +227,11 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) { Ember.run.scheduleOnce('render', bindView, 'rerender'); }; - Ember.addObserver(pathRoot, path, observer); - loc = 0; - while(loc < dependentKeys.length) { - Ember.addObserver(pathRoot, path + '.' + dependentKeys[loc], observer); - loc += 1; - } + view.registerObserver(pathRoot, path, observer); - view.one('willClearRender', function() { - Ember.removeObserver(pathRoot, path, observer); - loc = 0; - while(loc < dependentKeys.length) { - Ember.removeObserver(pathRoot, path + '.' + dependentKeys[loc], observer); - loc += 1; - } - }); + for (var i=0, l=dependentKeys.length; i Date: Mon, 21 Jan 2013 16:53:12 +0200 Subject: [PATCH 6/7] fix bug where history location does not account for root URL --- .../lib/location/history_location.js | 15 +++-- packages/ember/tests/routing/basic_test.js | 57 +++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/packages/ember-routing/lib/location/history_location.js b/packages/ember-routing/lib/location/history_location.js index 0db2ccbad95..13f23da4148 100644 --- a/packages/ember-routing/lib/location/history_location.js +++ b/packages/ember-routing/lib/location/history_location.js @@ -44,12 +44,18 @@ Ember.HistoryLocation = Ember.Object.extend({ /** @private - Returns the current `location.pathname`. + Returns the current `location.pathname` without rootURL @method getURL */ getURL: function() { - return get(this, 'location').pathname; + var rootURL = get(this, 'rootURL'), + url = get(this, 'location').pathname; + + rootURL = rootURL.replace(/\/$/, ''); + url = url.replace(rootURL, ''); + + return url; }, /** @@ -132,13 +138,14 @@ Ember.HistoryLocation = Ember.Object.extend({ @param callback {Function} */ onUpdateURL: function(callback) { - var guid = Ember.guidFor(this); + var guid = Ember.guidFor(this), + self = this; Ember.$(window).bind('popstate.ember-location-'+guid, function(e) { if(!popstateReady) { return; } - callback(location.pathname); + callback(self.getURL()); }); }, diff --git a/packages/ember/tests/routing/basic_test.js b/packages/ember/tests/routing/basic_test.js index 2a69222e10d..c22c7fcc9eb 100644 --- a/packages/ember/tests/routing/basic_test.js +++ b/packages/ember/tests/routing/basic_test.js @@ -1266,3 +1266,60 @@ test("Calling controllerFor for a non-route controller returns a controller", fu ok(controller instanceof Ember.ObjectController, "controller was able to be retrieved"); }); + +test("Router accounts for rootURL on page load when using history location", function() { + var rootURL = window.location.pathname + '/app', + postsTemplateRendered = false, + setHistory, + HistoryTestLocation; + + setHistory = function(obj, path) { + obj.set('history', { state: { path: path } }); + }; + + // Create new implementation that extends HistoryLocation + // and set current location to rootURL + '/posts' + HistoryTestLocation = Ember.HistoryLocation.extend({ + initState: function() { + var path = rootURL + '/posts'; + + setHistory(this, path); + this.set('location', { + pathname: path + }); + }, + + replaceState: function(path) { + setHistory(this, path); + }, + + pushState: function(path) { + setHistory(this, path); + } + }); + + Ember.Location.registerImplementation('historyTest', HistoryTestLocation); + + Router.reopen({ + location: 'historyTest', + rootURL: rootURL + }); + + Router.map(function() { + this.resource("posts", { path: '/posts' }); + }); + + App.PostsRoute = Ember.Route.extend({ + model: function() {}, + renderTemplate: function() { + postsTemplateRendered = true; + } + }); + + bootApplication(); + + ok(postsTemplateRendered, "Posts route successfully stripped from rootURL"); + + // clean after test + delete Ember.Location.implementations['historyTest']; +}); \ No newline at end of file From fef43f2b778f8dc222b6eaade653042be76d6f8a Mon Sep 17 00:00:00 2001 From: machty Date: Mon, 21 Jan 2013 12:02:38 -0500 Subject: [PATCH 7/7] load hooks now run hooks defined in ENV refined pre-Ember load hooks --- packages/ember-runtime/lib/system/lazy_load.js | 4 ++-- .../ember-runtime/tests/system/lazy_load_test.js | 13 +++++++++++++ tests/index.html | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/ember-runtime/lib/system/lazy_load.js b/packages/ember-runtime/lib/system/lazy_load.js index e50f8d5ac5c..5eb75409a4e 100644 --- a/packages/ember-runtime/lib/system/lazy_load.js +++ b/packages/ember-runtime/lib/system/lazy_load.js @@ -3,7 +3,7 @@ @submodule ember-runtime */ -var loadHooks = {}; +var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {}; var loaded = {}; /** @@ -30,7 +30,7 @@ Ember.onLoad = function(name, callback) { @param object {Object} object to pass to callbacks */ Ember.runLoadHooks = function(name, object) { - var hooks; + var hooks, i, len; loaded[name] = object; diff --git a/packages/ember-runtime/tests/system/lazy_load_test.js b/packages/ember-runtime/tests/system/lazy_load_test.js index eeae211a61e..45e7b3fc4df 100644 --- a/packages/ember-runtime/tests/system/lazy_load_test.js +++ b/packages/ember-runtime/tests/system/lazy_load_test.js @@ -37,3 +37,16 @@ test("if runLoadHooks was already run, it executes newly added hooks immediately equal(count, 1, "the original object was passed into the load hook"); }); + +test("hooks in ENV.EMBER_LOAD_HOOKS['hookName'] get executed", function() { + + // Note that the necessary code to perform this test is run before + // the Ember lib is loaded in tests/index.html + + Ember.run(function() { + Ember.runLoadHooks("__before_ember_test_hook__", 1); + }); + + equal(window.ENV.__test_hook_count__, 1, "the object was passed into the load hook"); +}); + diff --git a/tests/index.html b/tests/index.html index 1632c823702..86bc4c470cd 100644 --- a/tests/index.html +++ b/tests/index.html @@ -67,6 +67,14 @@ } window.ENV = window.ENV || {}; + // Test for "hooks in ENV.EMBER_LOAD_HOOKS['hookName'] get executed" + ENV.EMBER_LOAD_HOOKS = ENV.EMBER_LOAD_HOOKS || {}; + ENV.EMBER_LOAD_HOOKS.__before_ember_test_hook__ = ENV.EMBER_LOAD_HOOKS.__before_ember_test_hook__ || []; + ENV.__test_hook_count__ = 0; + ENV.EMBER_LOAD_HOOKS.__before_ember_test_hook__.push(function(object) { + ENV.__test_hook_count__ += object; + }); + // Handle extending prototypes QUnit.config.urlConfig.push('extendprototypes');