diff --git a/README.md b/README.md index b7fa878..bae0205 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,12 @@ Tags are always surrounded by mustaches like this `{{foobar}}`. template = "{{say_hello}}, {{name}}" +### Dotted Tags +Tags can also be nested to address object and array members in the context. + + var view = {name: {first: "Chris", last: "Anderson"}, values: [1, 2]}; + template = "{{name.last}}, {{name.first}} {{values.0}}"; + ### Conditional Sections Conditional sections begin with `{{#condition}}` and end with `{{/condition}}`. When `condition` evaluates to true, the section is rendered, otherwise the hole block will output nothing at all. `condition` may be a function returning true/false or a simple boolean. diff --git a/examples/nested.html b/examples/nested.html new file mode 100644 index 0000000..c8144c8 --- /dev/null +++ b/examples/nested.html @@ -0,0 +1,3 @@ +Yay {{person.name}}! +Array style {{value.0}} {{value.1}} +And {{more.nested.1.values}}! diff --git a/examples/nested.js b/examples/nested.js new file mode 100644 index 0000000..dd95086 --- /dev/null +++ b/examples/nested.js @@ -0,0 +1,10 @@ +var nested = { + person: { + name: "Chris" + }, + ohyeah: "awesome!", + value: ["is", function() {return this.ohyeah;}], + more: { + nested: [29, {values: "kbai"}] + } +}; diff --git a/examples/nested.txt b/examples/nested.txt new file mode 100644 index 0000000..bd1b510 --- /dev/null +++ b/examples/nested.txt @@ -0,0 +1,4 @@ +Yay Chris! +Array style is awesome! +And kbai! + diff --git a/examples/nested_array_bounds.html b/examples/nested_array_bounds.html new file mode 100644 index 0000000..abab7de --- /dev/null +++ b/examples/nested_array_bounds.html @@ -0,0 +1 @@ +Out of bounds! {{foo.5}} diff --git a/examples/nested_array_bounds.js b/examples/nested_array_bounds.js new file mode 100644 index 0000000..f02e7b8 --- /dev/null +++ b/examples/nested_array_bounds.js @@ -0,0 +1,3 @@ +var nested_array_bounds = { + foo: [1, 2] +}; diff --git a/examples/nested_array_bounds.txt b/examples/nested_array_bounds.txt new file mode 100644 index 0000000..7c865e7 --- /dev/null +++ b/examples/nested_array_bounds.txt @@ -0,0 +1 @@ +ERROR: 'foo.5' not found in context diff --git a/examples/nested_error.html b/examples/nested_error.html new file mode 100644 index 0000000..b774f36 --- /dev/null +++ b/examples/nested_error.html @@ -0,0 +1 @@ +This doesn't exist: {{foo.bar}} diff --git a/examples/nested_error.js b/examples/nested_error.js new file mode 100644 index 0000000..6f6403f --- /dev/null +++ b/examples/nested_error.js @@ -0,0 +1 @@ +var nested_error = {not_foo: {not_bar: "yay error!"}}; diff --git a/examples/nested_error.txt b/examples/nested_error.txt new file mode 100644 index 0000000..d85c393 --- /dev/null +++ b/examples/nested_error.txt @@ -0,0 +1 @@ +ERROR: 'foo.bar' not found in context diff --git a/mustache.js b/mustache.js index fbbb715..44dc394 100644 --- a/mustache.js +++ b/mustache.js @@ -130,11 +130,12 @@ var Mustache = function() { */ find: function(name, context) { name = this.trim(name); - if(typeof context[name] === "function") { - return context[name].apply(context); + var value = this.getValue(context, name); + if(typeof value === "function") { + return value.apply(context); } - if(context[name] !== undefined) { - return context[name]; + if(value !== undefined) { + return value; } throw({message: "'" + name + "' not found in context"}); }, @@ -157,6 +158,22 @@ var Mustache = function() { }); }, + getValue: function(context, name) { + if(name == "." && context[name] != undefined) { + return context[name]; + } + var ctx = context; + var parts = name.split("."); + while(parts.length) { + p = parts.shift(); + if(ctx[p] === undefined) { + throw({message: "'" + name + "' not found in context"}); + } + ctx = ctx[p]; + } + return ctx + }, + /* Merges all properties of object `b` into object `a`. `b.property` overwrites a.property`