├── examples
├── empty_partial.2.html
├── error_not_found.txt
├── i18n.txt
├── two_sections.txt
├── apostrophe.txt
├── double_render.txt
├── empty_sections.txt
├── error_not_found.html
├── array_partial.html
├── empty_partial.txt
├── two_in_a_row.txt
├── unescaped.html
├── apostrophe.html
├── array_of_strings.txt
├── bug_11_eating_whitespace.txt
├── i18n.html
├── inverted_section.txt
├── two_sections.js
├── unescaped.txt
├── array_of_partials_partial.2.html
├── comments.txt
├── i18n.js
├── template_partial.2.html
├── two_in_a_row.html
├── array_of_strings_options.txt
├── bug_11_eating_whitespace.html
├── double_render.html
├── empty_sections.js
├── empty_template.js
├── error_not_found.js
├── partial_recursion.txt
├── unknown_pragma.js
├── array_of_partials_implicit_partial.2.html
├── empty_partial.html
├── empty_sections.html
├── higher_order_sections.txt
├── nesting.txt
├── template_partial.html
├── unknown_pragma.html
├── apostrophe.js
├── empty_partial.js
├── escaped.html
├── escaped.txt
├── template_partial.txt
├── array_of_strings.html
├── higher_order_sections.html
├── two_sections.html
├── empty_template.html
├── inverted_section.js
├── array_of_partials_partial.txt
├── empty_template.txt
├── nesting.html
├── partial_recursion.html
├── comments.html
├── recursion_with_same_names.txt
├── view_partial.html
├── array_of_partials_implicit_partial.txt
├── array_of_strings.js
├── bug_11_eating_whitespace.js
├── partial_recursion.2.html
├── simple.txt
├── array_partial.txt
├── inverted_section.html
├── null_string.txt
├── reuse_of_enumerables.txt
├── two_in_a_row.js
├── array_partial.2.html
├── whitespace_partial.html
├── double_render.js
├── array_of_partials_implicit_partial.js
├── array_of_partials_partial.html
├── array_partial.js
├── unescaped.js
├── array_of_partials_implicit_partial.html
├── array_of_strings_options.js
├── comments.js
├── null_string.html
├── array_of_partials_partial.js
├── nesting.js
├── unknown_pragma.txt
├── delimiters.html
├── escaped.js
├── recursion_with_same_names.html
├── simple.html
├── array_of_strings_options.html
├── reuse_of_enumerables.html
├── reuse_of_enumerables.js
├── view_partial.2.html
├── view_partial.txt
├── whitespace_partial.2.html
├── whitespace_partial.txt
├── template_partial.js
├── delimiters.txt
├── complex.txt
├── simple.js
├── section_as_context.txt
├── null_string.js
├── recursion_with_same_names.js
├── partial_recursion.js
├── section_as_context.html
├── delimiters.js
├── section_as_context.js
├── higher_order_sections.js
├── complex.html
├── view_partial.js
├── whitespace_partial.js
└── complex.js
├── mustache-yui3
├── mustache.js.tpl.pre
└── mustache.js.tpl.post
├── mustache-requirejs
├── requirejs.mustache.js.tpl.post
└── requirejs.mustache.js.tpl.pre
├── .gitignore
├── mustache-dojo
├── mustache.js.tpl.post
└── mustache.js.tpl.pre
├── mustache-commonjs
├── mustache.js.tpl.pre
├── mustache.js.tpl.post
└── package.json
├── mustache-jquery
├── jquery.mustache.js.tpl.post
└── jquery.mustache.js.tpl.pre
├── lib
└── package.json
├── THANKS.md
├── LICENSE
├── CHANGES.md
├── Rakefile
├── test
└── mustache_spec.rb
├── README.md
└── mustache.js
/examples/empty_partial.2.html:
--------------------------------------------------------------------------------
1 | yo
--------------------------------------------------------------------------------
/examples/error_not_found.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/i18n.txt:
--------------------------------------------------------------------------------
1 | foo BAR
2 |
--------------------------------------------------------------------------------
/examples/two_sections.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/apostrophe.txt:
--------------------------------------------------------------------------------
1 | 'X
2 |
--------------------------------------------------------------------------------
/examples/double_render.txt:
--------------------------------------------------------------------------------
1 | {{win}}
2 |
--------------------------------------------------------------------------------
/examples/empty_sections.txt:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/examples/error_not_found.html:
--------------------------------------------------------------------------------
1 | {{foo}}
--------------------------------------------------------------------------------
/examples/array_partial.html:
--------------------------------------------------------------------------------
1 | {{>partial}}
--------------------------------------------------------------------------------
/examples/empty_partial.txt:
--------------------------------------------------------------------------------
1 | hey 1
2 | yo
3 |
--------------------------------------------------------------------------------
/examples/two_in_a_row.txt:
--------------------------------------------------------------------------------
1 | Welcome, Joe!
2 |
--------------------------------------------------------------------------------
/examples/unescaped.html:
--------------------------------------------------------------------------------
1 |
{{{title}}}
--------------------------------------------------------------------------------
/examples/apostrophe.html:
--------------------------------------------------------------------------------
1 | {{apos}}{{control}}
2 |
--------------------------------------------------------------------------------
/examples/array_of_strings.txt:
--------------------------------------------------------------------------------
1 | hello world
2 |
--------------------------------------------------------------------------------
/examples/bug_11_eating_whitespace.txt:
--------------------------------------------------------------------------------
1 | yo foo
2 |
--------------------------------------------------------------------------------
/examples/i18n.html:
--------------------------------------------------------------------------------
1 | {{_i}}foo {{bar}}{{/i}}
2 |
--------------------------------------------------------------------------------
/examples/inverted_section.txt:
--------------------------------------------------------------------------------
1 | No repos :(
2 |
--------------------------------------------------------------------------------
/examples/two_sections.js:
--------------------------------------------------------------------------------
1 | var two_sections = {};
--------------------------------------------------------------------------------
/examples/unescaped.txt:
--------------------------------------------------------------------------------
1 | Bear > Shark
2 |
--------------------------------------------------------------------------------
/examples/array_of_partials_partial.2.html:
--------------------------------------------------------------------------------
1 | {{i}}
2 |
--------------------------------------------------------------------------------
/examples/comments.txt:
--------------------------------------------------------------------------------
1 | A Comedy of Errors
2 |
--------------------------------------------------------------------------------
/examples/i18n.js:
--------------------------------------------------------------------------------
1 | var i18n = {
2 | bar: "BAR"
3 | };
--------------------------------------------------------------------------------
/examples/template_partial.2.html:
--------------------------------------------------------------------------------
1 | Again, {{again}}!
--------------------------------------------------------------------------------
/examples/two_in_a_row.html:
--------------------------------------------------------------------------------
1 | {{greeting}}, {{name}}!
--------------------------------------------------------------------------------
/examples/array_of_strings_options.txt:
--------------------------------------------------------------------------------
1 | hello world
2 |
--------------------------------------------------------------------------------
/examples/bug_11_eating_whitespace.html:
--------------------------------------------------------------------------------
1 | {{tag}} foo
2 |
--------------------------------------------------------------------------------
/examples/double_render.html:
--------------------------------------------------------------------------------
1 | {{#foo}}{{bar}}{{/foo}}
2 |
--------------------------------------------------------------------------------
/examples/empty_sections.js:
--------------------------------------------------------------------------------
1 | var empty_sections = {};
2 |
--------------------------------------------------------------------------------
/examples/empty_template.js:
--------------------------------------------------------------------------------
1 | var empty_template = {};
2 |
--------------------------------------------------------------------------------
/examples/error_not_found.js:
--------------------------------------------------------------------------------
1 | var error_not_found = {bar: 2};
--------------------------------------------------------------------------------
/examples/partial_recursion.txt:
--------------------------------------------------------------------------------
1 | 1
2 | 1.1
3 | 1.1.1
4 |
--------------------------------------------------------------------------------
/examples/unknown_pragma.js:
--------------------------------------------------------------------------------
1 | var unknown_pragma = {};
2 |
--------------------------------------------------------------------------------
/examples/array_of_partials_implicit_partial.2.html:
--------------------------------------------------------------------------------
1 | {{.}}
2 |
--------------------------------------------------------------------------------
/examples/empty_partial.html:
--------------------------------------------------------------------------------
1 | hey {{foo}}
2 | {{>partial}}
3 |
--------------------------------------------------------------------------------
/examples/empty_sections.html:
--------------------------------------------------------------------------------
1 | {{#foo}}{{/foo}}foo{{#bar}}{{/bar}}
2 |
--------------------------------------------------------------------------------
/examples/higher_order_sections.txt:
--------------------------------------------------------------------------------
1 | Hi Tater. To tinker?
2 |
--------------------------------------------------------------------------------
/examples/nesting.txt:
--------------------------------------------------------------------------------
1 | 1
2 | 2
3 | 3
4 |
5 |
--------------------------------------------------------------------------------
/examples/template_partial.html:
--------------------------------------------------------------------------------
1 | {{title}}
2 | {{>partial}}
--------------------------------------------------------------------------------
/examples/unknown_pragma.html:
--------------------------------------------------------------------------------
1 | {{%I-HAVE-THE-GREATEST-MUSTACHE}}
2 |
--------------------------------------------------------------------------------
/examples/apostrophe.js:
--------------------------------------------------------------------------------
1 | var apostrophe = {'apos': "'", 'control':'X'};
2 |
--------------------------------------------------------------------------------
/examples/empty_partial.js:
--------------------------------------------------------------------------------
1 | var partial_context = {
2 | foo: 1
3 | };
4 |
--------------------------------------------------------------------------------
/examples/escaped.html:
--------------------------------------------------------------------------------
1 | {{title}}
2 | But not {{entities}}.
3 |
--------------------------------------------------------------------------------
/examples/escaped.txt:
--------------------------------------------------------------------------------
1 | Bear > Shark
2 | But not ".
3 |
--------------------------------------------------------------------------------
/examples/template_partial.txt:
--------------------------------------------------------------------------------
1 | Welcome
2 | Again, Goodbye!
3 |
--------------------------------------------------------------------------------
/mustache-yui3/mustache.js.tpl.pre:
--------------------------------------------------------------------------------
1 | YUI.add("mustache", function(Y) {
2 |
--------------------------------------------------------------------------------
/examples/array_of_strings.html:
--------------------------------------------------------------------------------
1 | {{#array_of_strings}}{{.}} {{/array_of_strings}}
--------------------------------------------------------------------------------
/examples/higher_order_sections.html:
--------------------------------------------------------------------------------
1 | {{#bolder}}Hi {{name}}.{{/bolder}}
2 |
--------------------------------------------------------------------------------
/examples/two_sections.html:
--------------------------------------------------------------------------------
1 | {{#foo}}
2 | {{/foo}}
3 | {{#bar}}
4 | {{/bar}}
5 |
--------------------------------------------------------------------------------
/mustache-requirejs/requirejs.mustache.js.tpl.post:
--------------------------------------------------------------------------------
1 |
2 | return Mustache;
3 | });
--------------------------------------------------------------------------------
/examples/empty_template.html:
--------------------------------------------------------------------------------
1 | Test
--------------------------------------------------------------------------------
/examples/inverted_section.js:
--------------------------------------------------------------------------------
1 | var inverted_section = {
2 | "repo": []
3 | }
4 |
--------------------------------------------------------------------------------
/examples/array_of_partials_partial.txt:
--------------------------------------------------------------------------------
1 | Here is some stuff!
2 | 1
3 | 2
4 | 3
5 | 4
6 |
--------------------------------------------------------------------------------
/examples/empty_template.txt:
--------------------------------------------------------------------------------
1 | Test
2 |
--------------------------------------------------------------------------------
/examples/nesting.html:
--------------------------------------------------------------------------------
1 | {{#foo}}
2 | {{#a}}
3 | {{b}}
4 | {{/a}}
5 | {{/foo}}
6 |
--------------------------------------------------------------------------------
/examples/partial_recursion.html:
--------------------------------------------------------------------------------
1 | {{name}}
2 | {{#kids}}
3 | {{>partial}}
4 | {{/kids}}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | runner.js
2 | jquery.mustache.js
3 | dojox
4 | yui3
5 | commonjs.mustache.js
6 |
--------------------------------------------------------------------------------
/examples/comments.html:
--------------------------------------------------------------------------------
1 | {{title}}{{! just something interesting... or not... }}
2 |
--------------------------------------------------------------------------------
/examples/recursion_with_same_names.txt:
--------------------------------------------------------------------------------
1 | name
2 | desc
3 | t1
4 | 0
5 | t2
6 | 1
7 |
--------------------------------------------------------------------------------
/examples/view_partial.html:
--------------------------------------------------------------------------------
1 | {{greeting}}
2 | {{>partial}}
3 | {{farewell}}
--------------------------------------------------------------------------------
/examples/array_of_partials_implicit_partial.txt:
--------------------------------------------------------------------------------
1 | Here is some stuff!
2 | 1
3 | 2
4 | 3
5 | 4
6 |
--------------------------------------------------------------------------------
/examples/array_of_strings.js:
--------------------------------------------------------------------------------
1 | var array_of_strings = {array_of_strings: ['hello', 'world']};
2 |
--------------------------------------------------------------------------------
/examples/bug_11_eating_whitespace.js:
--------------------------------------------------------------------------------
1 | var bug_11_eating_whitespace = {
2 | tag: "yo"
3 | };
4 |
--------------------------------------------------------------------------------
/examples/partial_recursion.2.html:
--------------------------------------------------------------------------------
1 | {{name}}
2 | {{#children}}
3 | {{>partial}}
4 | {{/children}}
--------------------------------------------------------------------------------
/examples/simple.txt:
--------------------------------------------------------------------------------
1 | Hello Chris
2 | You have just won $10000!
3 | Well, $6000, after taxes.
4 |
--------------------------------------------------------------------------------
/mustache-yui3/mustache.js.tpl.post:
--------------------------------------------------------------------------------
1 |
2 | Y.mustache = Mustache.to_html;
3 |
4 | }, "0");
5 |
--------------------------------------------------------------------------------
/examples/array_partial.txt:
--------------------------------------------------------------------------------
1 | Here's a non-sense array of values
2 | 1
3 | 2
4 | 3
5 | 4
6 |
7 |
--------------------------------------------------------------------------------
/examples/inverted_section.html:
--------------------------------------------------------------------------------
1 | {{#repo}}{{name}}{{/repo}}
2 | {{^repo}}No repos :({{/repo}}
3 |
--------------------------------------------------------------------------------
/examples/null_string.txt:
--------------------------------------------------------------------------------
1 | Hello Elise
2 | glytch true
3 | binary false
4 | value
5 | numeric NaN
6 |
--------------------------------------------------------------------------------
/examples/reuse_of_enumerables.txt:
--------------------------------------------------------------------------------
1 | t1
2 | 0
3 | t2
4 | 1
5 | t1
6 | 0
7 | t2
8 | 1
9 |
--------------------------------------------------------------------------------
/examples/two_in_a_row.js:
--------------------------------------------------------------------------------
1 | var two_in_a_row = {
2 | name: "Joe",
3 | greeting: "Welcome"
4 | };
5 |
--------------------------------------------------------------------------------
/examples/array_partial.2.html:
--------------------------------------------------------------------------------
1 | Here's a non-sense array of values
2 | {{#array}}
3 | {{.}}
4 | {{/array}}
--------------------------------------------------------------------------------
/examples/whitespace_partial.html:
--------------------------------------------------------------------------------
1 | {{ greeting }}
2 | {{> partial }}
3 | {{ farewell }}
--------------------------------------------------------------------------------
/mustache-dojo/mustache.js.tpl.post:
--------------------------------------------------------------------------------
1 |
2 | dojox.mustache = dojo.hitch(Mustache, "to_html");
3 |
4 | })();
--------------------------------------------------------------------------------
/examples/double_render.js:
--------------------------------------------------------------------------------
1 | var double_render = {
2 | foo: true,
3 | bar: "{{win}}",
4 | win: "FAIL"
5 | };
--------------------------------------------------------------------------------
/examples/array_of_partials_implicit_partial.js:
--------------------------------------------------------------------------------
1 | var partial_context = {
2 | numbers: ['1', '2', '3', '4']
3 | };
4 |
--------------------------------------------------------------------------------
/examples/array_of_partials_partial.html:
--------------------------------------------------------------------------------
1 | Here is some stuff!
2 | {{#numbers}}
3 | {{>partial}}
4 | {{/numbers}}
5 |
--------------------------------------------------------------------------------
/examples/array_partial.js:
--------------------------------------------------------------------------------
1 | var partial_context = {
2 | partial: {
3 | array: ['1', '2', '3', '4']
4 | }
5 | };
--------------------------------------------------------------------------------
/examples/unescaped.js:
--------------------------------------------------------------------------------
1 | var unescaped = {
2 | title: function() {
3 | return "Bear > Shark";
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/examples/array_of_partials_implicit_partial.html:
--------------------------------------------------------------------------------
1 | Here is some stuff!
2 | {{#numbers}}
3 | {{>partial}}
4 | {{/numbers}}
5 |
--------------------------------------------------------------------------------
/examples/array_of_strings_options.js:
--------------------------------------------------------------------------------
1 | var array_of_strings_options = {array_of_strings_options: ['hello', 'world']};
2 |
--------------------------------------------------------------------------------
/examples/comments.js:
--------------------------------------------------------------------------------
1 | var comments = {
2 | title: function() {
3 | return "A Comedy of Errors";
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/examples/null_string.html:
--------------------------------------------------------------------------------
1 | Hello {{name}}
2 | glytch {{glytch}}
3 | binary {{binary}}
4 | value {{value}}
5 | numeric {{numeric}}
--------------------------------------------------------------------------------
/examples/array_of_partials_partial.js:
--------------------------------------------------------------------------------
1 | var partial_context = {
2 | numbers: [{i: '1'}, {i: '2'}, {i: '3'}, {i: '4'}]
3 | };
4 |
--------------------------------------------------------------------------------
/examples/nesting.js:
--------------------------------------------------------------------------------
1 | var nesting = {
2 | foo: [
3 | {a: {b: 1}},
4 | {a: {b: 2}},
5 | {a: {b: 3}}
6 | ]
7 | };
8 |
--------------------------------------------------------------------------------
/examples/unknown_pragma.txt:
--------------------------------------------------------------------------------
1 | ERROR: This implementation of mustache doesn't understand the 'I-HAVE-THE-GREATEST-MUSTACHE' pragma
2 |
--------------------------------------------------------------------------------
/examples/delimiters.html:
--------------------------------------------------------------------------------
1 | {{=<% %>=}}*
2 | <% first %>
3 | * <% second %>
4 | <%=| |=%>
5 | * | third |
6 | |={{ }}=|
7 | * {{ fourth }}
--------------------------------------------------------------------------------
/examples/escaped.js:
--------------------------------------------------------------------------------
1 | var escaped = {
2 | title: function() {
3 | return "Bear > Shark";
4 | },
5 | entities: """
6 | };
7 |
--------------------------------------------------------------------------------
/examples/recursion_with_same_names.html:
--------------------------------------------------------------------------------
1 | {{ name }}
2 | {{ description }}
3 |
4 | {{#terms}}
5 | {{name}}
6 | {{index}}
7 | {{/terms}}
8 |
--------------------------------------------------------------------------------
/examples/simple.html:
--------------------------------------------------------------------------------
1 | Hello {{name}}
2 | You have just won ${{value}}!
3 | {{#in_ca}}
4 | Well, ${{ taxed_value }}, after taxes.
5 | {{/in_ca}}
--------------------------------------------------------------------------------
/examples/array_of_strings_options.html:
--------------------------------------------------------------------------------
1 | {{%IMPLICIT-ITERATOR iterator=rob}}
2 | {{#array_of_strings_options}}{{rob}} {{/array_of_strings_options}}
--------------------------------------------------------------------------------
/examples/reuse_of_enumerables.html:
--------------------------------------------------------------------------------
1 | {{#terms}}
2 | {{name}}
3 | {{index}}
4 | {{/terms}}
5 | {{#terms}}
6 | {{name}}
7 | {{index}}
8 | {{/terms}}
9 |
--------------------------------------------------------------------------------
/examples/reuse_of_enumerables.js:
--------------------------------------------------------------------------------
1 | var reuse_of_enumerables = {
2 | terms: [
3 | {name: 't1', index: 0},
4 | {name: 't2', index: 1},
5 | ]
6 | };
--------------------------------------------------------------------------------
/examples/view_partial.2.html:
--------------------------------------------------------------------------------
1 | Hello {{name}}
2 | You have just won ${{value}}!
3 | {{#in_ca}}
4 | Well, ${{ taxed_value }}, after taxes.
5 | {{/in_ca}}
6 |
--------------------------------------------------------------------------------
/examples/view_partial.txt:
--------------------------------------------------------------------------------
1 | Welcome
2 | Hello Chris
3 | You have just won $10000!
4 | Well, $6000, after taxes.
5 |
6 | Fair enough, right?
7 |
--------------------------------------------------------------------------------
/examples/whitespace_partial.2.html:
--------------------------------------------------------------------------------
1 | Hello {{ name}}
2 | You have just won ${{value }}!
3 | {{# in_ca }}
4 | Well, ${{ taxed_value }}, after taxes.
5 | {{/ in_ca }}
6 |
--------------------------------------------------------------------------------
/examples/whitespace_partial.txt:
--------------------------------------------------------------------------------
1 | Welcome
2 | Hello Chris
3 | You have just won $10000!
4 | Well, $6000, after taxes.
5 |
6 | Fair enough, right?
7 |
--------------------------------------------------------------------------------
/examples/template_partial.js:
--------------------------------------------------------------------------------
1 | var partial_context = {
2 | title: function() {
3 | return "Welcome";
4 | },
5 | partial: {
6 | again: "Goodbye"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/mustache-commonjs/mustache.js.tpl.pre:
--------------------------------------------------------------------------------
1 | /*
2 | * CommonJS-compatible mustache.js module
3 | *
4 | * See http://github.com/janl/mustache.js for more info.
5 | */
6 |
7 |
--------------------------------------------------------------------------------
/examples/delimiters.txt:
--------------------------------------------------------------------------------
1 | *
2 | It worked the first time.
3 | * And it worked the second time.
4 | * Then, surprisingly, it worked the third time.
5 | * Fourth time also fine!.
6 |
--------------------------------------------------------------------------------
/examples/complex.txt:
--------------------------------------------------------------------------------
1 | Colors
2 |
7 |
--------------------------------------------------------------------------------
/examples/simple.js:
--------------------------------------------------------------------------------
1 | var simple = {
2 | name: "Chris",
3 | value: 10000,
4 | taxed_value: function() {
5 | return this.value - (this.value * 0.4);
6 | },
7 | in_ca: true
8 | };
9 |
--------------------------------------------------------------------------------
/mustache-jquery/jquery.mustache.js.tpl.post:
--------------------------------------------------------------------------------
1 |
2 | $.mustache = function(template, view, partials) {
3 | return Mustache.to_html(template, view, partials);
4 | };
5 |
6 | })(jQuery);
7 |
--------------------------------------------------------------------------------
/examples/section_as_context.txt:
--------------------------------------------------------------------------------
1 | this is an object
2 | one of its attributes is a list
3 |
4 | - listitem1
5 | - listitem2
6 |
7 |
--------------------------------------------------------------------------------
/mustache-requirejs/requirejs.mustache.js.tpl.pre:
--------------------------------------------------------------------------------
1 | /*
2 | Shameless port of a shameless port ^ 2
3 | @defunkt => @janl => @aq => @voodootikigod => @timruffles
4 |
5 | */
6 | define(function(){
7 |
--------------------------------------------------------------------------------
/examples/null_string.js:
--------------------------------------------------------------------------------
1 | var null_string = {
2 | name: "Elise",
3 | glytch: true,
4 | binary: false,
5 | value: null,
6 | numeric: function() {
7 | return NaN;
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/examples/recursion_with_same_names.js:
--------------------------------------------------------------------------------
1 | var recursion_with_same_names = {
2 | name: 'name',
3 | description: 'desc',
4 | terms: [
5 | {name: 't1', index: 0},
6 | {name: 't2', index: 1},
7 | ]
8 | };
--------------------------------------------------------------------------------
/mustache-commonjs/mustache.js.tpl.post:
--------------------------------------------------------------------------------
1 |
2 | exports.name = Mustache.name;
3 | exports.version = Mustache.version;
4 |
5 | exports.to_html = function() {
6 | return Mustache.to_html.apply(this, arguments);
7 | };
8 |
--------------------------------------------------------------------------------
/examples/partial_recursion.js:
--------------------------------------------------------------------------------
1 | var partial_context = {
2 | name: '1',
3 | kids: [
4 | {
5 | name: '1.1',
6 | children: [
7 | {name: '1.1.1'}
8 | ]
9 | }
10 | ]
11 | };
12 |
--------------------------------------------------------------------------------
/examples/section_as_context.html:
--------------------------------------------------------------------------------
1 | {{#a_object}}
2 | {{title}}
3 | {{description}}
4 |
5 | {{#a_list}}
6 | - {{label}}
7 | {{/a_list}}
8 |
9 | {{/a_object}}
10 |
--------------------------------------------------------------------------------
/mustache-jquery/jquery.mustache.js.tpl.pre:
--------------------------------------------------------------------------------
1 | /*
2 | Shameless port of a shameless port
3 | @defunkt => @janl => @aq
4 |
5 | See http://github.com/defunkt/mustache for more info.
6 | */
7 |
8 | ;(function($) {
9 |
10 |
--------------------------------------------------------------------------------
/examples/delimiters.js:
--------------------------------------------------------------------------------
1 | var delimiters = {
2 | first: "It worked the first time.",
3 | second: "And it worked the second time.",
4 | third: "Then, surprisingly, it worked the third time.",
5 | fourth: "Fourth time also fine!."
6 | }
7 |
--------------------------------------------------------------------------------
/examples/section_as_context.js:
--------------------------------------------------------------------------------
1 | var section_as_context = {
2 | a_object: {
3 | title: 'this is an object',
4 | description: 'one of its attributes is a list',
5 | a_list: [{label: 'listitem1'}, {label: 'listitem2'}]
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/mustache-commonjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mustache",
3 | "author": "http://mustache.github.com/",
4 | "description": "{{ mustache }} in JavaScript — Logic-less templates.",
5 | "keywords": ["template"],
6 | "version": "{{version}}"
7 | }
8 |
--------------------------------------------------------------------------------
/examples/higher_order_sections.js:
--------------------------------------------------------------------------------
1 | var higher_order_sections = {
2 | "name": "Tater",
3 | "helper": "To tinker?",
4 | "bolder": function() {
5 | return function(text, render) {
6 | return "" + render(text) + ' ' + this.helper;
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/mustache-dojo/mustache.js.tpl.pre:
--------------------------------------------------------------------------------
1 | /*
2 | Shameless port of a shameless port
3 | @defunkt => @janl => @aq => @voodootikigod
4 |
5 | See http://github.com/defunkt/mustache for more info.
6 | */
7 |
8 | dojo.provide("dojox.mustache._base");
9 | (function(){
10 |
--------------------------------------------------------------------------------
/lib/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mustache",
3 | "author": "http://mustache.github.com/",
4 | "description": "{{ mustache }} in JavaScript — Logic-less templates.",
5 | "keywords": ["template"],
6 | "version": "0.3.1-dev-twitter",
7 | "main": "./mustache"
8 | }
9 |
--------------------------------------------------------------------------------
/examples/complex.html:
--------------------------------------------------------------------------------
1 | {{header}}
2 | {{#list}}
3 |
4 | {{#item}}
5 | {{#current}}
6 | - {{name}}
7 | {{/current}}
8 | {{#link}}
9 | - {{name}}
10 | {{/link}}
11 | {{/item}}
12 |
13 | {{/list}}
14 | {{#empty}}
15 | The list is empty.
16 | {{/empty}}
--------------------------------------------------------------------------------
/examples/view_partial.js:
--------------------------------------------------------------------------------
1 | var partial_context = {
2 | greeting: function() {
3 | return "Welcome";
4 | },
5 |
6 | farewell: function() {
7 | return "Fair enough, right?";
8 | },
9 |
10 | partial: {
11 | name: "Chris",
12 | value: 10000,
13 | taxed_value: function() {
14 | return this.value - (this.value * 0.4);
15 | },
16 | in_ca: true
17 | }
18 | };
19 |
20 |
--------------------------------------------------------------------------------
/examples/whitespace_partial.js:
--------------------------------------------------------------------------------
1 | var partial_context = {
2 | greeting: function() {
3 | return "Welcome";
4 | },
5 |
6 | farewell: function() {
7 | return "Fair enough, right?";
8 | },
9 |
10 | partial: {
11 | name: "Chris",
12 | value: 10000,
13 | taxed_value: function() {
14 | return this.value - (this.value * 0.4);
15 | },
16 | in_ca: true
17 | }
18 | };
19 |
20 |
--------------------------------------------------------------------------------
/examples/complex.js:
--------------------------------------------------------------------------------
1 | var complex = {
2 | header: function() {
3 | return "Colors";
4 | },
5 | item: [
6 | {name: "red", current: true, url: "#Red"},
7 | {name: "green", current: false, url: "#Green"},
8 | {name: "blue", current: false, url: "#Blue"}
9 | ],
10 | link: function() {
11 | return this["current"] !== true;
12 | },
13 | list: function() {
14 | return this.item.length !== 0;
15 | },
16 | empty: function() {
17 | return this.item.length === 0;
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/THANKS.md:
--------------------------------------------------------------------------------
1 | # Thanks
2 |
3 | Mustache.js wouldn't kick ass if it weren't for these fine souls:
4 |
5 | * Chris Wanstrath / defunkt
6 | * Alexander Lang / langalex
7 | * Sebastian Cohnen / tisba
8 | * J Chris Anderson / jchris
9 | * Tom Robinson / tlrobinson
10 | * Aaron Quint / quirkey
11 | * Douglas Crockford
12 | * Nikita Vasilyev / NV
13 | * Elise Wood / glytch
14 | * Damien Mathieu / dmathieu
15 | * Jakub Kuźma / qoobaa
16 | * Will Leinweber / will
17 | * dpree
18 | * Jason Smith / jhs
19 | * Aaron Gibralter / agibralter
20 | * Ross Boucher / boucher
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009 Chris Wanstrath (Ruby)
2 | Copyright (c) 2010 Jan Lehnardt (JavaScript)
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | # mustache.js Changes
2 |
3 | ## 0.3.1 (??-??-????)
4 |
5 | ## 0.3.0 (21-07-2010)
6 |
7 | * Improved whitespace handling.
8 | * Make IMPLICIT ITERATORS a first class feature.
9 | * Fix Rhino compat.
10 | * CommonJS packaging is no longer a special case.
11 | * DRY Rakefile.
12 | * Allow whitespace around tag names.
13 | * Fix partial scope.
14 | * Fix Comments.
15 | * Added inverted sections.
16 | * Avoid double encoding of entities.
17 | * Use sections to dereference subcontexts.
18 | * Added higher order sections.
19 |
20 |
21 | ## 0.2.3 (28-03-2010)
22 |
23 | * Better error message for missing partials.
24 | * Added more robust type detection.
25 | * Parse pragmas only once.
26 | * Throw exception when encountering an unknown pragma.
27 | * Ignore undefined partial contexts. Returns verbatim partials.
28 | * Added yui3 packaging.
29 |
30 |
31 | ## 0.2.2 (11-02-2010)
32 |
33 | * ctemplate compat: Partials are indicated by >, not <.
34 | * Add support for {{%PRAGMA}} to enable features.
35 | * Made array of strings an option. Enable with `{{%JSTACHE-ENABLE-STRING-ARRAYS}}`.
36 | * mustache compat: Don't barf on unknown variables.
37 | * Add `rake dojo` target to create a dojo package.
38 | * Add streaming api.
39 | * Rename JSTACHE-ENABLE-STRING-ARRAYS to IMPLICIT-ITERATOR.
40 | * Add support for pragma options.
41 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rake'
2 | require 'spec/rake/spectask'
3 |
4 | task :default => :spec
5 |
6 | Spec::Rake::SpecTask.new(:spec) do |t|
7 | #t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
8 | t.spec_files = FileList['test/*_spec.rb']
9 | end
10 |
11 | desc "Run all specs"
12 | task :spec
13 |
14 | def templated_build(name, opts={})
15 | # Create a rule that uses the .tmpl.{pre,post} stuff to make a final,
16 | # wrapped, output file.
17 | # There is some extra complexity because Dojo and YUI3 use different
18 | # template files and final locations.
19 | short = name.downcase
20 | source = "mustache-#{short}"
21 | dependencies = ["mustache.js"] + Dir.glob("#{source}/*.tpl.*")
22 |
23 | desc "Package for #{name}"
24 | task short.to_sym => dependencies do
25 | target_js = opts[:location] ? "mustache.js" : "#{short}.mustache.js"
26 |
27 | puts "Packaging for #{name}"
28 | sh "mkdir -p #{opts[:location]}" if opts[:location]
29 | sh "cat #{source}/#{target_js}.tpl.pre mustache.js \
30 | #{source}/#{target_js}.tpl.post > #{opts[:location] || '.'}/#{target_js}"
31 |
32 | # extra
33 | if opts[:extra]
34 | sh "sed -e 's/{{version}}/#{version}/' #{source}/#{opts[:extra]} \
35 | > #{opts[:location]}/#{opts[:extra]}"
36 | end
37 |
38 | puts "Done, see #{opts[:location] || '.'}/#{target_js}"
39 |
40 | end
41 | end
42 |
43 | templated_build "CommonJS", :location => "lib", :extra => "package.json"
44 | templated_build "jQuery"
45 | templated_build "Dojo", :location => "dojox/string"
46 | templated_build "YUI3", :location => "yui3/mustache"
47 | templated_build "requirejs"
48 |
49 |
50 | def version
51 | File.read("mustache.js").match('version: "([^\"]+)",$')[1]
52 | end
53 |
54 |
55 | desc "Remove temporary files."
56 | task :clean do
57 | sh "git clean -fdx"
58 | end
59 |
--------------------------------------------------------------------------------
/test/mustache_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'json'
3 |
4 | __DIR__ = File.dirname(__FILE__)
5 |
6 | testnames = Dir.glob(__DIR__ + '/../examples/*.js').map do |name|
7 | File.basename name, '.js'
8 | end
9 |
10 | non_partials = testnames.select{|t| not t.include? "partial"}
11 | partials = testnames.select{|t| t.include? "partial"}
12 |
13 | def load_test(dir, name, partial=false)
14 | view = File.read(dir + "/../examples/#{name}.js")
15 | template = File.read(dir + "/../examples/#{name}.html").to_json
16 | expect = File.read(dir + "/../examples/#{name}.txt")
17 | if not partial
18 | [view, template, expect]
19 | else
20 | partial = File.read(dir + "/../examples/#{name}.2.html").to_json
21 | [view, template, partial, expect]
22 | end
23 | end
24 |
25 | describe "mustache" do
26 |
27 | shared_examples_for "Mustache rendering" do
28 |
29 | before(:all) do
30 | mustache = File.read(__DIR__ + "/../mustache.js")
31 | stubbed_gettext = <<-JS
32 | // Stubbed gettext translation method for {{_i}}{{/i}} tags in Mustache.
33 | function _(text) {
34 | return text;
35 | }
36 | JS
37 |
38 | @boilerplate = <<-JS
39 | #{mustache}
40 | #{stubbed_gettext}
41 | JS
42 | end
43 |
44 | it "should return the same when invoked multiple times" do
45 | js = <<-JS
46 | #{@boilerplate}
47 | Mustache.to_html("x")
48 | print(Mustache.to_html("x"));
49 | JS
50 | run_js(@run_js, js).should == "x\n"
51 |
52 | end
53 |
54 | it "should clear the context after each run" do
55 | js = <<-JS
56 | #{@boilerplate}
57 | Mustache.to_html("{{#list}}{{x}}{{/list}}", {list: [{x: 1}]})
58 | try {
59 | print(Mustache.to_html("{{#list}}{{x}}{{/list}}", {list: [{}]}));
60 | } catch(e) {
61 | print('ERROR: ' + e.message);
62 | }
63 | JS
64 | run_js(@run_js, js).should == "\n"
65 | end
66 |
67 | non_partials.each do |testname|
68 | describe testname do
69 | it "should generate the correct html" do
70 |
71 | view, template, expect = load_test(__DIR__, testname)
72 |
73 | runner = <<-JS
74 | try {
75 | #{@boilerplate}
76 | #{view}
77 | var template = #{template};
78 | var result = Mustache.to_html(template, #{testname});
79 | print(result);
80 | } catch(e) {
81 | print('ERROR: ' + e.message);
82 | }
83 | JS
84 |
85 | run_js(@run_js, runner).should == expect
86 | end
87 | it "should sendFun the correct html" do
88 |
89 | view, template, expect = load_test(__DIR__, testname)
90 |
91 | runner = <<-JS
92 | try {
93 | #{@boilerplate}
94 | #{view}
95 | var chunks = [];
96 | var sendFun = function(chunk) {
97 | if (chunk != "") {
98 | chunks.push(chunk);
99 | }
100 | }
101 | var template = #{template};
102 | Mustache.to_html(template, #{testname}, null, sendFun);
103 | print(chunks.join("\\n"));
104 | } catch(e) {
105 | print('ERROR: ' + e.message);
106 | }
107 | JS
108 |
109 | run_js(@run_js, runner).strip.should == expect.strip
110 | end
111 | end
112 | end
113 |
114 | partials.each do |testname|
115 | describe testname do
116 | it "should generate the correct html" do
117 |
118 | view, template, partial, expect =
119 | load_test(__DIR__, testname, true)
120 |
121 | runner = <<-JS
122 | try {
123 | #{@boilerplate}
124 | #{view}
125 | var template = #{template};
126 | var partials = {"partial": #{partial}};
127 | var result = Mustache.to_html(template, partial_context, partials);
128 | print(result);
129 | } catch(e) {
130 | print('ERROR: ' + e.message);
131 | }
132 | JS
133 |
134 | run_js(@run_js, runner).should == expect
135 | end
136 | it "should sendFun the correct html" do
137 |
138 | view, template, partial, expect =
139 | load_test(__DIR__, testname, true)
140 |
141 | runner = <<-JS
142 | try {
143 | #{@boilerplate}
144 | #{view};
145 | var template = #{template};
146 | var partials = {"partial": #{partial}};
147 | var chunks = [];
148 | var sendFun = function(chunk) {
149 | if (chunk != "") {
150 | chunks.push(chunk);
151 | }
152 | }
153 | Mustache.to_html(template, partial_context, partials, sendFun);
154 | print(chunks.join("\\n"));
155 | } catch(e) {
156 | print('ERROR: ' + e.message);
157 | }
158 | JS
159 |
160 | run_js(@run_js, runner).strip.should == expect.strip
161 | end
162 | end
163 | end
164 | end
165 |
166 | context "running in JavaScriptCore (WebKit, Safari)" do
167 | before(:each) do
168 | @run_js = :run_js_jsc
169 | end
170 | it_should_behave_like "Mustache rendering"
171 | end
172 |
173 | context "running in Rhino (Mozilla)" do
174 | before(:each) do
175 | @run_js = :run_js_rhino
176 | end
177 |
178 | it_should_behave_like "Mustache rendering"
179 | end
180 |
181 | def run_js(runner, js)
182 | send(runner, js)
183 | # run_js_rhino(js)
184 | # js_jsc = run_js_jsc(js)
185 | # js_rhino = run_js_rhino(js)
186 | # return js_jsc unless js_jsc != js_rhino
187 | end
188 |
189 | def run_js_jsc(js)
190 | File.open("runner.js", 'w') {|f| f << js}
191 | `jsc runner.js`
192 | end
193 |
194 | def run_js_rhino(js)
195 | File.open("runner.js", 'w') {|f| f << js}
196 | `java org.mozilla.javascript.tools.shell.Main runner.js`
197 | end
198 | end
199 |
200 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mustache.js — Logic-less templates with JavaScript
2 |
3 | > What could be more logical awesome than no logic at all?
4 |
5 | For a list of implementations (other than JavaScript) and editor
6 | plugins, see .
7 |
8 |
9 | ## Where to Use?
10 |
11 | You can use mustache.js rendering stuff in various scenarios. E.g. you can
12 | render templates in your browser, or rendering server-side stuff with
13 | [node.js][node.js], use it for rendering stuff in [CouchDB][couchdb]’s views.
14 |
15 |
16 | ## Who Uses Mustache?
17 |
18 | An updated list is kept on the Github wiki. Add yourself, if you use
19 | mustache.js:
20 |
21 |
22 | ## Usage
23 |
24 | A quick example how to use mustache.js:
25 |
26 | var view = {
27 | title: "Joe",
28 | calc: function() {
29 | return 2 + 4;
30 | }
31 | }
32 |
33 | var template = "{{title}} spends {{calc}}";
34 |
35 | var html = Mustache.to_html(template, view);
36 |
37 | `template` is a simple string with mustache tags and `view` is a JavaScript
38 | object containing the data and any code to render the template.
39 |
40 |
41 | ## Template Tag Types
42 |
43 | There are several types of tags currently implemented in mustache.js.
44 |
45 | For a language-agnostic overview of Mustache’s template syntax, see the
46 | `mustache(5)` manpage or .
47 |
48 | ### Simple Tags
49 |
50 | Tags are always surrounded by mustaches like this `{{foobar}}`.
51 |
52 | var view = {name: "Joe", say_hello: function(){ return "hello" }}
53 |
54 | template = "{{say_hello}}, {{name}}"
55 |
56 |
57 | ### Conditional Sections
58 |
59 | Conditional sections begin with `{{#condition}}` and end with
60 | `{{/condition}}`. When `condition` evaluates to true, the section is rendered,
61 | otherwise the whole block will output nothing at all. `condition` may be a
62 | function returning true/false or a simple boolean.
63 |
64 | var view = {condition: function() {
65 | // [...your code goes here...]
66 | return true;
67 | }}
68 |
69 | {{#condition}}
70 | I will be visible if condition is true
71 | {{/condition}}
72 |
73 |
74 | ### Enumerable Sections
75 |
76 | Enumerable Sections use the same syntax as condition sections do.
77 | `{{#shopping_items}}` and `{{/shopping_items}}`. Actually the view decides how
78 | mustache.js renders the section. If the view returns an array, it will
79 | iterator over the items. Use `{{.}}` to access the current item inside the
80 | enumeration section.
81 |
82 | var view = {name: "Joe's shopping card",
83 | items: ["bananas", "apples"]}
84 |
85 | var template = "{{name}}: {{#items}}- {{.}}
{{/items}}
"
86 |
87 | Outputs:
88 | Joe's shopping card:
89 |
90 |
91 | ### Higher Order Sections
92 |
93 | If a section key returns a function, it will be called and passed both the
94 | unrendered block of text and a renderer convenience function.
95 |
96 | Given this JS:
97 |
98 | "name": "Tater",
99 | "bolder": function() {
100 | return function(text, render) {
101 | return "" + render(text) + ''
102 | }
103 | }
104 |
105 | And this template:
106 |
107 | {{#bolder}}Hi {{name}}.{{/bolder}}
108 |
109 | We'll get this output:
110 |
111 | Hi Tater.
112 |
113 | As you can see, we’re pre-processing the text in the block. This can be used
114 | to implement caching, filters (like syntax highlighting), etc.
115 |
116 | You can use `this.name` to access the attribute `name` from your view.
117 |
118 | ### Dereferencing Section
119 |
120 | If you have a nested object structure in your view, it can sometimes be easier
121 | to use sections like this:
122 |
123 | var objects = {
124 | a_object: {
125 | title: 'this is an object',
126 | description: 'one of its attributes is a list',
127 | a_list: [{label: 'listitem1'}, {label: 'listitem2'}]
128 | }
129 | };
130 |
131 | This is our template:
132 |
133 | {{#a_object}}
134 | {{title}}
135 | {{description}}
136 |
137 | {{#a_list}}
138 | - {{label}}
139 | {{/a_list}}
140 |
141 | {{/a_object}}
142 |
143 | Here is the result:
144 |
145 | this is an object
146 | one of its attributes is a list
147 |
148 | - listitem1
149 | - listitem2
150 |
151 |
152 | ### Inverted Sections
153 |
154 | An inverted section opens with `{{^section}}` instead of `{{#section}}` and
155 | uses a boolean negative to evaluate. Empty arrays are considered falsy.
156 |
157 | View:
158 |
159 | var inverted_section = {
160 | "repo": []
161 | }
162 |
163 | Template:
164 |
165 | {{#repo}}{{name}}{{/repo}}
166 | {{^repo}}No repos :({{/repo}}
167 |
168 | Result:
169 |
170 | No repos :(
171 |
172 |
173 | ### View Partials
174 |
175 | mustache.js supports a quite powerful but yet simple view partial mechanism.
176 | Use the following syntax for partials: `{{>partial_name}}`
177 |
178 | var view = {
179 | name: "Joe",
180 | winnings: {
181 | value: 1000,
182 | taxed_value: function() {
183 | return this.value - (this.value * 0.4);
184 | }
185 | }
186 | };
187 |
188 | var template = "Welcome, {{name}}! {{>winnings}}"
189 | var partials = {
190 | winnings: "You just won ${{value}} (which is ${{taxed_value}} after tax)"};
191 |
192 | var output = Mustache.to_html(template, view, partials)
193 |
194 | output will be:
195 | Welcome, Joe! You just won $1000 (which is $600 after tax)
196 |
197 | You invoke a partial with `{{>winnings}}`. Invoking the partial `winnings`
198 | will tell mustache.js to look for a object in the context's property
199 | `winnings`. It will then use that object as the context for the template found
200 | in `partials` for `winnings`.
201 |
202 | ## Internationalization
203 |
204 | mustache.js supports i18n using the `{{_i}}{{/i}}` tags. When mustache.js encounters
205 | an internationalized section, it will call out to the standard global gettext function `_()` with the tag contents for a
206 | translation _before_ any rendering is done. For example:
207 |
208 | var template = "{{_i}}{{name}} is using mustache.js!{{/i}}"
209 |
210 | var view = {
211 | name: "Matt"
212 | };
213 |
214 | var translationTable = {
215 | // Welsh, according to Google Translate
216 | "{{name}} is using mustache.js!": "Mae {{name}} yn defnyddio mustache.js!"
217 | };
218 |
219 | function _(text) {
220 | return translationTable[text] || text;
221 | }
222 |
223 | alert(Mustache.to_html(template, view));
224 | // alerts "Mae Matt yn defnyddio mustache.js!"
225 |
226 | ## Escaping
227 |
228 | mustache.js does escape all values when using the standard double mustache
229 | syntax. Characters which will be escaped: `& \ " ' < >`. To disable escaping,
230 | simply use triple mustaches like `{{{unescaped_variable}}}`.
231 |
232 | Example: Using `{{variable}}` inside a template for `5 > 2` will result in `5 > 2`, where as the usage of `{{{variable}}}` will result in `5 > 2`.
233 |
234 |
235 | ## Streaming
236 |
237 | To stream template results out of mustache.js, you can pass an optional
238 | `send()` callback to the `to_html()` call:
239 |
240 | Mustache.to_html(template, view, partials, function(line) {
241 | print(line);
242 | });
243 |
244 |
245 | ## Pragmas
246 |
247 | Pragma tags let you alter the behaviour of mustache.js. They have the format
248 | of
249 |
250 | {{%PRAGMANAME}}
251 |
252 | and they accept options:
253 |
254 | {{%PRAGMANAME option=value}}
255 |
256 |
257 | ### IMPLICIT-ITERATOR
258 |
259 | When using a block to iterate over an enumerable (Array), mustache.js expects
260 | an objects as enumerable items. The implicit iterator pragma enables optional
261 | behaviour of allowing literals as enumerable items. Consider this view:
262 |
263 | var view = {
264 | foo: [1, 2, 3, 4, 5, "french"]
265 | };
266 |
267 | The following template can iterate over the member `foo`:
268 |
269 | {{%IMPLICIT-ITERATOR}}
270 | {{#foo}}
271 | {{.}}
272 | {{/foo}}
273 |
274 | If you don't like the dot in there, the pragma accepts an option to set your
275 | own iteration marker:
276 |
277 | {{%IMPLICIT-ITERATOR iterator=bob}}
278 | {{#foo}}
279 | {{bob}}
280 | {{/foo}}
281 |
282 | ## F.A.Q.
283 |
284 | ### Why doesn’t Mustache allow dot notation like `{{variable.member}}`?
285 |
286 | The reason is given in the [mustache.rb
287 | bugtracker](http://github.com/defunkt/mustache/issues/issue/6).
288 |
289 | Mustache implementations strive to be template-compatible.
290 |
291 |
292 | ## More Examples and Documentation
293 |
294 | See `examples/` for more goodies and read the [original mustache docs][m]
295 |
296 | ## Command Line
297 |
298 | See `mustache(1)` man page or
299 |
300 | for command line docs.
301 |
302 | Or just install it as a RubyGem:
303 |
304 | $ gem install mustache
305 | $ mustache -h
306 |
307 | [m]: http://github.com/defunkt/mustache/#readme
308 | [node.js]: http://nodejs.org
309 | [couchdb]: http://couchdb.apache.org
310 |
311 |
312 | ## Plugins for jQuery, Dojo, Yui, CommonJS
313 |
314 | This repository lets you build modules for [jQuery][], [Dojo][], [Yui][] and
315 | [CommonJS][] / [Node.js][] with the help of `rake`:
316 |
317 | Run `rake jquery` to get a jQuery compatible plugin file in the
318 | `mustache-jquery/` directory.
319 |
320 | Run `rake dojo` to get a Dojo compatible plugin file in the `mustache-dojo/`
321 | directory.
322 |
323 | Run `rake yui` to get a Yui compatible plugin file in the `mustache-yui/`
324 | directory.
325 |
326 | Run `rake commonjs` to get a CommonJS compatible plugin file in the
327 | `mustache-commonjs/` directory which you can also use with [Node.js][].
328 |
329 | [jQuery]: http://jquery.com/
330 | [Dojo]: http://www.dojotoolkit.org/
331 | [Yui]: http://developer.yahoo.com/yui/
332 | [CommonJS]: http://www.commonjs.org/
333 | [Node.js]: http://nodejs.org/
334 |
--------------------------------------------------------------------------------
/mustache.js:
--------------------------------------------------------------------------------
1 | /*
2 | mustache.js — Logic-less templates in JavaScript
3 |
4 | See http://mustache.github.com/ for more info.
5 | */
6 |
7 | var Mustache = function() {
8 | var Renderer = function() {};
9 |
10 | Renderer.prototype = {
11 | otag: "{{",
12 | ctag: "}}",
13 | pragmas: {},
14 | buffer: [],
15 | pragmas_implemented: {
16 | "IMPLICIT-ITERATOR": true,
17 | "TRANSLATION-HINT": true
18 | },
19 | context: {},
20 |
21 | render: function(template, context, partials, in_recursion) {
22 | // reset buffer & set context
23 | if(!in_recursion) {
24 | this.context = context;
25 | this.buffer = []; // TODO: make this non-lazy
26 | }
27 |
28 | // fail fast
29 | if(!this.includes("", template)) {
30 | if(in_recursion) {
31 | return template;
32 | } else {
33 | this.send(template);
34 | return;
35 | }
36 | }
37 |
38 | // Branching or moving down the partial stack, save any translation mode info.
39 | if (this.pragmas['TRANSLATION-HINT']) {
40 | context['_mode'] = this.pragmas['TRANSLATION-HINT']['mode'];
41 | }
42 |
43 | template = this.render_pragmas(template);
44 |
45 | template = this.render_i18n(template, context, partials);
46 |
47 | var html = this.render_section(template, context, partials);
48 |
49 | if (html === template) {
50 | if (in_recursion) {
51 | return this.render_tags(html, context, partials, true);
52 | }
53 |
54 | this.render_tags(html, context, partials, false);
55 | } else {
56 | if(in_recursion) {
57 | return html;
58 | } else {
59 | var lines = html.split("\n");
60 | for (var i = 0; i < lines.length; i++) {
61 | this.send(lines[i]);
62 | }
63 | return;
64 | }
65 | }
66 | },
67 |
68 | /*
69 | Sends parsed lines
70 | */
71 | send: function(line) {
72 | if(line != "") {
73 | this.buffer.push(line);
74 | }
75 | },
76 |
77 | /*
78 | Looks for %PRAGMAS
79 | */
80 | render_pragmas: function(template) {
81 | // no pragmas
82 | if(!this.includes("%", template)) {
83 | return template;
84 | }
85 |
86 | var that = this;
87 | var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
88 | this.ctag);
89 | return template.replace(regex, function(match, pragma, options) {
90 | if(!that.pragmas_implemented[pragma]) {
91 | throw({message:
92 | "This implementation of mustache doesn't understand the '" +
93 | pragma + "' pragma"});
94 | }
95 | that.pragmas[pragma] = {};
96 | if(options) {
97 | var opts = options.split("=");
98 | that.pragmas[pragma][opts[0]] = opts[1];
99 | }
100 | return "";
101 | // ignore unknown pragmas silently
102 | });
103 | },
104 |
105 | /*
106 | Tries to find a partial in the curent scope and render it
107 | */
108 | render_partial: function(name, context, partials) {
109 | name = this.trim(name);
110 | if(!partials || partials[name] === undefined) {
111 | throw({message: "unknown_partial '" + name + "'"});
112 | }
113 | if(typeof(context[name]) != "object") {
114 | return this.render(partials[name], context, partials, true);
115 | }
116 | return this.render(partials[name], context[name], partials, true);
117 | },
118 |
119 | render_i18n: function(html, context, partials) {
120 | if (html.indexOf(this.otag + "_i") == -1) {
121 | return html;
122 | }
123 | var that = this;
124 | var regex = new RegExp(this.otag + "\\_i" + this.ctag +
125 | "\\s*([\\s\\S]+?)" + this.otag + "\\/i" + this.ctag, "mg");
126 |
127 | // for each {{_i}}{{/i}} section do...
128 | return html.replace(regex, function(match, content) {
129 | var translation_mode = undefined;
130 | if (that.pragmas && that.pragmas["TRANSLATION-HINT"] && that.pragmas["TRANSLATION-HINT"]['mode']) {
131 | translation_mode = { _mode: that.pragmas["TRANSLATION-HINT"]['mode'] };
132 | } else if (context['_mode']) {
133 | translation_mode = { _mode: context['_mode'] };
134 | }
135 |
136 | return that.render(_(content, translation_mode), context, partials, true);
137 | });
138 | },
139 |
140 | /*
141 | Renders inverted (^) and normal (#) sections
142 | */
143 | render_section: function(template, context, partials) {
144 | if(!this.includes("#", template) && !this.includes("^", template)) {
145 | return template;
146 | }
147 |
148 | var that = this;
149 |
150 | // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
151 | var regex = new RegExp(
152 | "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1)
153 |
154 | this.otag + // {{
155 | "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3)
156 | this.ctag + // }}
157 |
158 | "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped
159 |
160 | this.otag + // {{
161 | "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag).
162 | this.ctag + // }}
163 |
164 | "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped.
165 |
166 | "g");
167 |
168 | // for each {{#foo}}{{/foo}} section do...
169 | return template.replace(regex, function(match, before, type, name, content, after) {
170 | // before contains only tags, no sections
171 | var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",
172 |
173 | // after may contain both sections and tags, so use full rendering function
174 | renderedAfter = after ? that.render(after, context, partials, true) : "";
175 |
176 | var value = that.find(name, context);
177 | if(type == "^") { // inverted section
178 | if(!value || that.is_array(value) && value.length === 0) {
179 | // false or empty list, render it
180 | return renderedBefore + that.render(content, context, partials, true) + renderedAfter;
181 | } else {
182 | return renderedBefore + "" + renderedAfter;
183 | }
184 | } else if(type == "#") { // normal section
185 | if(that.is_array(value)) { // Enumerable, Let's loop!
186 | return renderedBefore + that.map(value, function(row) {
187 | return that.render(content, that.create_context(row), partials, true);
188 | }).join("") + renderedAfter;
189 | } else if(that.is_object(value)) { // Object, Use it as subcontext!
190 | return renderedBefore + that.render(content, that.create_context(value),
191 | partials, true) + renderedAfter;
192 | } else if(typeof value === "function") {
193 | // higher order section
194 | return renderedBefore + value.call(context, content, function(text) {
195 | return that.render(text, context, partials, true);
196 | }) + renderedAfter;
197 | } else if(value) { // boolean section
198 | return renderedBefore + that.render(content, context, partials, true) + renderedAfter;
199 | } else {
200 | return renderedBefore + "" + renderedAfter;
201 | }
202 | }
203 | });
204 | },
205 |
206 | /*
207 | Replace {{foo}} and friends with values from our view
208 | */
209 | render_tags: function(template, context, partials, in_recursion) {
210 | // tit for tat
211 | var that = this;
212 |
213 | var new_regex = function() {
214 | return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
215 | that.ctag + "+", "g");
216 | };
217 |
218 | var regex = new_regex();
219 | var tag_replace_callback = function(match, operator, name) {
220 | switch(operator) {
221 | case "!": // ignore comments
222 | return "";
223 | case "=": // set new delimiters, rebuild the replace regexp
224 | that.set_delimiters(name);
225 | regex = new_regex();
226 | return "";
227 | case ">": // render partial
228 | return that.render_partial(name, context, partials);
229 | case "{": // the triple mustache is unescaped
230 | return that.find(name, context);
231 | default: // escape the value
232 | return that.escape(that.find(name, context));
233 | }
234 | };
235 | var lines = template.split("\n");
236 | for(var i = 0; i < lines.length; i++) {
237 | lines[i] = lines[i].replace(regex, tag_replace_callback, this);
238 | if(!in_recursion) {
239 | this.send(lines[i]);
240 | }
241 | }
242 |
243 | if(in_recursion) {
244 | return lines.join("\n");
245 | }
246 | },
247 |
248 | set_delimiters: function(delimiters) {
249 | var dels = delimiters.split(" ");
250 | this.otag = this.escape_regex(dels[0]);
251 | this.ctag = this.escape_regex(dels[1]);
252 | },
253 |
254 | escape_regex: function(text) {
255 | // thank you Simon Willison
256 | if(!arguments.callee.sRE) {
257 | var specials = [
258 | '/', '.', '*', '+', '?', '|',
259 | '(', ')', '[', ']', '{', '}', '\\'
260 | ];
261 | arguments.callee.sRE = new RegExp(
262 | '(\\' + specials.join('|\\') + ')', 'g'
263 | );
264 | }
265 | return text.replace(arguments.callee.sRE, '\\$1');
266 | },
267 |
268 | /*
269 | find `name` in current `context`. That is find me a value
270 | from the view object
271 | */
272 | find: function(name, context) {
273 | name = this.trim(name);
274 |
275 | // Checks whether a value is thruthy or false or 0
276 | function is_kinda_truthy(bool) {
277 | return bool === false || bool === 0 || bool;
278 | }
279 |
280 | var value;
281 | if(is_kinda_truthy(context[name])) {
282 | value = context[name];
283 | } else if(is_kinda_truthy(this.context[name])) {
284 | value = this.context[name];
285 | }
286 |
287 | if(typeof value === "function") {
288 | return value.apply(context);
289 | }
290 | if(value !== undefined) {
291 | return value;
292 | }
293 | // silently ignore unkown variables
294 | return "";
295 | },
296 |
297 | // Utility methods
298 |
299 | /* includes tag */
300 | includes: function(needle, haystack) {
301 | return haystack.indexOf(this.otag + needle) != -1;
302 | },
303 |
304 | /*
305 | Does away with nasty characters
306 | */
307 | escape: function(s) {
308 | s = String(s === null ? "" : s);
309 | return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
310 | switch(s) {
311 | case "&": return "&";
312 | case "\\": return "\\\\";
313 | case '"': return '"';
314 | case "'": return ''';
315 | case "<": return "<";
316 | case ">": return ">";
317 | default: return s;
318 | }
319 | });
320 | },
321 |
322 | // by @langalex, support for arrays of strings
323 | create_context: function(_context) {
324 | if(this.is_object(_context)) {
325 | return _context;
326 | } else {
327 | var iterator = ".";
328 | if(this.pragmas["IMPLICIT-ITERATOR"]) {
329 | iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
330 | }
331 | var ctx = {};
332 | ctx[iterator] = _context;
333 | return ctx;
334 | }
335 | },
336 |
337 | is_object: function(a) {
338 | return a && typeof a == "object";
339 | },
340 |
341 | is_array: function(a) {
342 | return Object.prototype.toString.call(a) === '[object Array]';
343 | },
344 |
345 | /*
346 | Gets rid of leading and trailing whitespace
347 | */
348 | trim: function(s) {
349 | return s.replace(/^\s*|\s*$/g, "");
350 | },
351 |
352 | /*
353 | Why, why, why? Because IE. Cry, cry cry.
354 | */
355 | map: function(array, fn) {
356 | if (typeof array.map == "function") {
357 | return array.map(fn);
358 | } else {
359 | var r = [];
360 | var l = array.length;
361 | for(var i = 0; i < l; i++) {
362 | r.push(fn(array[i]));
363 | }
364 | return r;
365 | }
366 | }
367 | };
368 |
369 | return({
370 | name: "mustache.js",
371 | version: "0.3.1-dev-twitter",
372 |
373 | /*
374 | Turns a template and view into HTML
375 | */
376 | to_html: function(template, view, partials, send_fun) {
377 | var renderer = new Renderer();
378 | if(send_fun) {
379 | renderer.send = send_fun;
380 | }
381 | renderer.render(template, view || {}, partials);
382 | if(!send_fun) {
383 | return renderer.buffer.join("\n");
384 | }
385 | }
386 | });
387 | }();
388 |
--------------------------------------------------------------------------------