Best JavaScript code snippet using ng-mocks
XTemplate.js
Source:XTemplate.js
1describe("Ext.XTemplate", function() {2 var tpl,3 data,4 arrayData,5 objectData;6 beforeEach(function() {7 data = {8 name: "Nicolas Ferrero",9 title: "Developer",10 company: "Sencha",11 email: "nico@sencha.com",12 address: "10 Rue St Ferreol",13 city: "Toulouse",14 country: "France",15 zip: "31000",16 drinks: ["Wine", "Coffee", "Corona"],17 something: {18 name: "root",19 child : {20 name: "child"21 }22 },23 kids: [{24 name: "Joshua",25 age:326 },{27 name: "Nina",28 age:229 },{30 name: "Solomon",31 age:032 }],33 computers: [{34 cpu: "2Ghz",35 hdd: "1To"36 },{37 cpu: "100Mhz",38 hdd: "500Mo"39 }]40 };41 arrayData = {42 arrays: [43 [ { name: 'Item A1' }, { name: 'Item A2' } ],44 [ { name: 'Item B1' }, { name: 'Item B2' } ]45 ]46 };47 objectData = {48 a: 'aValue',49 b: {50 x: 'xValue',51 y: 'yValue'52 },53 c: 'cValue'54 };55 });56 describe("instantiation", function() {57 it("should extend Ext.Template", function() {58 tpl = new Ext.XTemplate("");59 expect(tpl.superclass).toEqual(Ext.Template.prototype);60 });61 it("should alias apply with applyTemplate", function() {62 tpl = new Ext.XTemplate("");63 spyOn(tpl, 'apply');64 tpl.applyTemplate();65 expect(tpl.apply).toHaveBeenCalled();66 });67 it("should compile on first use", function() {68 tpl = new Ext.XTemplate('Hello {foo}');69 expect(tpl.fn).toBe(null);70 var s = tpl.apply({ foo: 42 });71 expect(s).toBe('Hello 42');72 expect(typeof tpl.fn).toBe('function');73 });74 /* begin this line with "//* to include this test or "/*" to remove it75 it('should perform better', function () {76 function run (name) {77 var T = Ext[name],78 t0 = new Date().getTime(),79 K = 2000,80 t, s;81 for (var i = 0; i < K; ++i) {82 t = new T(83 '<p>Name: {name}</p>',84 '<p>Kids: ',85 '<tpl for="kids">',86 '<tpl if="age > 1">',87 '<p>{name}</p>',88 '<p>Dad: {parent.name}</p>',89 '</tpl>',90 '</tpl></p>'91 );92 }93 var t1 = new Date().getTime();94 for (i = 0; i < K; ++i) {95 s = t.apply(data);96 }97 var t2 = new Date().getTime();98 for (i = 0; i < K; ++i) {99 t = new T(100 '<p>Name: {name}</p>',101 '<p>Kids: ',102 '<tpl for="kids">',103 '<tpl if="age > 1">',104 '<p>{name}</p>',105 '<p>Dad: {parent.name}</p>',106 '</tpl>',107 '</tpl></p>'108 );109 s = t.apply(data);110 }111 var t3 = new Date().getTime();112 113 Ext.log(name + ': total=' + (t2 - t0)/K + ' ctor=' + (t1 - t0)/K +114 ' apply=' + (t2 - t1)/K + ' ctorApply=' + (t3 - t2)/K);115 }116 run('XTemplate');117 run('XTemplate1');118 run('XTemplate2');119 });/**/120 });121 describe("tags", function() {122 describe("if", function() {123 it("should handle tpl tag with no attributes", function() {124 tpl = new Ext.XTemplate(125 '<tpl>{name}</tpl>'126 );127 expect(tpl.apply({name: 'Phil'})).toEqual('Phil');128 });129 it('should handle <tpl if=""> like <tpl>', function() {130 tpl = new Ext.XTemplate(131 '<p>Kids: ',132 '<tpl if="">',133 '<p>{name}</p>',134 '</tpl></p>'135 );136 expect(tpl.apply(data.kids)).toEqual('<p>Kids: <p></p></p>');137 });138 it('should handle if, elif and else', function() {139 tpl = new Ext.XTemplate(140 '<tpl for=\'kids\'>',141 '<tpl if="age > 2">',142 '<p>{name}</p>',143 '<p>Pops: {parent.name}</p>',144 '<tpl elif="age > 1">',145 '<p>{name}</p>',146 '<p>Dad: {parent.name}</p>',147 '<tpl else>',148 '<p>{name}</p>',149 '<p>Daddy: {parent.name}</p>',150 '</tpl>',151 '</tpl><p>!</p>'152 );153 var s = tpl.apply(data);154 expect(s).toEqual('<p>Joshua</p><p>Pops: Nicolas Ferrero</p>' +155 '<p>Nina</p><p>Dad: Nicolas Ferrero</p>' +156 '<p>Solomon</p><p>Daddy: Nicolas Ferrero</p><p>!</p>');157 });158 159 it('should handle verbatim block', function() {160 tpl = new Ext.XTemplate(161 '<tpl for=\'kids\'>',162 '<tpl if="age >= 3">',163 '{% continue; %}',164 '</tpl>',165 '<tpl if="this.count">',166 ' and ',167 '</tpl>',168 '{% ++this.count %}',169 '{name} is less than 3',170 '</tpl>!!!',171 {172 count: 0173 }174 );175 var s = tpl.apply(data);176 expect(s).toEqual('Nina is less than 3 and Solomon is less than 3!!!');177 });178 it('should handle verbatim if/else', function() {179 tpl = new Ext.XTemplate(180 '<tpl for=\'kids\'>',181 '{% if (values.age >= 3) { %}',182 '{% continue; %}',183 '{% }',184 'if (this.count) { %}',185 ' and ',186 '{% } %}',187 '{% ++this.count %}',188 '{name} is less than 3',189 '</tpl>!!!',190 {191 count: 0192 }193 );194 var s = tpl.apply(data);195 expect(s).toEqual('Nina is less than 3 and Solomon is less than 3!!!');196 });197 it('should handle double quotes', function() {198 tpl = new Ext.XTemplate(199 "<tpl for='kids'>",200 "<tpl if='name==\"Joshua\"'>",201 "Josh",202 "<tpl else>",203 " {name}",204 "</tpl>",205 '</tpl>!!!'206 );207 var s = tpl.apply(data);208 expect(s).toEqual('Josh Nina Solomon!!!');209 });210 // From http://www.sencha.com/forum/showthread.php?142918211 it('should handle single quotes', function () {212 tpl = new Ext.XTemplate(213 '<tpl for=".">',214 '<div class="dv-grup-body">',215 '<tpl for="menus">',216 '<div class="dv-element small" id="{id}" test="{test}" sample="{sample}" cmpName="{cmpName}">',217 '<span>',218 '<img src="img/icons/{icon}.png" title="{name}" align="left">',219 '<tpl if="values.test * values.sample == 0">',220 '<img src="img/icons/warning.png" align="right" title="{[ values.sample == 0 ? \'Sample Text 1\' : \'Sample Text 2\' ]}">',221 '</tpl>',222 '<span class="boldText" style="float:left;">',223 '{name}',224 '</span>',225 '</span>',226 '</div>',227 '</tpl>',228 '</div>',229 '</tpl>');230 var s = tpl.apply({231 menus: [232 { id: 'foo', test: 0, sample: 3, cmpName: 'cname', name: 'Name', icon: 'ico' }233 ]234 });235 expect(s).toEqual('<div class="dv-grup-body">'+236 '<div class="dv-element small" id="foo" test="0" sample="3" cmpName="cname">'+237 '<span>'+238 '<img src="img/icons/ico.png" title="Name" align="left">'+239 '<img src="img/icons/warning.png" align="right" title="Sample Text 2">'+240 '<span class="boldText" style="float:left;">'+241 'Name'+242 '</span>'+243 '</span>'+244 '</div></div>'245 );246 });247 });248 249 describe("switch", function() {250 it('should handle switch, case and default with numbers', function() {251 tpl = new Ext.XTemplate(252 '<tpl for=\'kids\'>',253 '<tpl switch="age">',254 '<tpl case="3" case="4">',255 '<p>{name} is 3...</p>',256 '<tpl case="2">',257 '<p>{name} is 2...</p>',258 '<tpl default>',259 '<p>{name} is {age}!</p>',260 '</tpl>',261 '</tpl><p>!</p>'262 );263 var s = tpl.apply(data);264 expect(s).toEqual('<p>Joshua is 3...</p><p>Nina is 2...</p><p>Solomon is 0!</p><p>!</p>');265 });266 it('should handle switch, case and default with strings', function() {267 tpl = new Ext.XTemplate(268 '<tpl for=\'kids\'>',269 '<tpl switch="name">',270 '<tpl case="Joshua" case="Solomon">',271 '<p>{name} is a boy</p>',272 '<tpl default>',273 '<p>{name} is a girl!</p>',274 '</tpl>',275 '</tpl><p>!</p>'276 );277 var s = tpl.apply(data);278 expect(s).toEqual('<p>Joshua is a boy</p><p>Nina is a girl!</p><p>Solomon is a boy</p><p>!</p>');279 });280 281 it("should be able to switch on xindex", function() {282 tpl = new Ext.XTemplate([283 '<tpl for=".">',284 '<tpl switch="#">',285 '<tpl case="1">One',286 '<tpl case="2">Two',287 '<tpl case="3">Three',288 '<tpl case="4">Four',289 '<tpl default>Bigger',290 '</tpl>',291 '</tpl>']);292 293 expect(tpl.apply([1, 2, 3, 4, 5, 6])).toBe('OneTwoThreeFourBiggerBigger');294 });295 it("should allow spaces after the switch", function() {296 tpl = new Ext.XTemplate('<tpl switch="foo"> <tpl case="bar">bar</tpl>');297 expect(tpl.apply({298 foo: 'bar'299 })).toBe('bar');300 });301 });302 describe("for", function () {303 it('should examine the data object provided if for="." is specified (include array index test)', function() {304 tpl = new Ext.XTemplate(305 '<p>Kids: ',306 '<tpl for=".">',307 '<p>{#}. {name}</p>',308 '</tpl></p>'309 );310 var s = tpl.apply(data.kids);311 expect(s).toEqual('<p>Kids: <p>1. Joshua</p><p>2. Nina</p><p>3. Solomon</p></p>');312 });313 314 it('should insert "between" values', function() {315 tpl = new Ext.XTemplate(316 '<p>Kids: ',317 '<tpl for="." between=",">',318 '{#}. {name}',319 '</tpl></p>'320 );321 var s = tpl.apply(data.kids);322 expect(s).toEqual('<p>Kids: 1. Joshua,2. Nina,3. Solomon</p>');323 });324 it('should handle "." and "parent" in loop', function () {325 var tpl = new Ext.XTemplate(326 '<div id="{id}-body" class="{baseCls}-body',327 '<tpl if="bodyCls"> {bodyCls}</tpl>',328 '<tpl if="uiCls">',329 '<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl>',330 '</tpl>"',331 '<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>>',332 '</div>'333 );334 var s = tpl.apply({335 baseCls: 'x-panel-header',336 componentCls: 'x-panel-header',337 frame: false,338 id: 'header-1026',339 ui: 'default',340 uiCls: ['horizontal', 'top']341 });342 expect(s).toEqual('<div id="header-1026-body" class="x-panel-header-body x-panel-header-body-default-horizontal x-panel-header-body-default-top"></div>');343 });344 it('should handle <tpl for=""> like <tpl>', function() {345 tpl = new Ext.XTemplate(346 '<p>Kids: ',347 '<tpl for="">',348 '<p>{name}</p>',349 '</tpl></p>'350 );351 expect(tpl.apply(data.kids)).toEqual('<p>Kids: <p></p></p>');352 });353 it('should examine the data of parent object if for=".." is specified', function() {354 tpl = new Ext.XTemplate(355 '<p>Computer: ',356 '<tpl for="computers">',357 '<p>Cpu: {cpu} Hdd: {hdd}',358 '<tpl for="..">',359 ' User: {name}',360 '</tpl>',361 '</p>',362 '</tpl></p>'363 );364 var s = tpl.apply(data);365 expect(s).toEqual('<p>Computer: <p>Cpu: 2Ghz Hdd: 1To User: Nicolas Ferrero</p><p>Cpu: 100Mhz Hdd: 500Mo User: Nicolas Ferrero</p></p>');366 });367 it("should be able to access specified members of the provided data object (include array index test)", function() {368 tpl = new Ext.XTemplate(369 '<p>Name: {name}</p>',370 '<p>Title: {title}</p>',371 '<p>Company: {company}</p>',372 '<p>Kids: ',373 '<tpl for="kids">',374 '<p>{#}. {name}</p>',375 '</tpl></p>'376 );377 expect(tpl.apply(data)).toEqual('<p>Name: Nicolas Ferrero</p><p>Title: Developer</p><p>Company: Sencha</p><p>Kids: <p>1. Joshua</p><p>2. Nina</p><p>3. Solomon</p></p>');378 });379 describe("{.}", function(){380 it("should be able to auto-render flat array content with special variable {.} (include array index test)", function() {381 tpl = new Ext.XTemplate(382 '<p>{name}\'s favorite beverages:</p>',383 '<tpl for="drinks">',384 '<div>{#} - {.}</div>',385 '</tpl>'386 );387 expect(tpl.apply(data)).toEqual("<p>Nicolas Ferrero's favorite beverages:</p><div>1 - Wine</div><div>2 - Coffee</div><div>3 - Corona</div>");388 });389 it("should render numbers, strings, booleans, and dates, but not objects or arrays", function(){390 tpl = new Ext.XTemplate('<tpl for=".">{.}</tpl>');391 var date = new Date();392 expect(tpl.apply([1, true, 2.3, false, 'test', [1, 2, 3], {a:1, b:2}, 'ing', date, undefined, null])).toEqual('1true2.3falsetesting' + date);393 });394 });395 it("should not fail if for try to handle an undefined variable.", function() {396 tpl = new Ext.XTemplate(397 '<p>{name}\'s:</p>',398 '<tpl for="nothing">',399 '<div>{nothing1}</div>',400 '</tpl>{badness}<p>Foo</p>'401 );402 var s = tpl.apply(data);403 expect(s).toEqual("<p>Nicolas Ferrero's:</p><p>Foo</p>");404 });405 406 describe("parent", function() {407 it("should be able to access parent object member via the parent object", function() {408 tpl = new Ext.XTemplate(409 '<p>Name: {name}</p>',410 '<p>Kids: ',411 '<tpl for="kids">',412 '<tpl if="age > 1">',413 '<p>{name}</p>',414 '<p>Dad: {parent.name}</p>',415 '</tpl>',416 '</tpl></p>'417 );418 var s = tpl.apply(data);419 expect(s).toEqual("<p>Name: Nicolas Ferrero</p><p>Kids: <p>Joshua</p><p>Dad: Nicolas Ferrero</p><p>Nina</p><p>Dad: Nicolas Ferrero</p></p>");420 });421 422 it("should set the parent to the parent array if the action is '.'", function(){423 var tpl = new Ext.XTemplate(424 '<tpl for=".">',425 '{parent.specialProp}',426 '<tpl for=".">',427 '{parent.specialProp}{.}',428 '</tpl>',429 '</tpl>'430 );431 432 var data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];433 data.specialProp = 'test';434 data[0].specialProp = 'foo';435 data[1].specialProp = 'bar';436 data[2].specialProp = 'baz';437 438 var s = tpl.apply(data);439 expect(s).toBe('testfoo1foo2foo3testbar4bar5bar6testbaz7baz8baz9');440 });441 442 it("should work with nested parents", function(){443 var tpl = new Ext.XTemplate(444 '{name}',445 '<tpl for="children">',446 '{name}{parent.name}',447 '<tpl for="children">',448 '{name}{parent.name}',449 '</tpl>',450 '</tpl>'451 );452 453 var s = tpl.apply({ 454 name : 'A1', 455 children : [{ 456 name : 'B1', 457 children : [{ 458 name : 'C1' 459 }, {460 name: 'C2'461 }] 462 }, {463 name: 'B2',464 children : [{ 465 name : 'C3' 466 }, {467 name: 'C4'468 }]469 }] 470 });471 expect(s).toBe('A1B1A1C1B1C2B1B2A1C3B2C4B2');472 });473 it("should reset the parent correctly during looping", function(){474 var data = [{475 id: 1,476 level2: [{477 id: 11,478 level3: [{479 id: 111480 }, {481 id: 112482 }, {483 id: 113484 }]485 }, {486 id: 12,487 level3: [{488 id: 121489 }, {490 id: 122491 }, {492 id: 123493 }]494 }, {495 id: 13,496 level3: [{497 id: 131498 }, {499 id: 132500 }, {501 id: 133502 }]503 }]504 }, {505 id: 2,506 level2: [{507 id: 21,508 level3: []509 }, {510 id: 22,511 level3: []512 }]513 }];514 var tpl = new Ext.XTemplate(515 '<tpl for=".">',516 'level 1: id: {id}',517 '<tpl for="level2">',518 'level 2: id: {id}, parent.id: {parent.id}',519 '<tpl for="level3">',520 'level 3: id: {id}, parent.id: {parent.id}',521 '</tpl>',522 '</tpl>',523 '</tpl>'524 );525 526 expect(tpl.apply(data)).toBe([527 'level 1: id: 1',528 'level 2: id: 11, parent.id: 1',529 'level 3: id: 111, parent.id: 11',530 'level 3: id: 112, parent.id: 11',531 'level 3: id: 113, parent.id: 11',532 'level 2: id: 12, parent.id: 1',533 'level 3: id: 121, parent.id: 12',534 'level 3: id: 122, parent.id: 12',535 'level 3: id: 123, parent.id: 12',536 'level 2: id: 13, parent.id: 1',537 'level 3: id: 131, parent.id: 13',538 'level 3: id: 132, parent.id: 13',539 'level 3: id: 133, parent.id: 13',540 'level 1: id: 2',541 'level 2: id: 21, parent.id: 2',542 'level 2: id: 22, parent.id: 2'543 ].join(''));544 });545 });546 it("should be able to access child object like a tree", function() {547 tpl = new Ext.XTemplate("{something.child.name}");548 expect(tpl.apply(data)).toEqual("child");549 });550 it('should handle sequential for loops nested in for loop using arrays', function () {551 // this bug one was found by Brian's calendar templates552 tpl = new Ext.XTemplate(553 '<tpl for="arrays">',554 '<tpl for=".">',555 '_{name}_',556 '</tpl>',557 '<tpl for=".">',558 '-{name}-',559 '</tpl>',560 '/',561 '</tpl>'562 );563 var s = tpl.apply(arrayData);564 expect(s).toEqual('_Item A1__Item A2_-Item A1--Item A2-/'+565 '_Item B1__Item B2_-Item B1--Item B2-/');566 });567 it("should set the xindex variable correctly when looping over nested arrays", function() {568 var result = new Ext.XTemplate(569 '<tpl for=".">',570 '{% if (Ext.isArray(values)) { %}',571 '<tpl for=".">',572 '{#}',573 '</tpl>',574 '{% } %}',575 '{#}',576 '</tpl>'577 ).apply([1,1,1,[1,1],1]);578 expect(result).toBe('1231245');579 });580 }); // for581 582 describe("foreach", function () {583 it('should examine the data object provided if foreach="." is specified', function() {584 var tpl = new Ext.XTemplate(585 '<tpl foreach=".">',586 '{% if (Ext.isObject(values)) { %}',587 '<tpl foreach=".">',588 '{[xkey]} {[values]}.',589 '</tpl>',590 '{% } %}',591 '{$} {.}.',592 '</tpl>'593 ), 594 result = Ext.Array.sort(tpl.apply(objectData).split('.'));595 expect(result[1]).toBe('a aValue');596 expect(result[2]).toBe('b ');597 expect(result[3]).toBe('c cValue');598 expect(result[4]).toBe('x xValue');599 expect(result[5]).toBe('y yValue');600 });601 it('should handle "." and "parent" in loop', function () {602 var tpl = new Ext.XTemplate(603 '<div id="{id}-body" class="{baseCls}-body',604 '<tpl if="bodyCls"> {bodyCls}</tpl>',605 '<tpl if="uiCls">',606 '<tpl foreach="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl>',607 '</tpl>"',608 '<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>>',609 '</div>'610 ),611 result = tpl.apply({612 baseCls: 'x-panel-header',613 componentCls: 'x-panel-header',614 frame: false,615 id: 'header-1026',616 ui: 'default',617 uiCls: {618 h: 'horizontal', 619 t: 'top'620 }621 });622 expect(result).toEqual('<div id="header-1026-body" class="x-panel-header-body x-panel-header-body-default-horizontal x-panel-header-body-default-top"></div>');623 });624 it('should handle <tpl foreach=""> like <tpl>', function() {625 var tpl = new Ext.XTemplate(626 '<p>Kids: ',627 '<tpl foreach="">',628 '<p>{name}</p>',629 '</tpl></p>'630 );631 expect(tpl.apply(data.kids)).toEqual('<p>Kids: <p></p></p>');632 });633 it('should examine the data of parent object if for=".." is specified', function() {634 var tpl = new Ext.XTemplate(635 '<tpl foreach="b">',636 '<p>{$} {.}</p>',637 '<tpl for="..">',638 'a: {a}',639 '</tpl>',640 '</p>',641 '</tpl></p>'642 );643 expect(tpl.apply(objectData)).toEqual('<p>x xValue</p>a: aValue</p><p>y yValue</p>a: aValue</p></p>');644 });645 646 it('should insert "between" values', function() {647 var tpl = new Ext.XTemplate(648 '<tpl foreach="b" between=",">',649 '{$}: {.}',650 '</tpl>'651 );652 expect(tpl.apply(objectData)).toEqual('x: xValue,y: yValue');653 });654 it("should be able to access the xindex using {#}", function() {655 var tpl = new Ext.XTemplate(656 '<tpl foreach="kids">',657 '{#}',658 '</tpl>'659 );660 expect(tpl.apply(data)).toEqual('123');661 });662 it("should not loop if foreach is passed an undefined variable.", function() {663 var tpl = new Ext.XTemplate(664 '<p>{name}\'s:</p>',665 '<tpl foreach="nothing">',666 '<div>{#}{$}{.}{nothing1}</div>',667 '</tpl>{badness}<p>Foo</p>'668 );669 expect(tpl.apply(data)).toEqual("<p>Nicolas Ferrero's:</p><p>Foo</p>");670 });671 672 describe("parent", function() {673 it("should be able to access parent object member via the parent object", function() {674 var tpl = new Ext.XTemplate(675 '<tpl foreach="b">',676 '<p>{parent.c}</p>',677 '</tpl>'678 );679 expect(tpl.apply(objectData)).toEqual("<p>cValue</p><p>cValue</p>");680 });681 682 it("should set the parent to the parent object if the action is '.'", function(){683 var tpl = new Ext.XTemplate(684 '<tpl foreach=".">',685 '{parent.x}',686 '</tpl>'687 ), data = {688 x: 1,689 y: 2,690 z: 3691 };692 693 expect(tpl.apply(data)).toBe('111'); 694 });695 });696 it("should set the xindex variable correctly when looping over nested objects", function() {697 var result = new Ext.XTemplate(698 '<tpl foreach=".">',699 '{% if (Ext.isObject(values)) { %}',700 '<tpl foreach=".">',701 '{#}',702 '</tpl>',703 '{% } %}',704 '{#}',705 '</tpl>'706 ).apply({a:1,b:1,c:1,d:{e:1,f:1},g:1});707 expect(result).toBe('1231245');708 });709 }); // foreach710 describe("insane overnesting of for and foreach loops", function () {711 it("should apply the template", function() {712 var id = 0,713 data = (function assignIds(data) {714 if (data instanceof Object) {715 data.id = id++;716 if (data instanceof Array) {717 Ext.Array.each(data, function(item) {718 assignIds(item);719 });720 } else {721 Ext.Object.each(data, function(key, value) {722 assignIds(value);723 });724 }725 }726 return data;727 })({728 a: [{729 b: [1, 2],730 c: {d: 3, e: 4}731 }, {732 f: {g: 5, h: 6},733 i: [7, 8]734 }, [735 {j: 9, k: 10},736 [11, 12]737 ]],738 l: {739 m: [{n: 13, o: 14}],740 p: [[15, 16], [17, 18]]741 }742 }),743 tpl = new Ext.XTemplate(744 '<tpl foreach=".">',745 '[key]{$}',746 '{% if (Ext.isObject(values)) { %}',747 '<tpl foreach=".">',748 '[key]{$}',749 '{% if (Ext.isObject(values)) { %}',750 '<tpl foreach=".">',751 '[key]{$}',752 '{% if (Ext.isObject(values)) { %}',753 '<tpl foreach=".">',754 '[key]{$}[value]{.}[parent]{parent.id}[index]{#}',755 '</tpl>',756 '{% } %}',757 '{% else if (Ext.isArray(values)) { %}',758 '<tpl for=".">',759 '[value]{.}[parent]{parent.id}[index]{#}',760 '</tpl>',761 '{% } %}',762 '[parent]{parent.id}[index]{#}',763 '</tpl>',764 '{% } %}',765 '{% else if (Ext.isArray(values)) { %}',766 '<tpl for=".">',767 '{% if (Ext.isObject(values)) { %}',768 '<tpl foreach=".">',769 '[key]{$}[value]{.}[parent]{parent.id}[index]{#}',770 '</tpl>',771 '{% } %}',772 '{% else if (Ext.isArray(values)) { %}',773 '<tpl for=".">',774 '[value]{.}[parent]{parent.id}[index]{#}',775 '</tpl>',776 '{% } %}',777 '[parent]{parent.id}[index]{#}',778 '</tpl>',779 '{% } %}',780 '[parent]{parent.id}[index]{#}',781 '</tpl>',782 '{% } %}',783 '{% else if (Ext.isArray(values)) { %}',784 '<tpl for=".">',785 '{% if (Ext.isObject(values)) { %}',786 '<tpl foreach=".">',787 '[key]{$}',788 '{% if (Ext.isObject(values)) { %}',789 '<tpl foreach=".">',790 '[key]{$}[value]{.}[parent]{parent.id}[index]{#}',791 '</tpl>',792 '{% } %}',793 '{% else if (Ext.isArray(values)) { %}',794 '<tpl for=".">',795 '[value]{.}[parent]{parent.id}[index]{#}',796 '</tpl>',797 '{% } %}',798 '[parent]{parent.id}[index]{#}',799 '</tpl>',800 '{% } %}',801 '{% else if (Ext.isArray(values)) { %}',802 '<tpl for=".">',803 '{% if (Ext.isObject(values)) { %}',804 '<tpl foreach=".">',805 '[key]{$}[value]{.}[parent]{parent.id}[index]{#}',806 '</tpl>',807 '{% } %}',808 '{% else if (Ext.isArray(values)) { %}',809 '<tpl for=".">',810 '[value]{.}[parent]{parent.id}[index]{#}',811 '</tpl>',812 '{% } %}',813 '[parent]{parent.id}[index]{#}',814 '</tpl>',815 '{% } %}',816 '[parent]{parent.id}[index]{#}',817 '</tpl>',818 '{% } %}',819 '[parent]{parent.id}[index]{#}',820 '</tpl>'821 );822 // Although not required by the ecmascript spec, all modern browsers currently823 // loop object properties in the order they/ were defined, which is why the824 // following expectation passes. If this ever changes in the future, we may825 // have to revisit this spec.826 expect(tpl.apply(data)).toBe([827 '[key]a[key]b[value]1[parent]3[index]1[value]2[parent]3[index]2',828 '[parent]2[index]1[key]c[key]d[value]3[parent]4[index]1[key]e[value]4',829 '[parent]4[index]2[key]id[value]4[parent]4[index]3[parent]2[index]2',830 '[key]id[parent]2[index]3[parent]1[index]1[key]f[key]g[value]5[parent]6',831 '[index]1[key]h[value]6[parent]6[index]2[key]id[value]6[parent]6[index]3',832 '[parent]5[index]1[key]i[value]7[parent]7[index]1[value]8[parent]7',833 '[index]2[parent]5[index]2[key]id[parent]5[index]3[parent]1[index]2',834 '[key]j[value]9[parent]9[index]1[key]k[value]10[parent]9[index]2',835 '[key]id[value]9[parent]9[index]3[parent]8[index]1[value]11[parent]10',836 '[index]1[value]12[parent]10[index]2[parent]8[index]2[parent]1[index]3',837 '[parent]0[index]1[key]l[key]m[key]n[value]13[parent]13[index]1[key]o',838 '[value]14[parent]13[index]2[key]id[value]13[parent]13[index]3[parent]12',839 '[index]1[parent]11[index]1[key]p[value]15[parent]15[index]1[value]16',840 '[parent]15[index]2[parent]14[index]1[value]17[parent]16[index]1',841 '[value]18[parent]16[index]2[parent]14[index]2[parent]11[index]2[key]id',842 '[parent]11[index]3[parent]0[index]2[key]id[parent]0[index]3'843 ].join(''));844 });845 });846 describe("exec", function() {847 it("should considerer that anything between {[ ... ]} is code to be executed in the scope of the template", function() {848 tpl = new Ext.XTemplate(849 '<p>Name: {name}</p>',850 '<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>',851 '<p>Kids: ',852 '<tpl for="kids">',853 '<div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',854 '{[fm.ellipsis(values.name, 5)]}/{[xcount]}',855 '</div>',856 '</tpl></p>'857 );858 var s = tpl.apply(data);859 expect(s).toEqual('<p>Name: Nicolas Ferrero</p><p>Company: SENCHA, Developer</p><p>Kids: <div class="odd">Jo.../3</div><div class="even">Nina/3</div><div class="odd">So.../3</div></p>');860 });861 });862 it('should handle <tpl exec=""> like <tpl>', function() {863 tpl = new Ext.XTemplate(864 '<p>Kids: ',865 '<tpl exec="++this.foo">',866 '<p>{name}</p>',867 '</tpl></p>',868 {869 foo: 1870 }871 );872 var s = tpl.apply(data.kids);873 expect(tpl.foo).toEqual(2);874 expect(s).toEqual('<p>Kids: <p></p></p>');875 });876 it('should handle nested tags', function() {877 tpl = new Ext.XTemplate(878 '{{id}-bar}'879 );880 var s = tpl.apply({881 id: 'foo'882 });883 expect(s).toEqual('{foo-bar}');884 });885 describe("execute code without producing any output with exec operator", function() {886 describe("simple exec operator", function() {887 beforeEach(function() {888 tpl = new Ext.XTemplate(889 '<tpl for="kids">',890 '<tpl exec="++this.calls; return 1">',891 '<p>{name}</p>',892 '</tpl>',893 '</tpl>',894 {895 calls: 0896 });897 });898 it("should execute the code", function() {899 tpl.apply(data);900 expect(tpl.calls).toEqual(3);901 });902 it("should not interfere with output even if exec return a value", function() {903 expect(tpl.apply(data)).toEqual('<p>Joshua</p><p>Nina</p><p>Solomon</p>');904 });905 });906 describe("for and exec declared in the same tpl tag", function() {907 beforeEach(function() {908 tpl = new Ext.XTemplate(909 '<tpl for="kids" exec="this.spy(values, xindex, parent); return 1">',910 '<p>{[this.spy.calls.length]}. {name}</p>',911 '</tpl>',912 {913 spy : jasmine.createSpy("tplMemberSpy")914 });915 });916 it("should execute code for each item in the array", function() {917 tpl.apply(data);918 expect(tpl.spy.calls.length).toEqual(3);919 });920 it("should be run for each item in the array with index of the loop you are in, values of the current scope, and scope of ancestor template", function() {921 tpl.apply(data);922 expect(tpl.spy.calls[0].args).toEqual([data.kids[0], 1, data]);923 expect(tpl.spy.calls[1].args).toEqual([data.kids[1], 2, data]);924 expect(tpl.spy.calls[2].args).toEqual([data.kids[2], 3, data]);925 });926 it("should not interfere with output even if exec return a value", function() {927 expect(tpl.apply(data)).toEqual('<p>0. Joshua</p><p>1. Nina</p><p>2. Solomon</p>');928 });929 });930 describe("if and exec declared in the same tpl tag", function() {931 beforeEach(function() {932 tpl = new Ext.XTemplate(933 '<tpl for="kids">',934 '<tpl if="name == \'Joshua\'" exec="this.inc++; return 1">',935 '<p>{[this.inc]} - {name}</p>',936 '</tpl>',937 '</tpl>',938 {939 inc : 0940 });941 });942 it("should be run only if the if operator conditional checks is true", function() {943 tpl.apply(data);944 expect(tpl.inc).toEqual(1);945 });946 it("should not interfere with output", function() {947 expect(tpl.apply(data)).toEqual('<p>1 - Joshua</p>');948 });949 });950 });951 });952 describe("template member functions", function() {953 var spy;954 beforeEach(function() {955 spy = jasmine.createSpy("membersArguments").andCallFake(function(value, suffix, limit) {956 return Ext.String.ellipsis(value + ' ' + suffix, 13);957 });958 tpl = new Ext.XTemplate(959 '<p>{[this.addMr(values.name)]}</p>',960 '<p>Company: {company:this.spy("Incorporated", 10)}</p>',961 '<p>Title: {title:this.addJs()}</p>',962 '<p>Kids: ',963 '<tpl for="kids">',964 '<tpl if="this.isGirl(name)">',965 '<p>Girl: {name} - {age}</p>',966 '<tpl else>',967 '<p>Boy: {name} - {age}</p>',968 '</tpl>',969 '<tpl if="this.isBaby(age)">',970 '<p>{name} is a baby!</p>',971 '</tpl>',972 '</tpl></p>',973 {974 addMr: function(name) {975 return "Mr. " + name;976 },977 addJs: function(title) {978 return "Js " + title;979 },980 isGirl: function(name) {981 return name == 'Nina';982 },983 isBaby: function(age) {984 return age < 1;985 },986 spy: spy987 }988 );989 });990 it("should call members functions using various methods", function() {991 var s = tpl.apply(data);992 expect(s).toEqual("<p>Mr. Nicolas Ferrero</p><p>Company: Sencha Inc...</p><p>Title: Js Developer</p><p>Kids: <p>Boy: Joshua - 3</p><p>Girl: Nina - 2</p><p>Boy: Solomon - 0</p><p>Solomon is a baby!</p></p>");993 });994 it("should call members format functions with passed arguments", function() {995 tpl.apply(data);996 expect(spy).toHaveBeenCalledWith(data.company, "Incorporated", 10);997 });998 });999 describe("basic math support", function() {1000 it("should be able to apply basic math operators + - * / on numeric data values", function() {1001 tpl = new Ext.XTemplate(1002 '<tpl for="kids">',1003 '<p>{age + 5} {age - 7} {age * 3} {age / 2}</p>',1004 '<p>{age + (5*2)}</p>',1005 '</tpl>'1006 );1007 expect(tpl.apply(data)).toEqual("<p>8 -4 9 1.5</p><p>13</p><p>7 -5 6 1</p><p>12</p><p>5 -7 0 0</p><p>10</p>");1008 });1009 });1010 1011 describe("special characters", function(){1012 it("should handle newlines", function(){1013 tpl = new Ext.XTemplate('<div>\n</div>');1014 expect(tpl.apply()).toBe('<div>\n</div>');1015 });1016 1017 it("should handle empty braces", function(){1018 var s = 'cfg = cfg || {};';1019 tpl = new Ext.XTemplate(s);1020 expect(tpl.apply()).toBe(s); 1021 });1022 it("should handle curly braces literally if there is no tag match", function() {1023 expect(new Ext.XTemplate(1024 '{ foo} foobar {bar } barfoo { foo bar } { foo {bar}}{\nfoo}{foo\n} {foo\nbar}{{bar}}',1025 ''1026 ).apply({1027 bar: 'baz'1028 })).toBe('{ foo} foobar {bar } barfoo { foo bar } { foo baz}{\nfoo}{foo\n} {foo\nbar}{baz}');1029 });1030 });1031 describe("Undefined and non-string properties", function(){1032 it("should ignore undefined", function () {1033 tpl = new Ext.XTemplate('-{foo}-');1034 expect(tpl.apply({})).toBe('--');1035 });1036 it("should ignore null", function () {1037 tpl = new Ext.XTemplate('-{foo}-');1038 expect(tpl.apply({foo:null})).toBe('--');1039 });1040 it("should ignore an empty string", function(){1041 tpl = new Ext.XTemplate('-{foo}-');1042 expect(tpl.apply({foo:''})).toBe('--');1043 });1044 it("should stringify false", function(){1045 tpl = new Ext.XTemplate('-{foo}-');1046 expect(tpl.apply({foo:false})).toBe('-false-');1047 });1048 it("should stringify zero", function(){1049 tpl = new Ext.XTemplate('-{foo}-');1050 expect(tpl.apply({foo:0})).toBe('-0-');1051 });1052 it("should evaluate undefined as false", function(){1053 tpl = new Ext.XTemplate('<tpl if="foo">foo<tpl else>not foo</tpl>');1054 expect(tpl.apply({})).toBe('not foo');1055 });1056 it("should evaluate null as false", function(){1057 tpl = new Ext.XTemplate('<tpl if="foo">foo<tpl else>not foo</tpl>');1058 expect(tpl.apply({foo:null})).toBe('not foo');1059 });1060 it("should evaluate zero as false", function(){1061 tpl = new Ext.XTemplate('<tpl if="foo">foo<tpl else>not foo</tpl>');1062 expect(tpl.apply({foo:0})).toBe('not foo');1063 });1064 });1065 describe("formats", function() {1066 var appliedObject;1067 beforeEach(function() {1068 appliedObject = {a: "123", b: "456789"};1069 });1070 describe("enabled", function() {1071 beforeEach(function() {1072 tpl = new Ext.XTemplate(1073 '{a:ellipsis(2)}'1074 );1075 });1076 it("should call ellipsis", function() {1077 expect(tpl.apply(appliedObject)).toEqual('...');1078 });1079 });1080 describe("disabled", function() {1081 beforeEach(function() {1082 tpl = new Ext.XTemplate(1083 '{a:ellipsis(2)}',1084 {disableFormats: true}1085 );1086 });1087 it("should not call Ext.String.ellipsis", function() {1088 expect(tpl.apply(appliedObject)).toEqual('123');1089 });1090 });1091 describe('method', function () {1092 it('should call a basic method', function () {1093 tpl = new Ext.XTemplate(1094 'Linkify: {text:this.linkify}',1095 {1096 /**1097 * Simply wraps a link tag around each detected url1098 */1099 linkify: function(value) {1100 return value.replace(/(http:\/\/[^\s]*)/g, "<a target=\"_blank\" href=\"$1\">$1</a>");1101 }1102 }1103 );1104 var s = tpl.apply({ text: 'This page http://foo.bar.com/foobar.html is cool' });1105 expect(s).toEqual('Linkify: This page <a target="_blank" href="http://foo.bar.com/foobar.html">http://foo.bar.com/foobar.html</a> is cool');1106 });1107 });1108 });1109 describe("Ext.XTemplate.from", function() {1110 var elWithHtml, elWithValue;1111 beforeEach(function() {1112 elWithHtml = Ext.getBody().createChild({tag: "div", html:"FOO {0}."});1113 elWithValue = Ext.getBody().createChild({tag: "input"});1114 elWithValue.dom.value = "BAR {0}.";1115 });1116 afterEach(function() {1117 elWithHtml.remove();1118 elWithValue.remove();1119 });1120 it("should create a template with dom element innerHTML", function() {1121 tpl = Ext.XTemplate.from(elWithHtml);1122 expect(tpl.apply(['BAR'])).toEqual('FOO BAR.');1123 });1124 it("should create a template with dom element value", function() {1125 tpl = Ext.XTemplate.from(elWithValue);1126 expect(tpl.apply(['FOO'])).toEqual('BAR FOO.');1127 });1128 });1129 describe('strict mode', function () {1130 it('should throw when substitution token is invalid', function () {1131 var tpl = new Ext.XTemplate('{foo.bar.baz}', {1132 strict: true1133 });1134 expect(function () {1135 tpl.apply({});1136 }).toThrow();1137 });1138 it('should throw when for expression is invalid', function () {1139 var tpl = new Ext.XTemplate('<tpl for="foo.bar.baz">{.}</tpl>', {1140 strict: true1141 });1142 expect(function () {1143 tpl.apply({});1144 }).toThrow();1145 });1146 it('should throw when if expression is invalid', function () {1147 var tpl = new Ext.XTemplate('<tpl if="foo.bar.baz">{.}</tpl>', {1148 strict: true1149 });1150 expect(function () {1151 tpl.apply({});1152 }).toThrow();1153 });1154 });...
Template.js
Source:Template.js
1describe('Ext.app.bind.Template', function () {2 var BindTemplate;3 function getNumFragments (tpl) {4 var count = 0;5 for (var i = tpl.buffer.length; i-- > 0; ) {6 if (tpl.buffer[i]) {7 ++count;8 }9 }10 return count;11 }12 function getNumSlots (tpl) {13 var count = 0;14 for (var i = tpl.slots.length; i-- > 0; ) {15 if (tpl.slots[i]) {16 ++count;17 }18 }19 return count;20 }21 beforeEach(function () {22 BindTemplate = Ext.app.bind.Template;23 });24 describe('tokens', function () {25 it('should parse on first use', function () {26 var tpl = new BindTemplate('Hello {foo}');27 expect(tpl.tokens).toBe(null);28 var tokens = tpl.getTokens();29 expect(tokens).toEqual(['foo']);30 expect(getNumFragments(tpl)).toBe(1);31 expect(getNumSlots(tpl)).toBe(1);32 });33 it('should parse simple names', function () {34 var tpl = new BindTemplate('Hello {foo} {bar}');35 var tokens = tpl.getTokens();36 expect(tokens).toEqual(['foo', 'bar']);37 expect(getNumFragments(tpl)).toBe(2);38 expect(getNumSlots(tpl)).toBe(2);39 });40 it('should parse dotted names', function () {41 var tpl = new BindTemplate('Hello {foo.bar} {bar.foo}');42 var tokens = tpl.getTokens();43 expect(tokens).toEqual(['foo.bar', 'bar.foo']);44 expect(getNumFragments(tpl)).toBe(2);45 expect(getNumSlots(tpl)).toBe(2);46 });47 it('should consolidate tokens', function () {48 var tpl = new BindTemplate('Hello {foo.bar} {bar} {foo.bar} {bar}');49 var tokens = tpl.getTokens();50 expect(tokens).toEqual(['foo.bar', 'bar']);51 expect(getNumFragments(tpl)).toBe(4);52 expect(getNumSlots(tpl)).toBe(4);53 });54 it('should match slots to consolidated tokens', function () {55 // 1 2 3 4 5 656 var tpl = new BindTemplate('Hello {foo.bar}{bar} - {foo.bar}{bar}');57 tpl.parse();58 expect(getNumFragments(tpl)).toBe(2);59 expect(getNumSlots(tpl)).toBe(4);60 expect(typeof tpl.slots[1]).toBe('function');61 expect(typeof tpl.slots[2]).toBe('function');62 // slots[3] is null due to " - " in buffer[3]63 expect(typeof tpl.slots[4]).toBe('function');64 expect(typeof tpl.slots[5]).toBe('function');65 });66 it("should not attempt to parse outside of curly braces", function() {67 var tpl = new BindTemplate('Hello `{foo}`!'),68 tokens = tpl.getTokens();69 expect(tokens).toEqual(['foo']);70 var s = tpl.apply([5]);71 expect(s).toBe('Hello `5`!');72 });73 });74 describe('unary operators', function(){75 it('should parse -', function(){76 var tpl = new BindTemplate('Hello {foo.bar + -5}!');77 var tokens = tpl.getTokens();78 expect(tokens).toEqual(['foo.bar']);79 var s = tpl.apply([10]);80 expect(s).toBe('Hello 5!');81 });82 it('should parse - before an expression', function(){83 var tpl = new BindTemplate('Hello {foo.bar + -(bar + 3):number("0.00")}!');84 var tokens = tpl.getTokens();85 expect(tokens).toEqual(['foo.bar', 'bar']);86 var s = tpl.apply([10, 7]);87 expect(s).toBe('Hello 0!'); // 10 - '10.00'88 });89 it('should parse - before an expression and follow parans', function(){90 var tpl = new BindTemplate('Hello {(foo.bar + -(bar + 3)):number("0.00")}!');91 var tokens = tpl.getTokens();92 expect(tokens).toEqual(['foo.bar', 'bar']);93 var s = tpl.apply([10, 7]);94 expect(s).toBe('Hello 0.00!');95 });96 it('should parse - before parans and before literal', function(){97 var tpl = new BindTemplate('Hello {(foo.bar + -(bar +- 3)):number("0.00")}!');98 var tokens = tpl.getTokens();99 expect(tokens).toEqual(['foo.bar', 'bar']);100 var s = tpl.apply([10, 7]);101 expect(s).toBe('Hello 6.00!');102 });103 it('should parse - before parans and before token', function(){104 var tpl = new BindTemplate('Hello {(foo.bar + -(bar -- foo)):number("0.00")}!');105 var tokens = tpl.getTokens();106 expect(tokens).toEqual(['foo.bar', 'bar', 'foo']);107 var s = tpl.apply([10, 7, 4]);108 expect(s).toBe('Hello -1.00!');109 });110 it('should parse @ unary operator', function(){111 var tpl = new BindTemplate('Hello {@Ext.justTemp}!');112 Ext.justTemp = 'foo';113 var s = tpl.apply();114 expect(s).toBe('Hello foo!');115 Ext.justTemp = 'bar';116 s = tpl.apply();117 expect(s).toBe('Hello bar!');118 expect(tpl.isStatic()).toBe(false);119 Ext.justTemp = null;120 });121 });122 describe('binary operators', function(){123 it('should parse + operations', function(){124 var tpl = new BindTemplate('Hello {foo.bar + bar.foo}!');125 var tokens = tpl.getTokens();126 expect(tokens).toEqual(['foo.bar', 'bar.foo']);127 var s = tpl.apply([5, 7]);128 expect(s).toBe('Hello 12!');129 });130 it('should parse - operations', function(){131 var tpl = new BindTemplate('Hello {foo.bar - bar.foo}!');132 var tokens = tpl.getTokens();133 expect(tokens).toEqual(['foo.bar', 'bar.foo']);134 var s = tpl.apply([5, 7]);135 expect(s).toBe('Hello -2!');136 });137 it('should parse * operations', function(){138 var tpl = new BindTemplate('Hello {foo.bar * bar.foo}!');139 var tokens = tpl.getTokens();140 expect(tokens).toEqual(['foo.bar', 'bar.foo']);141 var s = tpl.apply([5, 7]);142 expect(s).toBe('Hello 35!');143 });144 it('should parse / operations', function(){145 var tpl = new BindTemplate('Hello {foo.bar / bar.foo}!');146 var tokens = tpl.getTokens();147 expect(tokens).toEqual(['foo.bar', 'bar.foo']);148 var s = tpl.apply([10, 2]);149 expect(s).toBe('Hello 5!');150 });151 it('should parse > operations', function(){152 var tpl = new BindTemplate('{foo.bar > bar.foo}!');153 var tokens = tpl.getTokens();154 expect(tokens).toEqual(['foo.bar', 'bar.foo']);155 var s = tpl.apply([10, 2]);156 expect(s).toBe('true!');157 });158 it('should parse < operations', function(){159 var tpl = new BindTemplate('{foo.bar < bar.foo}!');160 var tokens = tpl.getTokens();161 expect(tokens).toEqual(['foo.bar', 'bar.foo']);162 var s = tpl.apply([2, 10]);163 expect(s).toBe('true!');164 });165 it('should parse >= operations', function(){166 var tpl = new BindTemplate('{foo.bar >= bar.foo}!');167 var tokens = tpl.getTokens();168 expect(tokens).toEqual(['foo.bar', 'bar.foo']);169 var s = tpl.apply([10, 10]);170 expect(s).toBe('true!');171 });172 it('should parse <= operations', function(){173 var tpl = new BindTemplate('{foo.bar <= bar.foo}!');174 var tokens = tpl.getTokens();175 expect(tokens).toEqual(['foo.bar', 'bar.foo']);176 var s = tpl.apply([10, 10]);177 expect(s).toBe('true!');178 });179 it('should parse === operations', function(){180 var tpl = new BindTemplate('{foo.bar === bar.foo}!');181 var tokens = tpl.getTokens();182 expect(tokens).toEqual(['foo.bar', 'bar.foo']);183 var s = tpl.apply([10, '10']);184 expect(s).toBe('false!');185 });186 it('should parse == operations', function(){187 var tpl = new BindTemplate('{foo.bar == bar.foo}!');188 var tokens = tpl.getTokens();189 expect(tokens).toEqual(['foo.bar', 'bar.foo']);190 var s = tpl.apply([10, '10']);191 expect(s).toBe('true!');192 });193 it('should parse !== operations', function(){194 var tpl = new BindTemplate('{foo.bar !== bar.foo}!');195 var tokens = tpl.getTokens();196 expect(tokens).toEqual(['foo.bar', 'bar.foo']);197 var s = tpl.apply([10, '10']);198 expect(s).toBe('true!');199 });200 it('should parse != operations', function(){201 var tpl = new BindTemplate('{foo.bar != bar.foo}!');202 var tokens = tpl.getTokens();203 expect(tokens).toEqual(['foo.bar', 'bar.foo']);204 var s = tpl.apply([10, '10']);205 expect(s).toBe('false!');206 });207 it('should parse && operations', function(){208 var tpl = new BindTemplate('{foo.bar > bar.foo && bar > 5}!');209 var tokens = tpl.getTokens();210 expect(tokens).toEqual(['foo.bar', 'bar.foo', 'bar']);211 var s = tpl.apply([10, 5, 3]);212 expect(s).toBe('false!');213 });214 it('should parse || operations', function(){215 var tpl = new BindTemplate('{foo.bar > bar.foo || bar > 5}!');216 var tokens = tpl.getTokens();217 expect(tokens).toEqual(['foo.bar', 'bar.foo', 'bar']);218 var s = tpl.apply([10, 5, 3]);219 expect(s).toBe('true!');220 });221 it('should parse operations by priority', function(){222 var tpl = new BindTemplate('Hello {foo.bar * foo + bar / bar.foo}!');223 var tokens = tpl.getTokens();224 expect(tokens).toEqual(['foo.bar', 'foo', 'bar', 'bar.foo']);225 var s = tpl.apply([10, 2, 5, 2]);226 expect(s).toBe('Hello 22.5!');227 });228 });229 describe('ternary operator', function(){230 it('should parse token condition', function () {231 var tpl = new BindTemplate('Hello {foo ? 5 : 6}');232 var tokens = tpl.getTokens();233 expect(tokens).toEqual(['foo']);234 var s = tpl.apply([true]);235 expect(s).toBe('Hello 5');236 });237 it('should parse binary condition >', function () {238 var tpl = new BindTemplate('Hello {foo > 3 ? 5 : 6}');239 var tokens = tpl.getTokens();240 expect(tokens).toEqual(['foo']);241 var s = tpl.apply([2]);242 expect(s).toBe('Hello 6');243 });244 it('should parse binary condition >=', function () {245 var tpl = new BindTemplate('Hello {foo >= 3 ? 5 : 6}');246 var tokens = tpl.getTokens();247 expect(tokens).toEqual(['foo']);248 var s = tpl.apply([3]);249 expect(s).toBe('Hello 5');250 });251 it('should parse binary condition <', function () {252 var tpl = new BindTemplate('Hello {foo < 3 ? 5 : 6}');253 var tokens = tpl.getTokens();254 expect(tokens).toEqual(['foo']);255 var s = tpl.apply([2]);256 expect(s).toBe('Hello 5');257 });258 it('should parse binary condition <=', function () {259 var tpl = new BindTemplate('Hello {foo <= 3 ? 5 : 6}');260 var tokens = tpl.getTokens();261 expect(tokens).toEqual(['foo']);262 var s = tpl.apply([4]);263 expect(s).toBe('Hello 6');264 });265 it('should parse binary condition ==', function () {266 var tpl = new BindTemplate('Hello {foo == "3" ? 5 : 6}');267 var tokens = tpl.getTokens();268 expect(tokens).toEqual(['foo']);269 var s = tpl.apply([3]);270 expect(s).toBe('Hello 5');271 });272 it('should parse binary condition ===', function () {273 var tpl = new BindTemplate('Hello {foo === "3" ? 5 : 6}');274 var tokens = tpl.getTokens();275 expect(tokens).toEqual(['foo']);276 var s = tpl.apply([3]);277 expect(s).toBe('Hello 6');278 });279 it('should parse binary condition !=', function () {280 var tpl = new BindTemplate('Hello {foo != "3" ? 5 : 6}');281 var tokens = tpl.getTokens();282 expect(tokens).toEqual(['foo']);283 var s = tpl.apply([3]);284 expect(s).toBe('Hello 6');285 });286 it('should parse binary condition !==', function () {287 var tpl = new BindTemplate('Hello {foo !== "3" ? 5 : 6}');288 var tokens = tpl.getTokens();289 expect(tokens).toEqual(['foo']);290 var s = tpl.apply([3]);291 expect(s).toBe('Hello 5');292 });293 it('should parse condition with format fn', function () {294 var tpl = new BindTemplate('Hello {foo:this.fn ? 5 : 6}');295 var tokens = tpl.getTokens();296 expect(tokens).toEqual(['foo']);297 var s = tpl.apply([4], {298 fn: function(){ return false; }299 });300 expect(s).toBe('Hello 6');301 });302 it('should parse condition with format fn and args', function () {303 var tpl = new BindTemplate('Hello {foo:this.fn("testing", 4) ? 5 : 6}');304 var tokens = tpl.getTokens();305 expect(tokens).toEqual(['foo']);306 var s = tpl.apply([4], {307 fn: function(){ return false; }308 });309 expect(s).toBe('Hello 6');310 });311 it('should parse condition with chained format fn and args', function () {312 var tpl = new BindTemplate('Hello {foo:this.fn("testing", 4):this.fn2 ? 5 : 6}');313 var tokens = tpl.getTokens();314 expect(tokens).toEqual(['foo']);315 var s = tpl.apply([4], {316 fn: function(){ return false; },317 fn2: function(){ return true; }318 });319 expect(s).toBe('Hello 5');320 });321 it('should parse condition with chained and nested format fn and args', function () {322 var tpl = new BindTemplate('Hello {foo:this.fn("testing", bar:this.fn3(null, true)):this.fn2 ? 5 : 6}');323 var tokens = tpl.getTokens();324 expect(tokens).toEqual(['foo', 'bar']);325 var s = tpl.apply([4], {326 fn: function(){ return false; },327 fn2: function(){ return true; },328 fn3: function(){ return 5; }329 });330 expect(s).toBe('Hello 5');331 });332 it('should parse true part with literal', function () {333 var tpl = new BindTemplate('Hello {foo ? "test" : 6}');334 var tokens = tpl.getTokens();335 expect(tokens).toEqual(['foo']);336 var s = tpl.apply([true]);337 expect(s).toBe('Hello test');338 });339 it('should parse true part with number', function () {340 var tpl = new BindTemplate('Hello {foo ? .04 : 6}');341 var tokens = tpl.getTokens();342 expect(tokens).toEqual(['foo']);343 var s = tpl.apply([true]);344 expect(s).toBe('Hello 0.04');345 });346 it('should parse true part with null', function () {347 var tpl = new BindTemplate('Hello {foo ? null : 6}');348 var tokens = tpl.getTokens();349 expect(tokens).toEqual(['foo']);350 var s = tpl.apply([true]);351 expect(s).toBe('Hello ');352 });353 it('should parse true part with boolean', function () {354 var tpl = new BindTemplate('Hello {foo ? true : 6}');355 var tokens = tpl.getTokens();356 expect(tokens).toEqual(['foo']);357 var s = tpl.apply([true]);358 expect(s).toBe('Hello true');359 });360 it('should parse true part enclosed in parans with simple format fn', function () {361 var tpl = new BindTemplate('Hello {foo ? (bar:number) : 6}');362 var tokens = tpl.getTokens();363 expect(tokens).toEqual(['foo', 'bar']);364 var s = tpl.apply([true, 5]);365 expect(s).toBe('Hello 5');366 });367 it('should parse true part enclosed in parans with format fn and args', function () {368 var tpl = new BindTemplate('Hello {foo ? (bar:number("0.00")) : 6}');369 var tokens = tpl.getTokens();370 expect(tokens).toEqual(['foo', 'bar']);371 var s = tpl.apply([true, 5]);372 expect(s).toBe('Hello 5.00');373 });374 it('should parse true part with basic algebra inside parans', function () {375 var tpl = new BindTemplate('Hello {foo ? (bar + 5 * foo.bar) : 6}');376 var tokens = tpl.getTokens();377 expect(tokens).toEqual(['foo', 'bar', 'foo.bar']);378 var s = tpl.apply([true, 4, 3]);379 expect(s).toBe('Hello 19');380 });381 it('should parse true part with basic algebra and no parans', function () {382 var tpl = new BindTemplate('Hello {foo ? bar + 5 * foo.bar : 6}');383 var tokens = tpl.getTokens();384 expect(tokens).toEqual(['foo', 'bar', 'foo.bar']);385 var s = tpl.apply([true, 4, 3]);386 expect(s).toBe('Hello 19');387 });388 it('should parse true part with basic algebra and format fn', function () {389 var tpl = new BindTemplate('Hello {foo ? ( ( bar + 5 * foo.bar:this.fn( 2 ) / 4 ):round:number("0.00") ) : 6}');390 var tokens = tpl.getTokens();391 expect(tokens).toEqual(['foo', 'bar', 'foo.bar']);392 var s = tpl.apply([true, 4, 3], {393 fn: function(v, factor){394 return v * factor;395 }396 });397 expect(s).toBe('Hello 12.00');398 });399 it('should parse true part with nested ternary', function () {400 var tpl = new BindTemplate('Hello {foo ? (bar ? (foo.bar + 9) : "failed") : 6}');401 var tokens = tpl.getTokens();402 expect(tokens).toEqual(['foo', 'bar', 'foo.bar']);403 var s = tpl.apply([true, 4, 3]);404 expect(s).toBe('Hello 12');405 });406 it('should parse true part with nested ternary and no parans', function () {407 var tpl = new BindTemplate('Hello {foo ? bar ? foo.bar + 9 : "failed" : 6}');408 var tokens = tpl.getTokens();409 expect(tokens).toEqual(['foo', 'bar', 'foo.bar']);410 var s = tpl.apply([true, 4, 3]);411 expect(s).toBe('Hello 12');412 });413 });414 describe('combined unary and binary operators', function(){415 it('should parse binary and unary -', function(){416 var tpl = new BindTemplate('Hello {foo.bar --5}!');417 var tokens = tpl.getTokens();418 expect(tokens).toEqual(['foo.bar']);419 var s = tpl.apply([10]);420 expect(s).toBe('Hello 15!');421 });422 it('should parse binary + and unary -', function(){423 var tpl = new BindTemplate('Hello {foo.bar +-5}!');424 var tokens = tpl.getTokens();425 expect(tokens).toEqual(['foo.bar']);426 var s = tpl.apply([10]);427 expect(s).toBe('Hello 5!');428 });429 it('should parse binary + and unary ! and -', function(){430 var tpl = new BindTemplate('Hello {foo.bar + !-5}!');431 var tokens = tpl.getTokens();432 expect(tokens).toEqual(['foo.bar']);433 var s = tpl.apply([10]);434 expect(s).toBe('Hello 10!'); // 10 + false435 });436 it('should parse ! operator in front of open paran', function(){437 var tpl = new BindTemplate('Hello {foo.bar + !(bar:number("0.00"))}!');438 var tokens = tpl.getTokens();439 expect(tokens).toEqual(['foo.bar', 'bar']);440 var s = tpl.apply([10, 4]);441 expect(s).toBe('Hello 10!'); // 10 + false442 });443 it('should parse ! operator in front of a token', function(){444 var tpl = new BindTemplate('Hello {foo.bar + !bar}!');445 var tokens = tpl.getTokens();446 expect(tokens).toEqual(['foo.bar', 'bar']);447 var s = tpl.apply([10, false]);448 expect(s).toBe('Hello 11!'); // 10 + true449 });450 it('should parse ! operator in front of a @', function(){451 var tpl = new BindTemplate('Hello {foo.bar + !@Ext.versions.core}!');452 var tokens = tpl.getTokens();453 expect(tokens).toEqual(['foo.bar']);454 var s = tpl.apply([10]);455 expect(s).toBe('Hello 10!'); // 10 + false456 });457 });458 describe('algebra', function(){459 it('should parse basic algebra', function(){460 var tpl = new BindTemplate('{foo:round + 2}');461 var tokens = tpl.getTokens();462 expect(tokens).toEqual(['foo']);463 var s = tpl.apply([15.6]);464 expect(s).toBe(18);465 });466 it('should parse operations by priority', function(){467 var tpl = new BindTemplate('Hello {(foo.bar * foo + bar +-test ? 7 : 1):this.thing(3) / bar.foo}!');468 var tokens = tpl.getTokens();469 expect(tokens).toEqual(['foo.bar', 'foo', 'bar', 'test', 'bar.foo']);470 var s = tpl.apply([10, 2, 5, 25, 2], {471 thing: function(v, factor){472 return v * factor;473 }474 });475 expect(s).toBe('Hello 1.5!');476 });477 it('should parse operations and apply formulas', function(){478 var tpl = new BindTemplate('Hello {(foo.bar * foo + bar):this.thing(3) / bar.foo}!');479 var tokens = tpl.getTokens();480 expect(tokens).toEqual(['foo.bar', 'foo', 'bar', 'bar.foo']);481 var s = tpl.apply([10, 2, 5, 2], {482 thing: function(v, factor){483 return v * factor;484 }485 });486 expect(s).toBe('Hello 37.5!');487 });488 it('should parse operations in formula arguments', function(){489 var tpl = new BindTemplate('Hello {((foo.bar * foo + bar):this.thing(bar + test:this.thing(3)) / bar.foo):number("0.00")}!');490 var tokens = tpl.getTokens();491 expect(tokens).toEqual(['foo.bar', 'foo', 'bar', 'test', 'bar.foo']);492 var s = tpl.apply([10, 2, 5, 7, 25], {493 thing: function(v, factor){494 return v * factor;495 }496 });497 expect(s).toBe('Hello 26.00!');498 });499 it('should parse complex operations', function(){500 var tpl = new BindTemplate('Hello {(foo.bar + bar.foo:this.thing):number("0.00")}!');501 var s = tpl.apply([5, 7], {502 thing: function(v){503 return v * 2;504 }505 });506 expect(s).toBe('Hello 19.00!');507 });508 });509 describe('default formatters', function () {510 it('should parse', function () {511 var tpl = new BindTemplate('Hello {foo:number} {bar.foo:lowercase}');512 expect(tpl.getTokens()).toEqual(['foo', 'bar.foo']);513 var s = tpl.apply([5, 'SENCHA']);514 expect(s).toBe('Hello 5 sencha');515 });516 it('should parse chained formatters', function(){517 var tpl = new BindTemplate('Hello {foo:lowercase:capitalize} {bar.foo:number("0.00")}');518 expect(tpl.getTokens()).toEqual(['foo', 'bar.foo']);519 var s = tpl.apply(['SENCHA', 23]);520 expect(s).toBe('Hello Sencha 23.00');521 });522 it('should parse nested formatters', function(){523 var tpl = new BindTemplate('Hello {foo:format(bar:pick("First: \\"param\\"", foo.bar:number("0")))}');524 expect(tpl.getTokens()).toEqual(['foo', 'bar', 'foo.bar']);525 var s = tpl.apply(['Result: {0}', false, 5]);526 expect(s).toBe('Hello Result: First: "param"');527 });528 it('should parse complex nested formatters', function(){529 var tpl = new BindTemplate('Hello {foo:format(bar:capitalize:leftPad(5, "x"))}');530 expect(tpl.getTokens()).toEqual(['foo', 'bar']);531 var s = tpl.apply(['there, {0}', 'john']);532 expect(s).toBe('Hello there, xJohn');533 });534 it('should parse nested and chained formatters', function(){535 var tpl = new BindTemplate('Hello {foo.bar:leftPad(!foo.test:pick(bar,foo), "X"):uppercase:ellipsis(8)} there and {foo:capitalize}!');536 expect(tpl.getTokens()).toEqual(['foo.bar', 'foo.test', 'bar', 'foo']);537 var s = tpl.apply(['sencha', true, 10, 'sencha']);538 expect(s).toBe('Hello XXXXS... there and Sencha!');539 });540 it('should parse escaped strings', function(){541 var tpl = new BindTemplate("{foo:leftPad(13, 'You\\'re ok ')}");542 // this expressions will fail: {foo:leftPad("You\", hi!",2)} or {foo:leftPad("(You\")",2)}543 expect(tpl.getTokens()).toEqual(['foo']);544 var s = tpl.apply(['now']);545 expect(s).toBe('You\'re ok now');546 });547 it('should parse more escaped strings', function(){548 var tpl = new BindTemplate('{foo:leftPad(10, "Y\\"): ")}');549 // this expression will fail: {foo:date("Y\"",2)}550 expect(tpl.getTokens()).toEqual(['foo']);551 var s = tpl.apply(['hello']);552 expect(s).toBe('Y"): hello');553 });554 it('should parse arguments', function () {555 var tpl = new BindTemplate('Hello {foo:number("0.00")} {bar.foo:number("0,000.00")}');556 expect(tpl.getTokens()).toEqual(['foo', 'bar.foo']);557 var s = tpl.apply([4554, 4554]);558 expect(s).toBe('Hello 4554.00 4,554.00');559 });560 it('should parse boolean arguments', function () {561 var tpl = new BindTemplate('Hello {foo:toggle("Flex", false)} {bar.foo:defaultValue(true)}');562 expect(tpl.getTokens()).toEqual(['foo', 'bar.foo']);563 var s = tpl.apply(['Flex', undefined]);564 expect(s).toBe('Hello false true');565 });566 it('should parse arguments that are functions', function(){567 var tpl = new BindTemplate('Hello {foo:defaultValue(bar.foo:lowercase)}');568 expect(tpl.getTokens()).toEqual(['foo', 'bar.foo']);569 var s = tpl.apply([undefined, 'THERE']);570 expect(s).toBe('Hello there');571 });572 it('should apply simple formatting', function () {573 var tpl = new BindTemplate('Hello {foo:number} {bar.foo:date("Y-m-d")} '+574 '-- {foo:number("0.00")}');575 var s = tpl.apply([123.456, new Date(2013, 2, 2)]);576 expect(s).toBe('Hello 123.456 2013-03-02 -- 123.46');577 });578 it('should apply complex formatting', function () {579 // The "," inside a string argument makes splitting on commas and producing an580 // args array early impossible (if we are to respect global references in them581 // as well)... but still needs to work.582 var tpl = new BindTemplate('Hello {foo:number} {bar.foo:date("Y-m-d")} '+583 '-- {foo:number("0,000.00")}');584 var s = tpl.apply([123456.789, new Date(2013, 2, 2)]);585 expect(s).toBe('Hello 123456.789 2013-03-02 -- 123,456.79');586 });587 });588 describe('scoped formatters', function () {589 it('should parse', function () {590 var tpl = new BindTemplate('Hello {foo:this.fn} {bar.foo:this.fn2}');591 expect(tpl.getTokens()).toEqual(['foo', 'bar.foo']);592 var s = tpl.apply([5, 6], {593 fn: function(v){594 return v + 1;595 },596 fn2: function(v){597 return v * 2;598 }599 });600 expect(s).toBe('Hello 6 12');601 });602 it('should parse arguments', function () {603 var tpl = new BindTemplate('Hello {foo:this.fn(4)} {bar.foo:this.fn2(20)}');604 expect(tpl.getTokens()).toEqual(['foo', 'bar.foo']);605 var s = tpl.apply([5, 6], {606 fn: function(v, a){607 return v + a;608 },609 fn2: function(v, a){610 return v * a;611 }612 });613 expect(s).toBe('Hello 9 120');614 });615 it('should apply simple formatting', function () {616 var tpl = new BindTemplate('Hello {foo:number} {bar.foo:date("Y-m-d")} '+617 '-- {foo:this.number("0.00")}');618 var s = tpl.apply([123.456, new Date(2013, 2, 2)], {619 scale: 2,620 number: function (v, str) {621 return '[[' + Ext.util.Format.number(v * this.scale, str) + ']]';622 }623 });624 expect(s).toBe('Hello 123.456 2013-03-02 -- [[246.91]]');625 });626 it('should apply complex formatting', function () {627 // This template uses a global reference as an argument. Odd but it works in628 // other templates.629 var tpl = new BindTemplate('Hello {foo:number} {bar.foo:date("Y-m-d")} '+630 '-- {foo:this.thing(@Ext.versions.core)}');631 var s = tpl.apply([123.456, new Date(2013, 2, 2)], {632 text: '::',633 thing: function (v, str) {634 return this.text + v + '=' + str + this.text;635 }636 });637 expect(s).toBe('Hello 123.456 2013-03-02 -- ::123.456=' +638 Ext.getVersion('core') + '::');639 });640 it('should apply chained and nested formatting', function(){641 var tpl = new BindTemplate('Hello {!foo.bar:pick(bar:number, "test"):number(\'0,000.00\')}, this is a {foo.test:this.thing("test", !test:pick("\\"man{}\\"",\'(joe)\'))}!');642 var s = tpl.apply([true, 123.456, 'complex', true], {643 text: '::',644 thing: function(v, str, a){645 return this.text + v + '=' + str + this.text + ' (' + a + ')';646 }647 });648 expect(s).toBe('Hello 123.46, this is a ::complex=test:: ("man{}")!');649 });650 });651 describe('syntax errors', function(){652 it('should fail when there\'s a format fn without prefixed token', function () {653 var tpl = new BindTemplate('Hello { :number }!');654 expect(function() {655 tpl.getTokens();656 }).toThrow();657 });658 it('should fail when @ prefixes an ! operator', function () {659 var tpl = new BindTemplate('Hello {foo.bar + @!Ext.versions.core}!');660 expect(function() {661 tpl.getTokens();662 }).toThrow();663 });664 it('should fail when @ prefixes a number', function () {665 var tpl = new BindTemplate('Hello {foo.bar + @5}!');666 expect(function() {667 tpl.getTokens();668 }).toThrow();669 });670 it('should fail when @ prefixes a string', function () {671 var tpl = new BindTemplate('Hello {foo.bar + @"test"}!');672 expect(function() {673 tpl.getTokens();674 }).toThrow();675 });676 it('should fail when @ prefixes other operators', function () {677 var tpl = new BindTemplate('Hello {foo.bar + @("test"}!');678 expect(function() {679 tpl.getTokens();680 }).toThrow();681 });682 it('should fail when there\'s a missing paran', function () {683 var tpl = new BindTemplate('Hello {foo.bar + (foo:number}!');684 expect(function() {685 tpl.getTokens();686 }).toThrow();687 });688 it('should fail when specifying an invalid Ext.util.Format fn', function () {689 var tpl = new BindTemplate('Hello {foo.bar + (foo:justTesting}!');690 expect(function() {691 tpl.getTokens();692 }).toThrow();693 });694 it('should fail when there is an unexpected operator', function () {695 var tpl = new BindTemplate('Hello {foo.bar + ! $ (foo:number)}!');696 expect(function() {697 tpl.getTokens();698 }).toThrow();699 });700 it('should fail when there is an unknown operator', function () {701 var tpl = new BindTemplate('Hello {foo.bar + dd[foo:number]}!');702 expect(function() {703 tpl.getTokens();704 }).toThrow();705 });706 it('should fail on unexpected . token', function () {707 var tpl = new BindTemplate('Hello {foo.bar + dd.(foo:number)}!');708 expect(function() {709 tpl.getTokens();710 }).toThrow();711 });712 it('should fail on not defined unary * operator', function () {713 var tpl = new BindTemplate('Hello {foo.bar + * 5}!');714 expect(function() {715 tpl.getTokens();716 }).toThrow();717 });718 it('should fail on undefined unary in format fn name', function () {719 var tpl = new BindTemplate('Hello {foo.bar:*number}!');720 expect(function() {721 tpl.getTokens();722 }).toThrow();723 });724 it('should fail when starting with an unknown operator', function () {725 var tpl = new BindTemplate('Hello { % foo.bar:number }!');726 expect(function() {727 tpl.getTokens();728 }).toThrow();729 });730 it('should fail when using open curly inside expression', function () {731 var tpl = new BindTemplate('Hello { { foo.bar:number }!');732 expect(function() {733 tpl.getTokens();734 }).toThrow();735 });736 it('should fail when using close curly inside expression', function () {737 var tpl = new BindTemplate('Hello { foo.bar:}number }!');738 expect(function() {739 tpl.getTokens();740 }).toThrow();741 });742 it('should fail on wrong literals', function () {743 var tpl = new BindTemplate('Hello { foo.bar:this.test("yep\" it fails") }!');744 expect(function() {745 tpl.getTokens();746 }).toThrow();747 });748 it('should fail when ending with an operator', function () {749 var tpl = new BindTemplate('Hello {foo.bar:number + }!');750 expect(function() {751 tpl.getTokens();752 }).toThrow();753 });754 it('should fail on undefined unary / operator', function () {755 var tpl = new BindTemplate('Hello {foo.bar + / 5}!');756 expect(function() {757 tpl.getTokens();758 }).toThrow();759 });760 it('should fail on undefined unary * operator', function () {761 var tpl = new BindTemplate('Hello {foo.bar + * 5}!');762 expect(function() {763 tpl.getTokens();764 }).toThrow();765 });766 it('should fail on undefined unary && operator', function () {767 var tpl = new BindTemplate('Hello {foo.bar + && 5}!');768 expect(function() {769 tpl.getTokens();770 }).toThrow();771 });772 it('should fail on undefined unary || operator', function () {773 var tpl = new BindTemplate('Hello {foo.bar + || 5}!');774 expect(function() {775 tpl.getTokens();776 }).toThrow();777 });778 it('should fail on undefined unary > operator', function () {779 var tpl = new BindTemplate('Hello {foo.bar + > 5}!');780 expect(function() {781 tpl.getTokens();782 }).toThrow();783 });784 it('should fail on undefined unary >= operator', function () {785 var tpl = new BindTemplate('Hello {foo.bar + >= 5}!');786 expect(function() {787 tpl.getTokens();788 }).toThrow();789 });790 it('should fail on undefined unary < operator', function () {791 var tpl = new BindTemplate('Hello {foo.bar + < 5}!');792 expect(function() {793 tpl.getTokens();794 }).toThrow();795 });796 it('should fail on undefined unary <= operator', function () {797 var tpl = new BindTemplate('Hello {foo.bar + <= 5}!');798 expect(function() {799 tpl.getTokens();800 }).toThrow();801 });802 it('should fail on undefined unary == operator', function () {803 var tpl = new BindTemplate('Hello {foo.bar + == 5}!');804 expect(function() {805 tpl.getTokens();806 }).toThrow();807 });808 it('should fail on undefined unary === operator', function () {809 var tpl = new BindTemplate('Hello {foo.bar + === 5}!');810 expect(function() {811 tpl.getTokens();812 }).toThrow();813 });814 it('should fail on undefined unary != operator', function () {815 var tpl = new BindTemplate('Hello {foo.bar + != 5}!');816 expect(function() {817 tpl.getTokens();818 }).toThrow();819 });820 it('should fail on undefined unary !== operator', function () {821 var tpl = new BindTemplate('Hello {foo.bar + !== 5}!');822 expect(function() {823 tpl.getTokens();824 }).toThrow();825 });826 it('should fail when the compiled function fails on global objects', function () {827 var tpl = new BindTemplate('Hello {foo.bar + @Something.b}!');828 expect(tpl.getTokens()).toEqual(['foo.bar']);829 expect(function() {830 tpl.apply([3]);831 }).toThrow();832 });833 it('should fail when the compiled function fails on missing scope function', function () {834 var tpl = new BindTemplate('Hello {foo.bar:this.test}!');835 expect(tpl.getTokens()).toEqual(['foo.bar']);836 expect(function() {837 tpl.apply([3]);838 }).toThrow();839 });840 it('should fail when ambiguous ternary provided', function () {841 var tpl = new BindTemplate('Hello {foo ? bar:number : 6}');842 expect(function() {843 tpl.getTokens();844 }).toThrow();845 });846 });...
filter.js
Source:filter.js
1dojo.provide("dojox.dtl.tests.text.filter");2dojo.require("dojox.dtl");3dojo.require("dojox.dtl.Context");4dojo.require("dojox.dtl.utils.date");5dojo.require("dojox.date.php");6dojo.require("dojox.string.sprintf");7// If you update something here, update it in the HTML tests8doh.register("dojox.dtl.text.filter",9 [10 function test_filter_add(t){11 var dd = dojox.dtl;12 var context = new dd.Context({ four: 4 });13 tpl = new dd.Template('{{ four|add:"6" }}');14 t.is("10", tpl.render(context));15 context.four = "4";16 t.is("10", tpl.render(context));17 tpl = new dd.Template('{{ four|add:"six" }}');18 t.is("4", tpl.render(context));19 tpl = new dd.Template('{{ four|add:"6.6" }}');20 t.is("10", tpl.render(context));21 },22 function test_filter_addslashes(t){23 var dd = dojox.dtl;24 var context = new dd.Context({ unslashed: "Test back slashes \\, double quotes \" and single quotes '" })25 var tpl = new dd.Template('{{ unslashed|addslashes|safe }}');26 t.is("Test back slashes \\\\, double quotes \\\" and single quotes \\'", tpl.render(context));27 },28 function test_filter_capfirst(t){29 var dd = dojox.dtl;30 var tpl = new dd.Template('{{ uncapped|capfirst }}');31 t.is("Cap", tpl.render(new dd.Context({ uncapped: "cap" })));32 },33 function test_filter_center(t){34 var dd = dojox.dtl;35 var context = new dd.Context();36 var tpl = new dd.Template('{{ narrow|center }}');37 context.narrow = "even";38 t.is("even", tpl.render(context));39 context.narrow = "odd";40 t.is("odd", tpl.render(context));41 tpl = new dd.Template('{{ narrow|center:"5" }}');42 context.narrow = "even";43 t.is("even ", tpl.render(context));44 context.narrow = "odd";45 t.is(" odd ", tpl.render(context));46 tpl = new dd.Template('{{ narrow|center:"6" }}');47 context.narrow = "even";48 t.is(" even ", tpl.render(context));49 context.narrow = "odd";50 t.is(" odd ", tpl.render(context));51 tpl = new dd.Template('{{ narrow|center:"12" }}');52 context.narrow = "even";53 t.is(" even ", tpl.render(context));54 context.narrow = "odd";55 t.is(" odd ", tpl.render(context));56 },57 function test_filter_cut(t){58 var dd = dojox.dtl;59 var context = new dd.Context({ uncut: "Apples and oranges" });60 var tpl = new dd.Template('{{ uncut|cut }}');61 t.is("Apples and oranges", tpl.render(context));62 tpl = new dd.Template('{{ uncut|cut:"A" }}');63 t.is("pples and oranges", tpl.render(context));64 tpl = new dd.Template('{{ uncut|cut:" " }}');65 t.is("Applesandoranges", tpl.render(context));66 tpl = new dd.Template('{{ uncut|cut:"e" }}');67 t.is("Appls and orangs", tpl.render(context));68 },69 function test_filter_date(t){70 var dd = dojox.dtl;71 var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) });72 var tpl = new dd.Template('{{ now|date }}');73 t.is(dojox.dtl.utils.date.format(context.now, "N j, Y"), tpl.render(context));74 context.then = new Date(2007, 0, 1);75 tpl = new dd.Template('{{ now|date:"d" }}');76 t.is("01", tpl.render(context));77 tpl = new dd.Template('{{ now|date:"D" }}');78 t.is("Mon", tpl.render(context));79 tpl = new dd.Template('{{ now|date:"j" }}');80 t.is("1", tpl.render(context));81 tpl = new dd.Template('{{ now|date:"l" }}');82 t.is("Monday", tpl.render(context));83 tpl = new dd.Template('{{ now|date:"N" }}');84 t.is("Jan.", tpl.render(context));85 tpl = new dd.Template('{{ now|date:"S" }}');86 t.is("st", tpl.render(context));87 context.now.setDate(2);88 t.is("nd", tpl.render(context));89 context.now.setDate(3);90 t.is("rd", tpl.render(context));91 context.now.setDate(4);92 t.is("th", tpl.render(context));93 context.now.setDate(5);94 t.is("th", tpl.render(context));95 context.now.setDate(6);96 t.is("th", tpl.render(context));97 context.now.setDate(7);98 t.is("th", tpl.render(context));99 context.now.setDate(8);100 t.is("th", tpl.render(context));101 context.now.setDate(9);102 t.is("th", tpl.render(context));103 context.now.setDate(10);104 t.is("th", tpl.render(context));105 context.now.setDate(11);106 t.is("th", tpl.render(context));107 context.now.setDate(12);108 t.is("th", tpl.render(context));109 context.now.setDate(13);110 t.is("th", tpl.render(context));111 context.now.setDate(14);112 t.is("th", tpl.render(context));113 context.now.setDate(15);114 t.is("th", tpl.render(context));115 context.now.setDate(16);116 t.is("th", tpl.render(context));117 context.now.setDate(17);118 t.is("th", tpl.render(context));119 context.now.setDate(18);120 t.is("th", tpl.render(context));121 context.now.setDate(19);122 t.is("th", tpl.render(context));123 context.now.setDate(20);124 t.is("th", tpl.render(context));125 context.now.setDate(21);126 t.is("st", tpl.render(context));127 context.now.setDate(22);128 t.is("nd", tpl.render(context));129 context.now.setDate(23);130 t.is("rd", tpl.render(context));131 context.now.setDate(24);132 t.is("th", tpl.render(context));133 context.now.setDate(25);134 t.is("th", tpl.render(context));135 context.now.setDate(26);136 t.is("th", tpl.render(context));137 context.now.setDate(27);138 t.is("th", tpl.render(context));139 context.now.setDate(28);140 t.is("th", tpl.render(context));141 context.now.setDate(29);142 t.is("th", tpl.render(context));143 context.now.setDate(30);144 t.is("th", tpl.render(context));145 context.now.setDate(31);146 t.is("st", tpl.render(context));147 context.now.setDate(1);148 tpl = new dd.Template('{{ now|date:"w" }}');149 t.is("1", tpl.render(context));150 tpl = new dd.Template('{{ now|date:"z" }}');151 t.is("0", tpl.render(context));152 tpl = new dd.Template('{{ now|date:"W" }}');153 t.is("1", tpl.render(context));154 },155 function test_filter_default(t){156 var dd = dojox.dtl;157 var context = new dd.Context();158 tpl = new dd.Template('{{ empty|default }}');159 t.is("", tpl.render(context));160 tpl = new dd.Template('{{ empty|default:"full" }}');161 t.is("full", tpl.render(context));162 context.empty = "not empty";163 t.is("not empty", tpl.render(context));164 },165 function test_filter_default_if_none(t){166 var dd = dojox.dtl;167 var context = new dd.Context();168 tpl = new dd.Template('{{ empty|default_if_none }}');169 t.is("", tpl.render(context));170 tpl = new dd.Template('{{ empty|default_if_none:"full" }}');171 t.is("", tpl.render(context));172 context.empty = null;173 t.is("full", tpl.render(context));174 context.empty = "not empty";175 t.is("not empty", tpl.render(context));176 },177 function test_filter_dictsort(t){178 var dd = dojox.dtl;179 var context = new dd.Context({180 fruit: [181 { name: "lemons", toString: function(){ return this.name; } },182 { name: "apples", toString: function(){ return this.name; } },183 { name: "grapes", toString: function(){ return this.name; } }184 ]185 });186 tpl = new dd.Template('{{ fruit|dictsort|join:"|" }}');187 t.is("lemons|apples|grapes", tpl.render(context));188 tpl = new dd.Template('{{ fruit|dictsort:"name"|join:"|" }}');189 t.is("apples|grapes|lemons", tpl.render(context));190 },191 function test_filter_dictsort_reversed(t){192 var dd = dojox.dtl;193 context = new dd.Context({194 fruit: [195 { name: "lemons", toString: function(){ return this.name; } },196 { name: "apples", toString: function(){ return this.name; } },197 { name: "grapes", toString: function(){ return this.name; } }198 ]199 });200 tpl = new dd.Template('{{ fruit|dictsortreversed:"name"|join:"|" }}');201 t.is("lemons|grapes|apples", tpl.render(context));202 },203 function test_filter_divisibleby(t){204 var dd = dojox.dtl;205 context = new dd.Context();206 tpl = new dd.Template('{{ 4|divisibleby:"2" }}');207 t.is("true", tpl.render(context));208 context = new dd.Context({ number: 4 });209 tpl = new dd.Template('{{ number|divisibleby:3 }}');210 t.is("false", tpl.render(context));211 },212 function test_filter_escape(t){213 var dd = dojox.dtl;214 var context = new dd.Context({ unescaped: "Try & cover <all> the \"major\" 'situations' at once" });215 tpl = new dd.Template('{{ unescaped|escape }}');216 t.is("Try & cover <all> the "major" 'situations' at once", tpl.render(context));217 },218 function test_filter_filesizeformat(t){219 var dd = dojox.dtl;220 var tpl = new dd.Template('{{ 1|filesizeformat }}');221 t.is("1 byte", tpl.render());222 tpl = new dd.Template('{{ 512|filesizeformat }}');223 t.is("512 bytes", tpl.render());224 tpl = new dd.Template('{{ 1024|filesizeformat }}');225 t.is("1.0 KB", tpl.render());226 tpl = new dd.Template('{{ 2048|filesizeformat }}');227 t.is("2.0 KB", tpl.render());228 tpl = new dd.Template('{{ 1048576|filesizeformat }}');229 t.is("1.0 MB", tpl.render());230 tpl = new dd.Template('{{ 1073741824|filesizeformat }}');231 t.is("1.0 GB", tpl.render());232 },233 function test_filter_first(t){234 var dd = dojox.dtl;235 var context = new dd.Context({236 fruit: [237 { name: "lemons", toString: function(){ return this.name; } },238 { name: "apples", toString: function(){ return this.name; } },239 { name: "grapes", toString: function(){ return this.name; } }240 ]241 });242 tpl = new dd.Template('{{ fruit|first }}');243 t.is("lemons", tpl.render(context));244 },245 function test_filter_fix_ampersands(t){246 var dd = dojox.dtl;247 var tpl = new dd.Template('{{ "One & Two"|fix_ampersands|safe }}');248 t.is("One & Two", tpl.render());249 },250 function test_filter_floatformat(t){251 var dd = dojox.dtl;252 var context = new dd.Context({ num1: 34.23234, num2: 34.00000 });253 var tpl = new dd.Template('{{ num1|floatformat }}');254 t.is("34.2", tpl.render(context));255 tpl = new dd.Template('{{ num2|floatformat }}');256 t.is("34", tpl.render(context));257 tpl = new dd.Template('{{ num1|floatformat:3 }}');258 t.is("34.232", tpl.render(context));259 tpl = new dd.Template('{{ num2|floatformat:3 }}');260 t.is("34.000", tpl.render(context));261 tpl = new dd.Template('{{ num1|floatformat:-3 }}');262 t.is("34.2", tpl.render(context));263 tpl = new dd.Template('{{ num2|floatformat:-3 }}');264 t.is("34", tpl.render(context));265 },266 function test_filter_get_digit(t){267 var dd = dojox.dtl;268 var context = new dd.Context({ pi: 314159265 });269 var tpl = new dd.Template('{{ pi|get_digit:1 }}');270 t.is("3", tpl.render(context));271 tpl = new dd.Template('{{ pi|get_digit:"2" }}');272 t.is("1", tpl.render(context));273 tpl = new dd.Template('{{ pi|get_digit:0 }}');274 t.is("314159265", tpl.render(context));275 tpl = new dd.Template('{{ "nada"|get_digit:1 }}');276 t.is("0", tpl.render(context));277 },278 function test_filter_iriencode(t){279 var dd = dojox.dtl;280 var tpl = new dd.Template('{{ "http://homepage.com/~user"|urlencode|iriencode }}');281 t.is("http%3A//homepage.com/%7Euser", tpl.render());282 tpl = new dd.Template('{{ "pottedmeat@dojotoolkit.org"|iriencode }}');283 t.is("pottedmeat%40dojotoolkit.org", tpl.render());284 },285 function test_filter_join(t){286 var dd = dojox.dtl;287 var context = new dd.Context({ items: ["foo", "bar", "baz" ]});288 var tpl = new dd.Template("{{ items|join }}");289 t.is("foo,bar,baz", tpl.render(context));290 tpl = new dd.Template('{{ items|join:"mustard" }}');291 t.is("foomustardbarmustardbaz", tpl.render(context));292 },293 function test_filter_length(t){294 var dd = dojox.dtl;295 var context = new dd.Context({296 fruit: [297 { name: "lemons", toString: function(){ return this.name; } },298 { name: "apples", toString: function(){ return this.name; } },299 { name: "grapes", toString: function(){ return this.name; } }300 ]301 });302 tpl = new dd.Template('{{ fruit|length }}');303 t.is("3", tpl.render(context));304 tpl = new dd.Template('{{ fruit|first|length }}');305 t.is("6", tpl.render(context));306 },307 function test_filter_length_is(t){308 var dd = dojox.dtl;309 var context = new dd.Context({310 fruit: [311 { name: "lemons", toString: function(){ return this.name; } },312 { name: "apples", toString: function(){ return this.name; } },313 { name: "grapes", toString: function(){ return this.name; } }314 ]315 });316 tpl = new dd.Template('{{ fruit|length_is:"3" }}');317 t.is("true", tpl.render(context));318 tpl = new dd.Template('{{ fruit|length_is:"4" }}');319 t.is("false", tpl.render(context));320 },321 function test_filter_linebreaks(t){322 var dd = dojox.dtl;323 var context = new dd.Context({ unbroken: "This is just\r\n\n\ra bunch\nof text\n\n\nand such" });324 tpl = new dd.Template('{{ unbroken|linebreaks|safe }}');325 t.is("<p>This is just</p>\n\n<p>a bunch<br />of text</p>\n\n<p>and such</p>", tpl.render(context));326 },327 function test_filter_linebreaksbr(t){328 var dd = dojox.dtl;329 var context = new dd.Context({ unbroken: "This is just\r\n\n\ra bunch\nof text\n\n\nand such" });330 tpl = new dd.Template('{{ unbroken|linebreaksbr|safe }}');331 t.is("This is just<br /><br />a bunch<br />of text<br /><br /><br />and such", tpl.render(context));332 },333 function test_filter_linenumbers(t){334 var dd = dojox.dtl;335 var context = new dd.Context({ lines: "One\nTwo\nThree\nFour\n" });336 var tpl = new dd.Template('{{ lines|linenumbers }}');337 t.is("1. One\n2. Two\n3. Three\n4. Four\n5. ", tpl.render(context));338 },339 function test_filter_ljust(t){340 var dd = dojox.dtl;341 var context = new dd.Context();342 var tpl = new dd.Template('{{ narrow|ljust }}');343 context.narrow = "even";344 t.is("even", tpl.render(context));345 context.narrow = "odd";346 t.is("odd", tpl.render(context));347 tpl = new dd.Template('{{ narrow|ljust:"5" }}');348 context.narrow = "even";349 t.is("even ", tpl.render(context));350 context.narrow = "odd";351 t.is("odd ", tpl.render(context));352 tpl = new dd.Template('{{ narrow|ljust:"6" }}');353 context.narrow = "even";354 t.is("even ", tpl.render(context));355 context.narrow = "odd";356 t.is("odd ", tpl.render(context));357 tpl = new dd.Template('{{ narrow|ljust:"12" }}');358 context.narrow = "even";359 t.is("even ", tpl.render(context));360 context.narrow = "odd";361 t.is("odd ", tpl.render(context));362 },363 function test_filter_lower(t){364 var dd = dojox.dtl;365 var context = new dd.Context({ mixed: "MiXeD" });366 var tpl = new dd.Template('{{ mixed|lower }}');367 t.is("mixed", tpl.render(context));368 },369 function test_filter_make_list(t){370 var dd = dojox.dtl;371 var context = new dd.Context({ word: "foo", number: 314159265, arr: ["first", "second"], obj: {first: "first", second: "second"} });372 var tpl = new dd.Template('{{ word|make_list|join:"|" }} {{ number|make_list|join:"|" }} {{ arr|make_list|join:"|" }} {{ obj|make_list|join:"|" }}');373 t.is("f|o|o 3|1|4|1|5|9|2|6|5 first|second first|second", tpl.render(context));374 },375 function test_filter_phone2numeric(t){376 var dd = dojox.dtl;377 tpl = new dd.Template('{{ "1-800-pottedmeat"|phone2numeric }}');378 t.is("1-800-7688336328", tpl.render());379 },380 function test_filter_pluralize(t){381 var dd = dojox.dtl;382 var context = new dd.Context({ animals: ["bear", "cougar", "aardvark"] });383 var tpl = new dd.Template('{{ animals|length }} animal{{ animals|length|pluralize }}');384 t.is("3 animals", tpl.render(context));385 context.animals = ["bear"];386 t.is("1 animal", tpl.render(context));387 context = new dd.Context({ fairies: ["tinkerbell", "Andy Dick" ]});388 tpl = new dd.Template('{{ fairies|length }} fair{{ fairies|length|pluralize:"y,ies" }}');389 t.is("2 fairies", tpl.render(context));390 context.fairies.pop();391 t.is("1 fairy", tpl.render(context));392 },393 function test_filter_pprint(t){394 var dd = dojox.dtl;395 var context = new dd.Context({ animals: ["bear", "cougar", "aardvark"] });396 tpl = new dd.Template("{{ animals|pprint|safe }}");397 t.is('["bear","cougar","aardvark"]', tpl.render(context));398 },399 function test_filter_random(t){400 var dd = dojox.dtl;401 var context = new dd.Context({402 fruit: [403 { name: "lemons", toString: function(){ return this.name; } },404 { name: "apples", toString: function(){ return this.name; } },405 { name: "grapes", toString: function(){ return this.name; } }406 ]407 });408 tpl = new dd.Template('{{ fruit|random }}');409 result = tpl.render(context);410 t.t(result == "lemons" || result == "apples" || result == "grapes");411 var different = false;412 for(var i = 0; i < 10; i++){413 // Check to see if it changes414 if(result != tpl.render(context) && result == "lemons" || result == "apples" || result == "grapes"){415 different = true;416 break;417 }418 }419 t.t(different);420 },421 function test_filter_removetags(t){422 var dd = dojox.dtl;423 var context = new dd.Context({ tagged: "I'm gonna do something <script>evil</script> with the <html>filter" });424 tpl = new dd.Template('{{ tagged|removetags:"script <html>"|safe }}');425 t.is("I'm gonna do something evil with the filter", tpl.render(context));426 },427 function test_filter_rjust(t){428 var dd = dojox.dtl;429 var context = new dd.Context();430 var tpl = new dd.Template('{{ narrow|rjust }}');431 context.narrow = "even";432 t.is("even", tpl.render(context));433 context.narrow = "odd";434 t.is("odd", tpl.render(context));435 tpl = new dd.Template('{{ narrow|rjust:"5" }}');436 context.narrow = "even";437 t.is(" even", tpl.render(context));438 context.narrow = "odd";439 t.is(" odd", tpl.render(context));440 tpl = new dd.Template('{{ narrow|rjust:"6" }}');441 context.narrow = "even";442 t.is(" even", tpl.render(context));443 context.narrow = "odd";444 t.is(" odd", tpl.render(context));445 tpl = new dd.Template('{{ narrow|rjust:"12" }}');446 context.narrow = "even";447 t.is(" even", tpl.render(context));448 context.narrow = "odd";449 t.is(" odd", tpl.render(context));450 },451 function test_filter_slice(t){452 var dd = dojox.dtl;453 var context = new dd.Context({454 fruit: [455 { name: "lemons", toString: function(){ return this.name; } },456 { name: "apples", toString: function(){ return this.name; } },457 { name: "grapes", toString: function(){ return this.name; } }458 ]459 });460 tpl = new dd.Template('{{ fruit|slice:":1"|join:"|" }}');461 t.is("lemons", tpl.render(context));462 tpl = new dd.Template('{{ fruit|slice:"1"|join:"|" }}');463 t.is("apples|grapes", tpl.render(context));464 tpl = new dd.Template('{{ fruit|slice:"1:3"|join:"|" }}');465 t.is("apples|grapes", tpl.render(context));466 tpl = new dd.Template('{{ fruit|slice:""|join:"|" }}');467 t.is("lemons|apples|grapes", tpl.render(context));468 tpl = new dd.Template('{{ fruit|slice:"-1"|join:"|" }}');469 t.is("grapes", tpl.render(context));470 tpl = new dd.Template('{{ fruit|slice:":-1"|join:"|" }}');471 t.is("lemons|apples", tpl.render(context));472 tpl = new dd.Template('{{ fruit|slice:"-2:-1"|join:"|" }}');473 t.is("apples", tpl.render(context));474 },475 function test_filter_slugify(t){476 var dd = dojox.dtl;477 var context = new dd.Context({ unslugged: "Apples and oranges()"});478 tpl = new dd.Template('{{ unslugged|slugify }}');479 t.is("apples-and-oranges", tpl.render(context));480 },481 function test_filter_stringformat(t){482 var dd = dojox.dtl;483 var tpl = new dd.Template('{{ 42|stringformat:"7.3f" }}');484 t.is(" 42.000", tpl.render());485 },486 function test_filter_striptags(t){487 var dd = dojox.dtl;488 var context = new dd.Context({ tagged: "I'm gonna do something <script>evil</script> with the <html>filter" });489 tpl = new dd.Template('{{ tagged|striptags|safe }}');490 t.is("I'm gonna do something evil with the filter", tpl.render(context));491 },492 function test_filter_time(t){493 var dd = dojox.dtl;494 var context = new dd.Context({ now: new Date(2007, 0, 1) });495 tpl = new dd.Template('{{ now|time }}');496 t.is(dojox.dtl.utils.date.format(context.now, "P"), tpl.render(context));497 tpl = new dd.Template('{{ now|time:"g" }}');498 t.is('12', tpl.render(context));499 },500 function test_filter_timesince(t){501 var dd = dojox.dtl;502 var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) });503 tpl = new dd.Template('{{ now|timesince:then }}');504 t.is("1 month", tpl.render(context));505 context.then = new Date(2007, 0, 5);506 t.is("4 days", tpl.render(context));507 context.then = new Date(2007, 0, 17);508 t.is("2 weeks", tpl.render(context));509 context.then = new Date(2008, 1, 1);510 t.is("1 year", tpl.render(context));511 },512 function test_filter_timeuntil(t){513 var dd = dojox.dtl;514 var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) });515 var tpl = new dd.Template('{{ now|timeuntil:then }}');516 t.is("1 month", tpl.render(context));517 context.then = new Date(2007, 0, 5);518 t.is("4 days", tpl.render(context));519 context.then = new Date(2007, 0, 17);520 t.is("2 weeks", tpl.render(context));521 context.then = new Date(2008, 1, 1);522 t.is("1 year", tpl.render(context));523 },524 function test_filter_title(t){525 var dd = dojox.dtl;526 var context = new dd.Context({ name: "potted meat" });527 var tpl = new dd.Template("{{ name|title|safe }}");528 t.is("Potted Meat", tpl.render(context));529 context.name = "What's going on?";530 t.is("What's Going On?", tpl.render(context));531 context.name = "use\nline\nbREAKs\tand tabs";532 t.is("Use\nLine\nBreaks\tAnd Tabs", tpl.render(context));533 },534 function test_filter_truncatewords(t){535 var dd = dojox.dtl;536 var context = new dd.Context({ word: "potted meat writes a lot of tests" });537 var tpl = new dd.Template("{{ word|truncatewords }}");538 t.is(context.word, tpl.render(context));539 tpl = new dd.Template('{{ word|truncatewords:"1" }}');540 t.is("potted ...", tpl.render(context));541 tpl = new dd.Template('{{ word|truncatewords:"2" }}');542 t.is("potted meat ...", tpl.render(context));543 tpl = new dd.Template('{{ word|truncatewords:20" }}');544 t.is(context.word, tpl.render(context));545 context.word = "potted \nmeat \nwrites a lot of tests";546 tpl = new dd.Template('{{ word|truncatewords:"3" }}');547 t.is("potted \nmeat \nwrites ...", tpl.render(context));548 },549 function test_filter_truncatewords_html(t){550 var dd = dojox.dtl;551 var context = new dd.Context({552 body: "Test a string <em>that ends <i>inside a</i> tag</em> with different args",553 size: 2554 })555 var tpl = new dd.Template('{{ body|truncatewords_html:size|safe }}');556 t.is("Test a ...", tpl.render(context));557 context.size = 4;558 t.is("Test a string <em>that ...</em>", tpl.render(context));559 context.size = 6;560 t.is("Test a string <em>that ends <i>inside ...</i></em>", tpl.render(context));561 },562 function test_filter_unordered_list(t){563 var dd = dojox.dtl;564 var context = new dd.Context({ states: ["States", [["Kansas", [["Lawrence", []], ["Topeka", []]]], ["Illinois", []]]] });565 tpl = new dd.Template('{{ states|unordered_list|safe }}');566 t.is("\t<li>States\n\t<ul>\n\t\t<li>Kansas\n\t\t<ul>\n\t\t\t<li>Lawrence</li>\n\t\t\t<li>Topeka</li>\n\t\t</ul>\n\t\t</li>\n\t\t<li>Illinois</li>\n\t</ul>\n\t</li>", tpl.render(context));567 },568 function test_filter_upper(t){569 var dd = dojox.dtl;570 var context = new dd.Context({ mixed: "MiXeD" });571 var tpl = new dd.Template('{{ mixed|upper }}');572 t.is("MIXED", tpl.render(context));573 },574 function test_filter_urlencode(t){575 var dd = dojox.dtl;576 var tpl = new dd.Template('{{ "http://homepage.com/~user"|urlencode }}');577 t.is("http%3A//homepage.com/%7Euser", tpl.render());578 // see http://bugs.dojotoolkit.org/ticket/12932579 tpl = new dd.Template('{{ "\t"|urlencode }}');580 t.is("\t", decodeURIComponent(tpl.render()));581 },582 function test_filter_urlize(t){583 var dd = dojox.dtl;584 var context = new dd.Context({585 body: "My favorite websites are www.televisionwithoutpity.com, http://daringfireball.net and you can email me at pottedmeat@sitepen.com"586 });587 var tpl = new dd.Template("{{ body|urlize|safe }}");588 t.is('My favorite websites are <a href="http://www.televisionwithoutpity.com" rel="nofollow">www.televisionwithoutpity.com</a> <a href="http://daringfireball.net" rel="nofollow">http://daringfireball.net</a> and you can email me at <a href="mailto:pottedmeat@sitepen.com">pottedmeat@sitepen.com</a>', tpl.render(context));589 },590 function test_filter_urlizetrunc(t){591 var dd = dojox.dtl;592 var context = new dd.Context({593 body: "My favorite websites are www.televisionwithoutpity.com, http://daringfireball.net and you can email me at pottedmeat@sitepen.com"594 });595 var tpl = new dd.Template("{{ body|urlizetrunc|safe }}");596 t.is('My favorite websites are <a href="http://www.televisionwithoutpity.com" rel="nofollow">www.televisionwithoutpity.com</a> <a href="http://daringfireball.net" rel="nofollow">http://daringfireball.net</a> and you can email me at <a href="mailto:pottedmeat@sitepen.com">pottedmeat@sitepen.com</a>', tpl.render(context));597 tpl = new dd.Template('{{ body|urlizetrunc:"2"|safe }}');598 t.is('My favorite websites are <a href="http://www.televisionwithoutpity.com" rel="nofollow">www.televisionwithoutpity.com</a> <a href="http://daringfireball.net" rel="nofollow">http://daringfireball.net</a> and you can email me at <a href="mailto:pottedmeat@sitepen.com">pottedmeat@sitepen.com</a>', tpl.render(context));599 tpl = new dd.Template('{{ body|urlizetrunc:"10"|safe }}');600 t.is('My favorite websites are <a href="http://www.televisionwithoutpity.com" rel="nofollow">www.tel...</a> <a href="http://daringfireball.net" rel="nofollow">http://...</a> and you can email me at <a href="mailto:pottedmeat@sitepen.com">pottedmeat@sitepen.com</a>', tpl.render(context));601 },602 function test_filter_wordcount(t){603 var dd = dojox.dtl;604 var context = new dd.Context({605 food: "Hot Pocket"606 });607 var tpl = new dd.Template("{{ food|wordcount }}");608 t.is("2", tpl.render(context));609 context.food = "";610 t.is("0", tpl.render(context));611 context.food = "A nice barbecue, maybe a little grilled veggies, some cole slaw.";612 t.is("11", tpl.render(context));613 },614 function test_filter_wordwrap(t){615 var dd = dojox.dtl;616 var context = new dd.Context({617 body: "shrimp gumbo, shrimp pie, shrimp scampi, shrimp stew, fried shrimp, baked shrimp, shrimp o grotten, grilled shrimp, shrimp on a stick, shrimp salad, shrimp pop overs, shrimp cake, shrimp legs, shrimp stuffed eggs, shrimp cre oll, shrimp soup, creamed shrimp on toast, shrimp crapes, shrimply good crescent rolls, shrimp pizza, scalloped shrimp, boiled shrimp, shrimp cocktail"618 });619 var tpl = new dd.Template("{{ body|wordwrap }}");620 t.is(context.body, tpl.render(context));621 tpl = new dd.Template("{{ body|wordwrap:width }}");622 context.width = 10;623 t.is("shrimp\ngumbo,\nshrimp\npie,\nshrimp\nscampi,\nshrimp\nstew,\nfried\nshrimp,\nbaked\nshrimp,\nshrimp o\ngrotten,\ngrilled\nshrimp,\nshrimp on\na stick,\nshrimp\nsalad,\nshrimp pop\novers,\nshrimp\ncake,\nshrimp\nlegs,\nshrimp\nstuffed\neggs,\nshrimp cre\noll,\nshrimp\nsoup,\ncreamed\nshrimp on\ntoast,\nshrimp\ncrapes,\nshrimply\ngood\ncrescent\nrolls,\nshrimp\npizza,\nscalloped\nshrimp,\nboiled\nshrimp,\nshrimp\ncocktail", tpl.render(context));624 tpl = new dd.Template('{{ body|wordwrap:"80" }}');625 t.is("shrimp gumbo, shrimp pie, shrimp scampi, shrimp stew, fried shrimp, baked\nshrimp, shrimp o grotten, grilled shrimp, shrimp on a stick, shrimp salad,\nshrimp pop overs, shrimp cake, shrimp legs, shrimp stuffed eggs, shrimp cre oll,\nshrimp soup, creamed shrimp on toast, shrimp crapes, shrimply good crescent\nrolls, shrimp pizza, scalloped shrimp, boiled shrimp, shrimp cocktail", tpl.render(context));626 },627 function test_filter_yesno(t){628 var dd = dojox.dtl;629 var context = new dd.Context();630 tpl = new dd.Template('{{ true|yesno }}');631 t.is("yes", tpl.render(context));632 context = new dd.Context({ test: "value" });633 tpl = new dd.Template('{{ test|yesno }}');634 t.is("yes", tpl.render(context));635 tpl = new dd.Template('{{ false|yesno }}');636 t.is("no", tpl.render(context));637 tpl = new dd.Template('{{ null|yesno }}');638 t.is("maybe", tpl.render(context));639 tpl = new dd.Template('{{ true|yesno:"bling,whack,soso" }}');640 t.is("bling", tpl.render(context));641 context = new dd.Context({ test: "value" });642 tpl = new dd.Template('{{ test|yesno:"bling,whack,soso" }}');643 t.is("bling", tpl.render(context));644 tpl = new dd.Template('{{ false|yesno:"bling,whack,soso" }}');645 t.is("whack", tpl.render(context));646 tpl = new dd.Template('{{ null|yesno:"bling,whack,soso" }}');647 t.is("soso", tpl.render(context));648 tpl = new dd.Template('{{ null|yesno:"bling,whack" }}');649 t.is("whack", tpl.render(context));650 },651 function test_filter_contrib_key(t){652 var dd = dojox.dtl;653 var context = new dd.Context({654 headers: ["action", "type"],655 items: [656 {657 action: "eat",658 type: "apple"659 },660 {661 action: "mash",662 type: "banana"663 }664 ]665 });666 var tpl = new dd.Template("{% load dojox.dtl.contrib.objects %}<ul>{% for item in items %}<li><ul>{% for header in headers %}<li>{{ header }}: {{ item|key:header }}</li>{% endfor %}</ul></li>{% endfor %}</ul>");667 t.is('<ul><li><ul><li>action: eat</li><li>type: apple</li></ul></li><li><ul><li>action: mash</li><li>type: banana</li></ul></li></ul>', tpl.render(context));668 }669 ]...
Using AI Code Generation
1import { MockBuilder, MockRender } from 'ng-mocks';2import { MyComponent } from './my.component';3import { MyModule } from './my.module';4describe('MyComponent', () => {5 beforeEach(() => MockBuilder(MyComponent).keep(MyModule));6 it('renders the component', () => {7 const fixture = MockRender(MyComponent);8 expect(fixture.point.componentInstance).toBeDefined();9 });10});11import { MockBuilder, MockRender } from 'ng-mocks';12import { MyComponent } from './my.component';13describe('MyComponent', () => {14 beforeEach(() => MockBuilder(MyComponent));15 it('renders the component', () => {16 const fixture = MockRender(MyComponent);17 expect(fixture.point.componentInstance).toBeDefined();18 });19});20import { MockBuilder, MockRender } from 'ng-mocks';21import { MyComponent } from './my.component';22describe('MyComponent', () => {23 beforeEach(() => MockBuilder(MyComponent));24 it('renders the component', () => {25 const fixture = MockRender(MyComponent);26 expect(fixture.point.componentInstance).toBeDefined();27 });28});29import { MockBuilder, MockRender } from 'ng-mocks';30import { MyComponent } from './my.component';31describe('MyComponent', () => {32 beforeEach(() => MockBuilder(MyComponent));33 it('renders the component', () => {34 const fixture = MockRender(MyComponent);35 expect(fixture.point.componentInstance).toBeDefined();36 });37});38import { MockBuilder, MockRender } from 'ng-mocks';39import { MyComponent } from './my.component';40describe('MyComponent', () => {41 beforeEach(() => MockBuilder(MyComponent));42 it('renders the component', () => {43 const fixture = MockRender(MyComponent);44 expect(fixture.point.componentInstance).toBeDefined();45 });46});47import { MockBuilder, MockRender } from 'ng-mocks';48import { MyComponent } from './my.component';49describe('MyComponent', () => {50 beforeEach(()
Using AI Code Generation
1import { tpl } from 'ng-mocks';2import { MockBuilder } from 'ng-mocks';3import { MockRender } from 'ng-mocks';4import { MockInstance } from 'ng-mocks';5import { MockProvider } from 'ng-mocks';6import { MockRenderOptions } from 'ng-mocks';7import { MockModule } from 'ng-mocks';8import { MockDirective } from 'ng-mocks';9import { MockComponent } from 'ng-mocks';10import { MockPipe } from 'ng-mocks';11import { MockService } from 'ng-mocks';12import { MockedComponent } from 'ng-mocks';13import { MockedDirective } from 'ng-mocks';14import { MockedPipe } from 'ng-mocks';15import { MockedService } from 'ng-mocks';16import { MockedType } from 'ng-mocks';17import { Mocked } from 'ng-mocks';18import { MockRenderResult } from 'ng-mocks';19import { MockedDebugElement } from 'ng-mocks';20import { MockedDebugNode } from 'ng-mocks';21import { MockedElementRef } from 'ng-mocks';22import { MockedInjector } from 'ng-mocks';23import { MockedTemplateRef } from 'ng-mocks';24import { MockedViewContainerRef } from 'ng-mocks';25import { MockedComponentFixture } from 'ng-mocks';26import { MockedTest
Using AI Code Generation
1import { tpl } from 'ng-mocks';2import { tpl } from 'ng-mocks';3import { tpl } from 'ng-mocks';4import { tpl } from 'ng-mocks';5import { tpl } from 'ng-mocks';6import { tpl } from 'ng-mocks';7import { tpl } from 'ng-mocks';8import { tpl } from 'ng-mocks';9import { tpl } from 'ng-mocks';10import { tpl } from 'ng-mocks';11import { tpl } from 'ng-mocks';12import { tpl } from 'ng-mocks';13import { tpl } from 'ng-mocks';14import { tpl } from 'ng-mocks';15import { tpl } from 'ng-mocks';16import { tpl } from 'ng-mocks';17import { tpl } from 'ng-mocks';18import { tpl } from 'ng-mocks';19import { tpl } from 'ng-mocks';20import { tpl } from 'ng-mocks';21import { tpl } from 'ng-mocks';
Using AI Code Generation
1import tpl from 'ng-mocks';2describe('MyComponent', () => {3 let fixture: ComponentFixture<MyComponent>;4 beforeEach(() => {5 TestBed.configureTestingModule({6 }).compileComponents();7 fixture = TestBed.createComponent(MyComponent);8 });9 it('should render the component', () => {10 const component = fixture.componentInstance;11 expect(component).toBeTruthy();12 });13 it('should render the template', () => {14 const element = fixture.nativeElement;15 expect(element.querySelector('div')).toBeTruthy();16 });17 it('should render the template with ng-mocks', () => {18 const element = tpl('<my-component></my-component>');19 expect(element.querySelector('div')).toBeTruthy();20 });21});22@Component({23 template: require('./my-component.component.html'),24})25export class MyComponent {}26import { ComponentFixture, TestBed } from '@angular/core/testing';27import { Component } from '@angular/core';28import tpl from 'ng-mocks';29@Component({30 template: require('./my-component.component.html'),31})32export class MyComponent {}33describe('MyComponent', () => {34 let fixture: ComponentFixture<MyComponent>;35 beforeEach(() => {36 TestBed.configureTestingModule({37 }).compileComponents();38 fixture = TestBed.createComponent(MyComponent);39 });40 it('should render the component', () => {41 const component = fixture.componentInstance;42 expect(component).toBeTruthy();43 });44 it('should render the template', () => {45 const element = fixture.nativeElement;46 expect(element.querySelector('div')).toBeTruthy();47 });48 it('should render the template with ng-mocks', () => {49 const element = tpl('<my-component></my-component>');50 expect(element.querySelector('div')).toBeTruthy();51 });52});53@Component({54 template: require('./my-component.component.html'),55})56export class MyComponent {}57import { ComponentFixture, TestBed } from '@angular/core/testing';58import { Component } from '@angular/core';59import tpl from 'ng-mocks';60@Component({61 template: require('./my-component
Using AI Code Generation
1import { tpl } from 'ng-mocks';2describe('MyComponent', () => {3 it('should render the component', () => {4 const fixture = tpl('<my-component></my-component>');5 fixture.detectChanges();6 expect(fixture.nativeElement).toMatchSnapshot();7 });8});9import { render } from 'ng-mocks';10describe('MyComponent', () => {11 it('should render the component', () => {12 const fixture = render(MyComponent);13 expect(fixture.nativeElement).toMatchSnapshot();14 });15});16import { MockBuilder, MockRender } from 'ng-mocks';17describe('MyComponent', () => {18 beforeEach(() => MockBuilder(MyComponent).mock(MyService));19 it('should render the component', () => {20 const fixture = MockRender(MyComponent);21 expect(fixture.nativeElement).toMatchSnapshot();22 });23});24import { MockBuilder, MockRender } from 'ng-mocks';25describe('MyComponent', () => {26 beforeEach(() => MockBuilder().mock(MyService));27 it('should render the component', () => {28 const fixture = MockRender(MyComponent);29 expect(fixture.nativeElement).toMatchSnapshot();30 });31});32import { MockBuilder, MockRender } from 'ng-mocks';33describe('MyComponent', () => {34 beforeEach(() => MockBuilder().mock(MyService));35 it('should render the component', () => {36 const fixture = MockRender(MyComponent, {37 });38 expect(fixture.nativeElement).toMatchSnapshot();39 });40});41import { MockBuilder, MockRender } from 'ng-mocks';42describe('MyComponent', () => {43 beforeEach(() => MockBuilder().mock(MyService));44 it('should render the component', () => {45 const fixture = MockRender(MyComponent, {46 });47 expect(fixture.nativeElement).toMatchSnapshot();48 });49});50import { MockBuilder,
Using AI Code Generation
1import { MockBuilder, MockRender } from 'ng-mocks';2import { AppModule } from './app.module';3import { AppComponent } from './app.component';4import { MockComponent } from 'ng-mocks';5import { SomeComponent } from './some.component';6describe('AppComponent', () => {7 beforeEach(() => MockBuilder(AppComponent, AppModule));8 it('renders the component', () => {9 const fixture = MockRender(AppComponent);10 expect(fixture.point.componentInstance).toBeDefined();11 });12 it('renders some component', () => {13 const fixture = MockRender(14 );15 const some = fixture.debugElement.query(16 );17 expect(some).toBeDefined();18 });19 it('renders some component with mock', () => {20 const fixture = MockRender(21 {22 SomeComponent: MockComponent(SomeComponent),23 },24 );25 const some = fixture.debugElement.query(26 );27 expect(some).toBeDefined();28 });29});30import { Component } from '@angular/core';31@Component({32})33export class AppComponent {}34import { Component } from '@angular/core';35@Component({36})37export class SomeComponent {}38import { NgModule } from '@angular/core';39import { BrowserModule } from '@angular/platform-browser';40import { AppComponent } from './app.component';41import { SomeComponent } from './some.component';42@NgModule({43 imports: [BrowserModule],44})45export class AppModule {}
Using AI Code Generation
1import {ngMocks} from 'ng-mocks';2describe('test', () => {3 it('should render', () => {4 const fixture = ngMocks.faster();5 fixture.detectChanges();6 expect(fixture.nativeElement).toMatchSnapshot();7 });8});9import 'zone.js/dist/zone-testing';10import {getTestBed} from '@angular/core/testing';11import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';12getTestBed().initTestEnvironment(13 platformBrowserDynamicTesting()14);15{16 "compilerOptions": {17 },18}19{20 "compilerOptions": {21 "importHelpers": true,22 }23}24import {Component, NgModule} from '@angular/core';25import {BrowserModule} from '@angular/platform-browser';26import {MockBuilder, MockRender} from 'ng-mocks';27@Component({28})29export class AppComponent {30}31@NgModule({32 imports: [BrowserModule],33})34export class AppModule {35}36describe('AppComponent', () => {37 beforeEach(() => MockBuilder(AppComponent));38 it('should create the app', () => {39 const fixture = MockRender(AppComponent);40 expect(fixture.nativeElement).toMatchSnapshot();41 });42});
Using AI Code Generation
1import { tpl } from 'ng-mocks';2describe('test', () => {3 it('should render', () => {4 const fixture = tpl('<div>hello</div>');5 expect(fixture).toBeDefined();6 });7});8import { tpl } from 'ng-mocks';9describe('test', () => {10 it('should render', () => {11 const fixture = tpl('<div>hello</div>');12 expect(fixture).toBeDefined();13 });14});15import { tpl } from 'ng-mocks';16describe('test', () => {17 it('should render', () => {18 const fixture = tpl('<div>hello</div>');19 expect(fixture).toBeDefined();20 });21});22import { tpl } from 'ng-mocks';23describe('test', () => {24 it('should render', () => {25 const fixture = tpl('<div>hello</div>');26 expect(fixture).toBeDefined();27 });28});29import { tpl } from 'ng-mocks';30describe('test', () => {31 it('should render', () => {32 const fixture = tpl('<div>hello</div>');33 expect(fixture).toBeDefined();34 });35});36import { tpl } from 'ng-mocks';37describe('test', () => {38 it('should render', () => {39 const fixture = tpl('<div>hello</div>');40 expect(fixture).toBeDefined();41 });42});43import { tpl } from 'ng-mocks';44describe('test', () => {45 it('should render', () => {46 const fixture = tpl('<div>hello</
Using AI Code Generation
1import { tpl } from 'ng-mocks';2@Component({3 template: tpl('test.html'),4})5export class TestComponent {6 constructor() {}7}8import { MockBuilder, MockRender } from 'ng-mocks';9import { TestComponent } from './test';10describe('TestComponent', () => {11 beforeEach(() => MockBuilder(TestComponent));12 it('should render the template', () => {13 const fixture = MockRender(TestComponent);14 expect(fixture.debugElement.nativeElement.innerHTML).toContain('Test Template');15 });16});17import { MockBuilder, MockRender } from 'ng-mocks';18import { TestComponent } from './test';19describe('TestComponent', () => {20 beforeEach(() => MockBuilder(TestComponent));21 it('should render the template', () => {22 const fixture = MockRender(TestComponent);23 expect(fixture.debugElement.nativeElement.innerHTML).toContain('Test Template');24 });25});26import { MockBuilder, MockRender } from 'ng-mocks';27import { TestComponent } from './test';28describe('TestComponent', () => {29 beforeEach(() => MockBuilder(TestComponent));30 it('should render the template', () => {31 const fixture = MockRender(TestComponent);32 expect(fixture.debugElement.nativeElement.innerHTML).toContain('Test Template');33 });34});35import { MockBuilder, MockRender } from 'ng-mocks';36import { TestComponent } from './test';37describe('TestComponent', () => {38 beforeEach(() => MockBuilder(TestComponent));39 it('should render the template', () => {40 const fixture = MockRender(TestComponent);41 expect(fixture.debugElement.nativeElement.innerHTML).toContain('Test Template');42 });43});44import { MockBuilder, MockRender } from 'ng-mocks';45import { TestComponent } from './test';46describe('TestComponent', () => {47 beforeEach(() => MockBuilder(TestComponent));48 it('should render the template', () => {49 const fixture = MockRender(TestComponent);50 expect(fixture.debugElement.nativeElement.innerHTML).toContain('Test Template');51 });52});53import { MockBuilder, MockRender } from 'ng-mocks
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!