diff options
-rw-r--r-- | lib/handlebars/base.js | 4 | ||||
-rw-r--r-- | lib/handlebars/compiler/compiler.js | 6 | ||||
-rw-r--r-- | lib/handlebars/compiler/javascript-compiler.js | 8 | ||||
-rw-r--r-- | lib/handlebars/runtime.js | 6 | ||||
-rw-r--r-- | spec/data.js | 35 | ||||
-rw-r--r-- | spec/parser.js | 4 |
6 files changed, 39 insertions, 24 deletions
diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 02d274d..26eb1a8 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -223,5 +223,7 @@ export var logger = { export function log(level, obj) { logger.log(level, obj); } export var createFrame = function(object) { - return Utils.extend({}, object); + var frame = Utils.extend({}, object); + frame._parent = object; + return frame; }; diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 21e1024..be17ac3 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -310,11 +310,7 @@ Compiler.prototype = { DATA: function(data) { this.options.data = true; - if (data.id.isScoped || data.id.depth) { - throw new Exception('Scoped data references are not supported: ' + data.original, data); - } - - this.opcode('lookupData'); + this.opcode('lookupData', data.id.depth); var parts = data.id.parts; for(var i=0, l=parts.length; i<l; i++) { this.opcode('lookup', parts[i]); diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 8781819..769179b 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -403,8 +403,12 @@ JavaScriptCompiler.prototype = { // On stack, after: data, ... // // Push the data lookup operator - lookupData: function() { - this.pushStackLiteral('data'); + lookupData: function(depth) { + if (!depth) { + this.pushStackLiteral('data'); + } else { + this.pushStackLiteral('this.data(data, ' + depth + ')'); + } }, // [pushStringParam] diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index e65db6e..9974c71 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -77,6 +77,12 @@ export function template(templateSpec, env) { } return data; }, + data: function(data, depth) { + while (data && depth--) { + data = data._parent; + } + return data; + }, merge: function(param, common) { var ret = param || common; diff --git a/spec/data.js b/spec/data.js index eab80ef..bb90df5 100644 --- a/spec/data.js +++ b/spec/data.js @@ -85,22 +85,6 @@ describe('data', function() { equals("Hello undefined", result, "@foo as a parameter retrieves template data"); }); - it("parameter data throws when using this scope references", function() { - var string = "{{#goodbyes}}{{text}} cruel {{@./name}}! {{/goodbyes}}"; - - shouldThrow(function() { - CompilerContext.compile(string); - }, Error); - }); - - it("parameter data throws when using parent scope references", function() { - var string = "{{#goodbyes}}{{text}} cruel {{@../name}}! {{/goodbyes}}"; - - shouldThrow(function() { - CompilerContext.compile(string); - }, Error); - }); - it("parameter data throws when using complex scope references", function() { var string = "{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}"; @@ -251,4 +235,23 @@ describe('data', function() { equals('hello', result); }); }); + + describe('nesting', function() { + it('the root context can be looked up via @root', function() { + var template = CompilerContext.compile('{{#helper}}{{#helper}}{{@./depth}} {{@../depth}} {{@../../depth}}{{/helper}}{{/helper}}'); + var result = template({foo: 'hello'}, { + helpers: { + helper: function(options) { + var frame = Handlebars.createFrame(options.data); + frame.depth = options.data.depth + 1; + return options.fn(this, {data: frame}); + } + }, + data: { + depth: 0 + } + }); + equals('2 1 0', result); + }); + }); }); diff --git a/spec/parser.js b/spec/parser.js index 097bb15..ebde171 100644 --- a/spec/parser.js +++ b/spec/parser.js @@ -21,6 +21,10 @@ describe('parser', function() { equals(ast_for("{{@foo}}"), "{{ @ID:foo [] }}\n"); }); + it('parses simple mustaches with data paths', function() { + equals(ast_for("{{@../foo}}"), "{{ @ID:foo [] }}\n"); + }); + it('parses mustaches with paths', function() { equals(ast_for("{{foo/bar}}"), "{{ PATH:foo/bar [] }}\n"); }); |