6056 |
efrain |
1 |
/*global QUnit*/
|
|
|
2 |
(function(undefined) {
|
|
|
3 |
"use strict";
|
|
|
4 |
|
|
|
5 |
var global = (0, eval)('this'), // jshint ignore:line
|
|
|
6 |
|
|
|
7 |
isBrowser = !!global.document,
|
|
|
8 |
|
|
|
9 |
$ = global.jsrender || global.jQuery; // On Node.js with QUnit, jsrender is added as namespace, to global
|
|
|
10 |
|
|
|
11 |
if (!isBrowser) {
|
|
|
12 |
global.document = {};
|
|
|
13 |
}
|
|
|
14 |
|
|
|
15 |
function compileTmpl(template) {
|
|
|
16 |
try {
|
|
|
17 |
return typeof $.templates(template).fn === "function" ? "compiled" : "failed compile";
|
|
|
18 |
} catch(e) {
|
|
|
19 |
return e.message;
|
|
|
20 |
}
|
|
|
21 |
}
|
|
|
22 |
|
|
|
23 |
function sort(array) {
|
|
|
24 |
var ret = "";
|
|
|
25 |
if (this.tagCtx.props.reverse) {
|
|
|
26 |
// Render in reverse order
|
|
|
27 |
if (arguments.length > 1) {
|
|
|
28 |
for (i = arguments.length; i; i--) {
|
|
|
29 |
ret += sort.call(this, arguments[ i - 1 ]);
|
|
|
30 |
}
|
|
|
31 |
} else {
|
|
|
32 |
for (var i = array.length; i; i--) {
|
|
|
33 |
ret += this.tagCtx.render(array[ i - 1 ]);
|
|
|
34 |
}
|
|
|
35 |
}
|
|
|
36 |
} else {
|
|
|
37 |
// Render in original order
|
|
|
38 |
ret += this.tmpl.render(array);
|
|
|
39 |
}
|
|
|
40 |
return ret;
|
|
|
41 |
}
|
|
|
42 |
|
|
|
43 |
var person = {name: "Jo"},
|
|
|
44 |
people = [{name: "Jo"}, {name: "Bill"}],
|
|
|
45 |
towns = [{name: "Seattle"}, {name: "Paris"}, {name: "Delhi"}];
|
|
|
46 |
|
|
|
47 |
var tmplString = "A_{{:name}}_B";
|
|
|
48 |
$.views.tags({sort: sort});
|
|
|
49 |
|
|
|
50 |
QUnit.module("tagParser");
|
|
|
51 |
QUnit.test("{{if}} {{else}}", function(assert) {
|
|
|
52 |
assert.equal(compileTmpl("A_{{if true}}{{/if}}_B"), "compiled", "Empty if block: {{if}}{{/if}}");
|
|
|
53 |
assert.equal(compileTmpl("A_{{if true}}yes{{/if}}_B"), "compiled", "{{if}}...{{/if}}");
|
|
|
54 |
assert.equal(compileTmpl("A_{{if true/}}yes{{/if}}_B"), "Syntax error\nUnmatched or missing {{/if}}, in template:\nA_{{if true/}}yes{{/if}}_B", "unmatched or missing tag error");
|
|
|
55 |
assert.equal($.templates("<span id='x'></span> a'b\"c\\").render(), "<span id=\'x\'></span> a\'b\"c\\", "Correct escaping of quotes and backslash");
|
|
|
56 |
});
|
|
|
57 |
|
|
|
58 |
QUnit.test("syntax errors", function(assert) {
|
|
|
59 |
assert.equal(compileTmpl("{^{*:foo}}"), "Syntax error\n{^{*:foo}}", "Syntax error for {^{* ...}}");
|
|
|
60 |
assert.equal(compileTmpl("{{:foo/}}"), "Syntax error\n{{:foo/}}", "Syntax error for {{: ... /}}");
|
|
|
61 |
assert.equal(compileTmpl("{{:foo:}}"), "Syntax error\n{{:foo:}}", "Syntax error for {{: ... :}}");
|
|
|
62 |
assert.equal(compileTmpl("{^{:foo:}}"), "Syntax error\n{^{:foo:}}", "Syntax error for {^{: ... :}}");
|
|
|
63 |
assert.equal(compileTmpl("{{mytag foo :}}"), "Syntax error\n{{mytag foo :}}", "Syntax error for {{mytag ... :}}");
|
|
|
64 |
assert.equal(compileTmpl("{^{mytag foo :}}"), "Syntax error\n{^{mytag foo :}}", "Syntax error for {^{mytag ... :}}");
|
|
|
65 |
assert.equal(compileTmpl("{{if foo?bar:baz}}{{/if}}"), "compiled", "No syntax error for {{tag foo?bar:baz}}");
|
|
|
66 |
assert.equal(compileTmpl("{{for [1,2]/}}"), "Syntax error\n[1,2]", "Syntax error for {{for [1,2]}} - top-level array");
|
|
|
67 |
assert.equal(compileTmpl("{{:constructor()}}"), "Syntax error\nconstructor", "Syntax error for {{: ...constructor ...}}");
|
|
|
68 |
assert.equal(compileTmpl("{{for #tmpl.constructor()}}"), "Syntax error\n#tmpl.constructor", "Syntax error for {{for ...constructor ...}}");
|
|
|
69 |
|
|
|
70 |
$.views.settings.debugMode(true);
|
|
|
71 |
assert.equal($.templates('{{:#data["constructor"]["constructor"]("alert(0);")()}}').render(), "{Error: Syntax error\n}", 'Syntax error 1 for ["constructor]"');
|
|
|
72 |
assert.equal($.templates('{{:valueOf["constructor"]("alert(1);")()}}').render(1), "{Error: Syntax error\n}", 'Syntax error 2 for ["constructor]"');
|
|
|
73 |
assert.equal($.templates('{{:valueOf["const"+"ructor"]("alert(2);")()}}').render(1), "{Error: Syntax error\n}", 'Syntax error 3 for ["constructor]"');
|
|
|
74 |
assert.equal($.templates('{{if true ~c=toString["con" + foo + "or"]}}{{:convert=~c("alert(3);")}}{{/if}}').render({foo: "struct"}), "{Error: Syntax error\n}", 'Syntax error 1 for indirect ["constructor]"');
|
|
|
75 |
assert.equal($.templates('{{if true ~tmp="constructo"}}{{if true ~tmp2="r"}}{{:toString[~tmp + ~tmp2]}}{{/if}}{{/if}}').render(1), "{Error: Syntax error\n}", 'Syntax error 2 for indirect ["constructor]"');
|
|
|
76 |
$.views.settings.debugMode(false);
|
|
|
77 |
});
|
|
|
78 |
|
|
|
79 |
QUnit.module("{{if}}");
|
|
|
80 |
QUnit.test("{{if}}", function(assert) {
|
|
|
81 |
assert.equal($.templates("A_{{if true}}yes{{/if}}_B").render(), "A_yes_B", "{{if a}}: a");
|
|
|
82 |
assert.equal($.templates("A_{{if false}}yes{{/if}}_B").render(), "A__B", "{{if a}}: !a");
|
|
|
83 |
assert.equal($.templates("A_{{if true}}{{/if}}_B").render(), "A__B", "{{if a}}: empty: a");
|
|
|
84 |
assert.equal($.templates("A_{{if false}}{{/if}}_B").render(), "A__B", "{{if a}}: empty: !a");
|
|
|
85 |
});
|
|
|
86 |
|
|
|
87 |
QUnit.test("{{if}} {{else}}", function(assert) {
|
|
|
88 |
assert.equal($.templates("A_{{if true}}yes{{else}}no{{/if}}_B").render(), "A_yes_B", "{{if a}} {{else}}: a");
|
|
|
89 |
assert.equal($.templates("A_{{if false}}yes{{else}}no{{/if}}_B").render(), "A_no_B", "{{if a}} {{else}}: !a");
|
|
|
90 |
assert.equal($.templates("A_{{if true}}yes{{else true}}or{{else}}no{{/if}}_B").render(), "A_yes_B", "{{if a}} {{else b}} {{else}}: a");
|
|
|
91 |
assert.equal($.templates("A_{{if false}}yes{{else true}}or{{else}}no{{/if}}_B").render(), "A_or_B", "{{if a}} {{else b}} {{else}}: b");
|
|
|
92 |
assert.equal($.templates("A_{{if false}}yes{{else false}}or{{else}}no{{/if}}_B").render(), "A_no_B", "{{if a}} {{else b}} {{else}}: !a!b");
|
|
|
93 |
assert.equal($.templates("A_{{if undefined}}yes{{else true}}or{{else}}no{{/if}}_B").render({}), "A_or_B", "{{if undefined}} {{else b}} {{else}}: !a!b");
|
|
|
94 |
assert.equal($.templates("A_{{if false}}yes{{else undefined}}or{{else}}no{{/if}}_B").render({}), "A_no_B", "{{if a}} {{else undefined}} {{else}}: !a!b");
|
|
|
95 |
assert.equal($.templates("A_{{if false}}<div title='yes'{{else}}<div title='no'{{/if}}>x</div>_B").render(), "A_<div title='no'>x</div>_B", "{{if}} and {{else}} work across HTML tags");
|
|
|
96 |
assert.equal($.templates("A_<div title='{{if true}}yes'{{else}}no'{{/if}}>x</div>_B").render(), "A_<div title='yes'>x</div>_B", "{{if}} and {{else}} work across quoted strings");
|
|
|
97 |
});
|
|
|
98 |
|
|
|
99 |
QUnit.test("{{if}} {{else}} external templates", function(assert) {
|
|
|
100 |
assert.equal($.templates("A_{{if true tmpl='yes<br/>'/}}_B").render(), "A_yes<br/>_B", "{{if a tmpl=foo/}}: a");
|
|
|
101 |
assert.equal($.templates("A_{{if false tmpl='yes<br/>'}}{{else false tmpl='or<br/>'}}{{else tmpl='no<br/>'}}{{/if}}_B").render(), "A_no<br/>_B", "{{if a tmpl=foo}}{{else b tmpl=bar}}{{else tmpl=baz}}: !a!b");
|
|
|
102 |
});
|
|
|
103 |
|
|
|
104 |
QUnit.module("{{:}}");
|
|
|
105 |
QUnit.test("convert", function(assert) {
|
|
|
106 |
assert.equal($.templates("{{>#data}}").render("<br/>'\"&"), "<br/>'"&", "default html converter");
|
|
|
107 |
assert.equal($.templates("{{html:#data}}").render("<br/>'\"&"), "<br/>'"&", "html converter");
|
|
|
108 |
assert.equal($.templates("{{:#data}}").render("<br/>'\"&"), "<br/>'\"&", "no convert");
|
|
|
109 |
|
|
|
110 |
function loc(data) {
|
|
|
111 |
switch (data) {case "desktop": return "bureau";}
|
|
|
112 |
}
|
|
|
113 |
$.views.converters("loc", loc);
|
|
|
114 |
assert.equal($.templates("{{loc:#data}}:{{loc:'desktop'}}").render("desktop"), "bureau:bureau", '$.views.converters("loc", locFunction);... {{loc:#data}}');
|
|
|
115 |
});
|
|
|
116 |
|
|
|
117 |
QUnit.test("paths", function(assert) {
|
|
|
118 |
assert.equal($.templates("{{:a}}").render({a: "aVal"}), "aVal", "a");
|
|
|
119 |
assert.equal($.templates("{{:a.b}}").render({a: {b: "bVal"}}), "bVal", "a.b");
|
|
|
120 |
assert.equal($.templates("{{:a.b.c}}").render({a: {b: {c: "cVal"}}}), "cVal", "a.b.c");
|
|
|
121 |
assert.equal($.templates("{{:a.name}}").render({a: {name: "aName"}}), "aName", "a.name");
|
|
|
122 |
assert.equal($.templates("{{:a['name']}}").render({a: {name: "aName"}}), "aName", "a['name']");
|
|
|
123 |
assert.equal($.templates("{{:a['x - _*!']}}").render({a: {"x - _*!": "aName"}}), "aName", "a['x - _*!']");
|
|
|
124 |
assert.equal($.templates("{{:#data['x - _*!']}}").render({"x - _*!": "aName"}), "aName", "#data['x - _*!']");
|
|
|
125 |
assert.equal($.templates('{{:a["x - _*!"]}}').render({a: {"x - _*!": "aName"}}), "aName", 'a["x - _*!"]');
|
|
|
126 |
assert.equal($.templates("{{:a.b[1].d}}").render({a: {b: [0, {d: "dVal"}]}}), "dVal", "a.b[1].d");
|
|
|
127 |
assert.equal($.templates("{{:a.b[1].d}}").render({a: {b: {1:{d: "dVal"}}}}), "dVal", "a.b[1].d");
|
|
|
128 |
assert.equal($.templates("{{:a.b[~incr(1-1)].d}}").render({a: {b: {1:{d: "dVal"}}}}, {incr:function(val) {return val + 1;}}), "dVal", "a.b[~incr(1-1)].d");
|
|
|
129 |
assert.equal($.templates("{{:a.b.c.d}}").render({a: {b: {c:{d: "dVal"}}}}), "dVal", "a.b.c.d");
|
|
|
130 |
assert.equal($.templates("{{:a[0]}}").render({a: [ "bVal" ]}), "bVal", "a[0]");
|
|
|
131 |
assert.equal($.templates("{{:a.b[1][0].msg}}").render({a: {b: [22,[{msg: " yes - that's right. "}]]}}), " yes - that's right. ", "a.b[1][0].msg");
|
|
|
132 |
assert.equal($.templates("{{:#data.a}}").render({a: "aVal"}), "aVal", "#data.a");
|
|
|
133 |
assert.equal($.templates("{{:#view.data.a}}").render({a: "aVal"}), "aVal", "#view.data.a");
|
|
|
134 |
assert.equal($.templates("{{:#index === 0}}").render([{a: "aVal"}]), "true", "#index");
|
|
|
135 |
});
|
|
|
136 |
|
|
|
137 |
QUnit.test("types", function(assert) {
|
|
|
138 |
assert.equal($.templates("{{:'abc'}}").render(), "abc", "'abc'");
|
|
|
139 |
assert.equal($.templates('{{:"abc"}}').render(), "abc", '"abc"');
|
|
|
140 |
assert.equal($.templates("{{:true}}").render(), "true", "true");
|
|
|
141 |
assert.equal($.templates("{{:false}}").render(), "false", "false");
|
|
|
142 |
assert.equal($.templates("{{:null}}").render(), "", 'null -> ""');
|
|
|
143 |
assert.equal($.templates("{{:199}}").render(), "199", "199");
|
|
|
144 |
assert.equal($.templates("{{: 199.9}}").render(), "199.9", "| 199.9 |");
|
|
|
145 |
assert.equal($.templates("{{:-33.33}}").render(), "-33.33", "-33.33");
|
|
|
146 |
assert.equal($.templates("{{: -33.33}}").render(), "-33.33", "| -33.33 |");
|
|
|
147 |
assert.equal($.templates("{{:-33.33 - 2.2}}").render(), "-35.53", "-33.33 - 2.2");
|
|
|
148 |
assert.equal($.templates("{{:notdefined}}").render({}), "", "notdefined");
|
|
|
149 |
assert.equal($.templates("{{:}}").render("aString"), "aString", "{{:}} returns current data item");
|
|
|
150 |
assert.equal($.templates("{{:x=22}}").render("aString"), "aString", "{{:x=...}} returns current data item");
|
|
|
151 |
assert.equal($.templates("{{html:x=22}}").render("aString"), "aString", "{{html:x=...}} returns current data item");
|
|
|
152 |
assert.equal($.templates("{{>x=22}}").render("aString"), "aString", "{{>x=...}} returns current data item");
|
|
|
153 |
assert.equal($.templates("{{:'abc('}}").render(), "abc(", "'abc(': final paren in string is rendered correctly"); // https://github.com/BorisMoore/jsviews/issues/300
|
|
|
154 |
assert.equal($.templates('{{:"abc("}}').render(), "abc(", '"abc(": final paren in string is rendered correctly');
|
|
|
155 |
assert.equal($.templates("{{:(('(abc('))}}").render(), "(abc(", "(('(abc('))");
|
|
|
156 |
assert.equal($.templates('{{:((")abc)"))}}').render(), ")abc)", '((")abc)"))');
|
|
|
157 |
});
|
|
|
158 |
|
|
|
159 |
QUnit.test("Fallbacks for missing or undefined paths:\nusing {{:some.path onError = 'fallback'}}, etc.", function(assert) {
|
|
|
160 |
var message;
|
|
|
161 |
try {
|
|
|
162 |
$.templates("{{:a.missing.willThrow.path}}").render({a:1});
|
|
|
163 |
} catch(e) {
|
|
|
164 |
message = e.message;
|
|
|
165 |
}
|
|
|
166 |
assert.ok(!!message,
|
|
|
167 |
"{{:a.missing.willThrow.path}} throws: " + message);
|
|
|
168 |
|
|
|
169 |
assert.equal($.templates("{{:a.missing.willThrow.path onError='Missing Object'}}").render({a:1}), "Missing Object",
|
|
|
170 |
'{{:a.missing.willThrow.path onError="Missing Object"}} renders "Missing Object"');
|
|
|
171 |
assert.equal($.templates('{{:a.missing.willThrow.path onError=""}}').render({a:1}), "",
|
|
|
172 |
'{{:a.missing.willThrow.path onError=""}} renders ""');
|
|
|
173 |
assert.equal($.templates("{{:a.missing.willThrow.path onError=null}}").render({a:1}), "",
|
|
|
174 |
'{{:a.missing.willThrow.path onError=null}} renders ""');
|
|
|
175 |
assert.equal($.templates("{{>a.missing.willThrow.path onError='Missing Object'}}").render({a:1}), "Missing Object",
|
|
|
176 |
'{{>a.missing.willThrow.path onError="Missing Object"}} renders "Missing Object"');
|
|
|
177 |
assert.equal($.templates('{{>a.missing.willThrow.path onError=""}}').render({a:1}), "",
|
|
|
178 |
'{{>a.missing.willThrow.path onError=""}} renders ""');
|
|
|
179 |
assert.equal($.templates("{{>a.missing.willThrow.path onError=defaultVal}}").render(
|
|
|
180 |
{
|
|
|
181 |
a:1,
|
|
|
182 |
defaultVal: "defaultFromData"
|
|
|
183 |
}), "defaultFromData",
|
|
|
184 |
'{{>a.missing.willThrow.path onError=defaultVal}} renders "defaultFromData"');
|
|
|
185 |
|
|
|
186 |
assert.equal($.templates("{{>a.missing.willThrow.path onError=~myOnErrorFunction}}").render({a:1}, {
|
|
|
187 |
myOnErrorFunction: function(e, view) {
|
|
|
188 |
return "Override onError using a callback: " + view.ctx.helperValue + e.message;
|
|
|
189 |
},
|
|
|
190 |
helperValue: "hlp"
|
|
|
191 |
}).slice(0, 38), "Override onError using a callback: hlp",
|
|
|
192 |
'{{>a.missing.willThrow.path onError=~myOnErrorFunction}}" >' +
|
|
|
193 |
'\nProviding a function "onError=~myOnErrorFunction" calls the function as onError callback');
|
|
|
194 |
|
|
|
195 |
assert.equal($.templates("{{>a.missing.willThrow.path onError=myOnErrorDataMethod}}").render(
|
|
|
196 |
{
|
|
|
197 |
a: "dataValue",
|
|
|
198 |
myOnErrorDataMethod: function(e) {
|
|
|
199 |
var data = this;
|
|
|
200 |
return "Override onError using a callback data method: " + data.a;
|
|
|
201 |
}
|
|
|
202 |
}), "Override onError using a callback data method: dataValue",
|
|
|
203 |
'{{>a.missing.willThrow.path onError=myOnErrorDataMethod}}" >' +
|
|
|
204 |
'\nProviding a function "onError=myOnErrorDataMethod" calls the function as onError callback');
|
|
|
205 |
|
|
|
206 |
assert.equal($.templates("1: {{>a.missing.willThrow.path onError=defaultVal}}" +
|
|
|
207 |
" 2: {{:a.missing.willThrow.path onError='Missing Object'}}" +
|
|
|
208 |
" 3: {{:a.missing.willThrow.path onError=''}}" +
|
|
|
209 |
" 4: {{:a.missing.willThrow.path onError=null}}" +
|
|
|
210 |
" 5: {{:a onError='missing'}}" +
|
|
|
211 |
" 6: {{:a.undefined onError='missing'}}" +
|
|
|
212 |
" 7: {{:a.missing.willThrow onError=myCb}} end").render(
|
|
|
213 |
{
|
|
|
214 |
a:"aVal",
|
|
|
215 |
defaultVal: "defaultFromData",
|
|
|
216 |
myCb: function(e, view) {
|
|
|
217 |
return "myCallback: " + this.a;
|
|
|
218 |
}
|
|
|
219 |
}), "1: defaultFromData 2: Missing Object 3: 4: 5: aVal 6: 7: myCallback: aVal end",
|
|
|
220 |
'multiple onError fallbacks in same template - correctly concatenated into output');
|
|
|
221 |
|
|
|
222 |
assert.equal($.templates({
|
|
|
223 |
markup: "{{withfallback:a.notdefined fallback='fallback for undefined'}}",
|
|
|
224 |
converters: {
|
|
|
225 |
withfallback: function(val) {
|
|
|
226 |
return val || this.tagCtx.props.fallback;
|
|
|
227 |
}
|
|
|
228 |
}
|
|
|
229 |
}).render({a:"yes"}), "fallback for undefined",
|
|
|
230 |
'{{withfallback:a.notdefined fallback="fallback for undefined"}}' +
|
|
|
231 |
'\nusing converter to get fallback value for undefined properties');
|
|
|
232 |
|
|
|
233 |
assert.equal($.templates({
|
|
|
234 |
markup: "1: {{withfallback:a.missing.y onError='Missing object' fallback='undefined prop'}}" +
|
|
|
235 |
" 2: {{withfallback:a.undefined onError='Missing object' fallback='undefined prop'}}",
|
|
|
236 |
converters: {
|
|
|
237 |
withfallback: function(val) {
|
|
|
238 |
return val || this.tagCtx.props.fallback;
|
|
|
239 |
}
|
|
|
240 |
}
|
|
|
241 |
}).render({a:"yes"}), "1: Missing object 2: undefined prop",
|
|
|
242 |
'both fallback for undefined and onError for missing on same tags');
|
|
|
243 |
|
|
|
244 |
assert.equal($.templates({
|
|
|
245 |
markup: "1: {{>a.missing.willThrow.path onError=defaultVal}}" +
|
|
|
246 |
" 2: {{:a.missing.willThrow.path onError='Missing Object'}}" +
|
|
|
247 |
" 3: {{:a.missing.willThrow.path onError=''}}" +
|
|
|
248 |
" 4: {{:a onError='missing'}}" +
|
|
|
249 |
" 5: {{:a.undefined onError='missing'}}" +
|
|
|
250 |
" 6: {{:a.missing.willThrow onError=myCb}}" +
|
|
|
251 |
" 7: {{withfallback:a.undefined fallback='undefined prop'}} end",
|
|
|
252 |
converters: {
|
|
|
253 |
withfallback: function(val) {
|
|
|
254 |
return val || this.tagCtx.props.fallback;
|
|
|
255 |
}
|
|
|
256 |
}
|
|
|
257 |
}).render(
|
|
|
258 |
{
|
|
|
259 |
a:"aVal",
|
|
|
260 |
defaultVal: "defaultFromData",
|
|
|
261 |
myCb: function(e, view) {
|
|
|
262 |
return "myCallback: " + this.a;
|
|
|
263 |
}
|
|
|
264 |
}), "1: defaultFromData 2: Missing Object 3: 4: aVal 5: 6: myCallback: aVal 7: undefined prop end",
|
|
|
265 |
'multiple onError fallbacks or undefined property fallbacks in same template - correctly concatenated into output');
|
|
|
266 |
|
|
|
267 |
try {
|
|
|
268 |
message = "";
|
|
|
269 |
$.templates({
|
|
|
270 |
markup: "1: {{>a.missing.willThrow.path onError=defaultVal}}" +
|
|
|
271 |
" 2: {{:a.missing.willThrow.path onError='Missing Object'}}" +
|
|
|
272 |
" 3: {{:a.missing.willThrow.path onError=''}}" +
|
|
|
273 |
" 4: {{:a onError='missing'}}" +
|
|
|
274 |
" 5: {{:a.missing.willThrow.foo}}" +
|
|
|
275 |
" 6: {{:a.undefined onError='missing'}}" +
|
|
|
276 |
" 7: {{:a.missing.willThrow onError=myCb}}" +
|
|
|
277 |
" 8: {{withfallback:a.undefined fallback='undefined prop'}} end",
|
|
|
278 |
converters: {
|
|
|
279 |
withfallback: function(val) {
|
|
|
280 |
return val || this.tagCtx.props.fallback;
|
|
|
281 |
}
|
|
|
282 |
}
|
|
|
283 |
}).render({
|
|
|
284 |
a:"aVal",
|
|
|
285 |
defaultVal: "defaultFromData",
|
|
|
286 |
myCb: function(e, view) {
|
|
|
287 |
return "myCallback: " + this.a;
|
|
|
288 |
}
|
|
|
289 |
});
|
|
|
290 |
} catch(e) {
|
|
|
291 |
message = e.message;
|
|
|
292 |
}
|
|
|
293 |
|
|
|
294 |
assert.ok(!!message,
|
|
|
295 |
'onError/fallback converter and regular thrown error message in same template: throws:\n"' + message + '"');
|
|
|
296 |
|
|
|
297 |
assert.equal($.templates("{{for missing.willThrow.path onError='Missing Object'}}yes{{/for}}").render({a:1}), "Missing Object",
|
|
|
298 |
'{{for missing.willThrow.path onError="Missing Object"}} -> "Missing Object"');
|
|
|
299 |
|
|
|
300 |
assert.equal($.templates("{{for true missing.willThrow.path onError='Missing Object'}}yes{{/for}}").render({a:1}), "Missing Object",
|
|
|
301 |
'{{for true missing.willThrow.path onError="Missing Object"}} -> "Missing Object"');
|
|
|
302 |
|
|
|
303 |
assert.equal($.templates("{{for true foo=missing.willThrow.path onError='Missing Object'}}yes{{/for}}").render({a:1}), "Missing Object",
|
|
|
304 |
'{{for ... foo=missing.willThrow.path onError="Missing Object"}} -> "Missing Object"');
|
|
|
305 |
|
|
|
306 |
assert.equal($.templates("{{for true ~foo=missing.willThrow.path onError='Missing Object'}}yes{{/for}}").render({a:1}), "Missing Object",
|
|
|
307 |
'{{for ... ~foo=missing.willThrow.path onError="Missing Object"}} -> "Missing Object"');
|
|
|
308 |
|
|
|
309 |
assert.equal($.templates({
|
|
|
310 |
markup: "{{mytag foo='a'/}} {{mytag foo=missing.willThrow.path onError='Missing Object'/}} {{mytag foo='c' bar=missing.willThrow.path onError='Missing Object'/}} {{mytag foo='c' missing.willThrow.path onError='Missing Object'/}} {{mytag foo='b'/}}",
|
|
|
311 |
tags: {
|
|
|
312 |
mytag: {template: "MyTag: {{:~tagCtx.props.foo}} end"}
|
|
|
313 |
}
|
|
|
314 |
}).render({a:1}), "MyTag: a end Missing Object Missing Object Missing Object MyTag: b end",
|
|
|
315 |
'onError=... for custom tags: e.g. {{mytag foo=missing.willThrow.path onError="Missing Object"/}}');
|
|
|
316 |
|
|
|
317 |
assert.equal($.templates({
|
|
|
318 |
markup: "1: {{for a.missing.willThrow.path onError=defaultVal}}yes{{/for}}" +
|
|
|
319 |
" 2: {{if a.missing.willThrow.path onError='Missing Object'}}yes{{/if}}" +
|
|
|
320 |
" 3: {{include a.missing.willThrow.path onError=''/}}" +
|
|
|
321 |
" 4: {{if a onError='missing'}}yes{{/if}}" +
|
|
|
322 |
" 5: {{for a.undefined onError='missing'}}yes{{/for}}" +
|
|
|
323 |
" 6: {{if a.missing.willThrow onError=myCb}}yes{{/if}}" +
|
|
|
324 |
" 7: {{withfallback:a.undefined fallback='undefined prop'}} end" +
|
|
|
325 |
" 8: {{mytag foo=missing.willThrow.path onError='Missing Object'/}}",
|
|
|
326 |
converters: {
|
|
|
327 |
withfallback: function(val) {
|
|
|
328 |
return val || this.tagCtx.props.fallback;
|
|
|
329 |
}
|
|
|
330 |
},
|
|
|
331 |
tags: {
|
|
|
332 |
mytag: {template: "MyTag: {{:~tagCtx.props.foo}} end"}
|
|
|
333 |
}
|
|
|
334 |
}).render(
|
|
|
335 |
{
|
|
|
336 |
a:"aVal",
|
|
|
337 |
defaultVal: "defaultFromData",
|
|
|
338 |
myCb: function(e, view) {
|
|
|
339 |
return "myCallback: " + this.a;
|
|
|
340 |
}
|
|
|
341 |
}), "1: defaultFromData 2: Missing Object 3: 4: yes 5: 6: myCallback: aVal 7: undefined prop end 8: Missing Object",
|
|
|
342 |
'multiple onError fallbacks or undefined property fallbacks in same template - correctly concatenated into output');
|
|
|
343 |
|
|
|
344 |
try {
|
|
|
345 |
message = "";
|
|
|
346 |
$.templates({
|
|
|
347 |
markup: "1: {{for a.missing.willThrow.path onError=defaultVal}}yes{{/for}}" +
|
|
|
348 |
" 2: {{if a.missing.willThrow.path onError='Missing Object'}}yes{{/if}}" +
|
|
|
349 |
" 3: {{include a.missing.willThrow.path onError=''/}}" +
|
|
|
350 |
" 4: {{if a onError='missing'}}yes{{/if}}" +
|
|
|
351 |
" 5: {{for missing.willThrow.foo}}yes{{/for}}" +
|
|
|
352 |
" 6: {{for a.undefined onError='missing'}}yes{{/for}}" +
|
|
|
353 |
" 7: {{if a.missing.willThrow onError=myCb}}yes{{/if}}" +
|
|
|
354 |
" 8: {{withfallback:a.undefined fallback='undefined prop'}} end",
|
|
|
355 |
converters: {
|
|
|
356 |
withfallback: function(val) {
|
|
|
357 |
return val || this.tagCtx.props.fallback;
|
|
|
358 |
}
|
|
|
359 |
}
|
|
|
360 |
}).render({
|
|
|
361 |
a:"aVal",
|
|
|
362 |
defaultVal: "defaultFromData",
|
|
|
363 |
myCb: function(e, view) {
|
|
|
364 |
return "myCallback: " + this.a;
|
|
|
365 |
}
|
|
|
366 |
});
|
|
|
367 |
} catch(e) {
|
|
|
368 |
message = e.message;
|
|
|
369 |
}
|
|
|
370 |
|
|
|
371 |
assert.ok(!!message,
|
|
|
372 |
'onError/fallback converter and regular thrown error message in same template: throws: \n"' + message + '"');
|
|
|
373 |
|
|
|
374 |
$.views.settings.debugMode(true);
|
|
|
375 |
assert.equal($.templates({
|
|
|
376 |
markup: "1: {{for a.missing.willThrow.path onError=defaultVal}}yes{{/for}}" +
|
|
|
377 |
" 2: {{if a.missing.willThrow.path onError='Missing Object'}}yes{{/if}}" +
|
|
|
378 |
" 3: {{include a.missing.willThrow.path onError=''/}}" +
|
|
|
379 |
" 4: {{if a onError='missing'}}yes{{/if}}" +
|
|
|
380 |
" 5: {{for missing.willThrow.foo}}yes{{/for}}" +
|
|
|
381 |
" 6: {{for a.undefined onError='missing'}}yes{{/for}}" +
|
|
|
382 |
" 7: {{if a.missing.willThrow onError=myCb}}yes{{/if}}" +
|
|
|
383 |
" 8: {{withfallback:a.undefined fallback='undefined prop'}} end",
|
|
|
384 |
converters: {
|
|
|
385 |
withfallback: function(val) {
|
|
|
386 |
return val || this.tagCtx.props.fallback;
|
|
|
387 |
}
|
|
|
388 |
}
|
|
|
389 |
}).render(
|
|
|
390 |
{
|
|
|
391 |
a:"aVal",
|
|
|
392 |
defaultVal: "defaultFromData",
|
|
|
393 |
myCb: function(e, view) {
|
|
|
394 |
return "myCallback: " + this.a;
|
|
|
395 |
}
|
|
|
396 |
}).slice(0, 21), "1: defaultFromData 2:",
|
|
|
397 |
'In debug mode, onError/fallback converter and regular thrown error message in same template:' +
|
|
|
398 |
'\override errors and regular thrown error each render for the corrresponding tag');
|
|
|
399 |
$.views.settings.debugMode(false);
|
|
|
400 |
|
|
|
401 |
});
|
|
|
402 |
|
|
|
403 |
QUnit.test("comparisons", function(assert) {
|
|
|
404 |
assert.equal($.templates("{{:1<2}}").render(), "true", "1<2");
|
|
|
405 |
assert.equal($.templates("{{:2<1}}").render(), "false", "2<1");
|
|
|
406 |
assert.equal($.templates("{{:5===5}}").render(), "true", "5===5");
|
|
|
407 |
assert.equal($.templates("{{:0==''}}").render(), "true", "0==''");
|
|
|
408 |
assert.equal($.templates("{{:'ab'=='ab'}}").render(), "true", "'ab'=='ab'");
|
|
|
409 |
assert.equal($.templates("{{:2>1}}").render(), "true", "2>1");
|
|
|
410 |
assert.equal($.templates("{{:2 == 2}}").render(), "true", "2 == 2");
|
|
|
411 |
assert.equal($.templates("{{:2<=2}}").render(), "true", "2<=2");
|
|
|
412 |
assert.equal($.templates("{{:'ab'<'ac'}}").render(), "true", "'ab'<'ac'");
|
|
|
413 |
assert.equal($.templates("{{:3>=3}}").render(), "true", "3 =3");
|
|
|
414 |
assert.equal($.templates("{{:3>=2}}").render(), "true", "3>=2");
|
|
|
415 |
assert.equal($.templates("{{:3>=4}}").render(), "false", "3>=4");
|
|
|
416 |
assert.equal($.templates("{{:3 !== 2}}").render(), "true", "3 !== 2");
|
|
|
417 |
assert.equal($.templates("{{:3 != 2}}").render(), "true", "3 != 2");
|
|
|
418 |
assert.equal($.templates("{{:0 !== null}}").render(), "true", "0 !== null");
|
|
|
419 |
assert.equal($.templates("{{:(3 >= 4)}}").render(), "false", "3>=4");
|
|
|
420 |
assert.equal($.templates("{{:3 >= 4}}").render(), "false", "3>=4");
|
|
|
421 |
assert.equal($.templates("{{:(3>=4)}}").render(), "false", "3>=4");
|
|
|
422 |
assert.equal($.templates("{{:(3 < 4)}}").render(), "true", "3>=4");
|
|
|
423 |
assert.equal($.templates("{{:3 < 4}}").render(), "true", "3>=4");
|
|
|
424 |
assert.equal($.templates("{{:(3<4)}}").render(), "true", "3>=4");
|
|
|
425 |
assert.equal($.templates("{{:0 != null}}").render(), "true", "0 != null");
|
|
|
426 |
});
|
|
|
427 |
|
|
|
428 |
QUnit.test("array access", function(assert) {
|
|
|
429 |
assert.equal($.templates("{{:a[1]}}").render({a: ["a0","a1"]}), "a1", "a[1]");
|
|
|
430 |
assert.equal($.templates("{{:a[1+1]+5}}").render({a: [11,22,33]}), "38", "a[1+1]+5)");
|
|
|
431 |
assert.equal($.templates("{{:a[~incr(1)]+5}}").render({a: [11,22,33]}, {incr:function(val) {return val + 1;}}), "38", "a[~incr(1)]+5");
|
|
|
432 |
assert.equal($.templates("{{:true && (a[0] || 'default')}}").render({a: [0,22,33]}, {incr:function(val) {return val + 1;}}), "default", "true && (a[0] || 'default')");
|
|
|
433 |
});
|
|
|
434 |
|
|
|
435 |
QUnit.test("context", function(assert) {
|
|
|
436 |
assert.equal($.templates("{{:~val}}").render(1, {val: "myvalue"}), "myvalue", "~val");
|
|
|
437 |
function format(value, upper) {
|
|
|
438 |
return value[upper ? "toUpperCase" : "toLowerCase"]();
|
|
|
439 |
}
|
|
|
440 |
assert.equal($.templates("{{:~format(name) + ~format(name, true)}}").render(person, {format: format}), "joJO",
|
|
|
441 |
"render(data, {format: formatFn}); ... {{:~format(name, true)}}");
|
|
|
442 |
assert.equal($.templates("{{for people[0]}}{{:~format(~type) + ~format(name, true)}}{{/for}}").render({people: people}, {format: format, type: "PascalCase"}), "pascalcaseJO",
|
|
|
443 |
"render(data, {format: formatFn}); ... {{:~format(name, true)}}");
|
|
|
444 |
assert.equal($.templates("{{for people ~twn=town}}{{:name}} lives in {{:~format(~twn, true)}}. {{/for}}").render({people: people, town:"Redmond"}, {format: format}),
|
|
|
445 |
"Jo lives in REDMOND. Bill lives in REDMOND. ",
|
|
|
446 |
"Passing in context to nested templates: {{for people ~twn=town}}");
|
|
|
447 |
assert.equal($.templates("{{if true}}{{for people}}{{:~root.people[0].name}}{{/for}}{{/if}}").render({people: people}), "JoJo",
|
|
|
448 |
"{{:~root}} returns the top-level data");
|
|
|
449 |
});
|
|
|
450 |
|
|
|
451 |
QUnit.test("values", function(assert) {
|
|
|
452 |
assert.equal($.templates("{{:a}}").render({a: 0}), "0", '{{:0}} returns "0"');
|
|
|
453 |
assert.equal($.templates("{{:a}}").render({}), "", "{{:undefined}} returns empty string");
|
|
|
454 |
assert.equal($.templates("{{:a}}").render({a: ""}), "", "{{:''}} returns empty string");
|
|
|
455 |
assert.equal($.templates("{{:a}}").render({a: null}), "", "{{:null}} returns empty string");
|
|
|
456 |
});
|
|
|
457 |
|
|
|
458 |
QUnit.test("expressions", function(assert) {
|
|
|
459 |
assert.equal(compileTmpl("{{:a++}}"), "Syntax error\na++", "a++");
|
|
|
460 |
assert.equal(compileTmpl("{{:(a,b)}}"), "Syntax error\n(a,b)", "(a,b)");
|
|
|
461 |
assert.equal($.templates("{{: a+2}}").render({a: 2, b: false}), "4", "a+2");
|
|
|
462 |
assert.equal($.templates("{{: b?'yes':'no'}}").render({a: 2, b: false}), "no", "b?'yes':'no'");
|
|
|
463 |
assert.equal($.templates("{{:(a||-1) + (b||-1)}}").render({a: 2, b: 0}), "1", "a||-1");
|
|
|
464 |
assert.equal($.templates("{{:3*b()*!a*4/3}}").render({a: false, b: function() {return 3;}}), "12", "3*b()*!a*4/3");
|
|
|
465 |
assert.equal($.templates("{{:a%b}}").render({a: 30, b: 16}), "14", "a%b");
|
|
|
466 |
assert.equal($.templates("A_{{if v1 && v2 && v3 && v4}}no{{else !v1 && v2 || v3 && v4}}yes{{/if}}_B").render({v1:true,v2:false,v3:2,v4:"foo"}), "A_yes_B", "x && y || z");
|
|
|
467 |
assert.equal($.templates("{{:!true}}").render({}), "false", "!true");
|
|
|
468 |
assert.equal($.templates("{{if !true}}yes{{else}}no{{/if}}").render({}), "no", "{{if !true}}...");
|
|
|
469 |
assert.equal($.templates("{{:!false}}").render({}), "true", "!false");
|
|
|
470 |
assert.equal($.templates("{{if !false}}yes{{else}}no{{/if}}").render({}), "yes", "{{if !false}}...");
|
|
|
471 |
assert.equal($.templates("{{:!!true}}").render({}), "true", "!!true");
|
|
|
472 |
assert.equal($.templates("{{if !!true}}yes{{else}}no{{/if}}").render({}), "yes", "{{if !!true}}...");
|
|
|
473 |
assert.equal($.templates("{{:!(true)}}").render({}), "false", "!(true)");
|
|
|
474 |
assert.equal($.templates("{{:!true === false}}").render({}), "true", "!true === false");
|
|
|
475 |
assert.equal($.templates("{{:false === !true}}").render({}), "true", "false === !true");
|
|
|
476 |
assert.equal($.templates("{{:false === !null}}").render({}), "false", "false === !null");
|
|
|
477 |
});
|
|
|
478 |
|
|
|
479 |
QUnit.module("{{for}}");
|
|
|
480 |
QUnit.test("{{for}}", function(assert) {
|
|
|
481 |
$.templates({
|
|
|
482 |
forTmpl: "header_{{for people}}{{:name}}{{/for}}_footer",
|
|
|
483 |
templateForArray: "header_{{for #data}}{{:name}}{{/for}}_footer",
|
|
|
484 |
pageTmpl: '{{for [people] tmpl="templateForArray"/}}',
|
|
|
485 |
simpleFor: "a{{for people}}Content{{:#data}}|{{/for}}b",
|
|
|
486 |
forPrimitiveDataTypes: "a{{for people}}|{{:#data}}{{/for}}b",
|
|
|
487 |
testTmpl: "xxx{{:name}} {{:~foo}}"
|
|
|
488 |
});
|
|
|
489 |
|
|
|
490 |
assert.equal($.render.forTmpl({people: people}), "header_JoBill_footer", '{{for people}}...{{/for}}');
|
|
|
491 |
assert.equal($.render.templateForArray([people]), "header_JoBill_footer", 'Can render a template against an array, as a "layout template", by wrapping array in an array');
|
|
|
492 |
assert.equal($.render.pageTmpl({people: people}), "header_JoBill_footer", '{{for [people] tmpl="templateForArray"/}}');
|
|
|
493 |
assert.equal($.templates("{{for}}xxx{{:name}} {{:~foo}}{{/for}}").render({name: "Jeff"}, {foo:"fooVal"}), "xxxJeff fooVal", "no parameter - renders once with parent #data context: {{for}}");
|
|
|
494 |
assert.equal($.templates("{{for tmpl='testTmpl'/}}").render({name: "Jeff"}, {foo:"fooVal"}), "xxxJeff fooVal", ": {{for tmpl=.../}} no parameter - equivalent to {{include tmpl=.../}} - renders once with parent #data context");
|
|
|
495 |
assert.equal($.templates("{{include tmpl='testTmpl'/}}").render({name: "Jeff"}, {foo:"fooVal"}), "xxxJeff fooVal", "{{include tmpl=.../}} with tmpl parameter - renders once with parent #data context. Equivalent to {{for tmpl=.../}}");
|
|
|
496 |
assert.equal($.templates("{{for missingProperty}}xxx{{:#data===~undefined}}{{/for}}").render({}), "", "missingProperty - renders empty string");
|
|
|
497 |
assert.equal($.templates("{{for null}}xxx{{:#data===null}}{{/for}}").render(), "xxxtrue", "null - renders once with #data null: {{for null}}");
|
|
|
498 |
assert.equal($.templates("{{for false}}xxx{{:#data}}{{/for}}").render(), "xxxfalse", "false - renders once with #data false: {{for false}}");
|
|
|
499 |
assert.equal($.templates("{{for 0}}xxx{{:#data}}{{/for}}").render(), "xxx0", "0 - renders once with #data false: {{for 0}}");
|
|
|
500 |
assert.equal($.templates("{{for ''}}xxx{{:#data===''}}{{/for}}").render(), "xxxtrue", "'' - renders once with #data false: {{for ''}}");
|
|
|
501 |
assert.equal($.templates("{{for #data}}{{:name}}{{/for}}").render(people), "JoBill", "If #data is an array, {{for #data}} iterates");
|
|
|
502 |
|
|
|
503 |
assert.equal($.render.simpleFor({people:[]}), "ab", 'Empty array renders empty string');
|
|
|
504 |
assert.equal($.render.simpleFor({people:["", false, null, undefined, 1]}), "aContent|Contentfalse|Content|Content|Content1|b", 'Empty string, false, null or undefined members of array are also rendered');
|
|
|
505 |
assert.equal($.render.simpleFor({people:null}), "aContent|b", 'null is rendered once with #data null');
|
|
|
506 |
assert.equal($.render.simpleFor({}), "ab", 'if #data is undefined, renders empty string');
|
|
|
507 |
assert.equal($.render.forPrimitiveDataTypes({people:[0, 1, "abc", "", ,null ,true ,false]}), "a|0|1|abc||||true|falseb", 'Primitive types render correctly, even if falsey');
|
|
|
508 |
});
|
|
|
509 |
QUnit.test("{{for start end sort filter reverse}}", function(assert) {
|
|
|
510 |
// =============================== Arrange ===============================
|
|
|
511 |
function level(aField, bField) {
|
|
|
512 |
return aField > bField ? 1 : aField < bField ? -1 : 0;
|
|
|
513 |
}
|
|
|
514 |
|
|
|
515 |
var oddValue = function(item, index, items) { return item%2; };
|
|
|
516 |
var oddIndex = function(item, index, items) { return index%2; };
|
|
|
517 |
var sortAgeName = function(a, b) {
|
|
|
518 |
return level(a.details.role.toLowerCase(), b.details.role.toLowerCase()) // First level sort: by role
|
|
|
519 |
|| (this.props.reverseAge ? level(b.details.age, a.details.age) : level(a.details.age, b.details.age)) // 2nd level sort: sort by age, or reverse sort by age
|
|
|
520 |
|| level(a.name.toLowerCase(), b.name.toLowerCase()); // 3rd level sort: sort by name
|
|
|
521 |
};
|
|
|
522 |
var underLimit = function(item, index, items) {
|
|
|
523 |
return item.details.age < this.props.limit;
|
|
|
524 |
};
|
|
|
525 |
|
|
|
526 |
// ................................ Assert ..................................
|
|
|
527 |
|
|
|
528 |
assert.equal($.templates("{{for start=0 end=10}}{{:}} {{/for}}").render(), "0 1 2 3 4 5 6 7 8 9 ", "{{for start=0 end=10}}: Auto-create array");
|
|
|
529 |
assert.equal($.templates("{{for start=5 end=9 reverse=1}}{{:}} {{/for}}").render(), "8 7 6 5 ", "{{for start=5 end=9 reverse=1}}: Auto-create array");
|
|
|
530 |
assert.equal($.templates("{{for start=8 end=4 step=-1}}{{:}} {{/for}}").render(), "8 7 6 5 ", "{{for start=8 end=4 step=-1}}: Auto-create array");
|
|
|
531 |
assert.equal($.templates("{{for start=8 end=4 step=-1 reverse=true}}{{:}} {{/for}}").render(), "5 6 7 8 ", "{{for start=8 end=4 step=-1 reverse=true}}: Auto-create array, with reverse");
|
|
|
532 |
assert.equal($.templates("{{for start=20 end='10' step=-2}}{{:}} {{/for}}").render(), "20 18 16 14 12 ", "{{for start=20 end='10' step=-2}}: Auto-create array");
|
|
|
533 |
assert.equal($.templates("{{for start=20 end='10' step=2}}{{:}} {{/for}}").render(), "", "{{for start=20 end='10' step=2}}: Auto-create array (outputs nothing)");
|
|
|
534 |
assert.equal($.templates("{{for start=2 end=-1.5 step=-.5}}{{:}} {{/for}}").render(), "2 1.5 1 0.5 0 -0.5 -1 ", "{{for start=0 end='10' step=-1}}: Auto-create array");
|
|
|
535 |
assert.equal($.templates("{{for start=2}}{{:}} {{/for}}").render(), "", "{{for start=2}}: (outputs nothing)");
|
|
|
536 |
assert.equal($.templates("{{for end=4}}{{:}} {{/for}}").render(), "0 1 2 3 ", "{{for end=4}}: (start defaults to 0)");
|
|
|
537 |
assert.equal($.templates("{{for start=8 end=4 step=-1 reverse=true sort=true filter=~oddIndex}}{{:}} {{/for}}").render({}, {oddIndex: oddIndex}), "5 6 7 8 ", "{{for start=8 end=4 step=-1 reverse=true sort=true}}: Auto-create array, sort and filter not supported with auto-create arrays - do nothing");
|
|
|
538 |
|
|
|
539 |
// =============================== Arrange ===============================
|
|
|
540 |
|
|
|
541 |
var myarray = [1, 9, 2, 8, 3, 7, 4, 6, 5];
|
|
|
542 |
|
|
|
543 |
assert.equal($.templates("{{for #data }}{{:}} {{/for}}").render(myarray, true), "1 9 2 8 3 7 4 6 5 ", "{{for #data}}");
|
|
|
544 |
assert.equal($.templates("{{for #data sort=true}}{{:}} {{/for}}").render(myarray, true), "1 2 3 4 5 6 7 8 9 ", "{{for #data sort=true}}");
|
|
|
545 |
assert.equal($.templates("{{for myarray reverse=true}}{{:}} {{/for}}").render({myarray: myarray}), "5 6 4 7 3 8 2 9 1 ", "{{for myarray reverse=true}}");
|
|
|
546 |
assert.equal($.templates("{{for myarray start=1 end=-1}}{{:}} {{/for}}").render({myarray: myarray}), "9 2 8 3 7 4 6 ", "{{for myarray start=1 end=-1}}");
|
|
|
547 |
assert.equal($.templates("{{for myarray start=1}}{{:}} {{/for}}").render({myarray: myarray}), "9 2 8 3 7 4 6 5 ", "{{for myarray start=1}}");
|
|
|
548 |
assert.equal($.templates("{{for myarray end=-1}}{{:}} {{/for}}").render({myarray: myarray}), "1 9 2 8 3 7 4 6 ", "{{for myarray end=-1}}");
|
|
|
549 |
assert.equal($.templates("{{for myarray sort=true}}{{:}} {{/for}}").render({myarray: myarray}), "1 2 3 4 5 6 7 8 9 ", "{{for myarray sort=true}}");
|
|
|
550 |
assert.equal($.templates("{{for myarray sort=true reverse=true}}{{:}} {{/for}}").render({myarray: myarray}), "9 8 7 6 5 4 3 2 1 ", "{{for myarray sort=true reverse=true}}");
|
|
|
551 |
|
|
|
552 |
assert.equal($.templates("{{for myarray filter=~oddValue}}{{:}} {{/for}}").render({myarray: myarray}, {oddValue: oddValue}), "1 9 3 7 5 ", "{{for myarray filter=~oddValue}}");
|
|
|
553 |
assert.equal($.templates("{{for myarray filter=~oddIndex}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "9 8 7 6 ", "{{for myarray filter=~oddIndex}}");
|
|
|
554 |
assert.equal($.templates("{{for myarray sort=true filter=~oddValue}}{{:}} {{/for}}").render({myarray: myarray}, {oddValue: oddValue}), "1 3 5 7 9 ", "{{for myarray sort=true filter=~oddValue}}");
|
|
|
555 |
assert.equal($.templates("{{for myarray sort=true filter=~oddIndex}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "2 4 6 8 ", "{{for myarray sort=true filter=~oddIndex}}");
|
|
|
556 |
assert.equal($.templates("{{for myarray sort=true filter=~oddIndex start=1 end=3}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "4 6 ", "{{for myarray sort=true filter=~oddIndex start=1 end=3}}");
|
|
|
557 |
assert.equal($.templates("{{for myarray sort=true filter=~oddIndex start=-3 end=-1}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "4 6 ", "{{for myarray sort=true filter=~oddIndex start=-3 end=-1}} Negative start or end count from the end");
|
|
|
558 |
assert.equal($.templates("{{for myarray sort=true filter=~oddIndex start=3 end=3}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "", "{{for myarray sort=true filter=~oddIndex start=3 end=3}} (outputs nothing)");
|
|
|
559 |
|
|
|
560 |
assert.equal($.templates("{{for myarray step=2 start=1}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "9 8 7 6 ", "{{for myarray step=2 start=1}}");
|
|
|
561 |
assert.equal($.templates("{{for myarray sort=true step=2 start=1}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "2 4 6 8 ", "{{for myarray sort=true step=2 start=1}}");
|
|
|
562 |
assert.equal($.templates("{{for myarray sort=true step=2 start=3 end=6}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "4 6 ", "{{for myarray sort=true step=2 start=3 end=6}}");
|
|
|
563 |
assert.equal($.templates("{{for myarray sort=true step=2 start=-6 end=-3}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "4 6 ", "{{for myarray sort=true step=2 start=-6 end=-3}} Negative start or end count from the end");
|
|
|
564 |
assert.equal($.templates("{{for myarray sort=true step=2 start=3 end=3}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "", "{{for myarray sort=true step=2 start=3 end=3}} (outputs nothing)");
|
|
|
565 |
assert.equal($.templates("{{for myarray step=3.5}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "1 8 4 ", "{{for myarray step=3.5}} - equivalent to step=3");
|
|
|
566 |
assert.equal($.templates("{{for myarray step=-2}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "1 9 2 8 3 7 4 6 5 ", "{{for myarray step=-2}} equivalent to no step");
|
|
|
567 |
assert.equal($.templates("{{for myarray step=1}}{{:}} {{/for}}").render({myarray: myarray}, {oddIndex: oddIndex}), "1 9 2 8 3 7 4 6 5 ", "{{for myarray step=1}} equivalent to no step");
|
|
|
568 |
// =============================== Arrange ===============================
|
|
|
569 |
|
|
|
570 |
var mypeople = [
|
|
|
571 |
{name: "Jo", details: {age: 22}},
|
|
|
572 |
{name: "Bob", details: {age: 2}},
|
|
|
573 |
{name: "Emma", details: {age: 12}},
|
|
|
574 |
{name: "Jeff", details: {age: 13.5}},
|
|
|
575 |
{name: "Julia", details: {age: 0.6}},
|
|
|
576 |
{name: "Xavier", details: {age: 0}}
|
|
|
577 |
];
|
|
|
578 |
|
|
|
579 |
// ................................ Assert ..................................
|
|
|
580 |
|
|
|
581 |
assert.equal($.templates("{{for mypeople sort='name'}}{{:name}}: age {{:details.age}} - {{/for}}").render({mypeople: mypeople}), "Bob: age 2 - Emma: age 12 - Jeff: age 13.5 - Jo: age 22 - Julia: age 0.6 - Xavier: age 0 - ",
|
|
|
582 |
"{{for mypeople sort='name'}}");
|
|
|
583 |
assert.equal($.templates("{{for mypeople sort='details.age'}}{{:name}}: age {{:details.age}} - {{/for}}").render({mypeople: mypeople}), "Xavier: age 0 - Julia: age 0.6 - Bob: age 2 - Emma: age 12 - Jeff: age 13.5 - Jo: age 22 - ",
|
|
|
584 |
"{{for mypeople sort='details.age'}}");
|
|
|
585 |
|
|
|
586 |
assert.equal($.templates("{{for mypeople sort='details.age' reverse=true filter=~underLimit limit=20}}{{:name}}: age {{:details.age}} - {{/for}}").render({mypeople: mypeople}, {underLimit: underLimit}), "Jeff: age 13.5 - Emma: age 12 - Bob: age 2 - Julia: age 0.6 - Xavier: age 0 - ",
|
|
|
587 |
"{{for mypeople sort='details.age' reverse=true filter=~underLimit...}}");
|
|
|
588 |
assert.equal($.templates("{{for mypeople sort='details.age' reverse=true filter=~underLimit limit=20 start=1 end=-1}}{{:name}}: age {{:details.age}} - {{/for}}").render({mypeople: mypeople}, {underLimit: underLimit}), "Emma: age 12 - Bob: age 2 - Julia: age 0.6 - ",
|
|
|
589 |
"{{for mypeople sort='details.age' reverse=true filter=~underLimit... start=1 end=-1}}");
|
|
|
590 |
assert.equal($.templates("{{for mypeople sort='details.age' reverse=true filter=~underLimit limit=20 start=1 end=-1}}{{:name}}: age {{:details.age}} - {{/for}}").render({mypeople: mypeople}, {underLimit: underLimit}), "Emma: age 12 - Bob: age 2 - Julia: age 0.6 - ",
|
|
|
591 |
"{{for mypeople sort='details.age' reverse=true filter=~underLimit... start=1 end=-1}}");
|
|
|
592 |
|
|
|
593 |
// =============================== Arrange ===============================
|
|
|
594 |
|
|
|
595 |
var mypeople2 = [
|
|
|
596 |
{name: "Bill", details: {age: 22, role: "Lead"}},
|
|
|
597 |
{name: "Anne", details: {age: 32, role: "Assistant"}},
|
|
|
598 |
{name: "Emma", details: {age: 19.1, role: "Team member"}},
|
|
|
599 |
{name: "Jeff", details: {age: 33.5, role: "Lead"}},
|
|
|
600 |
{name: "Xavier", details: {age: 32, role: "Team member"}},
|
|
|
601 |
{name: "Julia", details: {age: 18, role: "Assistant"}},
|
|
|
602 |
{name: "Bill", details: {age: 32, role: "Team member"}}
|
|
|
603 |
];
|
|
|
604 |
|
|
|
605 |
// ................................ Assert ..................................
|
|
|
606 |
|
|
|
607 |
assert.equal($.templates("{{for mypeople sort=~sortAgeName}}{{:name}}: ({{:details.role}}) age {{:details.age}} -{{/for}}").render({mypeople: mypeople2}, {sortAgeName: sortAgeName}),
|
|
|
608 |
"Julia: (Assistant) age 18 -Anne: (Assistant) age 32 -Bill: (Lead) age 22 -Jeff: (Lead) age 33.5 -Emma: (Team member) age 19.1 -Bill: (Team member) age 32 -Xavier: (Team member) age 32 -",
|
|
|
609 |
"{{for mypeople sort=~sortAgeName}}: custom sort function");
|
|
|
610 |
|
|
|
611 |
// ................................ Assert ..................................
|
|
|
612 |
|
|
|
613 |
assert.equal($.templates("{{for mypeople sort=~sortAgeName reverseAge=true}}{{:name}}: ({{:details.role}}) age {{:details.age}} -{{/for}}").render({mypeople: mypeople2}, {sortAgeName: sortAgeName}),
|
|
|
614 |
"Anne: (Assistant) age 32 -Julia: (Assistant) age 18 -Jeff: (Lead) age 33.5 -Bill: (Lead) age 22 -Bill: (Team member) age 32 -Xavier: (Team member) age 32 -Emma: (Team member) age 19.1 -",
|
|
|
615 |
"{{for mypeople sort=~sortAgeName}}: custom sort function - this pointer is tagCtx");
|
|
|
616 |
|
|
|
617 |
// ................................ Assert ..................................
|
|
|
618 |
|
|
|
619 |
assert.equal($.templates("{{for start=0 end=0}}{{else mypeople sort=~sortAgeName reverseAge=true}}{{:name}}: ({{:details.role}}) age {{:details.age}} -{{/for}}").render({mypeople: mypeople2}, {sortAgeName: sortAgeName}),
|
|
|
620 |
"Anne: (Assistant) age 32 -Julia: (Assistant) age 18 -Jeff: (Lead) age 33.5 -Bill: (Lead) age 22 -Bill: (Team member) age 32 -Xavier: (Team member) age 32 -Emma: (Team member) age 19.1 -",
|
|
|
621 |
"{{for start=0 end=0}}{{else mypeople sort=~sortAgeName}}: custom sort function - this pointer is tagCtx (else block)");
|
|
|
622 |
|
|
|
623 |
// =============================== Arrange ===============================
|
|
|
624 |
|
|
|
625 |
$.views.tags("for2", {
|
|
|
626 |
baseTag: "for"
|
|
|
627 |
});
|
|
|
628 |
|
|
|
629 |
// ................................ Assert ..................................
|
|
|
630 |
|
|
|
631 |
assert.equal($.templates("{{for2 mypeople sort='details.age' reverse=true filter=~underLimit limit=20 start=1 end=-1}}{{:name}}: age {{:details.age}} - {{/for2}}").render({mypeople: mypeople}, {underLimit: underLimit}), "Emma: age 12 - Bob: age 2 - Julia: age 0.6 - ",
|
|
|
632 |
"{{for2 mypeople sort='details.age' reverse=true filter=~underLimit... start=1 end=-1}} Derived tag");
|
|
|
633 |
});
|
|
|
634 |
|
|
|
635 |
QUnit.module("{{props}}");
|
|
|
636 |
QUnit.test("{{props}}", function(assert) {
|
|
|
637 |
$.templates({
|
|
|
638 |
propsTmpl: "header_{{props person}}Key: {{:key}} - Prop: {{:prop}}| {{/props}}_footer",
|
|
|
639 |
propsTmplObjectArray: "header_{{props people}}Key: {{:key}} - Prop: {{for prop}}{{:name}} {{/for}}{{/props}}_footer",
|
|
|
640 |
propsTmplPrimitivesArray: "header_{{props people}}Key: {{:key}} - Prop: {{for prop}}{{:name}} {{/for}}{{/props}}_footer",
|
|
|
641 |
templatePropsArray: "header_{{props #data}}Key: {{:key}} - Prop: {{for prop}}{{:name}} {{/for}}{{/props}}_footer",
|
|
|
642 |
propTmpl: "Key: {{:key}} - Prop: {{:prop}}",
|
|
|
643 |
pageTmpl: '{{props person tmpl="propTmpl"/}}',
|
|
|
644 |
simpleProps: "a{{props people}}Content{{:#data}}|{{/props}}b",
|
|
|
645 |
propsPrimitiveDataTypes: "a{{props people}}|{{:#data}}{{/props}}b",
|
|
|
646 |
testTmpl: "xxx{{:name}} {{:~foo}}"
|
|
|
647 |
});
|
|
|
648 |
|
|
|
649 |
assert.equal($.render.propsTmpl({person: people[0]}), "header_Key: name - Prop: Jo| _footer", '{{props person}}...{{/props}} for an object iterates over properties');
|
|
|
650 |
assert.equal($.render.propsTmplObjectArray({people: people}), "header_Key: 0 - Prop: Jo Key: 1 - Prop: Bill _footer", '{{props people}}...{{/props}} for an array iterates over the array - with index as key and object a prop');
|
|
|
651 |
assert.equal($.render.templatePropsArray([people]), "header_Key: 0 - Prop: Jo Key: 1 - Prop: Bill _footer", 'Can render a template against an array, as a "layout template", by wrapping array in an array');
|
|
|
652 |
assert.equal($.render.pageTmpl({person: people[0]}), "Key: name - Prop: Jo", '{{props person tmpl="propTmpl"/}}');
|
|
|
653 |
assert.equal($.templates("{{props}}{{:key}} {{:prop}}{{/props}}").render({name: "Jeff"}), "name Jeff", "no parameter - defaults to current data item");
|
|
|
654 |
assert.equal($.templates("{{props foo}}xxx{{:key}} {{:prop}} {{:~foo}}{{/props}}").render({name: "Jeff"}), "", "undefined arg - renders nothing");
|
|
|
655 |
assert.equal($.templates("{{props tmpl='propTmpl'/}}").render({name: "Jeff"}), "Key: name - Prop: Jeff", ": {{props tmpl=.../}} no parameter - defaults to current data item");
|
|
|
656 |
|
|
|
657 |
assert.equal($.templates("{{props null}}Key: {{:key}} - Prop: {{:prop}}| {{/props}}").render(), "", "null - renders nothing");
|
|
|
658 |
assert.equal($.templates("{{props false}}Key: {{:key}} - Prop: {{:prop}}| {{/props}}").render(), "", "false - renders nothing");
|
|
|
659 |
assert.equal($.templates("{{props 0}}Key: {{:key}} - Prop: {{:prop}}| {{/props}}").render(), "", "0 - renders nothing");
|
|
|
660 |
assert.equal($.templates("{{props 'abc'}}Key: {{:key}} - Prop: {{:prop}}| {{/props}}").render(), "", "'abc' - renders nothing");
|
|
|
661 |
assert.equal($.templates("{{props ''}}Key: {{:key}} - Prop: {{:prop}}| {{/props}}").render(), "", "'' - renders nothing");
|
|
|
662 |
assert.equal($.templates("{{props #data}}Key: {{:key}} - Prop: {{:prop}}| {{/props}}").render(people),
|
|
|
663 |
"Key: name - Prop: Jo| Key: name - Prop: Bill| ",
|
|
|
664 |
"If #data is an array, {{props #data}} iterates");
|
|
|
665 |
|
|
|
666 |
assert.equal($.render.propsTmpl({person:{}}), "header__footer", 'Empty object renders empty string');
|
|
|
667 |
assert.equal($.render.propsTmpl({person:{zero: 0, one: 1, str: "abc", emptyStr: "", nullVal: null , trueVal: true , falseVal: false}}),
|
|
|
668 |
"header_Key: zero - Prop: 0| Key: one - Prop: 1| Key: str - Prop: abc| Key: emptyStr - Prop: | Key: nullVal - Prop: | Key: trueVal - Prop: true| Key: falseVal - Prop: false| _footer",
|
|
|
669 |
'Primitive types render correctly, even if falsey');
|
|
|
670 |
});
|
|
|
671 |
|
|
|
672 |
QUnit.test("{{props start end sort filter reverse}}", function(assert) {
|
|
|
673 |
// =============================== Arrange ===============================
|
|
|
674 |
function level(aField, bField) {
|
|
|
675 |
return aField > bField ? 1 : aField < bField ? -1 : 0;
|
|
|
676 |
}
|
|
|
677 |
|
|
|
678 |
var oddValue = function(item, index, items) { return item.prop%2; };
|
|
|
679 |
var oddIndex = function(item, index, items) { return index%2; };
|
|
|
680 |
var sortAgeName = function(a, b) {
|
|
|
681 |
return level(a.prop.details.role.toLowerCase(), b.prop.details.role.toLowerCase()) // First level sort: by role
|
|
|
682 |
|| (this.props.reverseAge ? level(b.prop.details.age, a.prop.details.age) : level(a.prop.details.age, b.prop.details.age)) // 2nd level sort: sort by age, or reverse sort by age
|
|
|
683 |
|| level(a.prop.name.toLowerCase(), b.prop.name.toLowerCase()); // 3rd level sort: sort by name
|
|
|
684 |
};
|
|
|
685 |
|
|
|
686 |
var underLimit = function(item, index, items) {
|
|
|
687 |
return item.prop.details.age < this.props.limit;
|
|
|
688 |
};
|
|
|
689 |
|
|
|
690 |
var myobject = {a: 1, b: 9, c: 2, d:8, A:3, B:7, C:4, D:6, e:5};
|
|
|
691 |
|
|
|
692 |
assert.equal($.templates("{{props myobject}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}), "a 1 - b 9 - c 2 - d 8 - A 3 - B 7 - C 4 - D 6 - e 5 - ", "{{props myobject}} (original order)");
|
|
|
693 |
assert.equal($.templates("{{props #data sort='prop'}}{{:key}} {{:prop}} - {{/props}}").render(myobject, true), "a 1 - c 2 - A 3 - C 4 - e 5 - D 6 - B 7 - d 8 - b 9 - ", "{{props #data sort='prop'}}");
|
|
|
694 |
assert.equal($.templates("{{props #data sort='key'}}{{:key}} {{:prop}} - {{/props}}").render(myobject, true), "a 1 - A 3 - b 9 - B 7 - c 2 - C 4 - d 8 - D 6 - e 5 - ", "{{props #data sort='key'}}");
|
|
|
695 |
assert.equal($.templates("{{props #data sort='prop' reverse=true}}{{:key}} {{:prop}} - {{/props}}").render(myobject, true), "b 9 - d 8 - B 7 - D 6 - e 5 - C 4 - A 3 - c 2 - a 1 - ", "{{props #data sort='prop' reverse=true}}");
|
|
|
696 |
assert.equal($.templates("{{props #data sort='key' reverse=true}}{{:key}} {{:prop}} - {{/props}}").render(myobject, true), "e 5 - d 8 - D 6 - c 2 - C 4 - b 9 - B 7 - a 1 - A 3 - ", "{{props #data sort='key' reverse=true}}");
|
|
|
697 |
assert.equal($.templates("{{props myobject reverse=true}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}), "e 5 - D 6 - C 4 - B 7 - A 3 - d 8 - c 2 - b 9 - a 1 - ", "{{props myobject reverse=true}}");
|
|
|
698 |
assert.equal($.templates("{{props myobject sort='key' reverse=true}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}), "e 5 - d 8 - D 6 - c 2 - C 4 - b 9 - B 7 - a 1 - A 3 - ", "{{props myobject sort='key' reverse=true}}");
|
|
|
699 |
assert.equal($.templates("{{props myobject start=1 end=-1}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "b 9 - c 2 - d 8 - A 3 - B 7 - C 4 - D 6 - ", "{{props myobject start=1 end=-1}}");
|
|
|
700 |
assert.equal($.templates("{{props myobject start=1}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "b 9 - c 2 - d 8 - A 3 - B 7 - C 4 - D 6 - e 5 - ", "{{props myobject start=1}}");
|
|
|
701 |
assert.equal($.templates("{{props myobject end=-1}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "a 1 - b 9 - c 2 - d 8 - A 3 - B 7 - C 4 - D 6 - ", "{{props myobject end=-1}}");
|
|
|
702 |
|
|
|
703 |
assert.equal($.templates("{{props myobject filter=~oddValue}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddValue: oddValue}), "a 1 - b 9 - A 3 - B 7 - e 5 - ", "{{props myobject filter=~oddValue}}");
|
|
|
704 |
assert.equal($.templates("{{props myobject filter=~oddIndex}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "b 9 - d 8 - B 7 - D 6 - ", "{{props myobject filter=~oddIndex}}");
|
|
|
705 |
assert.equal($.templates("{{props myobject sort='prop' filter=~oddValue}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddValue: oddValue}), "a 1 - A 3 - e 5 - B 7 - b 9 - ", "{{props myobject sort='prop' filter=~oddValue}}");
|
|
|
706 |
assert.equal($.templates("{{props myobject sort='prop' filter=~oddIndex}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "c 2 - C 4 - D 6 - d 8 - ", "{{props myobject sort='prop' filter=~oddIndex}}");
|
|
|
707 |
assert.equal($.templates("{{props myobject sort='prop' filter=~oddIndex start=1 end=3}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "C 4 - D 6 - ", "{{props myobject sort='prop' filter=~oddIndex start=1 end=3}}");
|
|
|
708 |
assert.equal($.templates("{{props myobject sort='prop' filter=~oddIndex start=-3 end=-1}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "C 4 - D 6 - ", "{{props myobject sort='prop' filter=~oddIndex start=-3 end=-1}} Negative start or end count from the end");
|
|
|
709 |
assert.equal($.templates("{{props myobject sort='prop' filter=~oddIndex start=3 end=3}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "", "{{props myobject sort='key' filter=~oddIndex start=3 end=3}} (outputs nothing)");
|
|
|
710 |
|
|
|
711 |
assert.equal($.templates("{{props myobject step=2 start=1}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "b 9 - d 8 - B 7 - D 6 - ", "{{props myobject step=2 start=1}}");
|
|
|
712 |
assert.equal($.templates("{{props myobject sort='prop' step=2 start=1}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "c 2 - C 4 - D 6 - d 8 - ", "{{props myobject sort='prop' step=2 start=1}}");
|
|
|
713 |
assert.equal($.templates("{{props myobject sort='prop' step=2 start=3 end=6}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "C 4 - D 6 - ", "{{props myobject sort='prop' step=2 start=3 end=6}}");
|
|
|
714 |
assert.equal($.templates("{{props myobject sort='prop' step=2 start=-6 end=-3}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "C 4 - D 6 - ", "{{props myobject sort='prop' step=2 start=-6 end=-3}} Negative start or end count from the end");
|
|
|
715 |
assert.equal($.templates("{{props myobject sort='prop' step=2 start=3 end=3}}{{:key}} {{:prop}} - {{/props}}").render({myobject: myobject}, {oddIndex: oddIndex}), "", "{{props myobject sort='key' step=2 start=3 end=3}} (outputs nothing)");
|
|
|
716 |
// =============================== Arrange ===============================
|
|
|
717 |
|
|
|
718 |
var mypeople = {
|
|
|
719 |
p1: {name: "Jo", details: {age: 22}},
|
|
|
720 |
p2: {name: "Bob", details: {age: 2}},
|
|
|
721 |
p3: {name: "Emma", details: {age: 12}},
|
|
|
722 |
p7: {name: "Jeff", details: {age: 13.5}},
|
|
|
723 |
p6: {name: "Julia", details: {age: 0.6}},
|
|
|
724 |
p5: {name: "Xavier", details: {age: 0}}
|
|
|
725 |
};
|
|
|
726 |
|
|
|
727 |
// ................................ Assert ..................................
|
|
|
728 |
|
|
|
729 |
assert.equal($.templates("{{props mypeople sort='prop.name'}}{{:prop.name}}: age {{:prop.details.age}} - {{/props}}").render({mypeople: mypeople}), "Bob: age 2 - Emma: age 12 - Jeff: age 13.5 - Jo: age 22 - Julia: age 0.6 - Xavier: age 0 - ", "{{props mypeople sort='name'}}");
|
|
|
730 |
assert.equal($.templates("{{props mypeople sort='prop.details.age'}}{{:prop.name}}: age {{:prop.details.age}} - {{/props}}").render({mypeople: mypeople}), "Xavier: age 0 - Julia: age 0.6 - Bob: age 2 - Emma: age 12 - Jeff: age 13.5 - Jo: age 22 - ", "{{props mypeople sort='details.age'}}");
|
|
|
731 |
|
|
|
732 |
assert.equal($.templates("{{props mypeople sort='prop.details.age' reverse=true filter=~underLimit limit=20}}{{:prop.name}}: age {{:prop.details.age}} - {{/props}}").render({mypeople: mypeople}, {underLimit: underLimit}), "Jeff: age 13.5 - Emma: age 12 - Bob: age 2 - Julia: age 0.6 - Xavier: age 0 - ", "{{props mypeople sort='details.age' reverse=true filter=~underLimit...}}");
|
|
|
733 |
assert.equal($.templates("{{props mypeople sort='prop.details.age' reverse=true filter=~underLimit limit=20 start=1 end=-1}}{{:prop.name}}: age {{:prop.details.age}} - {{/props}}").render({mypeople: mypeople}, {underLimit: underLimit}), "Emma: age 12 - Bob: age 2 - Julia: age 0.6 - ", "{{props mypeople sort='details.age' reverse=true filter=~underLimit... start=1 end=-1}}");
|
|
|
734 |
assert.equal($.templates("{{props mypeople sort='prop.details.age' reverse=true filter=~underLimit limit=20 start=1 end=-1}}{{:prop.name}}: age {{:prop.details.age}} - {{/props}}").render({mypeople: mypeople}, {underLimit: underLimit}), "Emma: age 12 - Bob: age 2 - Julia: age 0.6 - ", "{{props mypeople sort='details.age' reverse=true filter=~underLimit... start=1 end=-1}}");
|
|
|
735 |
|
|
|
736 |
// =============================== Arrange ===============================
|
|
|
737 |
|
|
|
738 |
var mypeople2 = {
|
|
|
739 |
p1: {name: "Bill", details: {age: 22, role: "Lead"}},
|
|
|
740 |
p2: {name: "Anne", details: {age: 32, role: "Assistant"}},
|
|
|
741 |
p3: {name: "Emma", details: {age: 19.1, role: "Team member"}},
|
|
|
742 |
p7: {name: "Jeff", details: {age: 33.5, role: "Lead"}},
|
|
|
743 |
p6: {name: "Xavier", details: {age: 32, role: "Team member"}},
|
|
|
744 |
p5: {name: "Julia", details: {age: 18, role: "Assistant"}},
|
|
|
745 |
p4: {name: "Bill", details: {age: 32, role: "Team member"}}
|
|
|
746 |
};
|
|
|
747 |
|
|
|
748 |
// ................................ Assert ..................................
|
|
|
749 |
|
|
|
750 |
assert.equal($.templates("{{props mypeople sort=~sortAgeName}}{{:prop.name}}: ({{:prop.details.role}}) age {{:prop.details.age}} - {{/props}}").render({mypeople: mypeople2}, {sortAgeName: sortAgeName}),
|
|
|
751 |
"Julia: (Assistant) age 18 - Anne: (Assistant) age 32 - Bill: (Lead) age 22 - Jeff: (Lead) age 33.5 - Emma: (Team member) age 19.1 - Bill: (Team member) age 32 - Xavier: (Team member) age 32 - ",
|
|
|
752 |
"{{props mypeople sort=~sortAgeName}}: custom sort function");
|
|
|
753 |
|
|
|
754 |
// ................................ Assert ..................................
|
|
|
755 |
|
|
|
756 |
assert.equal($.templates("{{props mypeople sort=~sortAgeName reverseAge=true}}{{:prop.name}}: ({{:prop.details.role}}) age {{:prop.details.age}} - {{/props}}").render({mypeople: mypeople2}, {sortAgeName: sortAgeName}),
|
|
|
757 |
"Anne: (Assistant) age 32 - Julia: (Assistant) age 18 - Jeff: (Lead) age 33.5 - Bill: (Lead) age 22 - Bill: (Team member) age 32 - Xavier: (Team member) age 32 - Emma: (Team member) age 19.1 - ",
|
|
|
758 |
"{{props mypeople sort=~sortAgeName}}: custom sort function - this pointer is tagCtx");
|
|
|
759 |
|
|
|
760 |
// ................................ Assert ..................................
|
|
|
761 |
|
|
|
762 |
assert.equal($.templates("{{props ''}}{{else mypeople sort=~sortAgeName reverseAge=true}}{{:prop.name}}: ({{:prop.details.role}}) age {{:prop.details.age}} - {{/props}}").render({mypeople: mypeople2}, {sortAgeName: sortAgeName}),
|
|
|
763 |
"Anne: (Assistant) age 32 - Julia: (Assistant) age 18 - Jeff: (Lead) age 33.5 - Bill: (Lead) age 22 - Bill: (Team member) age 32 - Xavier: (Team member) age 32 - Emma: (Team member) age 19.1 - ",
|
|
|
764 |
"{{props ''}}{{else mypeople sort=~sortAgeName}}: custom sort function - this pointer is tagCtx (else block)");
|
|
|
765 |
|
|
|
766 |
// =============================== Arrange ===============================
|
|
|
767 |
|
|
|
768 |
$.views.tags("props2", {
|
|
|
769 |
baseTag: "props"
|
|
|
770 |
});
|
|
|
771 |
|
|
|
772 |
// ................................ Assert ..................................
|
|
|
773 |
|
|
|
774 |
assert.equal($.templates("{{props2 mypeople sort='prop.details.age' reverse=true filter=~underLimit limit=20 start=1 end=-1}}{{:prop.name}}: age {{:prop.details.age}} - {{/props2}}").render({mypeople: mypeople}, {underLimit: underLimit}), "Emma: age 12 - Bob: age 2 - Julia: age 0.6 - ", "{{for2 mypeople sort='details.age' reverse=true filter=~underLimit... start=1 end=-1}} Derived tag");
|
|
|
775 |
});
|
|
|
776 |
|
|
|
777 |
QUnit.module("{{!-- --}}");
|
|
|
778 |
QUnit.test("{{!-- --}}", function(assert) {
|
|
|
779 |
// =============================== Arrange ===============================
|
|
|
780 |
var result,
|
|
|
781 |
tmpl = $.templates("a {{:'--1'}}\n {{for '--2} }'}} {{:}} {{/for}} \n b"),
|
|
|
782 |
tmplWrappedInComment = $.templates("a {{!-- {{:'--1'}}\n {{for '--2} }'}} {{:}} {{/for}} \n--}} b");
|
|
|
783 |
|
|
|
784 |
// ................................ Assert ..................................
|
|
|
785 |
result = tmpl.render() + "|" + tmplWrappedInComment.render();
|
|
|
786 |
assert.equal(result, "a --1\n --2} } \n b|a b",
|
|
|
787 |
"{{!-- --}} comments out blocks including newlines and --");
|
|
|
788 |
});
|
|
|
789 |
|
|
|
790 |
QUnit.module("allowCode");
|
|
|
791 |
QUnit.test("{{*}}", function(assert) {
|
|
|
792 |
// =============================== Arrange ===============================
|
|
|
793 |
$.views.settings.allowCode(false);
|
|
|
794 |
global.glob = {a: "AA"};
|
|
|
795 |
|
|
|
796 |
var tmpl = $.templates("_{{*:glob.a}}_");
|
|
|
797 |
|
|
|
798 |
// ................................ Assert ..................................
|
|
|
799 |
assert.equal(tmpl.render(), "__",
|
|
|
800 |
"{{*:expression}} returns nothing if allowCode not set to true");
|
|
|
801 |
|
|
|
802 |
// =============================== Arrange ===============================
|
|
|
803 |
$.views.settings.allowCode(true);
|
|
|
804 |
|
|
|
805 |
var result = "" + !!tmpl.allowCode + " " + tmpl.render(); // Still returns "__" until we recompile
|
|
|
806 |
|
|
|
807 |
tmpl.allowCode = true;
|
|
|
808 |
|
|
|
809 |
result += "|" + !!tmpl.allowCode + " " + tmpl.render(); // Still returns "__" until we recompile
|
|
|
810 |
|
|
|
811 |
// ................................ Assert ..................................
|
|
|
812 |
assert.equal(result, "false __|true __",
|
|
|
813 |
"If $.settings.allowCode() or tmpl.allowCode are set to true, previously compiled template is unchanged, so {{*}} still inactive");
|
|
|
814 |
|
|
|
815 |
// ................................ Act ..................................
|
|
|
816 |
tmpl = $.templates("_{{*:glob.a}}_");
|
|
|
817 |
|
|
|
818 |
result = "" + !!tmpl.allowCode + " " + tmpl.render(); // Now {{*}} is active
|
|
|
819 |
|
|
|
820 |
// ................................ Assert ..................................
|
|
|
821 |
assert.equal(result, "true _AA_",
|
|
|
822 |
"If $.settings.allowCode() set to true, {{*: expression}} returns evaluated expression, with access to globals");
|
|
|
823 |
|
|
|
824 |
// =============================== Arrange ===============================
|
|
|
825 |
$.views.settings.allowCode(false);
|
|
|
826 |
|
|
|
827 |
tmpl = $.templates({
|
|
|
828 |
markup: "_{{*:glob.a}}_",
|
|
|
829 |
allowCode: true
|
|
|
830 |
});
|
|
|
831 |
|
|
|
832 |
// ................................ Assert ..................................
|
|
|
833 |
assert.equal(tmpl.render(), "_AA_",
|
|
|
834 |
"If template allowCode property set to true, {{*: expression}} returns evaluated expression, with access to globals");
|
|
|
835 |
|
|
|
836 |
// ................................ Act ..................................
|
|
|
837 |
tmpl = $.templates({
|
|
|
838 |
markup: "_{{*:glob.a}}_"
|
|
|
839 |
});
|
|
|
840 |
|
|
|
841 |
result = "" + !!tmpl.allowCode + ":" + tmpl();
|
|
|
842 |
|
|
|
843 |
tmpl = $.templates({markup: tmpl, allowCode: true});
|
|
|
844 |
|
|
|
845 |
result += "|" + tmpl.allowCode + ":" + tmpl();
|
|
|
846 |
|
|
|
847 |
// ................................ Assert ..................................
|
|
|
848 |
assert.equal(result, "false:__|true:_AA_",
|
|
|
849 |
"Can recompile tmpl to allow code, using tmpl = $.templates({markup: tmpl, allowCode: true})");
|
|
|
850 |
|
|
|
851 |
// ................................ Act ..................................
|
|
|
852 |
$.templates("myTmpl", {
|
|
|
853 |
markup: "_{{*:glob.a}}_"
|
|
|
854 |
});
|
|
|
855 |
|
|
|
856 |
tmpl = $.templates.myTmpl;
|
|
|
857 |
|
|
|
858 |
result = "" + !!tmpl.allowCode + ":" + tmpl();
|
|
|
859 |
|
|
|
860 |
$.templates("myTmpl", {markup: $.templates.myTmpl, allowCode: true});
|
|
|
861 |
|
|
|
862 |
tmpl = $.templates.myTmpl;
|
|
|
863 |
|
|
|
864 |
result += "|" + tmpl.allowCode + ":" + tmpl();
|
|
|
865 |
|
|
|
866 |
// ................................ Assert ..................................
|
|
|
867 |
assert.equal(result, "false:__|true:_AA_",
|
|
|
868 |
'Can recompile named tmpl to allow code, using $.templates("myTemplateName", {markup: $.templates.myTmpl, allowCode:true})"');
|
|
|
869 |
|
|
|
870 |
// =============================== Arrange ===============================
|
|
|
871 |
$.views.settings.allowCode(true);
|
|
|
872 |
|
|
|
873 |
// ................................ Act ..................................
|
|
|
874 |
global.myVar = 0;
|
|
|
875 |
|
|
|
876 |
tmpl = $.templates(
|
|
|
877 |
"{{* myvar=2; myvar+=4; }}"
|
|
|
878 |
+ "Initial value: {{*:myvar}} "
|
|
|
879 |
+ "{{* myvar+=11; }}"
|
|
|
880 |
+ "New value: {{*:myvar}}");
|
|
|
881 |
|
|
|
882 |
// ................................ Assert ..................................
|
|
|
883 |
assert.equal(tmpl.render(), "Initial value: 6 New value: 17",
|
|
|
884 |
"{{* expression}} or {{*: expression}} can access globals as window.myVar or myVar");
|
|
|
885 |
|
|
|
886 |
// ................................ Act ..................................
|
|
|
887 |
global.people = people;
|
|
|
888 |
tmpl = $.templates("{{:start}}"
|
|
|
889 |
|
|
|
890 |
+ "{{* for (var i=0, l=people.length; i<l; i++) { }}"
|
|
|
891 |
+ " {{:title}} = {{*: people[i].name + ' ' + data.sep + ' '}}!"
|
|
|
892 |
+ "{{* } }}"
|
|
|
893 |
|
|
|
894 |
+ "{{:end}}");
|
|
|
895 |
|
|
|
896 |
// ................................ Assert ..................................
|
|
|
897 |
assert.equal(tmpl.render({title: "name", start: "Start", end: "End", sep: "..."}), "Start name = Jo ... ! name = Bill ... !End",
|
|
|
898 |
"If allowCode set to true, on recompiling the template, {{*:expression}} returns evaluated expression, with access to globals");
|
|
|
899 |
|
|
|
900 |
// ................................ Act ..................................
|
|
|
901 |
global.myFunction = function() {
|
|
|
902 |
return "myGlobalfunction ";
|
|
|
903 |
};
|
|
|
904 |
document.title = "myTitle";
|
|
|
905 |
tmpl = $.templates("{{for people}}"
|
|
|
906 |
+ "{{*: ' ' + glob.a}} {{*: data.name}} {{*: view.index}} {{*: view.ctx.myHelper}} {{*: myFunction() + document.title}}"
|
|
|
907 |
+ "{{/for}}");
|
|
|
908 |
|
|
|
909 |
// ................................ Assert ..................................
|
|
|
910 |
assert.equal(tmpl.render({people: people}, {myHelper: "hi"}), " AA Jo 0 hi myGlobalfunction myTitle AA Bill 1 hi myGlobalfunction myTitle",
|
|
|
911 |
"{{* expression}} or {{*: expression}} can access globals, the data, the view, the view context, global functions etc.");
|
|
|
912 |
|
|
|
913 |
document.title = "";
|
|
|
914 |
|
|
|
915 |
$.views.settings.allowCode(false);
|
|
|
916 |
|
|
|
917 |
});
|
|
|
918 |
|
|
|
919 |
QUnit.module("useViews");
|
|
|
920 |
QUnit.test("", function(assert) {
|
|
|
921 |
|
|
|
922 |
// =============================== Arrange ===============================
|
|
|
923 |
$.views.settings.allowCode(true);
|
|
|
924 |
$.views.tags("exclaim", "!!! ");
|
|
|
925 |
var message = "",
|
|
|
926 |
|
|
|
927 |
tmpl = $.templates(
|
|
|
928 |
"{{for towns}}"
|
|
|
929 |
+ "{{>name}}"
|
|
|
930 |
+ "{{*:view.index===view.parent.data.length-2 ? ' and ' : view.index<view.parent.data.length-2 ? ', ': ''}}"
|
|
|
931 |
+ "{{/for}}");
|
|
|
932 |
|
|
|
933 |
// ................................ Act ..................................
|
|
|
934 |
try {
|
|
|
935 |
tmpl.render({towns: towns});
|
|
|
936 |
} catch(e) {
|
|
|
937 |
message = e.message;
|
|
|
938 |
}
|
|
|
939 |
|
|
|
940 |
// ................................ Assert ..................................
|
|
|
941 |
assert.ok(!tmpl.useViews && message.indexOf("undefined") > 0,
|
|
|
942 |
"A simple template with useViews=false will not provide access to the views through allowCode");
|
|
|
943 |
|
|
|
944 |
// ................................ Act ..................................
|
|
|
945 |
message = "";
|
|
|
946 |
tmpl.useViews = true;
|
|
|
947 |
|
|
|
948 |
// ................................ Assert ..................................
|
|
|
949 |
assert.equal(tmpl.render({towns: towns}), "Seattle, Paris and Delhi",
|
|
|
950 |
"If tmpl.useViews set to true (for an existing template - without recompiling), the template renders with view hierarchy");
|
|
|
951 |
|
|
|
952 |
// ................................ Act ..................................
|
|
|
953 |
tmpl.useViews = false;
|
|
|
954 |
|
|
|
955 |
$.views.settings.advanced({useViews: true});
|
|
|
956 |
// ................................ Assert ..................................
|
|
|
957 |
assert.equal(tmpl.render({towns: towns}), "Seattle, Paris and Delhi",
|
|
|
958 |
"If tmpl.useViews is set to false, but $.views.settings.advanced({useViews: ...}) is set to true, the template renders with view hierarchy, (without recompiling).");
|
|
|
959 |
|
|
|
960 |
// ................................ Act ..................................
|
|
|
961 |
$.views.settings.advanced({useViews: false});
|
|
|
962 |
|
|
|
963 |
tmpl = $.templates({markup: tmpl,
|
|
|
964 |
useViews: true
|
|
|
965 |
});
|
|
|
966 |
|
|
|
967 |
// ................................ Assert ..................................
|
|
|
968 |
tmpl = $.templates(
|
|
|
969 |
"{{:#type}} "
|
|
|
970 |
+ "{{for towns}}"
|
|
|
971 |
+ "{{>name}}"
|
|
|
972 |
+ "{{*:view.index===view.parent.data.length-2 ? ' and ' : view.index<view.parent.data.length-2 ? ', ': ''}}"
|
|
|
973 |
+ "{{/for}}");
|
|
|
974 |
|
|
|
975 |
var html = tmpl.render({towns: towns});
|
|
|
976 |
|
|
|
977 |
assert.equal(tmpl.useViews && html, "data Seattle, Paris and Delhi",
|
|
|
978 |
"Recompiling the template with useViews: true will create a template that has tmpl.useViews = true, which renders with a 'data' view");
|
|
|
979 |
|
|
|
980 |
// ................................ Act ..................................
|
|
|
981 |
tmpl.useViews = false;
|
|
|
982 |
|
|
|
983 |
html = tmpl.render({towns: towns});
|
|
|
984 |
|
|
|
985 |
// ................................ Assert ..................................
|
|
|
986 |
assert.equal(!tmpl.useViews && html, "top Seattle, Paris and Delhi",
|
|
|
987 |
"If tmpl.useViews set to false (for an existing template - without recompiling), the template renders without a 'data' view");
|
|
|
988 |
|
|
|
989 |
// ................................ Act ..................................
|
|
|
990 |
$.views.settings.advanced({useViews: true});
|
|
|
991 |
|
|
|
992 |
tmpl = $.templates({markup: tmpl});
|
|
|
993 |
|
|
|
994 |
$.views.settings.advanced({useViews: false});
|
|
|
995 |
|
|
|
996 |
// ................................ Assert ..................................
|
|
|
997 |
assert.equal(tmpl.useViews && tmpl.render({towns: towns}), "data Seattle, Paris and Delhi",
|
|
|
998 |
"If $.views.settings.advanced({useViews: ...}) was true when the template was compiled, then the template renders with views, even if $.views.settings.advanced({useViews: ...}) is no longer set to true");
|
|
|
999 |
|
|
|
1000 |
// =============================== Arrange ===============================
|
|
|
1001 |
$.views.settings.advanced({useViews: false});
|
|
|
1002 |
|
|
|
1003 |
tmpl = $.templates(
|
|
|
1004 |
"{{exclaim/}}"
|
|
|
1005 |
+ "{{for towns}}"
|
|
|
1006 |
+ "{{>name}}"
|
|
|
1007 |
+ "{{*:view.index===view.parent.data.length-2 ? ' and ' : view.index<view.parent.data.length-2 ? ', ': ''}}"
|
|
|
1008 |
+ "{{/for}}");
|
|
|
1009 |
|
|
|
1010 |
// ................................ Assert ..................................
|
|
|
1011 |
assert.equal(tmpl.useViews && tmpl.render({towns: towns}), "!!! Seattle, Paris and Delhi",
|
|
|
1012 |
"A template with richer features, (such as a custom tag, or nested tags) will automatically have tmpl.useViews=true and will render with views, even if $.views.settings.advanced({useViews: ...}) is set to false");
|
|
|
1013 |
|
|
|
1014 |
// ................................ Act ..................................
|
|
|
1015 |
var originalUseViews = tmpl.useViews;
|
|
|
1016 |
tmpl.useViews = false;
|
|
|
1017 |
|
|
|
1018 |
// ................................ Assert ..................................
|
|
|
1019 |
assert.equal(originalUseViews && !tmpl.useViews && tmpl.render({towns: towns}), "!!! Seattle, Paris and Delhi",
|
|
|
1020 |
"Setting tmpl.useViews=false will NOT prevent a richer template from rendering views.");
|
|
|
1021 |
|
|
|
1022 |
// =============================== Arrange ===============================
|
|
|
1023 |
tmpl = $.templates(
|
|
|
1024 |
"{{for towns}}"
|
|
|
1025 |
+ "{{>name}}"
|
|
|
1026 |
+ "{{*:view.index===view.parent.data.length-2 ? ' and ' : view.index<view.parent.data.length-2 ? ', ': ''}}"
|
|
|
1027 |
+ "{{/for}}");
|
|
|
1028 |
|
|
|
1029 |
// ................................ Act ..................................
|
|
|
1030 |
originalUseViews = tmpl.useViews;
|
|
|
1031 |
tmpl.useViews = true;
|
|
|
1032 |
|
|
|
1033 |
// ................................ Assert ..................................
|
|
|
1034 |
assert.equal(!originalUseViews && tmpl.useViews && tmpl.render({towns: towns}), "Seattle, Paris and Delhi",
|
|
|
1035 |
"Setting tmpl.useViews=true WILL prevent a simpler template from rendering without views.");
|
|
|
1036 |
|
|
|
1037 |
// ................................ Act ..................................
|
|
|
1038 |
tmpl.useViews = originalUseViews;
|
|
|
1039 |
$.views.settings.advanced({useViews: true});
|
|
|
1040 |
|
|
|
1041 |
// ................................ Assert ..................................
|
|
|
1042 |
assert.equal(!tmpl.useViews && tmpl.render({towns: towns}), "Seattle, Paris and Delhi",
|
|
|
1043 |
"Setting $.views.settings.advanced({useViews: true}) WILL prevent a simpler template from rendering without views.");
|
|
|
1044 |
|
|
|
1045 |
// =========================== Reset settings ============================
|
|
|
1046 |
$.views.settings.advanced({useViews: false});
|
|
|
1047 |
$.views.settings.allowCode(false);
|
|
|
1048 |
document.title = "";
|
|
|
1049 |
|
|
|
1050 |
// =============================== Arrange ===============================
|
|
|
1051 |
tmpl = $.templates("{{:a.getHtml()}} {{if true}}{{:b}} {{/if}}");
|
|
|
1052 |
var innerTmpl = $.templates("{{:inner}}"),
|
|
|
1053 |
|
|
|
1054 |
data = {
|
|
|
1055 |
a: {
|
|
|
1056 |
getHtml: function() {
|
|
|
1057 |
return $.templates("{{:inner}}").render(this);
|
|
|
1058 |
},
|
|
|
1059 |
inner: "INNER"
|
|
|
1060 |
},
|
|
|
1061 |
b: "OUTER"
|
|
|
1062 |
};
|
|
|
1063 |
|
|
|
1064 |
// ................................ Act ..................................
|
|
|
1065 |
html = tmpl.render(data);
|
|
|
1066 |
|
|
|
1067 |
// ................................ Assert ..................................
|
|
|
1068 |
assert.equal(!tmpl.useViews && !innerTmpl.useViews && html, "INNER OUTER ",
|
|
|
1069 |
"Nested top-level programmatic template calls which do not use views work correctly");
|
|
|
1070 |
// See https://github.com/BorisMoore/jsrender/issues/333
|
|
|
1071 |
|
|
|
1072 |
// ................................ Act ..................................
|
|
|
1073 |
tmpl = $.templates({
|
|
|
1074 |
markup: "{{:a.getHtml()}} {{if true}}{{:b}} {{/if}}",
|
|
|
1075 |
useViews: true
|
|
|
1076 |
});
|
|
|
1077 |
innerTmpl = $.templates({
|
|
|
1078 |
markup: "{{:inner}}",
|
|
|
1079 |
useViews: true
|
|
|
1080 |
});
|
|
|
1081 |
html = tmpl.render(data);
|
|
|
1082 |
|
|
|
1083 |
// ................................ Assert ..................................
|
|
|
1084 |
assert.equal(tmpl.useViews && innerTmpl.useViews && html, "INNER OUTER ",
|
|
|
1085 |
"Nested top-level programmatic template calls using views work correctly");
|
|
|
1086 |
// See https://github.com/BorisMoore/jsrender/issues/333
|
|
|
1087 |
|
|
|
1088 |
});
|
|
|
1089 |
|
|
|
1090 |
QUnit.module("All tags");
|
|
|
1091 |
QUnit.test("itemVar", function(assert) {
|
|
|
1092 |
var otherPeople = [
|
|
|
1093 |
{name: "Jo", otherTels: [1, 2]},
|
|
|
1094 |
{name: "Bill", tels: [91,92]},
|
|
|
1095 |
{name: "Fred"}
|
|
|
1096 |
];
|
|
|
1097 |
var message = "";
|
|
|
1098 |
try {
|
|
|
1099 |
$.templates(
|
|
|
1100 |
"{{for people itemVar='person'}}"
|
|
|
1101 |
+ "{{:~person.name}} "
|
|
|
1102 |
+ "{{/for}}"
|
|
|
1103 |
).render({people: people});
|
|
|
1104 |
} catch(e) {
|
|
|
1105 |
message = e.message;
|
|
|
1106 |
}
|
|
|
1107 |
|
|
|
1108 |
assert.equal(message, "Syntax error\nUse itemVar='~myItem'",
|
|
|
1109 |
"Setting itemVar='something' without initial '~' throws syntax error");
|
|
|
1110 |
|
|
|
1111 |
assert.equal($.templates(
|
|
|
1112 |
"{{for people itemVar='~person'}}"
|
|
|
1113 |
+ "{{:~person.name}} "
|
|
|
1114 |
+ "{{/for}}"
|
|
|
1115 |
).render({people: people}),
|
|
|
1116 |
"Jo Bill ",
|
|
|
1117 |
"Setting {{for people itemVar='~person'}} creates ~person contextual parameter");
|
|
|
1118 |
|
|
|
1119 |
assert.equal($.templates(
|
|
|
1120 |
"{{for people}}"
|
|
|
1121 |
+ "{{:name}}"
|
|
|
1122 |
+ "{{else others itemVar='~otherPerson'}}"
|
|
|
1123 |
+ "{{:~otherPerson.name}} "
|
|
|
1124 |
+ "{{/for}}"
|
|
|
1125 |
).render({others: people}),
|
|
|
1126 |
"Jo Bill ",
|
|
|
1127 |
"Can use itemVar on {{for}}{{else}} too: {{else others itemVar='~otherPerson'}}");
|
|
|
1128 |
|
|
|
1129 |
assert.equal($.templates(
|
|
|
1130 |
"{{for people}}"
|
|
|
1131 |
+ "{{if tels itemVar='~person'}}"
|
|
|
1132 |
+ "{{:name}} {{:~person.name}} "
|
|
|
1133 |
+ "{{else otherTels itemVar='~sameperson'}}"
|
|
|
1134 |
+ "{{:~sameperson.name}} "
|
|
|
1135 |
+ "{{else itemVar='~stillperson'}}"
|
|
|
1136 |
+ "{{:~stillperson.name}} "
|
|
|
1137 |
+ "{{/if}}"
|
|
|
1138 |
+ "{{/for}}"
|
|
|
1139 |
).render({people: otherPeople}),
|
|
|
1140 |
"Jo Bill Bill Fred ",
|
|
|
1141 |
"itemVar works also on {{if}}{{else}}{{/if}} even though the context is same as outer context for {{if}}.");
|
|
|
1142 |
|
|
|
1143 |
assert.equal($.templates(
|
|
|
1144 |
"{{for people itemVar='~person'}}"
|
|
|
1145 |
+ "{{for tels itemVar='~tel'}}"
|
|
|
1146 |
+ "{{:~person.name}} "
|
|
|
1147 |
+ "{{:~tel}} "
|
|
|
1148 |
+ "{{else otherTels itemVar='~othertel'}}"
|
|
|
1149 |
+ "{{:~person.name}} "
|
|
|
1150 |
+ "{{:~othertel}} "
|
|
|
1151 |
+ "{{else itemVar='~theperson'}}"
|
|
|
1152 |
+ "{{:~theperson===~person&&~person===#data}} "
|
|
|
1153 |
+ "{{:~theperson.name}} "
|
|
|
1154 |
+ "no phones"
|
|
|
1155 |
+ "{{/for}}"
|
|
|
1156 |
+ "{{/for}}"
|
|
|
1157 |
).render({people: otherPeople}),
|
|
|
1158 |
"Jo 1 Jo 2 Bill 91 Bill 92 true Fred no phones",
|
|
|
1159 |
"itemVar works also on {{for arr1}}{{else arr2}}{{else}}{{/for}}" +
|
|
|
1160 |
"\neven though the context for the final {{else}} is the same as outer context for {{if}}.");
|
|
|
1161 |
|
|
|
1162 |
assert.equal($.templates(
|
|
|
1163 |
"{{for people itemVar='~person'}}"
|
|
|
1164 |
+ "{{:~person.name}}"
|
|
|
1165 |
+ "{{if ~person.tels itemVar='~ifVar'}}"
|
|
|
1166 |
+ " Phones:"
|
|
|
1167 |
+ "{{for ~ifVar.tels itemVar='~tel'}}"
|
|
|
1168 |
+ " {{:~tel}}"
|
|
|
1169 |
+ "{{/for}}"
|
|
|
1170 |
+ "{{/if}}. "
|
|
|
1171 |
+ "{{/for}}"
|
|
|
1172 |
).render({people: otherPeople}),
|
|
|
1173 |
"Jo. Bill Phones: 91 92. Fred. ",
|
|
|
1174 |
"Using itemVar and passing context to nested templates");
|
|
|
1175 |
|
|
|
1176 |
assert.equal($.templates(
|
|
|
1177 |
"{{for people itemVar='~person'}}"
|
|
|
1178 |
+ "{{:~person.name}}"
|
|
|
1179 |
+ "{{for ~person.tels itemVar='~tel'}}"
|
|
|
1180 |
+ " {{:~tel}}"
|
|
|
1181 |
+ "{{else otherTels itemVar='~tel'}}"
|
|
|
1182 |
+ " {{:~tel}}"
|
|
|
1183 |
+ "{{else}}"
|
|
|
1184 |
+ " (No phones)"
|
|
|
1185 |
+ "{{/for}}"
|
|
|
1186 |
+ ". "
|
|
|
1187 |
+ "{{/for}}"
|
|
|
1188 |
).render({people: otherPeople}),
|
|
|
1189 |
"Jo 1 2. Bill 91 92. Fred (No phones). ",
|
|
|
1190 |
"Additional example using itemVar and passing context to nested templates");
|
|
|
1191 |
|
|
|
1192 |
assert.equal($.templates({
|
|
|
1193 |
markup:
|
|
|
1194 |
"{{wrappedFor people 'u' itemVar='~person'}}"
|
|
|
1195 |
+ "{{:~person.name}} "
|
|
|
1196 |
+ "{{wrappedFor ~person.tels 'i' itemVar='~tel'}}"
|
|
|
1197 |
+ "{{:~tel}} "
|
|
|
1198 |
+ "{{else otherTels 'b' itemVar='~tel'}}"
|
|
|
1199 |
+ "{{:~tel}} "
|
|
|
1200 |
+ "{{/wrappedFor}}"
|
|
|
1201 |
+ "{{/wrappedFor}}",
|
|
|
1202 |
tags: {
|
|
|
1203 |
wrappedFor: function(val, wrapTag) {
|
|
|
1204 |
if (val) {
|
|
|
1205 |
return "<" + wrapTag + ">" + this.tagCtx.render(val) + "</" + wrapTag + ">";
|
|
|
1206 |
}
|
|
|
1207 |
}
|
|
|
1208 |
}
|
|
|
1209 |
}).render({people: otherPeople}),
|
|
|
1210 |
"<u>Jo <b>1 2 </b>Bill <i>91 92 </i> Fred </u>",
|
|
|
1211 |
"itemVar with custom tags {{wrappedFor}}{{else}}{{/wrappedFor}}, and passing context to nested templates");
|
|
|
1212 |
|
|
|
1213 |
assert.equal($.templates(
|
|
|
1214 |
"{{for people itemVar='~person'}}"
|
|
|
1215 |
+ "{{props ~person itemVar='~prop'}}"
|
|
|
1216 |
+ "{{:~prop.key}}: {{:~prop.prop}} "
|
|
|
1217 |
+ "{{/props}}"
|
|
|
1218 |
+ "{{/for}}"
|
|
|
1219 |
).render({people: otherPeople}),
|
|
|
1220 |
"name: Jo otherTels: 1,2 name: Bill tels: 91,92 name: Fred ",
|
|
|
1221 |
"itemVar with {{props}}, and passing context to nested templates");
|
|
|
1222 |
|
|
|
1223 |
assert.equal($.templates(
|
|
|
1224 |
"{{for people itemVar='~person'}}"
|
|
|
1225 |
+ "{{props ~person.tels itemVar='~prop'}}"
|
|
|
1226 |
+ "{{:~person.name}} Tel: {{:~prop.key}}: {{:~prop.prop}} "
|
|
|
1227 |
+ "{{else itemVar='~personWithoutTels'}}"
|
|
|
1228 |
+ "{{:~personWithoutTels.name}}: has no tels "
|
|
|
1229 |
+ "{{/props}}"
|
|
|
1230 |
+ "{{/for}}"
|
|
|
1231 |
).render({people: otherPeople}),
|
|
|
1232 |
"Jo: has no tels Bill Tel: 0: 91 Bill Tel: 1: 92 Fred: has no tels ",
|
|
|
1233 |
"itemVar with {{props}}{{else}}{{/props}}, and passing context to nested templates");
|
|
|
1234 |
});
|
|
|
1235 |
|
|
|
1236 |
QUnit.module("api no jQuery");
|
|
|
1237 |
QUnit.test("templates", function(assert) {
|
|
|
1238 |
// ................................ Arrange ..................................
|
|
|
1239 |
$.templates("./test/templates/file/path.html", null); // In case template has been stored in a previous test
|
|
|
1240 |
|
|
|
1241 |
// ................................ Act ..................................
|
|
|
1242 |
var tmpl0 = $.templates({markup: "./test/templates/file/path.html"}); // Compile template but do not cache
|
|
|
1243 |
|
|
|
1244 |
// ............................... Assert .................................
|
|
|
1245 |
assert.equal(!$.templates["./test/templates/file/path.html"] && tmpl0.render({name: "Jo0"}),
|
|
|
1246 |
"ServerRenderedTemplate_Jo0_B",
|
|
|
1247 |
"Compile server-generated template, without caching");
|
|
|
1248 |
|
|
|
1249 |
// ................................ Act ..................................
|
|
|
1250 |
var tmpl1 = $.templates("./test/templates/file/path.html"); // Compile and cache, using path as key
|
|
|
1251 |
|
|
|
1252 |
// ............................... Assert .................................
|
|
|
1253 |
assert.equal(tmpl1 !== tmpl0 && $.templates["./test/templates/file/path.html"] === tmpl1 && tmpl1.render({name: "Jo1"}),
|
|
|
1254 |
"ServerRenderedTemplate_Jo1_B",
|
|
|
1255 |
"Compile server-generated template, and cache on file path");
|
|
|
1256 |
|
|
|
1257 |
// ................................ Act ..................................
|
|
|
1258 |
var tmpl2 = $.templates("./test/templates/file/path.html"); // Use cached template, accessed by path as key
|
|
|
1259 |
|
|
|
1260 |
// ............................... Assert .................................
|
|
|
1261 |
assert.equal(tmpl2 === tmpl1 && tmpl1.render({name: "Jo2"}),
|
|
|
1262 |
"ServerRenderedTemplate_Jo2_B",
|
|
|
1263 |
"Re-use cached server-generated template");
|
|
|
1264 |
|
|
|
1265 |
// ................................ Act ..................................
|
|
|
1266 |
var tmpl3 = $.templates({markup: "./test/templates/file/path.html"}); // Re-compile template but do not cache. Leaved cached template.
|
|
|
1267 |
|
|
|
1268 |
// ............................... Assert .................................
|
|
|
1269 |
assert.equal(tmpl3 !== tmpl0 && tmpl3 !== tmpl1 && $.templates["./test/templates/file/path.html"] === tmpl1 && tmpl3.render({name: "Jo3"}),
|
|
|
1270 |
"ServerRenderedTemplate_Jo3_B",
|
|
|
1271 |
"Recompile server-generated template, without caching");
|
|
|
1272 |
|
|
|
1273 |
// ................................ Reset ................................
|
|
|
1274 |
delete $.templates["./test/templates/file/path.html"];
|
|
|
1275 |
if (isBrowser) {
|
|
|
1276 |
document.getElementById("./test/templates/file/path.html").removeAttribute("data-jsv-tmpl");
|
|
|
1277 |
}
|
|
|
1278 |
|
|
|
1279 |
// =============================== Arrange ===============================
|
|
|
1280 |
tmplString = "A_{{:name}}_B";
|
|
|
1281 |
|
|
|
1282 |
var tmpl = $.templates(tmplString);
|
|
|
1283 |
// ............................... Assert .................................
|
|
|
1284 |
assert.equal(tmpl.render(person), "A_Jo_B",
|
|
|
1285 |
'Compile from string: var tmpl = $.templates(tmplString);');
|
|
|
1286 |
|
|
|
1287 |
// ............................... Assert .................................
|
|
|
1288 |
assert.equal(tmpl(person), "A_Jo_B",
|
|
|
1289 |
'Compiled template is itself the render function: html = tmpl(data);');
|
|
|
1290 |
|
|
|
1291 |
// =============================== Arrange ===============================
|
|
|
1292 |
var fnToString = tmpl.fn.toString();
|
|
|
1293 |
|
|
|
1294 |
// ............................... Assert .................................
|
|
|
1295 |
assert.equal($.templates("", tmplString).fn.toString() === fnToString && $.templates(null, tmplString).fn.toString() === fnToString && $.templates(undefined, tmplString).fn.toString() === fnToString, true,
|
|
|
1296 |
'if name is "", null, or undefined, then var tmpl = $.templates(name, tmplString)' +
|
|
|
1297 |
'\nis equivalent to var tmpl = $.templates(tmplString);');
|
|
|
1298 |
|
|
|
1299 |
// =============================== Arrange ===============================
|
|
|
1300 |
$.templates("myTmpl", tmplString);
|
|
|
1301 |
|
|
|
1302 |
// ............................... Assert .................................
|
|
|
1303 |
assert.equal($.render.myTmpl(person), "A_Jo_B",
|
|
|
1304 |
'Compile and register named template: $.templates("myTmpl", tmplString);');
|
|
|
1305 |
|
|
|
1306 |
// =============================== Arrange ===============================
|
|
|
1307 |
$.templates({myTmpl2: tmplString, myTmpl3: "X_{{:name}}_Y"});
|
|
|
1308 |
|
|
|
1309 |
// ............................... Assert .................................
|
|
|
1310 |
assert.equal($.render.myTmpl2(person) + $.render.myTmpl3(person), "A_Jo_BX_Jo_Y",
|
|
|
1311 |
'Compile and register named templates: $.templates({myTmpl: tmplString, myTmpl2: tmplString2});');
|
|
|
1312 |
|
|
|
1313 |
// =============================== Arrange ===============================
|
|
|
1314 |
$.templates("!'-#==", "x");
|
|
|
1315 |
$.templates({'&^~>"2': "y"});
|
|
|
1316 |
assert.equal($.render["!'-#=="](person) + $.render['&^~>"2'](person), "xy",
|
|
|
1317 |
'Named templates can have arbitrary names;');
|
|
|
1318 |
|
|
|
1319 |
$.templates({myTmpl4: "A_B"});
|
|
|
1320 |
|
|
|
1321 |
// ............................... Assert .................................
|
|
|
1322 |
assert.equal($.render.myTmpl4(person), "A_B",
|
|
|
1323 |
'$.templates({myTmpl: htmlWithNoTags});');
|
|
|
1324 |
|
|
|
1325 |
// =============================== Arrange ===============================
|
|
|
1326 |
$.templates("myTmpl5", {
|
|
|
1327 |
markup: tmplString
|
|
|
1328 |
});
|
|
|
1329 |
|
|
|
1330 |
// ............................... Assert .................................
|
|
|
1331 |
assert.equal($.render.myTmpl5(person), "A_Jo_B",
|
|
|
1332 |
'$.templates("myTmpl", {markup: markupString});');
|
|
|
1333 |
|
|
|
1334 |
// ............................... Assert .................................
|
|
|
1335 |
assert.equal($.templates("", {markup: tmplString}).render(person), "A_Jo_B",
|
|
|
1336 |
'Compile from template object without registering: var tmpl = $.templates("", {markup: markupString});');
|
|
|
1337 |
|
|
|
1338 |
// ............................... Assert .................................
|
|
|
1339 |
assert.equal($.templates({markup: tmplString}).render(person), "A_Jo_B",
|
|
|
1340 |
'Compile from template object without registering: var tmpl = $.templates({markup: markupString});');
|
|
|
1341 |
|
|
|
1342 |
// =============================== Arrange ===============================
|
|
|
1343 |
$.templates({
|
|
|
1344 |
myTmpl6: {
|
|
|
1345 |
markup: tmplString
|
|
|
1346 |
}
|
|
|
1347 |
});
|
|
|
1348 |
|
|
|
1349 |
// ............................... Assert .................................
|
|
|
1350 |
assert.equal($.render.myTmpl6(person), "A_Jo_B",
|
|
|
1351 |
'$.templates({myTmpl: {markup: markupString}});');
|
|
|
1352 |
|
|
|
1353 |
// =============================== Arrange ===============================
|
|
|
1354 |
$.templates("myTmpl7", tmpl);
|
|
|
1355 |
|
|
|
1356 |
// ............................... Assert .................................
|
|
|
1357 |
assert.equal($.render.myTmpl7(person), "A_Jo_B",
|
|
|
1358 |
'Cloning a template: $.templates("newName", tmpl);');
|
|
|
1359 |
|
|
|
1360 |
// ............................... Assert .................................
|
|
|
1361 |
assert.equal($.templates(tmpl) === tmpl, true,
|
|
|
1362 |
'$.templates(tmpl) returns tmpl');
|
|
|
1363 |
|
|
|
1364 |
// ............................... Assert .................................
|
|
|
1365 |
assert.equal($.templates("", tmpl) === tmpl, true,
|
|
|
1366 |
'$.templates("", tmpl) returns tmpl');
|
|
|
1367 |
|
|
|
1368 |
// =============================== Arrange ===============================
|
|
|
1369 |
var tmplWithHelper = $.templates("A_{{:name}}_B{{:~foo}}");
|
|
|
1370 |
var result = tmplWithHelper(person, {foo: "thisFoo"});
|
|
|
1371 |
|
|
|
1372 |
var tmplWithHelper2 = $.templates({markup: tmplWithHelper, helpers: {foo: "thatFoo"}});
|
|
|
1373 |
result += "|" + tmplWithHelper2(person);
|
|
|
1374 |
|
|
|
1375 |
// ............................... Assert .................................
|
|
|
1376 |
assert.equal(result, "A_Jo_BthisFoo|A_Jo_BthatFoo",
|
|
|
1377 |
'Cloning a template to add/replace/change some template properties: var tmpl2 = $.templates({markup: tmpl1, otherOptions...});');
|
|
|
1378 |
|
|
|
1379 |
// ............................... Assert .................................
|
|
|
1380 |
assert.equal($.templates("", tmpl) === tmpl, true,
|
|
|
1381 |
'$.templates(tmpl) returns tmpl');
|
|
|
1382 |
|
|
|
1383 |
// ............................... Assert .................................
|
|
|
1384 |
assert.equal($.templates("").render(), "",
|
|
|
1385 |
'$.templates("") is a template with empty string as content');
|
|
|
1386 |
|
|
|
1387 |
// =============================== Arrange ===============================
|
|
|
1388 |
$.templates("myEmptyTmpl", "");
|
|
|
1389 |
|
|
|
1390 |
// ............................... Assert .................................
|
|
|
1391 |
assert.equal($.templates.myEmptyTmpl.render(), "",
|
|
|
1392 |
'$.templates("myEmptyTmpl", "") is a template with empty string as content');
|
|
|
1393 |
|
|
|
1394 |
// =============================== Arrange ===============================
|
|
|
1395 |
$.templates("myTmpl", null);
|
|
|
1396 |
|
|
|
1397 |
// ............................... Assert .................................
|
|
|
1398 |
assert.equal($.templates.myTmpl === undefined && $.render.myTmpl === undefined, true,
|
|
|
1399 |
'Remove a named template: $.templates("myTmpl", null);');
|
|
|
1400 |
});
|
|
|
1401 |
|
|
|
1402 |
QUnit.test("render", function(assert) {
|
|
|
1403 |
var tmpl1 = $.templates("myTmpl8", tmplString);
|
|
|
1404 |
$.templates({
|
|
|
1405 |
simple: "Content{{:#data}}|",
|
|
|
1406 |
templateForArray: "Content{{for #data}}{{:#index}}{{/for}}{{:~foo}}",
|
|
|
1407 |
primitiveDataTypes: "|{{:#data}}"
|
|
|
1408 |
});
|
|
|
1409 |
|
|
|
1410 |
assert.equal(tmpl1.render(person), "A_Jo_B", 'tmpl1.render(data);');
|
|
|
1411 |
assert.equal($.render.myTmpl8(person), "A_Jo_B", '$.render.myTmpl8(data);');
|
|
|
1412 |
|
|
|
1413 |
$.templates("myTmpl9", "A_{{for}}inner{{:name}}content{{/for}}_B");
|
|
|
1414 |
assert.equal($.templates.myTmpl9.tmpls[0].render(person), "innerJocontent", 'Access nested templates: $.templates["myTmpl9[0]"];');
|
|
|
1415 |
|
|
|
1416 |
$.templates("myTmpl10", "top index:{{:#index}}|{{for 1}}nested index:{{:#get('item').index}}|{{if #get('item').index===0}}nested if index:{{:#get('item').index}}|{{else}}nested else index:{{:#get('item').index}}|{{/if}}{{/for}}");
|
|
|
1417 |
|
|
|
1418 |
assert.equal($.render.myTmpl10(people), "top index:0|nested index:0|nested if index:0|top index:1|nested index:1|nested else index:1|",
|
|
|
1419 |
"#get('item').index gives the integer index even in nested blocks");
|
|
|
1420 |
|
|
|
1421 |
$.templates("myTmpl11", "top index:{{:#index}}|{{for people}}nested index:{{:#index}}|{{if #index===0}}nested if index:{{:#get('item').index}}|{{else}}nested else index:{{:#get('item').index}}|{{/if}}{{/for}}");
|
|
|
1422 |
|
|
|
1423 |
assert.equal($.render.myTmpl11({people: people}), "top index:|nested index:0|nested if index:0|nested index:1|nested else index:1|",
|
|
|
1424 |
"#get('item').index gives the integer index even in nested blocks");
|
|
|
1425 |
|
|
|
1426 |
$.views.tags({
|
|
|
1427 |
myWrap: {}
|
|
|
1428 |
});
|
|
|
1429 |
|
|
|
1430 |
var templateWithIndex = $.templates(
|
|
|
1431 |
'{{for people}}'
|
|
|
1432 |
+ 'a{{:#index}} '
|
|
|
1433 |
+ '{{if true}}b{{:#index}}{{/if}} '
|
|
|
1434 |
+ 'c{{:#index}} '
|
|
|
1435 |
+ '{{myWrap}}d{{:#index}} {{/myWrap}}'
|
|
|
1436 |
+ '{{/for}}');
|
|
|
1437 |
|
|
|
1438 |
$.views.settings.debugMode(true);
|
|
|
1439 |
var result = templateWithIndex.render({people: [1,2]});
|
|
|
1440 |
|
|
|
1441 |
$.views.settings.debugMode(false);
|
|
|
1442 |
var result2 = templateWithIndex.render({people: [1,2]});
|
|
|
1443 |
|
|
|
1444 |
assert.equal(result2 === result && result,
|
|
|
1445 |
"a0 bFor #index in nested block use #getIndex(). c0 dFor #index in nested block use #getIndex(). a1 bFor #index in nested block use #getIndex(). c1 dFor #index in nested block use #getIndex(). ",
|
|
|
1446 |
"#index gives error message in nested blocks (whether or not debugMode is true).");
|
|
|
1447 |
|
|
|
1448 |
var templateWithGetIndex = $.templates(
|
|
|
1449 |
'{{for people}}'
|
|
|
1450 |
+ 'a{{:#getIndex()}} '
|
|
|
1451 |
+ '{{if true}}b{{:#getIndex()}}{{/if}} '
|
|
|
1452 |
+ 'c{{:#getIndex()}} '
|
|
|
1453 |
+ '{{myWrap}}d{{:#getIndex()}} {{/myWrap}}'
|
|
|
1454 |
+ '{{/for}}');
|
|
|
1455 |
|
|
|
1456 |
assert.equal(templateWithGetIndex.render({people: [1,2]}),
|
|
|
1457 |
"a0 b0 c0 d0 a1 b1 c1 d1 ",
|
|
|
1458 |
"#getIndex gives inherited index in nested blocks.");
|
|
|
1459 |
|
|
|
1460 |
$.views.helpers({myKeyIsCorrect: function(view) {
|
|
|
1461 |
return view.parent.views[view._.key] === view;
|
|
|
1462 |
}});
|
|
|
1463 |
$.templates("myTmpl12", "{{for people}}nested {{:~myKeyIsCorrect(#view)}}|{{if #index===0}}nested if {{:~myKeyIsCorrect(#view)}}|{{else}}nested else {{:~myKeyIsCorrect(#view)}}|{{/if}}{{/for}}");
|
|
|
1464 |
|
|
|
1465 |
assert.equal($.render.myTmpl12({people: people}), "nested true|nested if true|nested true|nested else true|",
|
|
|
1466 |
'view._key gives the key of this view in the parent views collection/object');
|
|
|
1467 |
|
|
|
1468 |
assert.equal($.templates(tmplString).render(person), "A_Jo_B", 'Compile from string: var html = $.templates(tmplString).render(data);');
|
|
|
1469 |
assert.equal($.render.myTmpl8(people), "A_Jo_BA_Bill_B", '$.render.myTmpl(array);');
|
|
|
1470 |
assert.equal($.render.simple([]), "", 'Empty array renders empty string');
|
|
|
1471 |
assert.equal($.render.simple(["",false,null,undefined,1]), "Content|Contentfalse|Content|Content|Content1|", 'Empty string, false, null or undefined members of array are also rendered');
|
|
|
1472 |
assert.equal($.render.simple(null), "Content|", 'null renders once with #data null');
|
|
|
1473 |
assert.equal($.render.simple(), "Content|", 'Undefined renders once with #data undefined');
|
|
|
1474 |
assert.equal($.render.simple(false), "Contentfalse|", 'false renders once with #data false');
|
|
|
1475 |
assert.equal($.render.simple(0), "Content0|", '0 renders once with #data 0');
|
|
|
1476 |
assert.equal($.render.simple(""), "Content|", '"" renders once with #data ""');
|
|
|
1477 |
|
|
|
1478 |
assert.equal($.render.templateForArray([[null,undefined,1]]), "Content012", 'Can render a template against an array without iteration, by wrapping array in an array');
|
|
|
1479 |
assert.equal($.render.templateForArray([null,undefined,1], true), "Content012", 'render(array, true) renders an array without iteration');
|
|
|
1480 |
assert.equal($.render.templateForArray([null,undefined,1], {foo:"foovalue"}, true), "Content012foovalue", 'render(array, helpers, true) renders an array without iteration, while passing in helpers');
|
|
|
1481 |
assert.equal($.templates.templateForArray.render([null,undefined,1], {foo:"foovalue"}, true), "Content012foovalue", 'render(array, helpers, true) renders an array without iteration, while passing in helpers');
|
|
|
1482 |
assert.equal($.render.templateForArray([[]]), "Content", 'Can render a template against an empty array without iteration, by wrapping array in an array');
|
|
|
1483 |
assert.equal($.render.templateForArray([], true), "Content", 'Can render a template against an empty array without iteration, by passing in true as second parameter');
|
|
|
1484 |
assert.equal($.render.templateForArray([], {foo: "foovalue"}, true), "Contentfoovalue", 'Can render a template against an empty array without iteration, by by passing in true as third parameter');
|
|
|
1485 |
assert.equal($.render.primitiveDataTypes([0,1,"abc","",,true,false]), "|0|1|abc|||true|false", 'Primitive types render correctly, even if falsey');
|
|
|
1486 |
});
|
|
|
1487 |
|
|
|
1488 |
QUnit.test("converters", function(assert) {
|
|
|
1489 |
function loc(data) {
|
|
|
1490 |
switch (data) {case "desktop": return "bureau";}
|
|
|
1491 |
return data;
|
|
|
1492 |
}
|
|
|
1493 |
$.views.converters({loc2: loc});
|
|
|
1494 |
assert.equal($.templates("{{loc2:#data}}:{{loc2:'desktop'}}").render("desktop"), "bureau:bureau", "$.views.converters({loc: locFunction})");
|
|
|
1495 |
|
|
|
1496 |
var locFn = $.views.converters("loc", loc);
|
|
|
1497 |
assert.equal(locFn === loc && $.views.converters.loc === loc && $.views.converters.loc2 === loc, true, 'locFunction === $.views.converters.loc === $.views.converters.loc2');
|
|
|
1498 |
|
|
|
1499 |
$.views.converters({loc2: null});
|
|
|
1500 |
assert.equal($.views.converters.loc2, undefined, '$.views.converters({loc2: null}) to remove registered converter');
|
|
|
1501 |
|
|
|
1502 |
assert.equal($.templates("{{attr:a}}").render({a: 0}), "0", '{{attr:0}} returns "0"');
|
|
|
1503 |
assert.equal($.templates("{{attr:a}}").render({}), "", "{{attr:undefined}} returns empty string");
|
|
|
1504 |
assert.equal($.templates("{{attr:a}}").render({a: ""}), "", "{{attr:''}} returns empty string");
|
|
|
1505 |
assert.equal($.templates("{{attr:a}}").render({a: null}), "", '{{attr:null}} returns empty string');
|
|
|
1506 |
assert.equal($.templates("{{attr:a}}").render({a: "<>&'" + '"'}), "<>&'"", '{{attr:"<>&' + "'" + '}} returns "<>&'""');
|
|
|
1507 |
|
|
|
1508 |
assert.equal($.templates("{{>a}}").render({a: 0}), "0", '{{>0}} returns "0"');
|
|
|
1509 |
assert.equal($.templates("{{>a}}").render({}), "", "{{>undefined}} returns empty string");
|
|
|
1510 |
assert.equal($.templates("{{>a}}").render({a: ""}), "", "{{>''}} returns empty string");
|
|
|
1511 |
assert.equal($.templates("{{>a}}").render({a: null}), "", "{{>null}} returns empty string");
|
|
|
1512 |
assert.equal($.templates("{{>a}}").render({a: "<>&'" + '"'}), "<>&'"", '{{>"<>&' + "'" + '}} returns "<>&'""');
|
|
|
1513 |
|
|
|
1514 |
assert.equal($.templates("{{loc:a}}").render({a: 0}), "0", '{{cnvt:0}} returns "0"');
|
|
|
1515 |
assert.equal($.templates("{{loc:a}}").render({}), "", '{{cnvt:undefined}} returns empty string');
|
|
|
1516 |
assert.equal($.templates("{{loc:a}}").render({a: ""}), "", "{{cnvt:''}} returns empty string");
|
|
|
1517 |
assert.equal($.templates("{{loc:a}}").render({a: null}), "", "{{cnvt:null}} returns empty string");
|
|
|
1518 |
|
|
|
1519 |
assert.equal($.templates("{{attr:a}}|{{>a}}|{{loc:a}}|{{:a}}").render({}), "|||", "{{attr:undefined}}|{{>undefined}}|{{loc:undefined}}|{{:undefined}} returns correct values");
|
|
|
1520 |
assert.equal($.templates("{{attr:a}}|{{>a}}|{{loc:a}}|{{:a}}").render({a:0}), "0|0|0|0", "{{attr:0}}|{{>0}}|{{loc:0}}|{{:0}} returns correct values");
|
|
|
1521 |
assert.equal($.templates("{{attr:a}}|{{>a}}|{{loc:a}}|{{:a}}").render({a:false}), "false|false|false|false", "{{attr:false}}|{{>false}}|{{loc:false}}|{{:false}} returns correct values");
|
|
|
1522 |
});
|
|
|
1523 |
|
|
|
1524 |
QUnit.test("{{sometag convert=converter}}", function(assert) {
|
|
|
1525 |
function loc(data) {
|
|
|
1526 |
switch (data) {
|
|
|
1527 |
case "desktop": return "bureau";
|
|
|
1528 |
case "a<b": return "a moins <que b";}
|
|
|
1529 |
return data;
|
|
|
1530 |
}
|
|
|
1531 |
$.views.converters("loc", loc);
|
|
|
1532 |
|
|
|
1533 |
assert.equal($.templates("1{{:#data convert='loc'}} 2{{:'desktop' convert='loc'}} 3{{:#data convert=~myloc}} 4{{:'desktop' convert=~myloc}}").render("desktop", {myloc: loc}), "1bureau 2bureau 3bureau 4bureau", "{{: convert=~myconverter}}");
|
|
|
1534 |
assert.equal($.templates("1:{{:'a<b' convert=~myloc}} 2:{{> 'a<b'}} 3:{{html: 'a<b' convert=~myloc}} 4:{{> 'a<b' convert=~myloc}} 5:{{attr: 'a<b' convert=~myloc}}").render(1, {myloc: loc}),
|
|
|
1535 |
"1:a moins <que b 2:a<b 3:a<b 4:a<b 5:a moins <que b",
|
|
|
1536 |
"{{foo: convert=~myconverter}} convert=converter is used rather than {{foo:, but with {{html: convert=~myconverter}}" +
|
|
|
1537 |
"\nor {{> convert=~myconverter}} html converter takes precedence and ~myconverter is ignored");
|
|
|
1538 |
assert.equal($.templates("{{if true convert=~invert}}yes{{else false convert=~invert}}no{{else}}neither{{/if}}").render('desktop', {invert: function(val) {return !val;}}), "no", "{{if expression convert=~myconverter}}...{{else expression2 convert=~myconverter}}... ");
|
|
|
1539 |
assert.equal($.templates("{{for #data convert=~reverse}}{{:#data}}{{/for}}").render([1,2,3], {reverse: function(val) {return val.reverse();}}, true), "321", "{{for expression convert=~myconverter}}");
|
|
|
1540 |
});
|
|
|
1541 |
|
|
|
1542 |
QUnit.test("tags", function(assert) {
|
|
|
1543 |
// ................................ Reset ..................................
|
|
|
1544 |
towns = [{name: "Seattle"}, {name: "Paris"}, {name: "Delhi"}];
|
|
|
1545 |
|
|
|
1546 |
// ................................ Act ..................................
|
|
|
1547 |
assert.equal($.templates("{{sort people reverse=true}}{{:name}}{{/sort}}").render({people: people}), "BillJo", "$.views.tags({sort: sortFunction})");
|
|
|
1548 |
|
|
|
1549 |
assert.equal($.templates("{^{sort people reverse=true}}{^{:name}}{{/sort}}").render({people: people}), "BillJo", "Calling render() with inline data-binding {^{...}} renders normally without binding");
|
|
|
1550 |
|
|
|
1551 |
assert.equal($.templates("{{sort people reverse=true towns}}{{:name}}{{/sort}}").render({people: people, towns:towns}), "DelhiParisSeattleBillJo", "Multiple parameters in arbitrary order: {{sort people reverse=true towns}}");
|
|
|
1552 |
|
|
|
1553 |
assert.equal($.templates("{{sort reverse=false people reverse=true towns}}{{:name}}{{/sort}}").render({people: people, towns:towns}), "DelhiParisSeattleBillJo", "Duplicate named parameters - last wins: {{sort reverse=false people reverse=true towns}}");
|
|
|
1554 |
|
|
|
1555 |
var sort2 = $.views.tags("sort2", sort);
|
|
|
1556 |
assert.equal(sort2.render === sort && $.views.tags.sort.render === sort && $.views.tags.sort2.render === sort, true, 'sortFunction === $.views.tags.sort.render === $.views.tags.sort2.render');
|
|
|
1557 |
|
|
|
1558 |
$.views.tags("sort2", null);
|
|
|
1559 |
assert.equal($.views.tags.sort2, undefined, '$.views.tags("sort2", null) to remove registered tag');
|
|
|
1560 |
|
|
|
1561 |
$.views.tags("boldTag", {
|
|
|
1562 |
render: function() {
|
|
|
1563 |
return "<em>" + this.tagCtx.render() + "</em>";
|
|
|
1564 |
},
|
|
|
1565 |
template: "{{:#data}}"
|
|
|
1566 |
});
|
|
|
1567 |
assert.equal($.templates("{{boldTag}}{{:#data}}{{/boldTag}}").render("theData"), "<em>theData</em>",
|
|
|
1568 |
'Data context inside a block tag using tagCtx.render() is the same as the outer context');
|
|
|
1569 |
|
|
|
1570 |
assert.equal($.templates("{{boldTag/}}").render("theData"), "<em>theData</em>",
|
|
|
1571 |
'Data context inside the built-in template of a self-closing tag using tagCtx.render() is the same as the outer context');
|
|
|
1572 |
|
|
|
1573 |
assert.equal($.templates("{{sort people reverse=true}}{{:name}}{{/sort}}").render({people: people}), "BillJo", "$.views.tags({sort: sortFunction})");
|
|
|
1574 |
|
|
|
1575 |
// =============================== Arrange ===============================
|
|
|
1576 |
// ................................ Act ..................................
|
|
|
1577 |
var eventData = "",
|
|
|
1578 |
|
|
|
1579 |
renderedOutput = $.templates({
|
|
|
1580 |
markup: '{^{myWidget name/}}',
|
|
|
1581 |
tags: {
|
|
|
1582 |
myWidget: {
|
|
|
1583 |
init: function(tagCtx, linkCtx) {
|
|
|
1584 |
eventData += " init";
|
|
|
1585 |
},
|
|
|
1586 |
render: function(name, things) {
|
|
|
1587 |
eventData += " render";
|
|
|
1588 |
return name + " " + this.getType();
|
|
|
1589 |
},
|
|
|
1590 |
getType: function() {
|
|
|
1591 |
eventData += " getType";
|
|
|
1592 |
return this.type;
|
|
|
1593 |
},
|
|
|
1594 |
type: "special"
|
|
|
1595 |
}
|
|
|
1596 |
}
|
|
|
1597 |
}).render(person);
|
|
|
1598 |
|
|
|
1599 |
// ............................... Assert .................................
|
|
|
1600 |
assert.equal(renderedOutput + "|" + eventData, "Jo special| init render getType", '{^{myWidget/}} - Events fire in order during rendering: init render');
|
|
|
1601 |
|
|
|
1602 |
// =============================== Arrange ===============================
|
|
|
1603 |
$.views.tags({
|
|
|
1604 |
noRenderNoTemplate: {},
|
|
|
1605 |
voidRender: function() {},
|
|
|
1606 |
emptyRender: function() {return "";},
|
|
|
1607 |
emptyTemplate: {
|
|
|
1608 |
template: ""
|
|
|
1609 |
},
|
|
|
1610 |
templateReturnsEmpty: {
|
|
|
1611 |
template: "{{:a}}"
|
|
|
1612 |
}
|
|
|
1613 |
});
|
|
|
1614 |
|
|
|
1615 |
// ............................... Assert .................................
|
|
|
1616 |
assert.equal($.templates("a{{noRenderNoTemplate/}}b{^{noRenderNoTemplate/}}c{{noRenderNoTemplate}}{{/noRenderNoTemplate}}d{^{noRenderNoTemplate}}{{/noRenderNoTemplate}}e").render(1), "abcde",
|
|
|
1617 |
"non-rendering tag (no template, no render function) renders empty string");
|
|
|
1618 |
|
|
|
1619 |
assert.equal($.templates("a{{voidRender/}}b{^{voidRender/}}c{{voidRender}}{{/voidRender}}d{^{voidRender}}{{/voidRender}}e").render(1), "abcde",
|
|
|
1620 |
"non-rendering tag (no template, no return from render function) renders empty string");
|
|
|
1621 |
|
|
|
1622 |
assert.equal($.templates("a{{emptyRender/}}b{^{emptyRender/}}c{{emptyRender}}{{/emptyRender}}d{^{emptyRender}}{{/emptyRender}}e").render(1), "abcde",
|
|
|
1623 |
"non-rendering tag (no template, empty string returned from render function) renders empty string");
|
|
|
1624 |
|
|
|
1625 |
assert.equal($.templates("a{{emptyTemplate/}}b{^{emptyTemplate/}}c{{emptyTemplate}}{{/emptyTemplate}}d{^{emptyTemplate}}{{/emptyTemplate}}e").render(1), "abcde",
|
|
|
1626 |
"non-rendering tag (template has no content, no render function) renders empty string");
|
|
|
1627 |
|
|
|
1628 |
assert.equal($.templates("a{{templateReturnsEmpty/}}b{^{templateReturnsEmpty/}}c{{templateReturnsEmpty}}{{/templateReturnsEmpty}}d{^{templateReturnsEmpty}}{{/templateReturnsEmpty}}e").render(1), "abcde",
|
|
|
1629 |
"non-rendering tag (template returns empty string, no render function) renders empty string");
|
|
|
1630 |
|
|
|
1631 |
$.views.tags({
|
|
|
1632 |
tagJustTemplate: {
|
|
|
1633 |
argDefault: false,
|
|
|
1634 |
template: "{{:#data ? name||length : 'Not defined'}} "
|
|
|
1635 |
},
|
|
|
1636 |
tagJustTemplateObject: {
|
|
|
1637 |
argDefault: false,
|
|
|
1638 |
template: {markup: "{{:#data ? name||length : 'Not defined'}} "}
|
|
|
1639 |
},
|
|
|
1640 |
tagWithTemplateWhichIteratesAgainstCurrentData: {
|
|
|
1641 |
template: "{{:#data ? name : 'Not defined'}} ",
|
|
|
1642 |
render: function() {
|
|
|
1643 |
return this.tagCtx.render(); // Renders against current data - and iterates if array
|
|
|
1644 |
}
|
|
|
1645 |
},
|
|
|
1646 |
tagJustRender: function(val) {
|
|
|
1647 |
return val.name + " ";
|
|
|
1648 |
},
|
|
|
1649 |
tagJustRenderArray: function(val) {
|
|
|
1650 |
return val.length + " ";
|
|
|
1651 |
},
|
|
|
1652 |
tagWithTemplateNoIteration: {
|
|
|
1653 |
contentCtx: true,
|
|
|
1654 |
render: function(val) {
|
|
|
1655 |
return this.tagCtx.render(val, true); // Render without iteration
|
|
|
1656 |
},
|
|
|
1657 |
template: "{{:#data.length}} "
|
|
|
1658 |
},
|
|
|
1659 |
tagWithTemplateNoIterationWithHelpers: {
|
|
|
1660 |
render: function(val) {
|
|
|
1661 |
return this.tagCtx.render(val, {foo: "foovalue"}, true); // Render without iteration
|
|
|
1662 |
},
|
|
|
1663 |
template: "{{:#data.length}} {{:~foo}}"
|
|
|
1664 |
},
|
|
|
1665 |
tagWithTemplateWhichIteratesFirstArg: {
|
|
|
1666 |
template: "{{:#data ? name : 'Not defined'}} ",
|
|
|
1667 |
render: function(val) {
|
|
|
1668 |
return this.tagCtx.render(val); // Renders against first arg - defaults to current data - and iterates if array
|
|
|
1669 |
}
|
|
|
1670 |
},
|
|
|
1671 |
tagWithTemplateWhichIteratesFirstArgNoDefaultArg: {
|
|
|
1672 |
template: "{{:#data ? name : 'Not defined'}} ",
|
|
|
1673 |
argDefault: false,
|
|
|
1674 |
render: function(val) {
|
|
|
1675 |
return this.tagCtx.render(val); // Renders against first arg and iterates if array. Does not default to current data
|
|
|
1676 |
}
|
|
|
1677 |
}
|
|
|
1678 |
});
|
|
|
1679 |
|
|
|
1680 |
assert.equal($.templates("a{{include person}}{{tagJustTemplate/}}{{/include}}").render({person: {name: "Jo"}}), "aJo ",
|
|
|
1681 |
"Tag with just a template and no param renders once against current data, if object");
|
|
|
1682 |
|
|
|
1683 |
assert.equal($.templates("a{{include person}}{{tagJustTemplateObject/}}{{/include}}").render({person: {name: "Jo"}}), "aJo ",
|
|
|
1684 |
"Tag with just a template object and no param renders once against current data, if object");
|
|
|
1685 |
|
|
|
1686 |
assert.equal($.templates("a{{include person}}{{tagJustTemplate undefinedProperty/}}{{/include}}").render({person: {name: "Jo"}}), "aNot defined ",
|
|
|
1687 |
"Tag with just a template and a parameter which is not defined renders once against 'undefined'");
|
|
|
1688 |
|
|
|
1689 |
assert.equal($.templates("a{{include people}}{{tagJustTemplate/}}{{/include}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "a2 ",
|
|
|
1690 |
"Tag with just a template and no param renders once against current data, even if array" +
|
|
|
1691 |
"\n- but can add render method with tagCtx.render(val) to iterate - (next test)");
|
|
|
1692 |
|
|
|
1693 |
assert.equal($.templates("a{{include people}}{{tagWithTemplateWhichIteratesAgainstCurrentData/}}{{/include}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "aJo Mary ",
|
|
|
1694 |
"Tag with a template and no param and render method calling tagCtx.render() iterates against current data if array");
|
|
|
1695 |
|
|
|
1696 |
assert.equal($.templates("a{{include people}}{{tagWithTemplateWhichIteratesAgainstCurrentData thisisignored/}}{{/include}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "aJo Mary ",
|
|
|
1697 |
"Tag with a template and no param and render method calling tagCtx.render() iterates against current data if array" +
|
|
|
1698 |
"\n- and ignores argument if provided");
|
|
|
1699 |
|
|
|
1700 |
assert.equal($.templates("a{{include people}}{{tagWithTemplateWhichIteratesFirstArg/}}{{/include}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "aJo Mary ",
|
|
|
1701 |
"Tag with a template and no param and render method calling tagCtx.render(val) renders against first arg" +
|
|
|
1702 |
"\n- or defaults to current data, and iterates if array");
|
|
|
1703 |
|
|
|
1704 |
assert.equal($.templates("a{{tagWithTemplateWhichIteratesFirstArg people/}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "aJo Mary ",
|
|
|
1705 |
"Tag with a template and no param and render method calling tagCtx.render(val) iterates against argument if array");
|
|
|
1706 |
|
|
|
1707 |
assert.equal($.templates("a{{include people}}{{tagWithTemplateNoIteration/}}{{/include}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "a2 ",
|
|
|
1708 |
"If current data is an array, a tag with a template and a render method calling" +
|
|
|
1709 |
"\ntagCtx.render(val, true) and no param renders against array without iteration");
|
|
|
1710 |
|
|
|
1711 |
assert.equal($.templates("a{{include people}}{{tagWithTemplateWhichIteratesFirstArgNoDefaultArg/}}{{/include}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "aNot defined ",
|
|
|
1712 |
"Tag with a template and no param and render method calling tagCtx.render(val) but with tag.argDefault=false renders against first arg" +
|
|
|
1713 |
"\n- and does not default to current data if arg is undefined");
|
|
|
1714 |
|
|
|
1715 |
assert.equal($.templates("a{{include people}}{{tagWithTemplateNoIterationWithHelpers/}}{{/include}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "a2 foovalue",
|
|
|
1716 |
"If current data is an array, a tag with a template and a render method calling" +
|
|
|
1717 |
"\ntagCtx.render(val, helpers, true) and no param renders against array without iteration");
|
|
|
1718 |
|
|
|
1719 |
assert.equal($.templates("a{{include person}}{{tagJustRender/}}{{/include}}").render({person: {name: "Jo"}}), "aJo ",
|
|
|
1720 |
"Tag with just a render and no param renders once against current data, if object");
|
|
|
1721 |
|
|
|
1722 |
assert.equal($.templates("a{{include people}}{{tagJustRenderArray/}}{{/include}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "a2 ",
|
|
|
1723 |
"Tag with just a render and no param renders once against current data, even if array - but render method can choose to iterate");
|
|
|
1724 |
|
|
|
1725 |
assert.equal($.templates("a{{tagJustTemplate person/}}").render({person: {name: "Jo"}}), "aJo ",
|
|
|
1726 |
"Tag with just a template and renders once against first argument data, if object");
|
|
|
1727 |
|
|
|
1728 |
assert.equal($.templates("a{{tagJustTemplate people/}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "a2 ",
|
|
|
1729 |
"Tag with just a template renders once against first argument data even if it is an array" +
|
|
|
1730 |
"\n- but can add render method with tagCtx.render(val) to iterate - (next test)");
|
|
|
1731 |
|
|
|
1732 |
assert.equal($.templates("a{{tagWithTemplateWhichIteratesFirstArg people/}}").render({people: [{name: "Jo"}, {name: "Mary"}]}), "aJo Mary ",
|
|
|
1733 |
"Tag with a template and render method calling tagCtx.render(val) renders against first param data, and iterates if array");
|
|
|
1734 |
|
|
|
1735 |
});
|
|
|
1736 |
|
|
|
1737 |
QUnit.test("derived tags", function(assert) {
|
|
|
1738 |
// =============================== Arrange ===============================
|
|
|
1739 |
var tmpl = $.templates("a:{{A 1/}} b:{{B 2/}}"),
|
|
|
1740 |
|
|
|
1741 |
tagA = $.views.tags("A",
|
|
|
1742 |
function(val) {return "A" + val;},
|
|
|
1743 |
tmpl
|
|
|
1744 |
);
|
|
|
1745 |
|
|
|
1746 |
$.views.tags("B",
|
|
|
1747 |
{
|
|
|
1748 |
baseTag: tagA,
|
|
|
1749 |
render: function(val) {
|
|
|
1750 |
return "B" + val + this.base(val);
|
|
|
1751 |
}
|
|
|
1752 |
},
|
|
|
1753 |
tmpl
|
|
|
1754 |
);
|
|
|
1755 |
|
|
|
1756 |
// ................................ Act ..................................
|
|
|
1757 |
var result = tmpl.render({});
|
|
|
1758 |
|
|
|
1759 |
// ............................... Assert .................................
|
|
|
1760 |
assert.equal(result, "a:A1 b:B2A2", "One level tag inheritance chain - calling base method");
|
|
|
1761 |
|
|
|
1762 |
// =============================== Arrange ===============================
|
|
|
1763 |
tmpl = $.templates("a:{{A 1 2 3/}} b:{{B 11 12 13/}} c:{{C 21 22 23/}} d:{{D 31 32 33/}} e:{{E 41 42 43/}}");
|
|
|
1764 |
|
|
|
1765 |
tagA = $.views.tags("A",
|
|
|
1766 |
function(val) {return "A" + val;},
|
|
|
1767 |
tmpl
|
|
|
1768 |
);
|
|
|
1769 |
|
|
|
1770 |
$.views.tags("B",
|
|
|
1771 |
{
|
|
|
1772 |
baseTag: tagA,
|
|
|
1773 |
foo: function(val) {
|
|
|
1774 |
return "FOO-B:" + val;
|
|
|
1775 |
},
|
|
|
1776 |
render: function(val) {
|
|
|
1777 |
return "B" + val + this.base(val);
|
|
|
1778 |
}
|
|
|
1779 |
},
|
|
|
1780 |
tmpl
|
|
|
1781 |
);
|
|
|
1782 |
|
|
|
1783 |
var tagC = $.views.tags("C",
|
|
|
1784 |
{
|
|
|
1785 |
baseTag: "A",
|
|
|
1786 |
foo: function(val) {
|
|
|
1787 |
return "FOO-C:" + val;
|
|
|
1788 |
},
|
|
|
1789 |
bar: function(x, y, z) {
|
|
|
1790 |
return "BAR-C" + x + y + z;
|
|
|
1791 |
},
|
|
|
1792 |
render: function(val) {
|
|
|
1793 |
return "C" + val + this.base(val) + this.foo(val) + this.bar.apply(this, this.tagCtx.args);
|
|
|
1794 |
}
|
|
|
1795 |
},
|
|
|
1796 |
tmpl
|
|
|
1797 |
);
|
|
|
1798 |
|
|
|
1799 |
$.views.tags("D",
|
|
|
1800 |
{
|
|
|
1801 |
baseTag: tagC,
|
|
|
1802 |
render: function(val) {
|
|
|
1803 |
return "D" + val + this.base(val);
|
|
|
1804 |
}
|
|
|
1805 |
},
|
|
|
1806 |
tmpl
|
|
|
1807 |
);
|
|
|
1808 |
|
|
|
1809 |
$.views.tags("E",
|
|
|
1810 |
{
|
|
|
1811 |
baseTag: "D",
|
|
|
1812 |
foo: function(val) {
|
|
|
1813 |
return "FOO-E" + val + this.base(val);
|
|
|
1814 |
},
|
|
|
1815 |
bar: function(x, y, z) {
|
|
|
1816 |
return "BAR-E" + x + y + z + this.baseApply(arguments);
|
|
|
1817 |
},
|
|
|
1818 |
render: function(val) {
|
|
|
1819 |
return "E" + val + this.base(val);
|
|
|
1820 |
}
|
|
|
1821 |
},
|
|
|
1822 |
tmpl
|
|
|
1823 |
);
|
|
|
1824 |
|
|
|
1825 |
// ................................ Act ..................................
|
|
|
1826 |
result = tmpl.render({});
|
|
|
1827 |
|
|
|
1828 |
// ............................... Assert .................................
|
|
|
1829 |
assert.equal(result, "a:A1 b:B11A11 c:C21A21FOO-C:21BAR-C212223 d:D31C31A31FOO-C:31BAR-C313233 e:E41D41C41A41FOO-E41FOO-C:41BAR-E414243BAR-C414243", "Complex multi-level inheritance chain");
|
|
|
1830 |
|
|
|
1831 |
// =============================== Arrange ===============================
|
|
|
1832 |
$.views.settings.debugMode(true);
|
|
|
1833 |
tmpl = $.templates("a:{{A 1 2 3/}}");
|
|
|
1834 |
|
|
|
1835 |
tagA = $.views.tags("A",
|
|
|
1836 |
function(val) {
|
|
|
1837 |
return "A" + val + this.baseApply(arguments);
|
|
|
1838 |
},
|
|
|
1839 |
tmpl
|
|
|
1840 |
);
|
|
|
1841 |
$.views.settings.debugMode(false);
|
|
|
1842 |
|
|
|
1843 |
// ................................ Act ..................................
|
|
|
1844 |
result = tmpl.render({});
|
|
|
1845 |
|
|
|
1846 |
// ............................... Assert .................................
|
|
|
1847 |
assert.equal(result.slice(0, 10), "a:{Error: ", "Calling base or baseApply when there is no base tag: Type Error");
|
|
|
1848 |
|
|
|
1849 |
// =============================== Arrange ===============================
|
|
|
1850 |
tmpl = $.templates("a:{{A 1 2 3/}} b:{{B 11 12 13/}} c:{{C 21 22 23/}}");
|
|
|
1851 |
|
|
|
1852 |
tagA = $.views.tags("A",
|
|
|
1853 |
function(val) {
|
|
|
1854 |
return "A" + val;
|
|
|
1855 |
},
|
|
|
1856 |
tmpl
|
|
|
1857 |
);
|
|
|
1858 |
|
|
|
1859 |
$.views.tags("B",
|
|
|
1860 |
{
|
|
|
1861 |
baseTag: tagA,
|
|
|
1862 |
render: function(val) {
|
|
|
1863 |
return "B" + val + this.base(val);
|
|
|
1864 |
}
|
|
|
1865 |
},
|
|
|
1866 |
tmpl
|
|
|
1867 |
);
|
|
|
1868 |
|
|
|
1869 |
tagC = $.views.tags("C",
|
|
|
1870 |
{
|
|
|
1871 |
baseTag: "A",
|
|
|
1872 |
bar: function(x, y, z) {
|
|
|
1873 |
return "BAR-C" + x + y + z + " Missing base method call: " + this.base(x) + this.baseApply(arguments) + ".";
|
|
|
1874 |
},
|
|
|
1875 |
render: function(val) {
|
|
|
1876 |
return "C" + val + this.bar.apply(this, this.tagCtx.args);
|
|
|
1877 |
}
|
|
|
1878 |
},
|
|
|
1879 |
tmpl
|
|
|
1880 |
);
|
|
|
1881 |
|
|
|
1882 |
// ................................ Act ..................................
|
|
|
1883 |
result = tmpl.render({});
|
|
|
1884 |
|
|
|
1885 |
// ............................... Assert .................................
|
|
|
1886 |
assert.equal(result, "a:A1 b:B11A11 c:C21BAR-C212223 Missing base method call: .",
|
|
|
1887 |
'Calling base or baseApply when there is no corresponding method on base tag implementation: noop - returning ""');
|
|
|
1888 |
|
|
|
1889 |
});
|
|
|
1890 |
|
|
|
1891 |
QUnit.test('{{include}} and wrapping content', function(assert) {
|
|
|
1892 |
var result = $.templates({
|
|
|
1893 |
markup:
|
|
|
1894 |
'Before {{include tmpl="wrapper"}}'
|
|
|
1895 |
+ '{{:name}}'
|
|
|
1896 |
+ '{{/include}} After',
|
|
|
1897 |
templates: {
|
|
|
1898 |
wrapper: "header{{include tmpl=#content/}}footer"
|
|
|
1899 |
}
|
|
|
1900 |
}).render(people);
|
|
|
1901 |
|
|
|
1902 |
assert.equal(result, "Before headerJofooter AfterBefore headerBillfooter After", 'Using {{include ... tmpl="wrapper"}}wrapped{{/include}}');
|
|
|
1903 |
|
|
|
1904 |
result = $.templates({
|
|
|
1905 |
markup:
|
|
|
1906 |
'This (render method) replaces: {{mytag override="replacementText" tmpl="wrapper"}}'
|
|
|
1907 |
+ '{{:name}}'
|
|
|
1908 |
+ '{{/mytag}} | '
|
|
|
1909 |
+ 'This (original template) adds: {{mytag}}'
|
|
|
1910 |
+ '{{:name}}'
|
|
|
1911 |
+ '{{/mytag}} | '
|
|
|
1912 |
+ 'This (new template) wraps: {{mytag setTmpl="wrapper"}}'
|
|
|
1913 |
+ '{{:name}}'
|
|
|
1914 |
+ '{{/mytag}} | ',
|
|
|
1915 |
tags: {
|
|
|
1916 |
mytag: {
|
|
|
1917 |
template: "add{{include tmpl=#content/}}",
|
|
|
1918 |
init: function() {
|
|
|
1919 |
this.template = this.tagCtx.props.setTmpl || this.template;
|
|
|
1920 |
},
|
|
|
1921 |
render: function() {
|
|
|
1922 |
return this.tagCtx.props.override;
|
|
|
1923 |
}
|
|
|
1924 |
}
|
|
|
1925 |
},
|
|
|
1926 |
templates: {
|
|
|
1927 |
wrapper: "header{{include tmpl=#content/}}footer"
|
|
|
1928 |
}
|
|
|
1929 |
}).render(people);
|
|
|
1930 |
|
|
|
1931 |
assert.equal(result,
|
|
|
1932 |
"This (render method) replaces: replacementText |"
|
|
|
1933 |
+ " This (original template) adds: addJo |"
|
|
|
1934 |
+ " This (new template) wraps: headerJofooter |"
|
|
|
1935 |
+ " This (render method) replaces: replacementText |"
|
|
|
1936 |
+ " This (original template) adds: addBill |"
|
|
|
1937 |
+ " This (new template) wraps: headerBillfooter | ",
|
|
|
1938 |
'Custom tag with wrapped content: {{mytag ... tmpl="wrapper"}}wrapped{{/myTmpl}}');
|
|
|
1939 |
|
|
|
1940 |
result = $.templates({
|
|
|
1941 |
markup:
|
|
|
1942 |
'Before {{include tmpl="wrapper"}}'
|
|
|
1943 |
+ '{{:name}}'
|
|
|
1944 |
+ '{{/include}} After',
|
|
|
1945 |
templates: {
|
|
|
1946 |
wrapper: "header{{for people tmpl=#content/}}footer"
|
|
|
1947 |
}
|
|
|
1948 |
}).render({people: people});
|
|
|
1949 |
|
|
|
1950 |
assert.equal(result, "Before headerJoBillfooter After", 'Using {{for ... tmpl="wrapper"}}wrapped{{/for}}');
|
|
|
1951 |
|
|
|
1952 |
result = $.templates({
|
|
|
1953 |
markup:
|
|
|
1954 |
'This replaces:{{mytag override="replacementText"}}'
|
|
|
1955 |
+ '{{:name}}'
|
|
|
1956 |
+ '{{/mytag}}'
|
|
|
1957 |
+ 'This wraps:{{mytag tmpl="wrapper"}}'
|
|
|
1958 |
+ '{{:name}}'
|
|
|
1959 |
+ '{{/mytag}}',
|
|
|
1960 |
tags: {
|
|
|
1961 |
mytag: function() {
|
|
|
1962 |
return this.tagCtx.props.override;
|
|
|
1963 |
}
|
|
|
1964 |
},
|
|
|
1965 |
templates: {
|
|
|
1966 |
wrapper: "header{{for people tmpl=#content/}}footer"
|
|
|
1967 |
}
|
|
|
1968 |
}).render({people: people});
|
|
|
1969 |
|
|
|
1970 |
assert.equal(result, "This replaces:replacementTextThis wraps:headerJoBillfooter", 'Using {{mytag ... tmpl="wrapper"}}wrapped{{/myTmpl}}');
|
|
|
1971 |
|
|
|
1972 |
result = $.templates({
|
|
|
1973 |
markup:
|
|
|
1974 |
'{{mytag}}'
|
|
|
1975 |
+ '{{:name}}'
|
|
|
1976 |
+ '{{/mytag}} | '
|
|
|
1977 |
+ '{{mytag tmpl="innerwrap"}}'
|
|
|
1978 |
+ '{{:name}}'
|
|
|
1979 |
+ '{{/mytag}} | '
|
|
|
1980 |
+ '{{mytag tmpl="middlewrap"}}'
|
|
|
1981 |
+ '{{:name}}'
|
|
|
1982 |
+ '{{/mytag}} | '
|
|
|
1983 |
+ '{{mytag tmpl="wrapper"}}'
|
|
|
1984 |
+ '{{:name}}'
|
|
|
1985 |
+ '{{/mytag}} | '
|
|
|
1986 |
|
|
|
1987 |
+ '{{mytag2}}'
|
|
|
1988 |
+ '{{:name}}'
|
|
|
1989 |
+ '{{/mytag2}} | '
|
|
|
1990 |
+ '{{mytag2 tmpl="innerwrap"}}'
|
|
|
1991 |
+ '{{:name}}'
|
|
|
1992 |
+ '{{/mytag2}} | '
|
|
|
1993 |
+ '{{mytag2 tmpl="middlewrap"}}'
|
|
|
1994 |
+ '{{:name}}'
|
|
|
1995 |
+ '{{/mytag2}} | '
|
|
|
1996 |
+ '{{mytag2 tmpl="wrapper"}}'
|
|
|
1997 |
+ '{{:name}}'
|
|
|
1998 |
+ '{{/mytag2}} | ',
|
|
|
1999 |
templates: {
|
|
|
2000 |
wrapper: "middle {{include tmpl=#content/}} {{include tmpl='middlewrap'/}} {{include tmpl='innerwrap'/}}/middle",
|
|
|
2001 |
middlewrap: "inner {{include tmpl=#content/}} and {{include tmpl='innerwrap'/}} /inner",
|
|
|
2002 |
innerwrap: "innermost {{include tmpl=#content/}} /innermost"
|
|
|
2003 |
},
|
|
|
2004 |
tags: {
|
|
|
2005 |
mytag: {
|
|
|
2006 |
template: "outer {{include tmpl=#content/}} /outer"
|
|
|
2007 |
},
|
|
|
2008 |
mytag2: {
|
|
|
2009 |
}
|
|
|
2010 |
}
|
|
|
2011 |
}).render(people);
|
|
|
2012 |
|
|
|
2013 |
assert.equal(result,
|
|
|
2014 |
"outer Jo /outer |"
|
|
|
2015 |
+ " outer innermost Jo /innermost /outer |"
|
|
|
2016 |
+ " outer inner Jo and innermost Jo /innermost /inner /outer |"
|
|
|
2017 |
+ " outer middle Jo inner Jo and innermost Jo /innermost /inner innermost Jo /innermost/middle /outer |"
|
|
|
2018 |
|
|
|
2019 |
+ " Jo |"
|
|
|
2020 |
+ " innermost Jo /innermost |"
|
|
|
2021 |
+ " inner Jo and innermost Jo /innermost /inner |"
|
|
|
2022 |
+ " middle Jo inner Jo and innermost Jo /innermost /inner innermost Jo /innermost/middle |"
|
|
|
2023 |
|
|
|
2024 |
+ " outer Bill /outer |"
|
|
|
2025 |
+ " outer innermost Bill /innermost /outer |"
|
|
|
2026 |
+ " outer inner Bill and innermost Bill /innermost /inner /outer |"
|
|
|
2027 |
+ " outer middle Bill inner Bill and innermost Bill /innermost /inner innermost Bill /innermost/middle /outer |"
|
|
|
2028 |
|
|
|
2029 |
+ " Bill |"
|
|
|
2030 |
+ " innermost Bill /innermost |"
|
|
|
2031 |
+ " inner Bill and innermost Bill /innermost /inner |"
|
|
|
2032 |
+ " middle Bill inner Bill and innermost Bill /innermost /inner innermost Bill /innermost/middle | ",
|
|
|
2033 |
'Cascading multi-level wrappers around #content'
|
|
|
2034 |
);
|
|
|
2035 |
|
|
|
2036 |
var data = [{
|
|
|
2037 |
phones: [
|
|
|
2038 |
{number: "Ph0", alt: "Alt0"},
|
|
|
2039 |
{number: "Ph1", alt: "Alt1"},
|
|
|
2040 |
{number: "Ph2", alt: "Alt2"}
|
|
|
2041 |
]
|
|
|
2042 |
}];
|
|
|
2043 |
|
|
|
2044 |
result = $.templates({
|
|
|
2045 |
markup:
|
|
|
2046 |
'{{mytag tmpl="phonelist"}}'
|
|
|
2047 |
+ '{{:number}} '
|
|
|
2048 |
+ '{{/mytag}} | '
|
|
|
2049 |
+ '{{mytag2 tmpl="phonelist"}}'
|
|
|
2050 |
+ '{{:number}} '
|
|
|
2051 |
+ '{{/mytag2}}',
|
|
|
2052 |
templates: {
|
|
|
2053 |
phonelist: "{{for phones}}{{include tmpl=#content/}}{{/for}}"
|
|
|
2054 |
},
|
|
|
2055 |
tags: {
|
|
|
2056 |
mytag: {
|
|
|
2057 |
template: "outer {{include tmpl=#content/}} /outer"
|
|
|
2058 |
},
|
|
|
2059 |
mytag2: {
|
|
|
2060 |
}
|
|
|
2061 |
}
|
|
|
2062 |
}).render(data);
|
|
|
2063 |
|
|
|
2064 |
assert.equal(result,
|
|
|
2065 |
"outer Ph0 Ph1 Ph2 /outer | Ph0 Ph1 Ph2 ",
|
|
|
2066 |
'Cascading multi-level wrapper around #content with {{for}}'
|
|
|
2067 |
);
|
|
|
2068 |
|
|
|
2069 |
result = $.templates({
|
|
|
2070 |
markup:
|
|
|
2071 |
'{{mytag tmpl="phonelist"}}'
|
|
|
2072 |
+ '{{:number}}'
|
|
|
2073 |
+ '{{else tmpl="altlist"}}'
|
|
|
2074 |
+ '{{:alt}}'
|
|
|
2075 |
+ '{{else tmpl="altlist2"}}'
|
|
|
2076 |
+ '{{:alt}}'
|
|
|
2077 |
+ '{{/mytag}}'
|
|
|
2078 |
+ '{{mytag2 tmpl="phonelist"}}'
|
|
|
2079 |
+ '{{:number}}'
|
|
|
2080 |
+ '{{else tmpl="altlist"}}'
|
|
|
2081 |
+ '{{:alt}}'
|
|
|
2082 |
+ '{{else tmpl="altlist2"}}'
|
|
|
2083 |
+ '{{:alt}}'
|
|
|
2084 |
+ '{{/mytag2}}',
|
|
|
2085 |
templates: {
|
|
|
2086 |
phonelist: "A< {{for phones}}{{include tmpl=#content/}} {{/for}} > ",
|
|
|
2087 |
altlist: "B< {{for phones tmpl='titlewrap'/}} > ",
|
|
|
2088 |
altlist2: "C< {{for phones}}{{include tmpl='titlewrap'/}}{{/for}} > ",
|
|
|
2089 |
titlewrap: "alternate: {{include tmpl=#content/}} "
|
|
|
2090 |
},
|
|
|
2091 |
tags: {
|
|
|
2092 |
mytag: {
|
|
|
2093 |
template: "outer {{include tmpl=#content/}} /outer | "
|
|
|
2094 |
},
|
|
|
2095 |
mytag2: {
|
|
|
2096 |
}
|
|
|
2097 |
}
|
|
|
2098 |
}).render(data);
|
|
|
2099 |
|
|
|
2100 |
assert.equal(result,
|
|
|
2101 |
"outer A< Ph0 Ph1 Ph2 > /outer |"
|
|
|
2102 |
+ " outer B< alternate: Alt0 alternate: Alt1 alternate: Alt2 > /outer |"
|
|
|
2103 |
+ " outer C< alternate: Alt0 alternate: Alt1 alternate: Alt2 > /outer |"
|
|
|
2104 |
+ " A< Ph0 Ph1 Ph2 >"
|
|
|
2105 |
+ " B< alternate: Alt0 alternate: Alt1 alternate: Alt2 >"
|
|
|
2106 |
+ " C< alternate: Alt0 alternate: Alt1 alternate: Alt2 > ",
|
|
|
2107 |
'Cascading multi-level wrapper around #content with {{for}}{{else}}'
|
|
|
2108 |
);
|
|
|
2109 |
});
|
|
|
2110 |
|
|
|
2111 |
QUnit.test("helpers", function(assert) {
|
|
|
2112 |
$.views.helpers({
|
|
|
2113 |
not: function(value) {
|
|
|
2114 |
return !value;
|
|
|
2115 |
},
|
|
|
2116 |
concat: function() {
|
|
|
2117 |
return "".concat.apply("", arguments) + "top";
|
|
|
2118 |
}
|
|
|
2119 |
});
|
|
|
2120 |
assert.equal($.templates("{{:~concat(a, 'b', ~not(false))}}").render({a: "aVal"}), "aValbtruetop", "~concat('a')");
|
|
|
2121 |
|
|
|
2122 |
function toUpperCase(value) {
|
|
|
2123 |
return value.toUpperCase();
|
|
|
2124 |
}
|
|
|
2125 |
var toUpperCaseFn = $.views.helpers("toUpperCase", toUpperCase);
|
|
|
2126 |
assert.equal($.templates("{{:~toUpperCase(name)}} {{:~toUpperCase('Foo')}}").render(person), "JO FOO", '$.views.helpers("toUpperCase", toUpperCaseFn);... {{:~toUpperCase(name)}}');
|
|
|
2127 |
|
|
|
2128 |
$.views.helpers({toUpperCase2: toUpperCase});
|
|
|
2129 |
assert.equal(toUpperCaseFn === toUpperCase && $.views.helpers.toUpperCase === toUpperCase && $.views.helpers.toUpperCase2 === toUpperCase, true, 'sortFunction === $.views.helpers.toUpperCase === $.views.helpers("toUpperCase")');
|
|
|
2130 |
|
|
|
2131 |
$.views.helpers("toUpperCase2", null);
|
|
|
2132 |
assert.equal($.views.helpers.toUpperCase2, undefined, '$.views.helpers("toUpperCase2", null) to remove registered helper');
|
|
|
2133 |
});
|
|
|
2134 |
|
|
|
2135 |
QUnit.test("settings", function(assert) {
|
|
|
2136 |
// ................................ Act ..................................
|
|
|
2137 |
// Delimiters
|
|
|
2138 |
|
|
|
2139 |
$.views.settings.delimiters("@%","%@");
|
|
|
2140 |
var result = $.templates("A_@%if true%@yes@%/if%@_B").render()
|
|
|
2141 |
+ "|" + $.views.settings.delimiters() + "|" + $.views.sub.settings.delimiters;
|
|
|
2142 |
|
|
|
2143 |
$.views.settings.delimiters("<<",">>", "*");
|
|
|
2144 |
|
|
|
2145 |
result += "|" + $.views.settings.delimiters() + "|" + $.views.sub.settings.delimiters;
|
|
|
2146 |
|
|
|
2147 |
$.views.settings.delimiters("{{","}}", "^");
|
|
|
2148 |
result += "|" + $.templates("A_{{if true}}YES{{/if}}_B").render()
|
|
|
2149 |
+ "|" + $.views.settings.delimiters() + "|" + $.views.sub.settings.delimiters;
|
|
|
2150 |
|
|
|
2151 |
// ............................... Assert .................................
|
|
|
2152 |
assert.equal(result, "A_yes_B|@%,%@,^|@%,%@,^|<<,>>,*|<<,>>,*|A_YES_B|{{,}},^|{{,}},^", "Custom delimiters with render()");
|
|
|
2153 |
|
|
|
2154 |
// =============================== Arrange ===============================
|
|
|
2155 |
// Debug mode false
|
|
|
2156 |
|
|
|
2157 |
var oldDebugMode = $.views.settings.debugMode();
|
|
|
2158 |
var app = {choose: true, name: "Jo"};
|
|
|
2159 |
result = "";
|
|
|
2160 |
|
|
|
2161 |
// ................................ Act ..................................
|
|
|
2162 |
$.views.settings.debugMode(false);
|
|
|
2163 |
|
|
|
2164 |
try {
|
|
|
2165 |
result = $.templates('{{:missing.willThrow}}').render(app);
|
|
|
2166 |
} catch(e) {
|
|
|
2167 |
result += !!e.message;
|
|
|
2168 |
}
|
|
|
2169 |
|
|
|
2170 |
// ............................... Assert .................................
|
|
|
2171 |
assert.equal($.views.settings.debugMode() + " " + result, 'false true',
|
|
|
2172 |
'Debug mode false: {{:missing.willThrow}} throws error');
|
|
|
2173 |
|
|
|
2174 |
// ................................ Act ..................................
|
|
|
2175 |
// Debug mode true
|
|
|
2176 |
|
|
|
2177 |
$.views.settings.debugMode(true);
|
|
|
2178 |
|
|
|
2179 |
try {
|
|
|
2180 |
result = $.templates('{{:missing.willThrow}}').render(app);
|
|
|
2181 |
} catch(e) {
|
|
|
2182 |
result += !!e.message;
|
|
|
2183 |
}
|
|
|
2184 |
|
|
|
2185 |
// ............................... Assert .................................
|
|
|
2186 |
assert.equal($.views.settings.debugMode() + " " + result.slice(0, 8), 'true {Error: ',
|
|
|
2187 |
'Debug mode true: {{:missing.willThrow}} renders error');
|
|
|
2188 |
|
|
|
2189 |
// ................................ Act ..................................
|
|
|
2190 |
// Debug mode 'onError' handler function with return value
|
|
|
2191 |
|
|
|
2192 |
$.views.settings.debugMode(function(e, fallback, view) {
|
|
|
2193 |
var data = this;
|
|
|
2194 |
return "Override error - " + (fallback||"") + "_" + (view ? data.name + " " + (e.message.indexOf("undefined")>-1): e); // For syntax errors e is a string, and view is undefined
|
|
|
2195 |
});
|
|
|
2196 |
|
|
|
2197 |
// ................................ Act ..................................
|
|
|
2198 |
result = typeof $.views.settings.debugMode() + " ";
|
|
|
2199 |
result += $.templates('{{:missing.willThrow}}').render(app);
|
|
|
2200 |
|
|
|
2201 |
// ............................... Assert .................................
|
|
|
2202 |
assert.equal(result, "function Override error - _Jo true",
|
|
|
2203 |
"Debug mode 'onError' handler override, with {{:missing.willThrow}}");
|
|
|
2204 |
|
|
|
2205 |
// ................................ Act ..................................
|
|
|
2206 |
result = typeof $.views.settings.debugMode() + " ";
|
|
|
2207 |
result += $.templates('{{:missing.willThrow onError="myFallback"}}').render(app);
|
|
|
2208 |
|
|
|
2209 |
// ............................... Assert .................................
|
|
|
2210 |
assert.equal(result, "function Override error - myFallback_Jo true",
|
|
|
2211 |
'Debug mode \'onError\' handler override, with onError fallback: {{:missing.willThrow onError="myFallback"}}');
|
|
|
2212 |
|
|
|
2213 |
// ................................ Act ..................................
|
|
|
2214 |
result = typeof $.views.settings.debugMode() + " ";
|
|
|
2215 |
result += $.templates('{{if missing.willThrow onError="myFallback"}}yes{{/if}}').render(app);
|
|
|
2216 |
|
|
|
2217 |
// ............................... Assert .................................
|
|
|
2218 |
assert.equal(result, 'function Override error - myFallback_Jo true',
|
|
|
2219 |
'Debug mode \'onError\' handler override, with onError fallback: {{if missing.willThrow onError="myFallback"}}');
|
|
|
2220 |
|
|
|
2221 |
// ................................ Act ..................................
|
|
|
2222 |
// Debug mode 'onError' handler function without return value
|
|
|
2223 |
var ret = "";
|
|
|
2224 |
$.views.settings.debugMode(function(e, fallback, view) {
|
|
|
2225 |
var data = this;
|
|
|
2226 |
ret = "Override error - " + (fallback||"") + "_" + data.name + " " + (e.message.indexOf("undefined")>-1); // For syntax errors e is a string, and view is undefined
|
|
|
2227 |
});
|
|
|
2228 |
|
|
|
2229 |
// ................................ Act ..................................
|
|
|
2230 |
result = typeof $.views.settings.debugMode() + " ";
|
|
|
2231 |
result += $.templates('{{:missing.willThrow}}').render(app);
|
|
|
2232 |
|
|
|
2233 |
// ............................... Assert .................................
|
|
|
2234 |
assert.equal(ret + "|" + result.slice(0, 17), "Override error - _Jo true|function {Error: ",
|
|
|
2235 |
"Debug mode 'onError' handler (no return) with {{:missing.willThrow}}");
|
|
|
2236 |
|
|
|
2237 |
// ................................ Act ..................................
|
|
|
2238 |
result = typeof $.views.settings.debugMode() + " ";
|
|
|
2239 |
result += $.templates('{{:missing.willThrow onError="myFallback"}}').render(app);
|
|
|
2240 |
|
|
|
2241 |
// ............................... Assert .................................
|
|
|
2242 |
assert.equal(ret + "|" + result, "Override error - myFallback_Jo true|function myFallback",
|
|
|
2243 |
'Debug mode \'onError\' handler (no return) with onError fallback: {{:missing.willThrow onError="myFallback"}}');
|
|
|
2244 |
|
|
|
2245 |
// ................................ Act ..................................
|
|
|
2246 |
result = typeof $.views.settings.debugMode() + " ";
|
|
|
2247 |
result += $.templates('{{if missing.willThrow onError="myFallback"}}yes{{/if}}').render(app);
|
|
|
2248 |
|
|
|
2249 |
// ............................... Assert .................................
|
|
|
2250 |
assert.equal(ret + "|" + result, "Override error - myFallback_Jo true|function myFallback",
|
|
|
2251 |
'Debug mode \'onError\' handler (no return) with onError fallback: {{if missing.willThrow onError="myFallback"}}');
|
|
|
2252 |
|
|
|
2253 |
// ................................ Reset ..................................
|
|
|
2254 |
$.views.settings.debugMode(oldDebugMode);
|
|
|
2255 |
});
|
|
|
2256 |
|
|
|
2257 |
QUnit.test("template encapsulation", function(assert) {
|
|
|
2258 |
// =============================== Arrange ===============================
|
|
|
2259 |
$.templates({
|
|
|
2260 |
myTmpl6: {
|
|
|
2261 |
markup: "{{sort reverse=true people}}{{:name}}{{/sort}}",
|
|
|
2262 |
tags: {
|
|
|
2263 |
sort: sort
|
|
|
2264 |
}
|
|
|
2265 |
}
|
|
|
2266 |
});
|
|
|
2267 |
|
|
|
2268 |
// ............................... Assert .................................
|
|
|
2269 |
assert.equal($.render.myTmpl6({people: people}), "BillJo", '$.templates("myTmpl", tmplObjWithNestedItems);');
|
|
|
2270 |
|
|
|
2271 |
// =============================== Arrange ===============================
|
|
|
2272 |
$.views.helpers("h1", "globalHelper");
|
|
|
2273 |
|
|
|
2274 |
var tmpl = $.templates({
|
|
|
2275 |
markup: "{{if true}}{{:~h1}} {{:~h2}} {{:~h3}}{{/if}}",
|
|
|
2276 |
helpers: {
|
|
|
2277 |
h2: "templateHelper"
|
|
|
2278 |
}
|
|
|
2279 |
});
|
|
|
2280 |
|
|
|
2281 |
// ............................... Assert .................................
|
|
|
2282 |
assert.equal(tmpl.render({}, {h3:"optionHelper"}), "globalHelper templateHelper optionHelper", 'Passing in helpers - global, template or option');
|
|
|
2283 |
|
|
|
2284 |
// =============================== Arrange ===============================
|
|
|
2285 |
tmpl = $.templates({
|
|
|
2286 |
markup: "{{if true}}{{:~h1}}{{/if}}",
|
|
|
2287 |
helpers: {
|
|
|
2288 |
h1: "templateHelper"
|
|
|
2289 |
}
|
|
|
2290 |
});
|
|
|
2291 |
|
|
|
2292 |
// ............................... Assert .................................
|
|
|
2293 |
assert.equal(tmpl.render({}), "templateHelper", 'template helper overrides global helper');
|
|
|
2294 |
|
|
|
2295 |
// =============================== Arrange ===============================
|
|
|
2296 |
tmpl = $.templates({
|
|
|
2297 |
markup: "{{if true}}{{:~h1}}{{/if}}"
|
|
|
2298 |
});
|
|
|
2299 |
|
|
|
2300 |
// ............................... Assert .................................
|
|
|
2301 |
assert.equal(tmpl.render({}, {h1: "optionHelper"}), "optionHelper", 'option helper overrides global helper');
|
|
|
2302 |
|
|
|
2303 |
// =============================== Arrange ===============================
|
|
|
2304 |
tmpl = $.templates({
|
|
|
2305 |
markup: "{{if true}}{{:~h2}}{{/if}}",
|
|
|
2306 |
helpers: {
|
|
|
2307 |
h2: "templateHelper"
|
|
|
2308 |
}
|
|
|
2309 |
});
|
|
|
2310 |
|
|
|
2311 |
// ............................... Assert .................................
|
|
|
2312 |
assert.equal(tmpl.render({}, {h2: "optionHelper"}), "templateHelper", 'template helper overrides option helper');
|
|
|
2313 |
|
|
|
2314 |
// =============================== Arrange ===============================
|
|
|
2315 |
$.views.converters("c1", function(val) {return val + "globalCvt";});
|
|
|
2316 |
|
|
|
2317 |
tmpl = $.templates({
|
|
|
2318 |
markup: "{{if true}}{{c1:1}}{{c2:2}}{{/if}}",
|
|
|
2319 |
converters: {
|
|
|
2320 |
c2: function(val) {return val + "templateCvt";}
|
|
|
2321 |
}
|
|
|
2322 |
});
|
|
|
2323 |
|
|
|
2324 |
// ............................... Assert .................................
|
|
|
2325 |
assert.equal(tmpl.render({}), "1globalCvt2templateCvt", 'template converter and global converter');
|
|
|
2326 |
|
|
|
2327 |
// =============================== Arrange ===============================
|
|
|
2328 |
tmpl = $.templates({
|
|
|
2329 |
markup: "{{if true}}{{c1:1}}{{/if}}",
|
|
|
2330 |
converters: {
|
|
|
2331 |
c1: function(val) {return val + "templateCvt";}
|
|
|
2332 |
}
|
|
|
2333 |
});
|
|
|
2334 |
|
|
|
2335 |
// ............................... Assert .................................
|
|
|
2336 |
assert.equal(tmpl.render({}), "1templateCvt", 'template converter overrides global converter');
|
|
|
2337 |
|
|
|
2338 |
// =============================== Arrange ===============================
|
|
|
2339 |
|
|
|
2340 |
$.templates({
|
|
|
2341 |
cascade: "outerCascade",
|
|
|
2342 |
nesting: {
|
|
|
2343 |
markup: "{{if true}} {{c1:~h1}} {{include tmpl='inner'/}}{{/if}} {{include tmpl='cascade'/}}",
|
|
|
2344 |
helpers: {
|
|
|
2345 |
h1: "templateHelper"
|
|
|
2346 |
},
|
|
|
2347 |
converters: {
|
|
|
2348 |
c1: function(val) {return val + " templateCvt";}
|
|
|
2349 |
},
|
|
|
2350 |
templates: {
|
|
|
2351 |
cascade: "innerCascade",
|
|
|
2352 |
inner: {
|
|
|
2353 |
markup: "{{if true}}{{c1:~h1}}{{/if}} {{include tmpl='cascade'/}}",
|
|
|
2354 |
helpers: {
|
|
|
2355 |
h1: "innerTemplateHelper"
|
|
|
2356 |
},
|
|
|
2357 |
converters: {
|
|
|
2358 |
c1: function(val) {return val + " innerTemplateCvt";}
|
|
|
2359 |
},
|
|
|
2360 |
templates: {
|
|
|
2361 |
cascade: "innerInnerCascade"
|
|
|
2362 |
}
|
|
|
2363 |
}
|
|
|
2364 |
}
|
|
|
2365 |
}
|
|
|
2366 |
});
|
|
|
2367 |
|
|
|
2368 |
// ............................... Assert .................................
|
|
|
2369 |
assert.equal($.templates.nesting.render({}, {b: "optionHelper"}), " templateHelper templateCvt innerTemplateHelper innerTemplateCvt innerInnerCascade innerCascade",
|
|
|
2370 |
'Inner template, helper, and converter override outer template, helper, and converter');
|
|
|
2371 |
});
|
|
|
2372 |
|
|
|
2373 |
QUnit.module("Custom tags");
|
|
|
2374 |
|
|
|
2375 |
QUnit.test("contentCtx", function(assert) {
|
|
|
2376 |
|
|
|
2377 |
var tmpl = $.templates("{{for 'parent'}}{{mytag 'arg1' 'arg2' 'arg3'}} {{:#data}}A{{else 'elseArg1'}} {{:#data}}B{{else}} {{:#data}}C{{/mytag}}{{/for}}");
|
|
|
2378 |
|
|
|
2379 |
// =============================== Arrange ===============================
|
|
|
2380 |
|
|
|
2381 |
$.views.tags({mytag: {
|
|
|
2382 |
}}, tmpl);
|
|
|
2383 |
|
|
|
2384 |
// ............................... Assert .................................
|
|
|
2385 |
assert.equal(tmpl.render("outer"), " arg1A elseArg1B parentC", 'No contentCtx - context is 1st arg or parentView.data');
|
|
|
2386 |
|
|
|
2387 |
// =============================== Arrange ===============================
|
|
|
2388 |
|
|
|
2389 |
$.views.tags({mytag: {
|
|
|
2390 |
contentCtx: function(val) {
|
|
|
2391 |
return 0;
|
|
|
2392 |
}
|
|
|
2393 |
}}, tmpl);
|
|
|
2394 |
|
|
|
2395 |
// ............................... Assert .................................
|
|
|
2396 |
assert.equal(tmpl.render("outer"), " 0A 0B 0C", 'contentCtx returns 0 - context is 0 (even for falsy values like 0');
|
|
|
2397 |
|
|
|
2398 |
// =============================== Arrange ===============================
|
|
|
2399 |
|
|
|
2400 |
$.views.tags({mytag: {
|
|
|
2401 |
contentCtx: function(val) {
|
|
|
2402 |
return val;
|
|
|
2403 |
}
|
|
|
2404 |
}}, tmpl);
|
|
|
2405 |
|
|
|
2406 |
// ............................... Assert .................................
|
|
|
2407 |
assert.equal(tmpl.render("outer"), " arg1A elseArg1B parentC", 'contentCtx returns first arg/parentView - context is 1st arg or parentView.data');
|
|
|
2408 |
|
|
|
2409 |
// =============================== Arrange ===============================
|
|
|
2410 |
|
|
|
2411 |
$.views.tags({mytag: {
|
|
|
2412 |
contentCtx: function(val) {
|
|
|
2413 |
return this.tagCtx.view;
|
|
|
2414 |
}
|
|
|
2415 |
}}, tmpl);
|
|
|
2416 |
|
|
|
2417 |
// ............................... Assert .................................
|
|
|
2418 |
assert.equal(tmpl.render("outer"), " parentA parentB parentC", 'contentCtx returns this.tagCtx.view - context is parentView.data');
|
|
|
2419 |
|
|
|
2420 |
// =============================== Arrange ===============================
|
|
|
2421 |
|
|
|
2422 |
$.views.tags({mytag: {
|
|
|
2423 |
contentCtx: function(val) {
|
|
|
2424 |
return this.tagCtx.view.data;
|
|
|
2425 |
}
|
|
|
2426 |
}}, tmpl);
|
|
|
2427 |
|
|
|
2428 |
// ............................... Assert .................................
|
|
|
2429 |
assert.equal(tmpl.render("outer"), " parentA parentB parentC", 'contentCtx returns this.tagCtx.view.data - context is parentView.data');
|
|
|
2430 |
|
|
|
2431 |
// =============================== Arrange ===============================
|
|
|
2432 |
|
|
|
2433 |
$.views.tags({mytag: {
|
|
|
2434 |
contentCtx: function(val) {
|
|
|
2435 |
return this.tagCtxs[0].args[this.tagCtx.index];
|
|
|
2436 |
}
|
|
|
2437 |
}}, tmpl);
|
|
|
2438 |
|
|
|
2439 |
// ............................... Assert .................................
|
|
|
2440 |
assert.equal(tmpl.render("outer"), " arg1A arg2B arg3C", 'contentCtx returns arg from first tagCtx indexed on else - context is arg1/arg2/arg3');
|
|
|
2441 |
|
|
|
2442 |
// =============================== Arrange ===============================
|
|
|
2443 |
|
|
|
2444 |
tmpl = $.templates("{{for 'outerparent'}}{{for 'parent'}}{{mytag 'arg1' 'arg2' 'arg3'}} {{:#data}}A{{else 'elseArg1'}} {{:#data}}B{{else}} {{:#data}}C{{/mytag}}{{/for}}{{/for}}");
|
|
|
2445 |
|
|
|
2446 |
$.views.tags({mytag: {
|
|
|
2447 |
contentCtx: function(val) {
|
|
|
2448 |
return this.tagCtx.view.parent;
|
|
|
2449 |
}
|
|
|
2450 |
}}, tmpl);
|
|
|
2451 |
|
|
|
2452 |
// ............................... Assert .................................
|
|
|
2453 |
assert.equal(tmpl.render("outer"), " outerparentA outerparentB outerparentC", 'contentCtx returns this.tagCtx.view.parent');
|
|
|
2454 |
|
|
|
2455 |
});
|
|
|
2456 |
|
|
|
2457 |
})();
|