From 4950beea1c8d20f37cc876a0c73b05cab8e92111 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Wed, 4 Aug 2010 22:18:40 -0400 Subject: [PATCH] Made path parser reusable so that we can use it inside of __get__. --- lib/handlebars.js | 66 +++++++++++++++++++++++++++++----------------- test/handlebars.js | 10 +++++++ 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/lib/handlebars.js b/lib/handlebars.js index a1efa288..b4f3654c 100644 --- a/lib/handlebars.js +++ b/lib/handlebars.js @@ -24,6 +24,40 @@ Handlebars.ParseError = function(message) { this.message = message; } +// Returns a two element array containing the numbers of contexts to back up the stack and +// the properties to dig into on the current context +Handlebars.parsePath = function(path) { + if (path == null) { + return [0, []]; + } + + var parts = path.split("/"); + var readDepth = false; + var depth = 0; + var dig = []; + for (var i = 0; i < parts.length; i++) { + switch(parts[i]) { + case "..": + if (readDepth) { + throw new Handlebars.ParseError("Cannot jump out of context after moving into a context."); + } else { + depth += 1; + } + break; + case ".": + // do nothing - using .'s is pretty dumb, but it's also basically free for us to support + case "this": + // if we do nothing you'll end up sticking in the same context + break; + default: + readDepth = true; + dig.push(parts[i]); + } + } + + return [depth, dig]; +} + Handlebars.helperMissing = function(object, fn) { var ret = ""; @@ -88,37 +122,21 @@ Handlebars.Compiler.prototype = { }, lookupFor: function(param) { - if (!param) { - return "context"; - } + var parsed = Handlebars.parsePath(param); + var depth = parsed[0]; + var parts = parsed[1]; + console.log(depth) - var parts = param.split("/"); - var readDepth = false; - var depth = 0; var paramExpr = ""; - for (var i = 0; i < parts.length; i++) { - switch(parts[i]) { - case "..": - if (readDepth) { - throw new Handlebars.ParseError("Cannot jump out of context after moving into a context."); - } else { - depth += 1; - } - break; - case ".": - // do nothing - using .'s is pretty dumb, but it's also basically free for us to support - case "this": - // if we do nothing you'll end up sticking in the same context - break; - default: - readDepth = true; - paramExpr += "['" + parts[i] + "']"; - } + for(var i = 0; i < parts.length; i++) { + paramExpr += "['" + parts[i] + "']"; } if (depth > 0) { + console.log(depth + ", " + paramExpr); return "( stack[stack.length - " + depth + "]" + paramExpr + ")"; } else { + console.log(paramExpr); return "( context" + paramExpr + " || fallback " + paramExpr + " )"; } }, diff --git a/test/handlebars.js b/test/handlebars.js index 15c231c6..26ad2bbc 100644 --- a/test/handlebars.js +++ b/test/handlebars.js @@ -83,6 +83,16 @@ test("block with complex lookup", function() { "Templates can access variables in contexts up the stack with relative path syntax"); }); +test("helper with complex lookup", function() { + var string = "{{#goodbyes}}{{link}}{{/goodbyes}}" + var hash = {prefix: "/root", goodbyes: [{text: "Goodbye", link: "goodbye"}]}; + var fallback = {link: function() { + return "" + this.text + "" + }}; + shouldCompileTo(string, [hash, fallback], "Goodbye") +}); + + test("block with deep nested complex lookup", function() { var string = "{{#outer}}Goodbye {{#inner}}cruel {{../../omg}}{{/inner}}{{/outer}}"; var hash = {omg: "OMG!", outer: [{ inner: [{ text: "goodbye" }] }] };