Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
6056 efrain 1
/*global test, equal, module, ok*/
2
(function(global, $, undefined) {
3
"use strict";
4
 
5
function sort(array) {
6
	var ret = "";
7
	if (this.tagCtx.props.reverse) {
8
		// Render in reverse order
9
		for (var i = array.length; i; i--) {
10
			ret += this.tagCtx.render(array[ i - 1 ]);
11
		}
12
	} else {
13
		// Render in original order
14
		ret += this.tmpl.render(array);
15
	}
16
	return ret;
17
}
18
 
19
var person = {name: "Jo"},
20
	people = [{name: "Jo"},{name: "Bill"}],
21
	towns = [{name: "Seattle"},{name: "Paris"},{name: "Delhi"}];
22
 
23
var tmplString = "A_{{:name}}_B";
24
 
25
QUnit.module("api");
26
 
27
QUnit.test("templates", function(assert) {
28
	var tmplElem = document.getElementById("./test/templates/file/path.html");
29
 
30
	// =============================== Arrange ===============================
31
	$.removeData(tmplElem, "jsvTmpl"); // In case data has been set in a previous test
32
 
33
	// ................................ Act ..................................
34
	var tmpl0 = $.templates({markup: "./test/templates/file/path.html"}); // Compile template but do not cache
35
 
36
	// ............................... Assert .................................
37
	assert.equal(!$.data(tmplElem).jsvTmpl && tmpl0.render({name: "Jo0"}), "ServerRenderedTemplate_Jo0_B", "Compile server-generated template, without caching");
38
 
39
	// ................................ Act ..................................
40
	var tmpl1 = $.templates("./test/templates/file/path.html"); // Compile and cache, using $.data(elem, "jsvTmpl", tmpl);
41
 
42
	// ............................... Assert .................................
43
	assert.equal(tmpl1 !== tmpl0 && $.data(tmplElem).jsvTmpl === tmpl1 && tmpl1.render({name: "Jo1"}), "ServerRenderedTemplate_Jo1_B", "Compile server-generated template, and cache on file path");
44
 
45
	// ................................ Act ..................................
46
	var tmpl2 = $.templates("./test/templates/file/path.html"); // Use cached template, accessed by path as key
47
 
48
	// ............................... Assert .................................
49
	assert.equal(tmpl2 === tmpl1 && tmpl1.render({name: "Jo2"}), "ServerRenderedTemplate_Jo2_B", "Re-use cached server-generated template");
50
 
51
	// ................................ Act ..................................
52
	var tmpl3 = $.templates({markup: "./test/templates/file/path.html"}); // Re-compile template but do not cache. Leaved cached template.
53
 
54
	// ............................... Assert .................................
55
	assert.equal(tmpl3 !== tmpl0 && tmpl3 !== tmpl1 && $.data(tmplElem).jsvTmpl === tmpl1 && tmpl3.render({name: "Jo3"}), "ServerRenderedTemplate_Jo3_B", "Recompile server-generated template, without caching");
56
 
57
	// ................................ Reset ................................
58
	delete $.data(tmplElem).jsvTmpl;
59
	document.getElementById("./test/templates/file/path.html").removeAttribute("data-jsv-tmpl");
60
 
61
	tmplElem = $("#myTmpl")[0];
62
	delete $.data(tmplElem).jsvTmpl;
63
	tmplElem.removeAttribute("data-jsv-tmpl");
64
 
65
	// ................................ Act ..................................
66
	tmpl0 = $.templates({markup: "#myTmpl"}); // Compile template declared in script block, but do not cache
67
 
68
	// ............................... Assert .................................
69
	assert.equal(!$.data(tmplElem).jsvTmpl && tmpl0.render({name: "Jo0"}), "A_Jo0_B", "Compile template declared in script block, without caching");
70
 
71
	// ................................ Act ..................................
72
	tmpl1 = $.templates("#myTmpl"); // Compile and cache, using $.data(elem, "jsvTmpl", tmpl);
73
 
74
	// ............................... Assert .................................
75
	assert.equal(tmpl1 !== tmpl0 && $.data(tmplElem).jsvTmpl === tmpl1 && tmpl1.render({name: "Jo1"}), "A_Jo1_B", "Compile template declared in script block, and cache on file path");
76
 
77
	// ................................ Act ..................................
78
	tmpl2 = $.templates("#myTmpl"); // Use cached template, accessed by $.data(elem, "jsvTmpl")
79
 
80
	// ............................... Assert .................................
81
	assert.equal(tmpl2 === tmpl1 && tmpl1.render({name: "Jo2"}), "A_Jo2_B", "Re-use cached template declared in script block");
82
 
83
	// ................................ Act ..................................
84
	tmpl3 = $.templates({markup: "#myTmpl"}); // Re-compile template but do not cache. Leave cached template.
85
 
86
	// ............................... Assert .................................
87
	assert.equal(tmpl3 !== tmpl0 && tmpl3 !== tmpl1 && $.data(tmplElem).jsvTmpl === tmpl1 && tmpl3.render({name: "Jo3"}), "A_Jo3_B", "Recompile template declared in script block, without caching");
88
 
89
	// ................................ Reset ................................
90
	delete $.data(tmplElem).jsvTmpl;
91
	tmplElem.removeAttribute("data-jsv-tmpl");
92
 
93
	// =============================== Arrange ===============================
94
	// ............................... Assert .................................
95
	assert.equal($.templates("#my_tmpl2").render(), "' \" \\ \\' \\\"", "correct treatment of ' \" and ' in template declared in script block");
96
 
97
	assert.equal($.templates("' \" \\ \\' \\\"").render(), "' \" \\ \\' \\\"", "correct treatment of ' \" and ' in template compiled from string");
98
 
99
	$.templates("my_tmpl", tmplString);
100
	assert.equal($.render.my_tmpl(person), "A_Jo_B", 'Compile a template and then render it: $.templates("my_tmpl", tmplString); $.render.my_tmpl(data);');
101
 
102
	$.templates({myTmpl2: tmplString});
103
	assert.equal($.render.myTmpl2(person), "A_Jo_B", 'Compile and register templates: $.templates({"my_tmpl", tmplString, ...}); $.render.my_tmpl(data);');
104
 
105
	assert.equal($.templates.myTmpl2.render(person), "A_Jo_B", 'Get named template: $.templates.my_tmpl.render(data);');
106
 
107
	assert.equal($.templates(tmplString).render(person), "A_Jo_B", 'Compile without registering as named template: $.templates(tmplString).render(person);');
108
 
109
	tmpl2 = $.templates("#my_tmpl");
110
	tmpl3 = $.templates("#my_tmpl");
111
	assert.equal(tmpl2 === tmpl3 && $.trim(tmpl2.render(person)), "A_Jo_B", 'var tmpl = $.templates("#my_tmpl"); returns compiled template for script element');
112
 
113
	$.templates({
114
		my_tmpl3: {
115
			markup: "#my_tmpl"
116
		}
117
	});
118
 
119
	assert.equal($.render.my_tmpl3 === $.templates.my_tmpl3 && $.templates.my_tmpl3 !== tmpl2 && $.trim($.render.my_tmpl3(person)), "A_Jo_B", 'Named template for template object with selector: {markup: "#my_tmpl"}');
120
 
121
	tmpl3 = $.templates("", {
122
		markup: "#my_tmpl"
123
	});
124
	assert.equal($.trim(tmpl3.render(person)), "A_Jo_B", 'Compile from template object with selector, without registering: {markup: "#my_tmpl"}');
125
 
126
	var tmpl4 = $.templates({
127
		markup: "#my_tmpl"
128
	});
129
	assert.equal($.trim(tmpl4.render(person)), "A_Jo_B", 'Compile from template object with selector, without registering: {markup: "#my_tmpl"}');
130
 
131
	assert.equal($.templates("#my_tmpl"), $.templates("#my_tmpl"), '$.templates("#my_tmpl") caches compiled template, and does not recompile each time;');
132
 
133
	assert.ok($.templates({markup: "#my_tmpl"}) !== $.templates({markup: "#my_tmpl"}), '$.templates({markup: "#my_tmpl" ...}) recompiles template, so as to merge additional options;');
134
 
135
	assert.equal($.templates("", "#my_tmpl"), $.templates("#my_tmpl"), '$.templates("#my_tmpl") and $.templates("", "#my_tmpl") are equivalent');
136
 
137
	var renamed = $.templates("renamed", "#my_tmpl");
138
	assert.ok(renamed === tmpl2 && renamed.tmplName === "renamed", '$.templates("renamed", "#my_tmpl") will rename the cached template');
139
 
140
	$.templates({renamed2: "#my_tmpl"});
141
	assert.ok($.templates.renamed2 === tmpl2 && $.templates.renamed2.tmplName === "renamed2", '$.templates({renamed2: "#my_tmpl"}) will rename the cached template');
142
 
143
	$.templates("cloned", {markup: "#my_tmpl"});
144
	assert.ok($.templates.cloned !== tmpl2 && $.templates.cloned.tmplName === "cloned", '$.templates("cloned", {markup: "#my_tmpl"}}) will clone the cached template');
145
 
146
	$.templates({cloned2: {markup: "#my_tmpl"}});
147
	assert.ok($.templates.cloned2 !== tmpl2 && $.templates.cloned2.tmplName === "cloned2", '$.templates({cloned: {markup: "#my_tmpl"}}) will clone the cached template');
148
 
149
	$.templates("my_tmpl", null);
150
	assert.equal($.templates.my_tmpl, undefined, 'Remove a named template: $.templates("my_tmpl", null);');
151
 
152
	$.templates({
153
		scriptTmpl: {
154
			markup: "#my_tmpl",
155
			debug:true
156
		},
157
		tmplFromString: {
158
			markup: "X_{{:name}}_Y",
159
			debug:true
160
		}
161
	});
162
	assert.equal($.templates.tmplFromString.fn.toString().indexOf("debugger;") > 0
163
		&& $.templates.scriptTmpl.fn.toString().indexOf("debugger;") > 0
164
		&& $.templates.scriptTmpl({name: "Jo"}) + $.templates.tmplFromString({name: "Jo"}), "A_Jo_BX_Jo_Y",
165
		'Debug a template: set debug:true on object');
166
 
167
	// reset
168
	$("#my_tmpl")[0].removeAttribute("data-jsv-tmpl");
169
 
170
	delete $.templates.scriptTmpl;
171
});
172
 
173
QUnit.test("render", function(assert) {
174
	assert.equal($.trim($("#my_tmpl").render(person)), "A_Jo_B", '$(tmplSelector).render(data);'); // Trimming because IE adds whitespace
175
 
176
	var tmpl3 = $.templates("my_tmpl4", tmplString);
177
 
178
	assert.equal($.render.my_tmpl4(person), "A_Jo_B", '$.render.my_tmpl(object);');
179
	assert.equal($.render.my_tmpl4(people), "A_Jo_BA_Bill_B", '$.render.my_tmpl(array);');
180
 
181
	var tmplObject = $.templates.my_tmpl4;
182
	assert.equal(tmplObject.render(people), "A_Jo_BA_Bill_B", 'var tmplObject = $.templates.my_tmpl; tmplObject.render(data);');
183
 
184
	$.templates("my_tmpl5", "A_{{for}}inner{{:name}}content{{/for}}_B");
185
	assert.equal($.templates.my_tmpl5.tmpls[0].render(person), "innerJocontent", 'Nested template objects: $.templates.my_tmpl.tmpls');
186
 
187
	$("#result").html("<script id='tmpl' type='text/x-jsrender'>Content{{for #data}}{{:#index}}{{/for}}{{:~foo}}</script>");
188
	assert.equal($("#tmpl").render([null,undefined,1], {foo:"foovalue"}, true), "Content012foovalue", 'render(array, helpers, true) renders an array without iteration, while passing in helpers');
189
 
190
	$("#result").html("<script id='tmpl' type='text/x-jsrender'>Content{{for #data}}{{:#index}}{{/for}}{{:~foo}}</script>");
191
	assert.equal($("#tmpl").render([null, undefined, 1], true), "Content012", 'render(array, true) renders an array without iteration');
192
	$("#result").empty();
193
});
194
 
195
QUnit.test("converters", function(assert) {
196
	function loc(data) {
197
		switch (data) {case "desktop": return "bureau"; }
198
	}
199
	$.views.converters({loc: loc});
200
	assert.equal($.templates("{{loc:#data}}:{{loc:'desktop'}}").render("desktop"), "bureau:bureau", "$.views.converters({loc: locFunction})");
201
 
202
	$.views.converters("loc2", loc);
203
	assert.equal($.views.converters.loc2 === loc, true, 'locFunction === $.views.converters.loc');
204
 
205
	$.views.converters({loc2: null});
206
	assert.equal($.views.converters.loc2, undefined, 'Remove a registered converter: $.views.converters({loc: null})');
207
});
208
 
209
QUnit.test("tags", function(assert) {
210
	$.views.tags({sort1: sort});
211
	assert.equal($.templates("{{sort1 people reverse=true}}{{:name}}{{/sort1}}").render({people: people}), "BillJo", "$.views.tags({sort: sortFunction})");
212
 
213
	$.views.tags("sort2", sort);
214
	assert.equal($.views.tags.sort1.render === sort, true, 'sortFunction === $.views.tags.sort');
215
 
216
	$.views.tags("sort2", null);
217
	assert.equal($.views.tags.sort2, undefined, 'Remove a registered tag: $.views.tag({sor: null})');
218
});
219
 
220
QUnit.test("helpers", function(assert) {
221
	function concat() {
222
		return "".concat.apply("", arguments);
223
	}
224
 
225
	$.views.helpers({
226
		not: function(value) {
227
			return !value;
228
		},
229
		concat: concat
230
	});
231
	assert.equal($.templates("{{:~concat(a, 'b', ~not(false))}}").render({a: "aVal"}), "aValbtrue", "$.views.helpers({concat: concatFunction})");
232
 
233
	$.views.helpers({concat2: concat});
234
 
235
	assert.equal($.views.helpers.concat === concat, true, 'concatFunction === $.views.helpers.concat');
236
 
237
	$.views.helpers("concat2", null);
238
	assert.equal($.views.helpers.concat2, undefined, 'Remove a registered helper: $.views.helpers({concat: null})');
239
});
240
 
241
QUnit.test("template encapsulation", function(assert) {
242
	$.templates({
243
		myTmpl6: {
244
			markup: "{{sort reverse=true people}}{{:name}}{{/sort}}",
245
			tags: {
246
				sort: sort
247
			}
248
		}
249
	});
250
	assert.equal($.render.myTmpl6({people: people}), "BillJo", '$.templates("my_tmpl", tmplObjWithNestedItems);');
251
});
252
 
253
QUnit.test("$.views.viewModels", function(assert) {
254
	// =============================== Arrange ===============================
255
	var Constr = $.views.viewModels({getters: ["a", "b"]});
256
	// ................................ Act ..................................
257
	var vm = Constr("a1 ", "b1 ");
258
	var result = vm.a() + vm.b();
259
	vm.a("a2 ");
260
	vm.b("b2 ");
261
	result += vm.a() + vm.b();
262
	// ............................... Assert .................................
263
	assert.equal(result, "a1 b1 a2 b2 ", "viewModels, two getters, no methods");
264
 
265
	// =============================== Arrange ===============================
266
	Constr = $.views.viewModels({getters: ["a", "b", "c"], extend: {add: function(val) {
267
		this.c(val + this.a() + this.b() + this.c());
268
	}}});
269
	// ................................ Act ..................................
270
	vm = Constr("a1 ", "b1 ", "c1 ");
271
	vm.add("before ");
272
	result = vm.c();
273
	// ............................... Assert .................................
274
	assert.equal(result, "before a1 b1 c1 ", "viewModels, two getters, one method");
275
 
276
	// =============================== Arrange ===============================
277
	Constr = $.views.viewModels({extend: {add: function(val) {
278
		this.foo = val;
279
	}}});
280
	// ................................ Act ..................................
281
	vm = Constr();
282
	vm.add("before");
283
	result = vm.foo;
284
	// ............................... Assert .................................
285
	assert.equal(result, "before", "viewModels, no getters, one method");
286
 
287
	// =============================== Arrange ===============================
288
	Constr = $.views.viewModels({getters: []});
289
	// ................................ Act ..................................
290
	vm = Constr();
291
	result = JSON.stringify(vm);
292
	// ............................... Assert .................................
293
	assert.equal(result, "{}", "viewModels, no getters, no methods");
294
 
295
	// =============================== Arrange ===============================
296
	$.views.viewModels({
297
		T1: {
298
			getters: ["a", "b"]
299
		}
300
	});
301
	// ................................ Act ..................................
302
	vm = $.views.viewModels.T1.map({a: "a1 ", b: "b1 "});
303
 
304
	result = vm.a() + vm.b();
305
	vm.a("a2 ");
306
	vm.b("b2 ");
307
	result += vm.a() + vm.b();
308
 
309
	// ............................... Assert .................................
310
	assert.equal(result, "a1 b1 a2 b2 ", "viewModels, two getters, no methods");
311
 
312
	// ................................ Act ..................................
313
	vm.merge({a: "a3 ", b: "b3 "});
314
 
315
	result = vm.a() + vm.b();
316
 
317
	// ............................... Assert .................................
318
	assert.equal(result, "a3 b3 ", "viewModels merge, two getters, no methods");
319
 
320
	// ................................ Act ..................................
321
	result = vm.unmap();
322
	result = JSON.stringify(result);
323
 
324
	// ............................... Assert .................................
325
	assert.equal(result, '{"a":"a3 ","b":"b3 "}', "viewModels unmap, two getters, no methods");
326
 
327
	// =============================== Arrange ===============================
328
	var viewModels = $.views.viewModels({
329
		T1: {
330
			getters: ["a", {getter: "b"}, "c", "d", {getter: "e", type: undefined}, {getter: "f", type: null}, {getter: "g", type: "foo"}, {getter: "h", type: ""}]
331
		}
332
	}, {});
333
	// ................................ Act ..................................
334
	vm = viewModels.T1.map({a: "a1 ", b: "b1 ", c: "c1 ", d: "d1 ", e: "e1 ", f: "f1 ", g: "g1 ", h: "h1 "});
335
	result = vm.a() + vm.b() + vm.c() + vm.d() + vm.e() + vm.f() + vm.g() + vm.h();
336
	vm.a("a2 ");
337
	vm.b("b2 ");
338
	result += vm.a() + vm.b();
339
	// ............................... Assert .................................
340
	assert.equal(result, "a1 b1 c1 d1 e1 f1 g1 h1 a2 b2 ",
341
		"viewModels, multiple unmapped getters, no methods");
342
 
343
	// ................................ Act ..................................
344
	vm.merge({a: "a3 ", b: "b3 ", c: "c3 ", d: "d3 ", e: "e3 ", f: "f3 ", g: "g3 ", h: "h3 "});
345
 
346
	result = vm.a() + vm.b() + vm.c() + vm.d() + vm.e() + vm.f() + vm.g() + vm.h();
347
 
348
	// ............................... Assert .................................
349
	assert.equal(result, "a3 b3 c3 d3 e3 f3 g3 h3 ",
350
		"viewModels merge, multiple unmapped getters, no methods");
351
 
352
	// ................................ Act ..................................
353
	result = vm.unmap();
354
	result = JSON.stringify(result);
355
 
356
	// ............................... Assert .................................
357
	assert.equal(result, '{"a":"a3 ","b":"b3 ","c":"c3 ","d":"d3 ","e":"e3 ","f":"f3 ","g":"g3 ","h":"h3 "}',
358
		"viewModels unmap, multiple unmapped getters, no methods");
359
 
360
	// =============================== Arrange ===============================
361
	$.views.viewModels({
362
		T1: {
363
			getters: ["a", "b", "c"],
364
			extend : {
365
				add: function(val) {
366
					this.c(val + this.a() + this.b() + this.c());
367
				}
368
			}
369
		}
370
	});
371
 
372
	// ................................ Act ..................................
373
	vm = $.views.viewModels.T1.map({a: "a1 ", b: "b1 ", c: "c1 "});
374
 
375
	vm.add("before ");
376
	result = vm.c();
377
 
378
	// ............................... Assert .................................
379
	assert.equal(result, "before a1 b1 c1 ", "viewModels, getters and one method");
380
 
381
	// ................................ Act ..................................
382
	vm.merge({a: "a3 ", b: "b3 ", c: "c3 "});
383
	vm.add("updated ");
384
	result = vm.c();
385
 
386
	// ............................... Assert .................................
387
	assert.equal(result, "updated a3 b3 c3 ", "viewModels merge, getters and one method");
388
 
389
	// ................................ Act ..................................
390
	result = vm.unmap();
391
	result = JSON.stringify(result);
392
 
393
	// ............................... Assert .................................
394
	assert.equal(result, '{"a":"a3 ","b":"b3 ","c":"updated a3 b3 c3 "}', "viewModels unmap, getters and one method");
395
 
396
	// =============================== Arrange ===============================
397
	$.views.viewModels({
398
		T1: {
399
			getters: ["a", "b"]
400
		},
401
		T2: {
402
			getters: [{getter: "t1", type: "T1"}, {getter: "t1Arr", type: "T1"}, {getter: "t1OrNull", type: "T1", defaultVal: null}]
403
		}
404
	});
405
	viewModels = $.views.viewModels;
406
	// ................................ Act ..................................
407
	var t1 = viewModels.T1.map({a: "a1 ", b: "b1 "}); // Create a T1
408
	var t2 = viewModels.T2.map({t1: {a: "a3 ", b: "b3 "}, t1Arr: [t1.unmap(), {a: "a2 ", b: "b2 "}]}); // Create a T2 (using unmap to scrape values the T1: vm)
409
 
410
	result = JSON.stringify(t2.unmap());
411
 
412
	// ............................... Assert .................................
413
	assert.equal(result, '{"t1":{"a":"a3 ","b":"b3 "},"t1Arr":[{"a":"a1 ","b":"b1 "},{"a":"a2 ","b":"b2 "}],"t1OrNull":null}',
414
		"viewModels, hierarchy");
415
 
416
	// ................................ Act ..................................
417
	t2.t1Arr()[0].merge({a: "a1x ", b: "b1x "}); // merge not the root, but a VM instance within hierarchy: vm2.t1Arr()[0] - leaving rest unchanged
418
	result = JSON.stringify(t2.unmap());
419
 
420
	// ............................... Assert .................................
421
	assert.equal(result, '{"t1":{"a":"a3 ","b":"b3 "},"t1Arr":[{"a":"a1x ","b":"b1x "},{"a":"a2 ","b":"b2 "}],"t1OrNull":null}',
422
		"viewModels, merge deep node");
423
 
424
	// ................................ Act ..................................
425
	var t1Arr = viewModels.T1.map([{a: "a1 ", b: "b1 "}, {a: "a2 ", b: "b2 "}]); // Create a T1 array
426
	var t2FromArr =  viewModels.T2.map({t1: {a: "a3 ", b: "b3 "}, t1Arr: t1Arr.unmap()}); // Create a T2 (using unmap to scrape values the T1: vm)
427
	result = JSON.stringify(t2FromArr.unmap());
428
 
429
	// ............................... Assert .................................
430
	assert.equal(result, '{"t1":{"a":"a3 ","b":"b3 "},"t1Arr":[{"a":"a1 ","b":"b1 "},{"a":"a2 ","b":"b2 "}],"t1OrNull":null}',
431
		"viewModels, hierarchy");
432
 
433
	// ................................ Act ..................................
434
	t1Arr = viewModels.T1.map([{a: "a1 ", b: "b1 "}, {a: "a2 ", b: "b2 "}]); // Create a T1 array
435
	t1Arr.push(viewModels.T1("a3 ", "b3 "));
436
	t2FromArr = viewModels.T2.map({t1: {a: "a4 ", b: "b4 "}, t1Arr: t1Arr.unmap()}); // Create a T2 (using unmap to scrape values the T1: vm)
437
	result = JSON.stringify(t2FromArr.unmap());
438
 
439
	// ............................... Assert .................................
440
	assert.equal(result, '{"t1":{"a":"a4 ","b":"b4 "},"t1Arr":[{"a":"a1 ","b":"b1 "},{"a":"a2 ","b":"b2 "},{"a":"a3 ","b":"b3 "}],"t1OrNull":null}',
441
		"viewModels, hierarchy");
442
 
443
	// ................................ Act ..................................
444
	var t2new= viewModels.T2(viewModels.T1("a3 ", "b3 "), [viewModels.T1("a1 ", "b1 "), viewModels.T1("a2 ", "b2 ")], viewModels.T1("a4 ", "b4 "));
445
	result = JSON.stringify(t2new.unmap());
446
 
447
	// ............................... Assert .................................
448
	assert.equal(result, '{"t1":{"a":"a3 ","b":"b3 "},"t1Arr":[{"a":"a1 ","b":"b1 "},{"a":"a2 ","b":"b2 "}],"t1OrNull":{"a":"a4 ","b":"b4 "}}',
449
		"viewModels, hierarchy");
450
});
451
 
452
})(this, this.jQuery);