OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library template_binding.test.template_binding_test; | 5 library template_binding.test.template_binding_test; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:html'; | 8 import 'dart:html'; |
| 9 import 'dart:js' show JsObject; |
9 import 'dart:math' as math; | 10 import 'dart:math' as math; |
10 import 'package:observe/observe.dart'; | 11 import 'package:observe/observe.dart'; |
11 import 'package:template_binding/template_binding.dart'; | 12 import 'package:template_binding/template_binding.dart'; |
12 import 'package:unittest/html_config.dart'; | 13 import 'package:unittest/html_config.dart'; |
13 import 'package:unittest/unittest.dart'; | 14 import 'package:unittest/unittest.dart'; |
14 | 15 |
15 // TODO(jmesserly): merge this file? | 16 // TODO(jmesserly): merge this file? |
16 import 'binding_syntax.dart' show syntaxTests; | 17 import 'binding_syntax.dart' show syntaxTests; |
17 import 'utils.dart'; | 18 import 'utils.dart'; |
18 | 19 |
19 // Note: this file ported from | 20 // Note: this file ported from TemplateBinding's tests/tests.js |
20 // https://github.com/Polymer/TemplateBinding/blob/fcb7a502794f19544f2d4b77c96ee
bb70830591d/tests/tests.js | |
21 | 21 |
22 // TODO(jmesserly): submit a small cleanup patch to original. I fixed some | 22 // TODO(jmesserly): submit a small cleanup patch to original. I fixed some |
23 // cases where "div" and "t" were unintentionally using the JS global scope; | 23 // cases where "div" and "t" were unintentionally using the JS global scope; |
24 // look for "assertNodesAre". | 24 // look for "assertNodesAre". |
25 | 25 |
26 main() => dirtyCheckZone().run(() { | 26 main() => dirtyCheckZone().run(() { |
27 useHtmlConfiguration(); | 27 useHtmlConfiguration(); |
28 | 28 |
29 // Load MutationObserver polyfill in case IE needs it. | 29 // Load MutationObserver polyfill in case IE needs it. |
30 var script = new ScriptElement() | 30 var script = new ScriptElement() |
31 ..src = '/root_dart/pkg/mutation_observer/lib/mutation_observer.min.js'; | 31 ..src = '/root_dart/pkg/mutation_observer/lib/mutation_observer.min.js'; |
32 var polyfillLoaded = script.onLoad.first; | 32 var polyfillLoaded = script.onLoad.first; |
33 document.head.append(script); | 33 document.head.append(script); |
34 | 34 |
35 setUp(() => polyfillLoaded.then((_) { | 35 setUp(() => polyfillLoaded.then((_) { |
36 document.body.append(testDiv = new DivElement()); | 36 document.body.append(testDiv = new DivElement()); |
37 })); | 37 })); |
38 | 38 |
39 tearDown(() { | 39 tearDown(() { |
40 testDiv.remove(); | 40 testDiv.remove(); |
| 41 clearAllTemplates(testDiv); |
41 testDiv = null; | 42 testDiv = null; |
42 }); | 43 }); |
43 | 44 |
44 test('MutationObserver is supported', () { | 45 test('MutationObserver is supported', () { |
45 expect(MutationObserver.supported, true, reason: 'polyfill was loaded.'); | 46 expect(MutationObserver.supported, true, reason: 'polyfill was loaded.'); |
46 }); | 47 }); |
47 | 48 |
48 group('Template', templateInstantiationTests); | 49 group('Template', templateInstantiationTests); |
49 | 50 |
50 group('Binding Delegate API', () { | 51 group('Binding Delegate API', () { |
(...skipping 21 matching lines...) Expand all Loading... |
72 expect(node, isNotNull); | 73 expect(node, isNotNull); |
73 while (node != null) { | 74 while (node != null) { |
74 expect(expando[node], node.text); | 75 expect(expando[node], node.text); |
75 node = node.nextNode; | 76 node = node.nextNode; |
76 } | 77 } |
77 } | 78 } |
78 | 79 |
79 templateInstantiationTests() { | 80 templateInstantiationTests() { |
80 // Dart note: renamed some of these tests to have unique names | 81 // Dart note: renamed some of these tests to have unique names |
81 | 82 |
82 test('Bind (simple)', () { | 83 test('accessing bindingDelegate getter without Bind', () { |
| 84 var div = createTestHtml('<template>'); |
| 85 var template = div.firstChild; |
| 86 expect(templateBind(template).bindingDelegate, null); |
| 87 }); |
| 88 |
| 89 test('Bind - simple', () { |
83 var div = createTestHtml('<template bind={{}}>text</template>'); | 90 var div = createTestHtml('<template bind={{}}>text</template>'); |
84 templateBind(div.firstChild).model = {}; | 91 templateBind(div.firstChild).model = {}; |
85 return new Future(() { | 92 return new Future(() { |
86 expect(div.nodes.length, 2); | 93 expect(div.nodes.length, 2); |
87 expect(div.nodes.last.text, 'text'); | 94 expect(div.nodes.last.text, 'text'); |
88 | 95 |
89 // Dart note: null is used instead of undefined to clear the template. | 96 // Dart note: null is used instead of undefined to clear the template. |
90 templateBind(div.firstChild).model = null; | 97 templateBind(div.firstChild).model = null; |
91 | 98 |
92 }).then(endOfMicrotask).then((_) { | 99 }).then(endOfMicrotask).then((_) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 expect(template.nodes.length, 0); | 132 expect(template.nodes.length, 0); |
126 expect(template.nextNode, null); | 133 expect(template.nextNode, null); |
127 }); | 134 }); |
128 }); | 135 }); |
129 | 136 |
130 test('Bind - no defaultView', () { | 137 test('Bind - no defaultView', () { |
131 var div = createTestHtml('<template bind>text</template>'); | 138 var div = createTestHtml('<template bind>text</template>'); |
132 var template = div.firstChild; | 139 var template = div.firstChild; |
133 var doc = document.implementation.createHtmlDocument(''); | 140 var doc = document.implementation.createHtmlDocument(''); |
134 doc.adoptNode(div); | 141 doc.adoptNode(div); |
135 recursivelySetTemplateModel(template, {}); | 142 templateBind(template).model = {}; |
136 return new Future(() => expect(div.nodes.length, 1)); | 143 return new Future(() => expect(div.nodes.length, 2)); |
137 }); | 144 }); |
138 | 145 |
139 test('Empty Bind', () { | 146 test('Empty Bind', () { |
140 var div = createTestHtml('<template bind>text</template>'); | 147 var div = createTestHtml('<template bind>text</template>'); |
141 var template = div.firstChild; | 148 var template = div.firstChild; |
142 templateBind(template).model = {}; | 149 templateBind(template).model = {}; |
143 return new Future(() { | 150 return new Future(() { |
144 expect(div.nodes.length, 2); | 151 expect(div.nodes.length, 2); |
145 expect(div.nodes.last.text, 'text'); | 152 expect(div.nodes.last.text, 'text'); |
146 }); | 153 }); |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 templateBind(template).model = null; | 356 templateBind(template).model = null; |
350 | 357 |
351 }).then(endOfMicrotask).then((_) { | 358 }).then(endOfMicrotask).then((_) { |
352 expect(div.nodes.length, 1); | 359 expect(div.nodes.length, 1); |
353 }); | 360 }); |
354 }); | 361 }); |
355 | 362 |
356 test('Bind If, 2', () { | 363 test('Bind If, 2', () { |
357 var div = createTestHtml( | 364 var div = createTestHtml( |
358 '<template bind="{{ foo }}" if="{{ bar }}">{{ bat }}</template>'); | 365 '<template bind="{{ foo }}" if="{{ bar }}">{{ bat }}</template>'); |
| 366 var template = div.firstChild; |
359 var m = toObservable({ 'bar': null, 'foo': { 'bat': 'baz' } }); | 367 var m = toObservable({ 'bar': null, 'foo': { 'bat': 'baz' } }); |
360 recursivelySetTemplateModel(div, m); | 368 templateBind(template).model = m; |
361 return new Future(() { | 369 return new Future(() { |
362 expect(div.nodes.length, 1); | 370 expect(div.nodes.length, 1); |
363 | 371 |
364 m['bar'] = 1; | 372 m['bar'] = 1; |
365 }).then(endOfMicrotask).then((_) { | 373 }).then(endOfMicrotask).then((_) { |
366 expect(div.nodes.length, 2); | 374 expect(div.nodes.length, 2); |
367 expect(div.lastChild.text, 'baz'); | 375 expect(div.lastChild.text, 'baz'); |
368 }); | 376 }); |
369 }); | 377 }); |
370 | 378 |
(...skipping 13 matching lines...) Expand all Loading... |
384 expect(div.lastChild.text, 'foo'); | 392 expect(div.lastChild.text, 'foo'); |
385 | 393 |
386 templateBind(template).model = null; | 394 templateBind(template).model = null; |
387 }).then(endOfMicrotask).then((_) { | 395 }).then(endOfMicrotask).then((_) { |
388 expect(div.nodes.length, 1); | 396 expect(div.nodes.length, 1); |
389 }); | 397 }); |
390 }); | 398 }); |
391 | 399 |
392 test('Empty-If', () { | 400 test('Empty-If', () { |
393 var div = createTestHtml('<template if>{{ value }}</template>'); | 401 var div = createTestHtml('<template if>{{ value }}</template>'); |
| 402 var template = div.firstChild; |
394 var m = toObservable({ 'value': 'foo' }); | 403 var m = toObservable({ 'value': 'foo' }); |
395 recursivelySetTemplateModel(div, null); | 404 templateBind(template).model = null; |
396 return new Future(() { | 405 return new Future(() { |
397 expect(div.nodes.length, 1); | 406 expect(div.nodes.length, 1); |
398 | 407 |
399 recursivelySetTemplateModel(div, m); | 408 templateBind(template).model = m; |
400 }).then(endOfMicrotask).then((_) { | 409 }).then(endOfMicrotask).then((_) { |
401 expect(div.nodes.length, 2); | 410 expect(div.nodes.length, 2); |
402 expect(div.lastChild.text, 'foo'); | 411 expect(div.lastChild.text, 'foo'); |
403 }); | 412 }); |
404 }); | 413 }); |
405 | 414 |
406 test('OneTime - simple text', () { | 415 test('OneTime - simple text', () { |
407 var div = createTestHtml('<template bind>[[ value ]]</template>'); | 416 var div = createTestHtml('<template bind>[[ value ]]</template>'); |
| 417 var template = div.firstChild; |
408 var m = toObservable({ 'value': 'foo' }); | 418 var m = toObservable({ 'value': 'foo' }); |
409 recursivelySetTemplateModel(div, m); | 419 templateBind(template).model = m; |
410 return new Future(() { | 420 return new Future(() { |
411 expect(div.nodes.length, 2); | 421 expect(div.nodes.length, 2); |
412 expect(div.lastChild.text, 'foo'); | 422 expect(div.lastChild.text, 'foo'); |
413 | 423 |
414 m['value'] = 'bar'; | 424 m['value'] = 'bar'; |
415 | 425 |
416 }).then(endOfMicrotask).then((_) { | 426 }).then(endOfMicrotask).then((_) { |
417 // unchanged. | 427 // unchanged. |
418 expect(div.lastChild.text, 'foo'); | 428 expect(div.lastChild.text, 'foo'); |
419 }); | 429 }); |
420 }); | 430 }); |
421 | 431 |
422 test('OneTime - compound text', () { | 432 test('OneTime - compound text', () { |
423 var div = createTestHtml( | 433 var div = createTestHtml( |
424 '<template bind>[[ foo ]] bar [[ baz ]]</template>'); | 434 '<template bind>[[ foo ]] bar [[ baz ]]</template>'); |
| 435 var template = div.firstChild; |
425 var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' }); | 436 var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' }); |
426 recursivelySetTemplateModel(div, m); | 437 templateBind(template).model = m; |
427 return new Future(() { | 438 return new Future(() { |
428 expect(div.nodes.length, 2); | 439 expect(div.nodes.length, 2); |
429 expect(div.lastChild.text, 'FOO bar BAZ'); | 440 expect(div.lastChild.text, 'FOO bar BAZ'); |
430 | 441 |
431 m['foo'] = 'FI'; | 442 m['foo'] = 'FI'; |
432 m['baz'] = 'BA'; | 443 m['baz'] = 'BA'; |
433 | 444 |
434 }).then(endOfMicrotask).then((_) { | 445 }).then(endOfMicrotask).then((_) { |
435 // unchanged. | 446 // unchanged. |
436 expect(div.nodes.length, 2); | 447 expect(div.nodes.length, 2); |
437 expect(div.lastChild.text, 'FOO bar BAZ'); | 448 expect(div.lastChild.text, 'FOO bar BAZ'); |
438 }); | 449 }); |
439 }); | 450 }); |
440 | 451 |
441 test('OneTime/Dynamic Mixed - compound text', () { | 452 test('OneTime/Dynamic Mixed - compound text', () { |
442 var div = createTestHtml( | 453 var div = createTestHtml( |
443 '<template bind>[[ foo ]] bar {{ baz }}</template>'); | 454 '<template bind>[[ foo ]] bar {{ baz }}</template>'); |
| 455 var template = div.firstChild; |
444 var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' }); | 456 var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' }); |
445 recursivelySetTemplateModel(div, m); | 457 templateBind(template).model = m; |
446 return new Future(() { | 458 return new Future(() { |
447 expect(div.nodes.length, 2); | 459 expect(div.nodes.length, 2); |
448 expect(div.lastChild.text, 'FOO bar BAZ'); | 460 expect(div.lastChild.text, 'FOO bar BAZ'); |
449 | 461 |
450 m['foo'] = 'FI'; | 462 m['foo'] = 'FI'; |
451 m['baz'] = 'BA'; | 463 m['baz'] = 'BA'; |
452 | 464 |
453 }).then(endOfMicrotask).then((_) { | 465 }).then(endOfMicrotask).then((_) { |
454 // unchanged [[ foo ]]. | 466 // unchanged [[ foo ]]. |
455 expect(div.nodes.length, 2); | 467 expect(div.nodes.length, 2); |
456 expect(div.lastChild.text, 'FOO bar BA'); | 468 expect(div.lastChild.text, 'FOO bar BA'); |
457 }); | 469 }); |
458 }); | 470 }); |
459 | 471 |
460 test('OneTime - simple attribute', () { | 472 test('OneTime - simple attribute', () { |
461 var div = createTestHtml( | 473 var div = createTestHtml( |
462 '<template bind><div foo="[[ value ]]"></div></template>'); | 474 '<template bind><div foo="[[ value ]]"></div></template>'); |
| 475 var template = div.firstChild; |
463 var m = toObservable({ 'value': 'foo' }); | 476 var m = toObservable({ 'value': 'foo' }); |
464 recursivelySetTemplateModel(div, m); | 477 templateBind(template).model = m; |
465 return new Future(() { | 478 return new Future(() { |
466 expect(div.nodes.length, 2); | 479 expect(div.nodes.length, 2); |
467 expect(div.lastChild.attributes['foo'], 'foo'); | 480 expect(div.lastChild.attributes['foo'], 'foo'); |
468 | 481 |
469 m['value'] = 'bar'; | 482 m['value'] = 'bar'; |
470 | 483 |
471 }).then(endOfMicrotask).then((_) { | 484 }).then(endOfMicrotask).then((_) { |
472 // unchanged. | 485 // unchanged. |
473 expect(div.nodes.length, 2); | 486 expect(div.nodes.length, 2); |
474 expect(div.lastChild.attributes['foo'], 'foo'); | 487 expect(div.lastChild.attributes['foo'], 'foo'); |
475 }); | 488 }); |
476 }); | 489 }); |
477 | 490 |
478 test('OneTime - compound attribute', () { | 491 test('OneTime - compound attribute', () { |
479 var div = createTestHtml( | 492 var div = createTestHtml( |
480 '<template bind>' | 493 '<template bind>' |
481 '<div foo="[[ value ]]:[[ otherValue ]]"></div>' | 494 '<div foo="[[ value ]]:[[ otherValue ]]"></div>' |
482 '</template>'); | 495 '</template>'); |
| 496 var template = div.firstChild; |
483 var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' }); | 497 var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' }); |
484 recursivelySetTemplateModel(div, m); | 498 templateBind(template).model = m; |
485 return new Future(() { | 499 return new Future(() { |
486 expect(div.nodes.length, 2); | 500 expect(div.nodes.length, 2); |
487 expect(div.lastChild.attributes['foo'], 'foo:bar'); | 501 expect(div.lastChild.attributes['foo'], 'foo:bar'); |
488 | 502 |
489 m['value'] = 'baz'; | 503 m['value'] = 'baz'; |
490 m['otherValue'] = 'bot'; | 504 m['otherValue'] = 'bot'; |
491 | 505 |
492 }).then(endOfMicrotask).then((_) { | 506 }).then(endOfMicrotask).then((_) { |
493 // unchanged. | 507 // unchanged. |
494 expect(div.lastChild.attributes['foo'], 'foo:bar'); | 508 expect(div.lastChild.attributes['foo'], 'foo:bar'); |
495 }); | 509 }); |
496 }); | 510 }); |
497 | 511 |
498 test('OneTime/Dynamic mixed - compound attribute', () { | 512 test('OneTime/Dynamic mixed - compound attribute', () { |
499 var div = createTestHtml( | 513 var div = createTestHtml( |
500 '<template bind>' | 514 '<template bind>' |
501 '<div foo="{{ value }}:[[ otherValue ]]"></div>' | 515 '<div foo="{{ value }}:[[ otherValue ]]"></div>' |
502 '</template>'); | 516 '</template>'); |
| 517 var template = div.firstChild; |
503 var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' }); | 518 var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' }); |
504 recursivelySetTemplateModel(div, m); | 519 templateBind(template).model = m; |
505 return new Future(() { | 520 return new Future(() { |
506 expect(div.nodes.length, 2); | 521 expect(div.nodes.length, 2); |
507 expect(div.lastChild.attributes['foo'], 'foo:bar'); | 522 expect(div.lastChild.attributes['foo'], 'foo:bar'); |
508 | 523 |
509 m['value'] = 'baz'; | 524 m['value'] = 'baz'; |
510 m['otherValue'] = 'bot'; | 525 m['otherValue'] = 'bot'; |
511 | 526 |
512 }).then(endOfMicrotask).then((_) { | 527 }).then(endOfMicrotask).then((_) { |
513 // unchanged [[ otherValue ]]. | 528 // unchanged [[ otherValue ]]. |
514 expect(div.lastChild.attributes['foo'], 'baz:bar'); | 529 expect(div.lastChild.attributes['foo'], 'baz:bar'); |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 expect(div.nodes[1].text, '1'); | 700 expect(div.nodes[1].text, '1'); |
686 | 701 |
687 templateBind(template).model = null; | 702 templateBind(template).model = null; |
688 }).then(endOfMicrotask).then((_) { | 703 }).then(endOfMicrotask).then((_) { |
689 expect(div.nodes.length, 1); | 704 expect(div.nodes.length, 1); |
690 }); | 705 }); |
691 }); | 706 }); |
692 | 707 |
693 test('TextTemplateWithNullStringBinding', () { | 708 test('TextTemplateWithNullStringBinding', () { |
694 var div = createTestHtml('<template bind={{}}>a{{b}}c</template>'); | 709 var div = createTestHtml('<template bind={{}}>a{{b}}c</template>'); |
| 710 var template = div.firstChild; |
695 var model = toObservable({'b': 'B'}); | 711 var model = toObservable({'b': 'B'}); |
696 recursivelySetTemplateModel(div, model); | 712 templateBind(template).model = model; |
697 | 713 |
698 return new Future(() { | 714 return new Future(() { |
699 expect(div.nodes.length, 2); | 715 expect(div.nodes.length, 2); |
700 expect(div.nodes.last.text, 'aBc'); | 716 expect(div.nodes.last.text, 'aBc'); |
701 | 717 |
702 model['b'] = 'b'; | 718 model['b'] = 'b'; |
703 }).then(endOfMicrotask).then((_) { | 719 }).then(endOfMicrotask).then((_) { |
704 expect(div.nodes.last.text, 'abc'); | 720 expect(div.nodes.last.text, 'abc'); |
705 | 721 |
706 model['b'] = null; | 722 model['b'] = null; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 | 756 |
741 model['data'] = null; | 757 model['data'] = null; |
742 }).then(endOfMicrotask).then((_) { | 758 }).then(endOfMicrotask).then((_) { |
743 expect(div.nodes.length, 1); | 759 expect(div.nodes.length, 1); |
744 }); | 760 }); |
745 }); | 761 }); |
746 | 762 |
747 test('TextTemplateWithBindingAndConditional', () { | 763 test('TextTemplateWithBindingAndConditional', () { |
748 var div = createTestHtml( | 764 var div = createTestHtml( |
749 '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>'); | 765 '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>'); |
| 766 var template = div.firstChild; |
750 var model = toObservable({'b': 'B', 'd': 1}); | 767 var model = toObservable({'b': 'B', 'd': 1}); |
751 recursivelySetTemplateModel(div, model); | 768 templateBind(template).model = model; |
752 | 769 |
753 return new Future(() { | 770 return new Future(() { |
754 expect(div.nodes.length, 2); | 771 expect(div.nodes.length, 2); |
755 expect(div.nodes.last.text, 'aBc'); | 772 expect(div.nodes.last.text, 'aBc'); |
756 | 773 |
757 model['b'] = 'b'; | 774 model['b'] = 'b'; |
758 }).then(endOfMicrotask).then((_) { | 775 }).then(endOfMicrotask).then((_) { |
759 expect(div.nodes.last.text, 'abc'); | 776 expect(div.nodes.last.text, 'abc'); |
760 | 777 |
761 // TODO(jmesserly): MDV set this to empty string and relies on JS conversi
on | 778 // TODO(jmesserly): MDV set this to empty string and relies on JS conversi
on |
762 // rules. Is that intended? | 779 // rules. Is that intended? |
763 // See https://github.com/Polymer/TemplateBinding/issues/59 | 780 // See https://github.com/Polymer/TemplateBinding/issues/59 |
764 model['d'] = null; | 781 model['d'] = null; |
765 }).then(endOfMicrotask).then((_) { | 782 }).then(endOfMicrotask).then((_) { |
766 expect(div.nodes.length, 1); | 783 expect(div.nodes.length, 1); |
767 | 784 |
768 model['d'] = 'here'; | 785 model['d'] = 'here'; |
769 model['b'] = 'd'; | 786 model['b'] = 'd'; |
770 | 787 |
771 }).then(endOfMicrotask).then((_) { | 788 }).then(endOfMicrotask).then((_) { |
772 expect(div.nodes.length, 2); | 789 expect(div.nodes.length, 2); |
773 expect(div.nodes.last.text, 'adc'); | 790 expect(div.nodes.last.text, 'adc'); |
774 }); | 791 }); |
775 }); | 792 }); |
776 | 793 |
777 test('TemplateWithTextBinding2', () { | 794 test('TemplateWithTextBinding2', () { |
778 var div = createTestHtml( | 795 var div = createTestHtml( |
779 '<template bind="{{ b }}">a{{value}}c</template>'); | 796 '<template bind="{{ b }}">a{{value}}c</template>'); |
780 expect(div.nodes.length, 1); | 797 expect(div.nodes.length, 1); |
| 798 var template = div.firstChild; |
781 var model = toObservable({'b': {'value': 'B'}}); | 799 var model = toObservable({'b': {'value': 'B'}}); |
782 recursivelySetTemplateModel(div, model); | 800 templateBind(template).model = model; |
783 | 801 |
784 return new Future(() { | 802 return new Future(() { |
785 expect(div.nodes.length, 2); | 803 expect(div.nodes.length, 2); |
786 expect(div.nodes.last.text, 'aBc'); | 804 expect(div.nodes.last.text, 'aBc'); |
787 | 805 |
788 model['b'] = toObservable({'value': 'b'}); | 806 model['b'] = toObservable({'value': 'b'}); |
789 }).then(endOfMicrotask).then((_) { | 807 }).then(endOfMicrotask).then((_) { |
790 expect(div.nodes.last.text, 'abc'); | 808 expect(div.nodes.last.text, 'abc'); |
791 }); | 809 }); |
792 }); | 810 }); |
793 | 811 |
794 test('TemplateWithAttributeBinding', () { | 812 test('TemplateWithAttributeBinding', () { |
795 var div = createTestHtml( | 813 var div = createTestHtml( |
796 '<template bind="{{}}">' | 814 '<template bind="{{}}">' |
797 '<div foo="a{{b}}c"></div>' | 815 '<div foo="a{{b}}c"></div>' |
798 '</template>'); | 816 '</template>'); |
| 817 var template = div.firstChild; |
799 var model = toObservable({'b': 'B'}); | 818 var model = toObservable({'b': 'B'}); |
800 recursivelySetTemplateModel(div, model); | 819 templateBind(template).model = model; |
801 | 820 |
802 return new Future(() { | 821 return new Future(() { |
803 expect(div.nodes.length, 2); | 822 expect(div.nodes.length, 2); |
804 expect(div.nodes.last.attributes['foo'], 'aBc'); | 823 expect(div.nodes.last.attributes['foo'], 'aBc'); |
805 | 824 |
806 model['b'] = 'b'; | 825 model['b'] = 'b'; |
807 }).then(endOfMicrotask).then((_) { | 826 }).then(endOfMicrotask).then((_) { |
808 expect(div.nodes.last.attributes['foo'], 'abc'); | 827 expect(div.nodes.last.attributes['foo'], 'abc'); |
809 | 828 |
810 model['b'] = 'X'; | 829 model['b'] = 'X'; |
811 }).then(endOfMicrotask).then((_) { | 830 }).then(endOfMicrotask).then((_) { |
812 expect(div.nodes.last.attributes['foo'], 'aXc'); | 831 expect(div.nodes.last.attributes['foo'], 'aXc'); |
813 }); | 832 }); |
814 }); | 833 }); |
815 | 834 |
816 test('TemplateWithConditionalBinding', () { | 835 test('TemplateWithConditionalBinding', () { |
817 var div = createTestHtml( | 836 var div = createTestHtml( |
818 '<template bind="{{}}">' | 837 '<template bind="{{}}">' |
819 '<div foo?="{{b}}"></div>' | 838 '<div foo?="{{b}}"></div>' |
820 '</template>'); | 839 '</template>'); |
| 840 var template = div.firstChild; |
821 var model = toObservable({'b': 'b'}); | 841 var model = toObservable({'b': 'b'}); |
822 recursivelySetTemplateModel(div, model); | 842 templateBind(template).model = model; |
823 | 843 |
824 return new Future(() { | 844 return new Future(() { |
825 expect(div.nodes.length, 2); | 845 expect(div.nodes.length, 2); |
826 expect(div.nodes.last.attributes['foo'], ''); | 846 expect(div.nodes.last.attributes['foo'], ''); |
827 expect(div.nodes.last.attributes, isNot(contains('foo?'))); | 847 expect(div.nodes.last.attributes, isNot(contains('foo?'))); |
828 | 848 |
829 model['b'] = null; | 849 model['b'] = null; |
830 }).then(endOfMicrotask).then((_) { | 850 }).then(endOfMicrotask).then((_) { |
831 expect(div.nodes.last.attributes, isNot(contains('foo'))); | 851 expect(div.nodes.last.attributes, isNot(contains('foo'))); |
832 }); | 852 }); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 test('Repeat - Reuse Instances', () { | 928 test('Repeat - Reuse Instances', () { |
909 var div = createTestHtml('<template repeat>{{ val }}</template>'); | 929 var div = createTestHtml('<template repeat>{{ val }}</template>'); |
910 | 930 |
911 var model = toObservable([ | 931 var model = toObservable([ |
912 {'val': 10}, | 932 {'val': 10}, |
913 {'val': 5}, | 933 {'val': 5}, |
914 {'val': 2}, | 934 {'val': 2}, |
915 {'val': 8}, | 935 {'val': 8}, |
916 {'val': 1} | 936 {'val': 1} |
917 ]); | 937 ]); |
918 recursivelySetTemplateModel(div, model); | |
919 var template = div.firstChild; | 938 var template = div.firstChild; |
| 939 templateBind(template).model = model; |
920 | 940 |
921 return new Future(() { | 941 return new Future(() { |
922 expect(div.nodes.length, 6); | 942 expect(div.nodes.length, 6); |
923 | 943 |
924 addExpandos(template.nextNode); | 944 addExpandos(template.nextNode); |
925 checkExpandos(template.nextNode); | 945 checkExpandos(template.nextNode); |
926 | 946 |
927 model.sort((a, b) => a['val'] - b['val']); | 947 model.sort((a, b) => a['val'] - b['val']); |
928 }).then(endOfMicrotask).then((_) { | 948 }).then(endOfMicrotask).then((_) { |
929 checkExpandos(template.nextNode); | 949 checkExpandos(template.nextNode); |
930 | 950 |
931 model = toObservable(model.reversed); | 951 model = toObservable(model.reversed); |
932 recursivelySetTemplateModel(div, model); | 952 templateBind(template).model = model; |
933 }).then(endOfMicrotask).then((_) { | 953 }).then(endOfMicrotask).then((_) { |
934 checkExpandos(template.nextNode); | 954 checkExpandos(template.nextNode); |
935 | 955 |
936 for (var item in model) { | 956 for (var item in model) { |
937 item['val'] += 1; | 957 item['val'] += 1; |
938 } | 958 } |
939 | 959 |
940 }).then(endOfMicrotask).then((_) { | 960 }).then(endOfMicrotask).then((_) { |
941 expect(div.nodes[1].text, "11"); | 961 expect(div.nodes[1].text, "11"); |
942 expect(div.nodes[2].text, "9"); | 962 expect(div.nodes[2].text, "9"); |
943 expect(div.nodes[3].text, "6"); | 963 expect(div.nodes[3].text, "6"); |
944 expect(div.nodes[4].text, "3"); | 964 expect(div.nodes[4].text, "3"); |
945 expect(div.nodes[5].text, "2"); | 965 expect(div.nodes[5].text, "2"); |
946 }); | 966 }); |
947 }); | 967 }); |
948 | 968 |
949 test('Bind - Reuse Instance', () { | 969 test('Bind - Reuse Instance', () { |
950 var div = createTestHtml( | 970 var div = createTestHtml( |
951 '<template bind="{{ foo }}">{{ bar }}</template>'); | 971 '<template bind="{{ foo }}">{{ bar }}</template>'); |
952 | 972 |
| 973 var template = div.firstChild; |
953 var model = toObservable({ 'foo': { 'bar': 5 }}); | 974 var model = toObservable({ 'foo': { 'bar': 5 }}); |
954 recursivelySetTemplateModel(div, model); | 975 templateBind(template).model = model; |
955 var template = div.firstChild; | |
956 | 976 |
957 return new Future(() { | 977 return new Future(() { |
958 expect(div.nodes.length, 2); | 978 expect(div.nodes.length, 2); |
959 | 979 |
960 addExpandos(template.nextNode); | 980 addExpandos(template.nextNode); |
961 checkExpandos(template.nextNode); | 981 checkExpandos(template.nextNode); |
962 | 982 |
963 model = toObservable({'foo': model['foo']}); | 983 model = toObservable({'foo': model['foo']}); |
964 recursivelySetTemplateModel(div, model); | 984 templateBind(template).model = model; |
965 }).then(endOfMicrotask).then((_) { | 985 }).then(endOfMicrotask).then((_) { |
966 checkExpandos(template.nextNode); | 986 checkExpandos(template.nextNode); |
967 }); | 987 }); |
968 }); | 988 }); |
969 | 989 |
970 test('Repeat-Empty', () { | 990 test('Repeat-Empty', () { |
971 var div = createTestHtml( | 991 var div = createTestHtml( |
972 '<template repeat>text</template>'); | 992 '<template repeat>text</template>'); |
973 | 993 |
| 994 var template = div.firstChild; |
974 var model = toObservable([0, 1, 2]); | 995 var model = toObservable([0, 1, 2]); |
975 recursivelySetTemplateModel(div, model); | 996 templateBind(template).model = model; |
976 | 997 |
977 return new Future(() { | 998 return new Future(() { |
978 expect(div.nodes.length, 4); | 999 expect(div.nodes.length, 4); |
979 | 1000 |
980 model.length = 1; | 1001 model.length = 1; |
981 }).then(endOfMicrotask).then((_) { | 1002 }).then(endOfMicrotask).then((_) { |
982 expect(div.nodes.length, 2); | 1003 expect(div.nodes.length, 2); |
983 | 1004 |
984 model.addAll(toObservable([3, 4])); | 1005 model.addAll(toObservable([3, 4])); |
985 }).then(endOfMicrotask).then((_) { | 1006 }).then(endOfMicrotask).then((_) { |
986 expect(div.nodes.length, 4); | 1007 expect(div.nodes.length, 4); |
987 | 1008 |
988 model.removeRange(1, 2); | 1009 model.removeRange(1, 2); |
989 }).then(endOfMicrotask).then((_) { | 1010 }).then(endOfMicrotask).then((_) { |
990 expect(div.nodes.length, 3); | 1011 expect(div.nodes.length, 3); |
991 }); | 1012 }); |
992 }); | 1013 }); |
993 | 1014 |
994 test('Removal from iteration needs to unbind', () { | 1015 test('Removal from iteration needs to unbind', () { |
995 var div = createTestHtml( | 1016 var div = createTestHtml( |
996 '<template repeat="{{}}"><a>{{v}}</a></template>'); | 1017 '<template repeat="{{}}"><a>{{v}}</a></template>'); |
| 1018 var template = div.firstChild; |
997 var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3}, | 1019 var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3}, |
998 {'v': 4}]); | 1020 {'v': 4}]); |
999 recursivelySetTemplateModel(div, model); | 1021 templateBind(template).model = model; |
1000 | 1022 |
1001 var nodes, vs; | 1023 var nodes, vs; |
1002 return new Future(() { | 1024 return new Future(() { |
1003 | 1025 |
1004 nodes = div.nodes.skip(1).toList(); | 1026 nodes = div.nodes.skip(1).toList(); |
1005 vs = model.toList(); | 1027 vs = model.toList(); |
1006 | 1028 |
1007 for (var i = 0; i < 5; i++) { | 1029 for (var i = 0; i < 5; i++) { |
1008 expect(nodes[i].text, '$i'); | 1030 expect(nodes[i].text, '$i'); |
1009 } | 1031 } |
1010 | 1032 |
1011 model.length = 3; | 1033 model.length = 3; |
1012 }).then(endOfMicrotask).then((_) { | 1034 }).then(endOfMicrotask).then((_) { |
1013 for (var i = 0; i < 5; i++) { | 1035 for (var i = 0; i < 5; i++) { |
1014 expect(nodes[i].text, '$i'); | 1036 expect(nodes[i].text, '$i'); |
1015 } | 1037 } |
1016 | 1038 |
1017 vs[3]['v'] = 33; | 1039 vs[3]['v'] = 33; |
1018 vs[4]['v'] = 44; | 1040 vs[4]['v'] = 44; |
1019 }).then(endOfMicrotask).then((_) { | 1041 }).then(endOfMicrotask).then((_) { |
1020 for (var i = 0; i < 5; i++) { | 1042 for (var i = 0; i < 5; i++) { |
1021 expect(nodes[i].text, '$i'); | 1043 expect(nodes[i].text, '$i'); |
1022 } | 1044 } |
1023 }); | 1045 }); |
1024 }); | 1046 }); |
1025 | 1047 |
| 1048 test('Template.clear', () { |
| 1049 var div = createTestHtml( |
| 1050 '<template repeat>{{}}</template>'); |
| 1051 var template = div.firstChild; |
| 1052 templateBind(template).model = [0, 1, 2]; |
| 1053 |
| 1054 return new Future(() { |
| 1055 expect(div.nodes.length, 4); |
| 1056 expect(div.nodes[1].text, '0'); |
| 1057 expect(div.nodes[2].text, '1'); |
| 1058 expect(div.nodes[3].text, '2'); |
| 1059 |
| 1060 // clear() synchronously removes instances and clears the model. |
| 1061 templateBind(div.firstChild).clear(); |
| 1062 expect(div.nodes.length, 1); |
| 1063 expect(templateBind(template).model, null); |
| 1064 |
| 1065 // test that template still works if new model assigned |
| 1066 templateBind(template).model = [3, 4]; |
| 1067 |
| 1068 }).then(endOfMicrotask).then((_) { |
| 1069 expect(div.nodes.length, 3); |
| 1070 expect(div.nodes[1].text, '3'); |
| 1071 expect(div.nodes[2].text, '4'); |
| 1072 }); |
| 1073 }); |
| 1074 |
1026 test('DOM Stability on Iteration', () { | 1075 test('DOM Stability on Iteration', () { |
1027 var div = createTestHtml( | 1076 var div = createTestHtml( |
1028 '<template repeat="{{}}">{{}}</template>'); | 1077 '<template repeat="{{}}">{{}}</template>'); |
| 1078 var template = div.firstChild; |
1029 var model = toObservable([1, 2, 3, 4, 5]); | 1079 var model = toObservable([1, 2, 3, 4, 5]); |
1030 recursivelySetTemplateModel(div, model); | 1080 templateBind(template).model = model; |
1031 | 1081 |
1032 var nodes; | 1082 var nodes; |
1033 return new Future(() { | 1083 return new Future(() { |
1034 // Note: the node at index 0 is the <template>. | 1084 // Note: the node at index 0 is the <template>. |
1035 nodes = div.nodes.toList(); | 1085 nodes = div.nodes.toList(); |
1036 expect(nodes.length, 6, reason: 'list has 5 items'); | 1086 expect(nodes.length, 6, reason: 'list has 5 items'); |
1037 | 1087 |
1038 model.removeAt(0); | 1088 model.removeAt(0); |
1039 model.removeLast(); | 1089 model.removeLast(); |
1040 | 1090 |
(...skipping 30 matching lines...) Expand all Loading... |
1071 expect(identical(div.nodes[5], nodes[4]), true); | 1121 expect(identical(div.nodes[5], nodes[4]), true); |
1072 expect(identical(div.nodes[6], nodes[5]), true); | 1122 expect(identical(div.nodes[6], nodes[5]), true); |
1073 }); | 1123 }); |
1074 }); | 1124 }); |
1075 | 1125 |
1076 test('Repeat2', () { | 1126 test('Repeat2', () { |
1077 var div = createTestHtml( | 1127 var div = createTestHtml( |
1078 '<template repeat="{{}}">{{value}}</template>'); | 1128 '<template repeat="{{}}">{{value}}</template>'); |
1079 expect(div.nodes.length, 1); | 1129 expect(div.nodes.length, 1); |
1080 | 1130 |
| 1131 var template = div.firstChild; |
1081 var model = toObservable([ | 1132 var model = toObservable([ |
1082 {'value': 0}, | 1133 {'value': 0}, |
1083 {'value': 1}, | 1134 {'value': 1}, |
1084 {'value': 2} | 1135 {'value': 2} |
1085 ]); | 1136 ]); |
1086 recursivelySetTemplateModel(div, model); | 1137 templateBind(template).model = model; |
1087 | 1138 |
1088 return new Future(() { | 1139 return new Future(() { |
1089 expect(div.nodes.length, 4); | 1140 expect(div.nodes.length, 4); |
1090 expect(div.nodes[1].text, '0'); | 1141 expect(div.nodes[1].text, '0'); |
1091 expect(div.nodes[2].text, '1'); | 1142 expect(div.nodes[2].text, '1'); |
1092 expect(div.nodes[3].text, '2'); | 1143 expect(div.nodes[3].text, '2'); |
1093 | 1144 |
1094 model[1]['value'] = 'One'; | 1145 model[1]['value'] = 'One'; |
1095 }).then(endOfMicrotask).then((_) { | 1146 }).then(endOfMicrotask).then((_) { |
1096 expect(div.nodes.length, 4); | 1147 expect(div.nodes.length, 4); |
1097 expect(div.nodes[1].text, '0'); | 1148 expect(div.nodes[1].text, '0'); |
1098 expect(div.nodes[2].text, 'One'); | 1149 expect(div.nodes[2].text, 'One'); |
1099 expect(div.nodes[3].text, '2'); | 1150 expect(div.nodes[3].text, '2'); |
1100 | 1151 |
1101 model.replaceRange(0, 1, toObservable([{'value': 'Zero'}])); | 1152 model.replaceRange(0, 1, toObservable([{'value': 'Zero'}])); |
1102 }).then(endOfMicrotask).then((_) { | 1153 }).then(endOfMicrotask).then((_) { |
1103 expect(div.nodes.length, 4); | 1154 expect(div.nodes.length, 4); |
1104 expect(div.nodes[1].text, 'Zero'); | 1155 expect(div.nodes[1].text, 'Zero'); |
1105 expect(div.nodes[2].text, 'One'); | 1156 expect(div.nodes[2].text, 'One'); |
1106 expect(div.nodes[3].text, '2'); | 1157 expect(div.nodes[3].text, '2'); |
1107 }); | 1158 }); |
1108 }); | 1159 }); |
1109 | 1160 |
1110 test('TemplateWithInputValue', () { | 1161 test('TemplateWithInputValue', () { |
1111 var div = createTestHtml( | 1162 var div = createTestHtml( |
1112 '<template bind="{{}}">' | 1163 '<template bind="{{}}">' |
1113 '<input value="{{x}}">' | 1164 '<input value="{{x}}">' |
1114 '</template>'); | 1165 '</template>'); |
| 1166 var template = div.firstChild; |
1115 var model = toObservable({'x': 'hi'}); | 1167 var model = toObservable({'x': 'hi'}); |
1116 recursivelySetTemplateModel(div, model); | 1168 templateBind(template).model = model; |
1117 | 1169 |
1118 return new Future(() { | 1170 return new Future(() { |
1119 expect(div.nodes.length, 2); | 1171 expect(div.nodes.length, 2); |
1120 expect(div.nodes.last.value, 'hi'); | 1172 expect(div.nodes.last.value, 'hi'); |
1121 | 1173 |
1122 model['x'] = 'bye'; | 1174 model['x'] = 'bye'; |
1123 expect(div.nodes.last.value, 'hi'); | 1175 expect(div.nodes.last.value, 'hi'); |
1124 }).then(endOfMicrotask).then((_) { | 1176 }).then(endOfMicrotask).then((_) { |
1125 expect(div.nodes.last.value, 'bye'); | 1177 expect(div.nodes.last.value, 'bye'); |
1126 | 1178 |
1127 div.nodes.last.value = 'hello'; | 1179 div.nodes.last.value = 'hello'; |
1128 dispatchEvent('input', div.nodes.last); | 1180 dispatchEvent('input', div.nodes.last); |
1129 expect(model['x'], 'hello'); | 1181 expect(model['x'], 'hello'); |
1130 }).then(endOfMicrotask).then((_) { | 1182 }).then(endOfMicrotask).then((_) { |
1131 expect(div.nodes.last.value, 'hello'); | 1183 expect(div.nodes.last.value, 'hello'); |
1132 }); | 1184 }); |
1133 }); | 1185 }); |
1134 | 1186 |
1135 ////////////////////////////////////////////////////////////////////////////// | 1187 ////////////////////////////////////////////////////////////////////////////// |
1136 | 1188 |
1137 test('Decorated', () { | 1189 test('Decorated', () { |
1138 var div = createTestHtml( | 1190 var div = createTestHtml( |
1139 '<template bind="{{ XX }}" id="t1">' | 1191 '<template bind="{{ XX }}" id="t1">' |
1140 '<p>Crew member: {{name}}, Job title: {{title}}</p>' | 1192 '<p>Crew member: {{name}}, Job title: {{title}}</p>' |
1141 '</template>' | 1193 '</template>' |
1142 '<template bind="{{ XY }}" id="t2" ref="t1"></template>'); | 1194 '<template bind="{{ XY }}" id="t2" ref="t1"></template>'); |
1143 | 1195 |
| 1196 var t1 = document.getElementById('t1'); |
| 1197 var t2 = document.getElementById('t2'); |
1144 var model = toObservable({ | 1198 var model = toObservable({ |
1145 'XX': {'name': 'Leela', 'title': 'Captain'}, | 1199 'XX': {'name': 'Leela', 'title': 'Captain'}, |
1146 'XY': {'name': 'Fry', 'title': 'Delivery boy'}, | 1200 'XY': {'name': 'Fry', 'title': 'Delivery boy'}, |
1147 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'} | 1201 'XZ': {'name': 'Zoidberg', 'title': 'Doctor'} |
1148 }); | 1202 }); |
1149 recursivelySetTemplateModel(div, model); | 1203 templateBind(t1).model = model; |
| 1204 templateBind(t2).model = model; |
1150 | 1205 |
1151 return new Future(() { | 1206 return new Future(() { |
1152 var t1 = document.getElementById('t1'); | |
1153 var instance = t1.nextElementSibling; | 1207 var instance = t1.nextElementSibling; |
1154 expect(instance.text, 'Crew member: Leela, Job title: Captain'); | 1208 expect(instance.text, 'Crew member: Leela, Job title: Captain'); |
1155 | 1209 |
1156 var t2 = document.getElementById('t2'); | |
1157 instance = t2.nextElementSibling; | 1210 instance = t2.nextElementSibling; |
1158 expect(instance.text, 'Crew member: Fry, Job title: Delivery boy'); | 1211 expect(instance.text, 'Crew member: Fry, Job title: Delivery boy'); |
1159 | 1212 |
1160 expect(div.children.length, 4); | 1213 expect(div.children.length, 4); |
1161 expect(div.nodes.length, 4); | 1214 expect(div.nodes.length, 4); |
1162 | 1215 |
1163 expect(div.nodes[1].tagName, 'P'); | 1216 expect(div.nodes[1].tagName, 'P'); |
1164 expect(div.nodes[3].tagName, 'P'); | 1217 expect(div.nodes[3].tagName, 'P'); |
1165 }); | 1218 }); |
1166 }); | 1219 }); |
1167 | 1220 |
1168 test('DefaultStyles', () { | 1221 test('DefaultStyles', () { |
1169 var t = new Element.tag('template'); | 1222 var t = new Element.tag('template'); |
1170 TemplateBindExtension.decorate(t); | 1223 TemplateBindExtension.decorate(t); |
1171 | 1224 |
1172 document.body.append(t); | 1225 document.body.append(t); |
1173 expect(t.getComputedStyle().display, 'none'); | 1226 expect(t.getComputedStyle().display, 'none'); |
1174 | 1227 |
1175 t.remove(); | 1228 t.remove(); |
1176 }); | 1229 }); |
1177 | 1230 |
1178 | 1231 |
1179 test('Bind', () { | 1232 test('Bind', () { |
1180 var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>'); | 1233 var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>'); |
| 1234 var template = div.firstChild; |
1181 var model = toObservable({'name': 'Leela'}); | 1235 var model = toObservable({'name': 'Leela'}); |
1182 recursivelySetTemplateModel(div, model); | 1236 templateBind(template).model = model; |
1183 | 1237 |
1184 return new Future(() => expect(div.nodes[1].text, 'Hi Leela')); | 1238 return new Future(() => expect(div.nodes[1].text, 'Hi Leela')); |
1185 }); | 1239 }); |
1186 | 1240 |
1187 test('BindPlaceHolderHasNewLine', () { | 1241 test('BindPlaceHolderHasNewLine', () { |
1188 var div = createTestHtml( | 1242 var div = createTestHtml( |
1189 '<template bind="{{}}">Hi {{\nname\n}}</template>'); | 1243 '<template bind="{{}}">Hi {{\nname\n}}</template>'); |
| 1244 var template = div.firstChild; |
1190 var model = toObservable({'name': 'Leela'}); | 1245 var model = toObservable({'name': 'Leela'}); |
1191 recursivelySetTemplateModel(div, model); | 1246 templateBind(template).model = model; |
1192 | 1247 |
1193 return new Future(() => expect(div.nodes[1].text, 'Hi Leela')); | 1248 return new Future(() => expect(div.nodes[1].text, 'Hi Leela')); |
1194 }); | 1249 }); |
1195 | 1250 |
1196 test('BindWithRef', () { | 1251 test('BindWithRef', () { |
1197 var id = 't${new math.Random().nextInt(100)}'; | 1252 var id = 't${new math.Random().nextInt(100)}'; |
1198 var div = createTestHtml( | 1253 var div = createTestHtml( |
1199 '<template id="$id">' | 1254 '<template id="$id">' |
1200 'Hi {{ name }}' | 1255 'Hi {{ name }}' |
1201 '</template>' | 1256 '</template>' |
1202 '<template ref="$id" bind="{{}}"></template>'); | 1257 '<template ref="$id" bind="{{}}"></template>'); |
1203 | 1258 |
1204 var t1 = div.nodes.first; | 1259 var t1 = div.nodes.first; |
1205 var t2 = div.nodes[1]; | 1260 var t2 = div.nodes[1]; |
1206 | 1261 |
1207 expect(templateBind(t2).ref, t1); | |
1208 | |
1209 var model = toObservable({'name': 'Fry'}); | 1262 var model = toObservable({'name': 'Fry'}); |
1210 recursivelySetTemplateModel(div, model); | 1263 templateBind(t1).model = model; |
| 1264 templateBind(t2).model = model; |
1211 | 1265 |
1212 return new Future(() => expect(t2.nextNode.text, 'Hi Fry')); | 1266 return new Future(() => expect(t2.nextNode.text, 'Hi Fry')); |
1213 }); | 1267 }); |
1214 | 1268 |
| 1269 test('Ref at multiple', () { |
| 1270 // Note: this test is asserting that template "ref"erences can be located |
| 1271 // at various points. In particular: |
| 1272 // -in the document (at large) (e.g. ref=doc) |
| 1273 // -within template content referenced from sub-content |
| 1274 // -both before and after the reference |
| 1275 // The following asserts ensure that all referenced templates content is |
| 1276 // found. |
| 1277 var div = createTestHtml( |
| 1278 '<template bind>' |
| 1279 '<template bind ref=doc></template>' |
| 1280 '<template id=elRoot>EL_ROOT</template>' |
| 1281 '<template bind>' |
| 1282 '<template bind ref=elRoot></template>' |
| 1283 '<template bind>' |
| 1284 '<template bind ref=subA></template>' |
| 1285 '<template id=subB>SUB_B</template>' |
| 1286 '<template bind>' |
| 1287 '<template bind ref=subB></template>' |
| 1288 '</template>' |
| 1289 '</template>' |
| 1290 '<template id=subA>SUB_A</template>' |
| 1291 '</template>' |
| 1292 '</template>' |
| 1293 '<template id=doc>DOC</template>'); |
| 1294 var t = div.firstChild; |
| 1295 var fragment = templateBind(t).createInstance({}); |
| 1296 expect(fragment.nodes.length, 14); |
| 1297 expect(fragment.nodes[1].text, 'DOC'); |
| 1298 expect(fragment.nodes[5].text, 'EL_ROOT'); |
| 1299 expect(fragment.nodes[8].text, 'SUB_A'); |
| 1300 expect(fragment.nodes[12].text, 'SUB_B'); |
| 1301 div.append(fragment); |
| 1302 }); |
1215 | 1303 |
1216 test('Update Ref', () { | 1304 test('Update Ref', () { |
| 1305 // Updating ref by observing the attribute is dependent on MutationObserver |
1217 var div = createTestHtml( | 1306 var div = createTestHtml( |
1218 '<template id=A>Hi, {{}}</template>' | 1307 '<template id=A>Hi, {{}}</template>' |
1219 '<template id=B>Hola, {{}}</template>' | 1308 '<template id=B>Hola, {{}}</template>' |
1220 '<template ref=A repeat></template>'); | 1309 '<template ref=A repeat></template>'); |
1221 | 1310 |
| 1311 var template = div.nodes[2]; |
1222 var model = new ObservableList.from(['Fry']); | 1312 var model = new ObservableList.from(['Fry']); |
1223 recursivelySetTemplateModel(div, model); | 1313 templateBind(template).model = model; |
1224 | 1314 |
1225 return new Future(() { | 1315 return new Future(() { |
1226 expect(div.nodes.length, 4); | 1316 expect(div.nodes.length, 4); |
1227 expect('Hi, Fry', div.nodes[3].text); | 1317 expect('Hi, Fry', div.nodes[3].text); |
1228 | 1318 |
1229 div.nodes[2].attributes['ref'] = 'B'; | 1319 div.nodes[2].attributes['ref'] = 'B'; |
1230 model.add('Leela'); | 1320 model.add('Leela'); |
1231 | 1321 |
| 1322 }).then(nextMicrotask).then((x) { |
| 1323 expect(div.nodes.length, 5); |
| 1324 |
| 1325 expect('Hola, Fry', div.nodes[3].text); |
| 1326 expect('Hola, Leela', div.nodes[4].text); |
| 1327 }); |
| 1328 }); |
| 1329 |
| 1330 test('Bound Ref', () { |
| 1331 var div = createTestHtml( |
| 1332 '<template id=A>Hi, {{}}</template>' |
| 1333 '<template id=B>Hola, {{}}</template>' |
| 1334 '<template ref="{{ ref }}" repeat="{{ people }}"></template>'); |
| 1335 |
| 1336 var template = div.nodes[2]; |
| 1337 var model = toObservable({'ref': 'A', 'people': ['Fry']}); |
| 1338 templateBind(template).model = model; |
| 1339 |
| 1340 return new Future(() { |
| 1341 expect(div.nodes.length, 4); |
| 1342 expect('Hi, Fry', div.nodes[3].text); |
| 1343 |
| 1344 model['ref'] = 'B'; |
| 1345 model['people'].add('Leela'); |
| 1346 |
1232 }).then(endOfMicrotask).then((x) { | 1347 }).then(endOfMicrotask).then((x) { |
1233 expect(div.nodes.length, 5); | 1348 expect(div.nodes.length, 5); |
1234 | 1349 |
1235 expect('Hi, Fry', div.nodes[3].text); | 1350 expect('Hola, Fry', div.nodes[3].text); |
1236 expect('Hola, Leela', div.nodes[4].text); | 1351 expect('Hola, Leela', div.nodes[4].text); |
1237 }); | 1352 }); |
1238 }); | 1353 }); |
1239 | 1354 |
1240 test('BindWithDynamicRef', () { | 1355 test('BindWithDynamicRef', () { |
1241 var id = 't${new math.Random().nextInt(100)}'; | 1356 var id = 't${new math.Random().nextInt(100)}'; |
1242 var div = createTestHtml( | 1357 var div = createTestHtml( |
1243 '<template id="$id">' | 1358 '<template id="$id">' |
1244 'Hi {{ name }}' | 1359 'Hi {{ name }}' |
1245 '</template>' | 1360 '</template>' |
1246 '<template ref="{{ id }}" bind="{{}}"></template>'); | 1361 '<template ref="{{ id }}" bind="{{}}"></template>'); |
1247 | 1362 |
1248 var t1 = div.firstChild; | 1363 var t1 = div.firstChild; |
1249 var t2 = div.nodes[1]; | 1364 var t2 = div.nodes[1]; |
1250 var model = toObservable({'name': 'Fry', 'id': id }); | 1365 var model = toObservable({'name': 'Fry', 'id': id }); |
1251 recursivelySetTemplateModel(div, model); | 1366 templateBind(t1).model = model; |
| 1367 templateBind(t2).model = model; |
1252 | 1368 |
1253 return new Future(() => expect(t2.nextNode.text, 'Hi Fry')); | 1369 return new Future(() => expect(t2.nextNode.text, 'Hi Fry')); |
1254 }); | 1370 }); |
1255 | 1371 |
1256 assertNodesAre(div, [arguments]) { | 1372 assertNodesAre(div, [arguments]) { |
1257 var expectedLength = arguments.length; | 1373 var expectedLength = arguments.length; |
1258 expect(div.nodes.length, expectedLength + 1); | 1374 expect(div.nodes.length, expectedLength + 1); |
1259 | 1375 |
1260 for (var i = 0; i < arguments.length; i++) { | 1376 for (var i = 0; i < arguments.length; i++) { |
1261 var targetNode = div.nodes[i + 1]; | 1377 var targetNode = div.nodes[i + 1]; |
1262 expect(targetNode.text, arguments[i]); | 1378 expect(targetNode.text, arguments[i]); |
1263 } | 1379 } |
1264 } | 1380 } |
1265 | 1381 |
1266 test('Repeat3', () { | 1382 test('Repeat3', () { |
1267 var div = createTestHtml( | 1383 var div = createTestHtml( |
1268 '<template repeat="{{ contacts }}">Hi {{ name }}</template>'); | 1384 '<template repeat="{{ contacts }}">Hi {{ name }}</template>'); |
1269 var t = div.nodes.first; | 1385 var t = div.nodes.first; |
1270 | 1386 |
1271 var m = toObservable({ | 1387 var m = toObservable({ |
1272 'contacts': [ | 1388 'contacts': [ |
1273 {'name': 'Raf'}, | 1389 {'name': 'Raf'}, |
1274 {'name': 'Arv'}, | 1390 {'name': 'Arv'}, |
1275 {'name': 'Neal'} | 1391 {'name': 'Neal'} |
1276 ] | 1392 ] |
1277 }); | 1393 }); |
1278 | 1394 |
1279 recursivelySetTemplateModel(div, m); | 1395 templateBind(t).model = m; |
1280 return new Future(() { | 1396 return new Future(() { |
1281 | 1397 |
1282 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); | 1398 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); |
1283 | 1399 |
1284 m['contacts'].add(toObservable({'name': 'Alex'})); | 1400 m['contacts'].add(toObservable({'name': 'Alex'})); |
1285 }).then(endOfMicrotask).then((_) { | 1401 }).then(endOfMicrotask).then((_) { |
1286 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); | 1402 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); |
1287 | 1403 |
1288 m['contacts'].replaceRange(0, 2, | 1404 m['contacts'].replaceRange(0, 2, |
1289 toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])); | 1405 toObservable([{'name': 'Rafael'}, {'name': 'Erik'}])); |
(...skipping 23 matching lines...) Expand all Loading... |
1313 }).then(endOfMicrotask).then((_) { | 1429 }).then(endOfMicrotask).then((_) { |
1314 assertNodesAre(div, []); | 1430 assertNodesAre(div, []); |
1315 }); | 1431 }); |
1316 }); | 1432 }); |
1317 | 1433 |
1318 test('RepeatModelSet', () { | 1434 test('RepeatModelSet', () { |
1319 var div = createTestHtml( | 1435 var div = createTestHtml( |
1320 '<template repeat="{{ contacts }}">' | 1436 '<template repeat="{{ contacts }}">' |
1321 'Hi {{ name }}' | 1437 'Hi {{ name }}' |
1322 '</template>'); | 1438 '</template>'); |
| 1439 var template = div.firstChild; |
1323 var m = toObservable({ | 1440 var m = toObservable({ |
1324 'contacts': [ | 1441 'contacts': [ |
1325 {'name': 'Raf'}, | 1442 {'name': 'Raf'}, |
1326 {'name': 'Arv'}, | 1443 {'name': 'Arv'}, |
1327 {'name': 'Neal'} | 1444 {'name': 'Neal'} |
1328 ] | 1445 ] |
1329 }); | 1446 }); |
1330 recursivelySetTemplateModel(div, m); | 1447 templateBind(template).model = m; |
1331 return new Future(() { | 1448 return new Future(() { |
1332 var t = div.nodes.first; | |
1333 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); | 1449 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); |
1334 }); | 1450 }); |
1335 }); | 1451 }); |
1336 | 1452 |
1337 test('RepeatEmptyPath', () { | 1453 test('RepeatEmptyPath', () { |
1338 var div = createTestHtml( | 1454 var div = createTestHtml( |
1339 '<template repeat="{{}}">Hi {{ name }}</template>'); | 1455 '<template repeat="{{}}">Hi {{ name }}</template>'); |
1340 var t = div.nodes.first; | 1456 var t = div.nodes.first; |
1341 | 1457 |
1342 var m = toObservable([ | 1458 var m = toObservable([ |
1343 {'name': 'Raf'}, | 1459 {'name': 'Raf'}, |
1344 {'name': 'Arv'}, | 1460 {'name': 'Arv'}, |
1345 {'name': 'Neal'} | 1461 {'name': 'Neal'} |
1346 ]); | 1462 ]); |
1347 recursivelySetTemplateModel(div, m); | 1463 templateBind(t).model = m; |
1348 return new Future(() { | 1464 return new Future(() { |
1349 | 1465 |
1350 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); | 1466 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); |
1351 | 1467 |
1352 m.add(toObservable({'name': 'Alex'})); | 1468 m.add(toObservable({'name': 'Alex'})); |
1353 }).then(endOfMicrotask).then((_) { | 1469 }).then(endOfMicrotask).then((_) { |
1354 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); | 1470 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']); |
1355 | 1471 |
1356 m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]))
; | 1472 m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]))
; |
1357 }).then(endOfMicrotask).then((_) { | 1473 }).then(endOfMicrotask).then((_) { |
(...skipping 18 matching lines...) Expand all Loading... |
1376 assertNodesAre(div, ['Hi Alex']); | 1492 assertNodesAre(div, ['Hi Alex']); |
1377 }); | 1493 }); |
1378 }); | 1494 }); |
1379 | 1495 |
1380 test('RepeatNullModel', () { | 1496 test('RepeatNullModel', () { |
1381 var div = createTestHtml( | 1497 var div = createTestHtml( |
1382 '<template repeat="{{}}">Hi {{ name }}</template>'); | 1498 '<template repeat="{{}}">Hi {{ name }}</template>'); |
1383 var t = div.nodes.first; | 1499 var t = div.nodes.first; |
1384 | 1500 |
1385 var m = null; | 1501 var m = null; |
1386 recursivelySetTemplateModel(div, m); | 1502 templateBind(t).model = m; |
1387 | 1503 |
1388 expect(div.nodes.length, 1); | 1504 expect(div.nodes.length, 1); |
1389 | 1505 |
1390 t.attributes['iterate'] = ''; | 1506 t.attributes['iterate'] = ''; |
1391 m = toObservable({}); | 1507 m = toObservable({}); |
1392 recursivelySetTemplateModel(div, m); | 1508 templateBind(t).model = m; |
1393 return new Future(() => expect(div.nodes.length, 1)); | 1509 return new Future(() => expect(div.nodes.length, 1)); |
1394 }); | 1510 }); |
1395 | 1511 |
1396 test('RepeatReuse', () { | 1512 test('RepeatReuse', () { |
1397 var div = createTestHtml( | 1513 var div = createTestHtml( |
1398 '<template repeat="{{}}">Hi {{ name }}</template>'); | 1514 '<template repeat="{{}}">Hi {{ name }}</template>'); |
1399 var t = div.nodes.first; | 1515 var t = div.nodes.first; |
1400 | 1516 |
1401 var m = toObservable([ | 1517 var m = toObservable([ |
1402 {'name': 'Raf'}, | 1518 {'name': 'Raf'}, |
1403 {'name': 'Arv'}, | 1519 {'name': 'Arv'}, |
1404 {'name': 'Neal'} | 1520 {'name': 'Neal'} |
1405 ]); | 1521 ]); |
1406 recursivelySetTemplateModel(div, m); | 1522 templateBind(t).model = m; |
1407 | 1523 |
1408 var node1, node2, node3; | 1524 var node1, node2, node3; |
1409 return new Future(() { | 1525 return new Future(() { |
1410 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); | 1526 assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']); |
1411 node1 = div.nodes[1]; | 1527 node1 = div.nodes[1]; |
1412 node2 = div.nodes[2]; | 1528 node2 = div.nodes[2]; |
1413 node3 = div.nodes[3]; | 1529 node3 = div.nodes[3]; |
1414 | 1530 |
1415 m.replaceRange(1, 2, toObservable([{'name': 'Erik'}])); | 1531 m.replaceRange(1, 2, toObservable([{'name': 'Erik'}])); |
1416 }).then(endOfMicrotask).then((_) { | 1532 }).then(endOfMicrotask).then((_) { |
1417 assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']); | 1533 assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']); |
1418 expect(div.nodes[1], node1, | 1534 expect(div.nodes[1], node1, |
1419 reason: 'model[0] did not change so the node should not have changed')
; | 1535 reason: 'model[0] did not change so the node should not have changed')
; |
1420 expect(div.nodes[2], isNot(equals(node2)), | 1536 expect(div.nodes[2], isNot(equals(node2)), |
1421 reason: 'Should not reuse when replacing'); | 1537 reason: 'Should not reuse when replacing'); |
1422 expect(div.nodes[3], node3, | 1538 expect(div.nodes[3], node3, |
1423 reason: 'model[2] did not change so the node should not have changed')
; | 1539 reason: 'model[2] did not change so the node should not have changed')
; |
1424 | 1540 |
1425 node2 = div.nodes[2]; | 1541 node2 = div.nodes[2]; |
1426 m.insert(0, toObservable({'name': 'Alex'})); | 1542 m.insert(0, toObservable({'name': 'Alex'})); |
1427 }).then(endOfMicrotask).then((_) { | 1543 }).then(endOfMicrotask).then((_) { |
1428 assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']); | 1544 assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']); |
1429 }); | 1545 }); |
1430 }); | 1546 }); |
1431 | 1547 |
1432 test('TwoLevelsDeepBug', () { | 1548 test('TwoLevelsDeepBug', () { |
1433 var div = createTestHtml( | 1549 var div = createTestHtml( |
1434 '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>'); | 1550 '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>'); |
1435 | 1551 var template = div.firstChild; |
1436 var model = toObservable({'foo': 'bar'}); | 1552 var model = toObservable({'foo': 'bar'}); |
1437 recursivelySetTemplateModel(div, model); | 1553 templateBind(template).model = model; |
1438 return new Future(() { | 1554 return new Future(() { |
1439 expect(div.nodes[1].nodes[0].nodes[0].text, 'bar'); | 1555 expect(div.nodes[1].nodes[0].nodes[0].text, 'bar'); |
1440 }); | 1556 }); |
1441 }); | 1557 }); |
1442 | 1558 |
1443 test('Checked', () { | 1559 test('Checked', () { |
1444 var div = createTestHtml( | 1560 var div = createTestHtml( |
1445 '<template bind>' | 1561 '<template bind>' |
1446 '<input type="checkbox" checked="{{a}}">' | 1562 '<input type="checkbox" checked="{{a}}">' |
1447 '</template>'); | 1563 '</template>'); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1479 expect(div.nodes[i++].tagName, 'TEMPLATE'); | 1595 expect(div.nodes[i++].tagName, 'TEMPLATE'); |
1480 expect(div.nodes[i++].text, '2'); | 1596 expect(div.nodes[i++].text, '2'); |
1481 | 1597 |
1482 m['a']['b'] = 11; | 1598 m['a']['b'] = 11; |
1483 }).then(endOfMicrotask).then((_) { | 1599 }).then(endOfMicrotask).then((_) { |
1484 expect(div.nodes[start].text, '11'); | 1600 expect(div.nodes[start].text, '11'); |
1485 | 1601 |
1486 m['a']['c'] = toObservable({'d': 22}); | 1602 m['a']['c'] = toObservable({'d': 22}); |
1487 }).then(endOfMicrotask).then((_) { | 1603 }).then(endOfMicrotask).then((_) { |
1488 expect(div.nodes[start + 2].text, '22'); | 1604 expect(div.nodes[start + 2].text, '22'); |
| 1605 |
| 1606 //clearAllTemplates(div); |
1489 }); | 1607 }); |
1490 } | 1608 } |
1491 | 1609 |
1492 test('Nested', () => nestedHelper( | 1610 test('Nested', () => nestedHelper( |
1493 '<template bind="{{a}}">' | 1611 '<template bind="{{a}}">' |
1494 '{{b}}' | 1612 '{{b}}' |
1495 '<template bind="{{c}}">' | 1613 '<template bind="{{c}}">' |
1496 '{{d}}' | 1614 '{{d}}' |
1497 '</template>' | 1615 '</template>' |
1498 '</template>', 1)); | 1616 '</template>', 1)); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1619 '<template ref="inner" repeat="{{c}}"></template>' | 1737 '<template ref="inner" repeat="{{c}}"></template>' |
1620 '</template>', 2)); | 1738 '</template>', 2)); |
1621 | 1739 |
1622 test('NestedRepeatSelfRef', () { | 1740 test('NestedRepeatSelfRef', () { |
1623 var div = createTestHtml( | 1741 var div = createTestHtml( |
1624 '<template id="t" repeat="{{}}">' | 1742 '<template id="t" repeat="{{}}">' |
1625 '{{name}}' | 1743 '{{name}}' |
1626 '<template ref="t" repeat="{{items}}"></template>' | 1744 '<template ref="t" repeat="{{items}}"></template>' |
1627 '</template>'); | 1745 '</template>'); |
1628 | 1746 |
| 1747 var template = div.firstChild; |
| 1748 |
1629 var m = toObservable([ | 1749 var m = toObservable([ |
1630 { | 1750 { |
1631 'name': 'Item 1', | 1751 'name': 'Item 1', |
1632 'items': [ | 1752 'items': [ |
1633 { | 1753 { |
1634 'name': 'Item 1.1', | 1754 'name': 'Item 1.1', |
1635 'items': [ | 1755 'items': [ |
1636 { | 1756 { |
1637 'name': 'Item 1.1.1', | 1757 'name': 'Item 1.1.1', |
1638 'items': [] | 1758 'items': [] |
1639 } | 1759 } |
1640 ] | 1760 ] |
1641 }, | 1761 }, |
1642 { | 1762 { |
1643 'name': 'Item 1.2' | 1763 'name': 'Item 1.2' |
1644 } | 1764 } |
1645 ] | 1765 ] |
1646 }, | 1766 }, |
1647 { | 1767 { |
1648 'name': 'Item 2', | 1768 'name': 'Item 2', |
1649 'items': [] | 1769 'items': [] |
1650 }, | 1770 }, |
1651 ]); | 1771 ]); |
1652 | 1772 |
1653 recursivelySetTemplateModel(div, m); | 1773 templateBind(template).model = m; |
1654 | 1774 |
1655 int i = 1; | 1775 int i = 1; |
1656 return new Future(() { | 1776 return new Future(() { |
1657 expect(div.nodes[i++].text, 'Item 1'); | 1777 expect(div.nodes[i++].text, 'Item 1'); |
1658 expect(div.nodes[i++].tagName, 'TEMPLATE'); | 1778 expect(div.nodes[i++].tagName, 'TEMPLATE'); |
1659 expect(div.nodes[i++].text, 'Item 1.1'); | 1779 expect(div.nodes[i++].text, 'Item 1.1'); |
1660 expect(div.nodes[i++].tagName, 'TEMPLATE'); | 1780 expect(div.nodes[i++].tagName, 'TEMPLATE'); |
1661 expect(div.nodes[i++].text, 'Item 1.1.1'); | 1781 expect(div.nodes[i++].text, 'Item 1.1.1'); |
1662 expect(div.nodes[i++].tagName, 'TEMPLATE'); | 1782 expect(div.nodes[i++].tagName, 'TEMPLATE'); |
1663 expect(div.nodes[i++].text, 'Item 1.2'); | 1783 expect(div.nodes[i++].text, 'Item 1.2'); |
(...skipping 15 matching lines...) Expand all Loading... |
1679 test('Attribute Template Option/Optgroup', () { | 1799 test('Attribute Template Option/Optgroup', () { |
1680 var div = createTestHtml( | 1800 var div = createTestHtml( |
1681 '<template bind>' | 1801 '<template bind>' |
1682 '<select selectedIndex="{{ selected }}">' | 1802 '<select selectedIndex="{{ selected }}">' |
1683 '<optgroup template repeat="{{ groups }}" label="{{ name }}">' | 1803 '<optgroup template repeat="{{ groups }}" label="{{ name }}">' |
1684 '<option template repeat="{{ items }}">{{ val }}</option>' | 1804 '<option template repeat="{{ items }}">{{ val }}</option>' |
1685 '</optgroup>' | 1805 '</optgroup>' |
1686 '</select>' | 1806 '</select>' |
1687 '</template>'); | 1807 '</template>'); |
1688 | 1808 |
| 1809 var template = div.firstChild; |
1689 var m = toObservable({ | 1810 var m = toObservable({ |
1690 'selected': 1, | 1811 'selected': 1, |
1691 'groups': [{ | 1812 'groups': [{ |
1692 'name': 'one', 'items': [{ 'val': 0 }, { 'val': 1 }] | 1813 'name': 'one', 'items': [{ 'val': 0 }, { 'val': 1 }] |
1693 }], | 1814 }], |
1694 }); | 1815 }); |
1695 | 1816 |
1696 recursivelySetTemplateModel(div, m); | 1817 templateBind(template).model = m; |
1697 | 1818 |
1698 var completer = new Completer(); | 1819 var completer = new Completer(); |
1699 | 1820 |
1700 new MutationObserver((records, observer) { | 1821 new MutationObserver((records, observer) { |
1701 var select = div.nodes[0].nextNode; | 1822 var select = div.nodes[0].nextNode; |
1702 if (select == null || select.querySelector('option') == null) return; | 1823 if (select == null || select.querySelector('option') == null) return; |
1703 | 1824 |
1704 observer.disconnect(); | 1825 observer.disconnect(); |
1705 new Future(() { | 1826 new Future(() { |
1706 expect(select.nodes.length, 2); | 1827 expect(select.nodes.length, 2); |
1707 | 1828 |
1708 expect(select.selectedIndex, 1, reason: 'selected index should update ' | 1829 expect(select.selectedIndex, 1, reason: 'selected index should update ' |
1709 'after template expands.'); | 1830 'after template expands.'); |
1710 | 1831 |
1711 expect(select.nodes[0].tagName, 'TEMPLATE'); | 1832 expect(select.nodes[0].tagName, 'TEMPLATE'); |
1712 expect((templateBind(templateBind(select.nodes[0]).ref) | |
1713 .content.nodes[0] as Element).tagName, 'OPTGROUP'); | |
1714 | |
1715 var optgroup = select.nodes[1]; | 1833 var optgroup = select.nodes[1]; |
1716 expect(optgroup.nodes[0].tagName, 'TEMPLATE'); | 1834 expect(optgroup.nodes[0].tagName, 'TEMPLATE'); |
1717 expect(optgroup.nodes[1].tagName, 'OPTION'); | 1835 expect(optgroup.nodes[1].tagName, 'OPTION'); |
1718 expect(optgroup.nodes[1].text, '0'); | 1836 expect(optgroup.nodes[1].text, '0'); |
1719 expect(optgroup.nodes[2].tagName, 'OPTION'); | 1837 expect(optgroup.nodes[2].tagName, 'OPTION'); |
1720 expect(optgroup.nodes[2].text, '1'); | 1838 expect(optgroup.nodes[2].text, '1'); |
1721 | 1839 |
1722 completer.complete(); | 1840 completer.complete(); |
1723 }); | 1841 }); |
1724 })..observe(div, childList: true, subtree: true); | 1842 })..observe(div, childList: true, subtree: true); |
1725 | 1843 |
1726 Observable.dirtyCheck(); | 1844 Observable.dirtyCheck(); |
1727 | 1845 |
1728 return completer.future; | 1846 return completer.future; |
1729 }); | 1847 }); |
1730 | 1848 |
1731 test('NestedIterateTableMixedSemanticNative', () { | 1849 test('NestedIterateTableMixedSemanticNative', () { |
1732 if (!parserHasNativeTemplate) return null; | 1850 if (!parserHasNativeTemplate) return null; |
1733 | 1851 |
1734 var div = createTestHtml( | 1852 var div = createTestHtml( |
1735 '<table><tbody>' | 1853 '<table><tbody>' |
1736 '<template repeat="{{}}">' | 1854 '<template repeat="{{}}">' |
1737 '<tr>' | 1855 '<tr>' |
1738 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' | 1856 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' |
1739 '</tr>' | 1857 '</tr>' |
1740 '</template>' | 1858 '</template>' |
1741 '</tbody></table>'); | 1859 '</tbody></table>'); |
| 1860 var template = div.firstChild.firstChild.firstChild; |
1742 | 1861 |
1743 var m = toObservable([ | 1862 var m = toObservable([ |
1744 [{ 'val': 0 }, { 'val': 1 }], | 1863 [{ 'val': 0 }, { 'val': 1 }], |
1745 [{ 'val': 2 }, { 'val': 3 }] | 1864 [{ 'val': 2 }, { 'val': 3 }] |
1746 ]); | 1865 ]); |
1747 | 1866 |
1748 recursivelySetTemplateModel(div, m); | 1867 templateBind(template).model = m; |
1749 return new Future(() { | 1868 return new Future(() { |
1750 var tbody = div.nodes[0].nodes[0]; | 1869 var tbody = div.nodes[0].nodes[0]; |
1751 | 1870 |
1752 // 1 for the <tr template>, 2 * (1 tr) | 1871 // 1 for the <tr template>, 2 * (1 tr) |
1753 expect(tbody.nodes.length, 3); | 1872 expect(tbody.nodes.length, 3); |
1754 | 1873 |
1755 // 1 for the <td template>, 2 * (1 td) | 1874 // 1 for the <td template>, 2 * (1 td) |
1756 expect(tbody.nodes[1].nodes.length, 3); | 1875 expect(tbody.nodes[1].nodes.length, 3); |
1757 | 1876 |
1758 expect(tbody.nodes[1].nodes[1].text, '0'); | 1877 expect(tbody.nodes[1].nodes[1].text, '0'); |
(...skipping 10 matching lines...) Expand all Loading... |
1769 }); | 1888 }); |
1770 }); | 1889 }); |
1771 | 1890 |
1772 test('NestedIterateTable', () { | 1891 test('NestedIterateTable', () { |
1773 var div = createTestHtml( | 1892 var div = createTestHtml( |
1774 '<table><tbody>' | 1893 '<table><tbody>' |
1775 '<tr template repeat="{{}}">' | 1894 '<tr template repeat="{{}}">' |
1776 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' | 1895 '<td template repeat="{{}}" class="{{ val }}">{{ val }}</td>' |
1777 '</tr>' | 1896 '</tr>' |
1778 '</tbody></table>'); | 1897 '</tbody></table>'); |
| 1898 var template = div.firstChild.firstChild.firstChild; |
1779 | 1899 |
1780 var m = toObservable([ | 1900 var m = toObservable([ |
1781 [{ 'val': 0 }, { 'val': 1 }], | 1901 [{ 'val': 0 }, { 'val': 1 }], |
1782 [{ 'val': 2 }, { 'val': 3 }] | 1902 [{ 'val': 2 }, { 'val': 3 }] |
1783 ]); | 1903 ]); |
1784 | 1904 |
1785 recursivelySetTemplateModel(div, m); | 1905 templateBind(template).model = m; |
1786 return new Future(() { | 1906 return new Future(() { |
1787 | 1907 |
1788 var i = 1; | 1908 var i = 1; |
1789 var tbody = div.nodes[0].nodes[0]; | 1909 var tbody = div.nodes[0].nodes[0]; |
1790 | 1910 |
1791 // 1 for the <tr template>, 2 * (1 tr) | 1911 // 1 for the <tr template>, 2 * (1 tr) |
1792 expect(tbody.nodes.length, 3); | 1912 expect(tbody.nodes.length, 3); |
1793 | 1913 |
1794 // 1 for the <td template>, 2 * (1 td) | 1914 // 1 for the <td template>, 2 * (1 td) |
1795 expect(tbody.nodes[1].nodes.length, 3); | 1915 expect(tbody.nodes[1].nodes.length, 3); |
(...skipping 10 matching lines...) Expand all Loading... |
1806 expect(tbody.nodes[2].nodes[2].attributes['class'], '3'); | 1926 expect(tbody.nodes[2].nodes[2].attributes['class'], '3'); |
1807 }); | 1927 }); |
1808 }); | 1928 }); |
1809 | 1929 |
1810 test('NestedRepeatDeletionOfMultipleSubTemplates', () { | 1930 test('NestedRepeatDeletionOfMultipleSubTemplates', () { |
1811 var div = createTestHtml( | 1931 var div = createTestHtml( |
1812 '<ul>' | 1932 '<ul>' |
1813 '<template repeat="{{}}" id=t1>' | 1933 '<template repeat="{{}}" id=t1>' |
1814 '<li>{{name}}' | 1934 '<li>{{name}}' |
1815 '<ul>' | 1935 '<ul>' |
1816 '<template ref=t1 repaet="{{items}}"></template>' | 1936 '<template ref=t1 repeat="{{items}}"></template>' |
1817 '</ul>' | 1937 '</ul>' |
1818 '</li>' | 1938 '</li>' |
1819 '</template>' | 1939 '</template>' |
1820 '</ul>'); | 1940 '</ul>'); |
1821 | 1941 |
1822 var m = toObservable([ | 1942 var m = toObservable([ |
1823 { | 1943 { |
1824 'name': 'Item 1', | 1944 'name': 'Item 1', |
1825 'items': [ | 1945 'items': [ |
1826 { | 1946 { |
1827 'name': 'Item 1.1' | 1947 'name': 'Item 1.1' |
1828 } | 1948 } |
1829 ] | 1949 ] |
1830 } | 1950 } |
1831 ]); | 1951 ]); |
| 1952 var ul = div.firstChild; |
| 1953 var t = ul.firstChild; |
1832 | 1954 |
1833 recursivelySetTemplateModel(div, m); | 1955 templateBind(t).model = m; |
1834 return new Future(() => m.removeAt(0)); | 1956 return new Future(() { |
| 1957 expect(ul.nodes.length, 2); |
| 1958 var ul2 = ul.nodes[1].nodes[1]; |
| 1959 expect(ul2.nodes.length, 2); |
| 1960 var ul3 = ul2.nodes[1].nodes[1]; |
| 1961 expect(ul3.nodes.length, 1); |
| 1962 |
| 1963 m.removeAt(0); |
| 1964 }).then(endOfMicrotask).then((_) { |
| 1965 expect(ul.nodes.length, 1); |
| 1966 }); |
1835 }); | 1967 }); |
1836 | 1968 |
1837 test('DeepNested', () { | 1969 test('DeepNested', () { |
1838 var div = createTestHtml( | 1970 var div = createTestHtml( |
1839 '<template bind="{{a}}">' | 1971 '<template bind="{{a}}">' |
1840 '<p>' | 1972 '<p>' |
1841 '<template bind="{{b}}">' | 1973 '<template bind="{{b}}">' |
1842 '{{ c }}' | 1974 '{{ c }}' |
1843 '</template>' | 1975 '</template>' |
1844 '</p>' | 1976 '</p>' |
1845 '</template>'); | 1977 '</template>'); |
1846 | 1978 var template = div.firstChild; |
1847 var m = toObservable({ | 1979 var m = toObservable({ |
1848 'a': { | 1980 'a': { |
1849 'b': { | 1981 'b': { |
1850 'c': 42 | 1982 'c': 42 |
1851 } | 1983 } |
1852 } | 1984 } |
1853 }); | 1985 }); |
1854 recursivelySetTemplateModel(div, m); | 1986 templateBind(template).model = m; |
1855 return new Future(() { | 1987 return new Future(() { |
1856 expect(div.nodes[1].tagName, 'P'); | 1988 expect(div.nodes[1].tagName, 'P'); |
1857 expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE'); | 1989 expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE'); |
1858 expect(div.nodes[1].nodes[1].text, '42'); | 1990 expect(div.nodes[1].nodes[1].text, '42'); |
1859 }); | 1991 }); |
1860 }); | 1992 }); |
1861 | 1993 |
1862 test('TemplateContentRemoved', () { | 1994 test('TemplateContentRemoved', () { |
1863 var div = createTestHtml('<template bind="{{}}">{{ }}</template>'); | 1995 var div = createTestHtml('<template bind="{{}}">{{ }}</template>'); |
| 1996 var template = div.firstChild; |
1864 var model = 42; | 1997 var model = 42; |
1865 | 1998 |
1866 recursivelySetTemplateModel(div, model); | 1999 templateBind(template).model = model; |
1867 return new Future(() { | 2000 return new Future(() { |
1868 expect(div.nodes[1].text, '42'); | 2001 expect(div.nodes[1].text, '42'); |
1869 expect(div.nodes[0].text, ''); | 2002 expect(div.nodes[0].text, ''); |
1870 }); | 2003 }); |
1871 }); | 2004 }); |
1872 | 2005 |
1873 test('TemplateContentRemovedEmptyArray', () { | 2006 test('TemplateContentRemovedEmptyArray', () { |
1874 var div = createTestHtml('<template iterate>Remove me</template>'); | 2007 var div = createTestHtml('<template iterate>Remove me</template>'); |
1875 var model = toObservable([]); | 2008 var template = div.firstChild; |
1876 | 2009 templateBind(template).model = []; |
1877 recursivelySetTemplateModel(div, model); | |
1878 return new Future(() { | 2010 return new Future(() { |
1879 expect(div.nodes.length, 1); | 2011 expect(div.nodes.length, 1); |
1880 expect(div.nodes[0].text, ''); | 2012 expect(div.nodes[0].text, ''); |
1881 }); | 2013 }); |
1882 }); | 2014 }); |
1883 | 2015 |
1884 test('TemplateContentRemovedNested', () { | 2016 test('TemplateContentRemovedNested', () { |
1885 var div = createTestHtml( | 2017 var div = createTestHtml( |
1886 '<template bind="{{}}">' | 2018 '<template bind="{{}}">' |
1887 '{{ a }}' | 2019 '{{ a }}' |
1888 '<template bind="{{}}">' | 2020 '<template bind="{{}}">' |
1889 '{{ b }}' | 2021 '{{ b }}' |
1890 '</template>' | 2022 '</template>' |
1891 '</template>'); | 2023 '</template>'); |
1892 | 2024 var template = div.firstChild; |
1893 var model = toObservable({ | 2025 var model = toObservable({ |
1894 'a': 1, | 2026 'a': 1, |
1895 'b': 2 | 2027 'b': 2 |
1896 }); | 2028 }); |
1897 recursivelySetTemplateModel(div, model); | 2029 templateBind(template).model = model; |
1898 return new Future(() { | 2030 return new Future(() { |
1899 expect(div.nodes[0].text, ''); | 2031 expect(div.nodes[0].text, ''); |
1900 expect(div.nodes[1].text, '1'); | 2032 expect(div.nodes[1].text, '1'); |
1901 expect(div.nodes[2].text, ''); | 2033 expect(div.nodes[2].text, ''); |
1902 expect(div.nodes[3].text, '2'); | 2034 expect(div.nodes[3].text, '2'); |
1903 }); | 2035 }); |
1904 }); | 2036 }); |
1905 | 2037 |
1906 test('BindWithUndefinedModel', () { | 2038 test('BindWithUndefinedModel', () { |
1907 var div = createTestHtml( | 2039 var div = createTestHtml( |
1908 '<template bind="{{}}" if="{{}}">{{ a }}</template>'); | 2040 '<template bind="{{}}" if="{{}}">{{ a }}</template>'); |
| 2041 var template = div.firstChild; |
1909 | 2042 |
1910 var model = toObservable({'a': 42}); | 2043 var model = toObservable({'a': 42}); |
1911 recursivelySetTemplateModel(div, model); | 2044 templateBind(template).model = model; |
1912 return new Future(() { | 2045 return new Future(() { |
1913 expect(div.nodes[1].text, '42'); | 2046 expect(div.nodes[1].text, '42'); |
1914 | 2047 |
1915 model = null; | 2048 model = null; |
1916 recursivelySetTemplateModel(div, model); | 2049 templateBind(template).model = model; |
1917 }).then(endOfMicrotask).then((_) { | 2050 }).then(endOfMicrotask).then((_) { |
1918 expect(div.nodes.length, 1); | 2051 expect(div.nodes.length, 1); |
1919 | 2052 |
1920 model = toObservable({'a': 42}); | 2053 model = toObservable({'a': 42}); |
1921 recursivelySetTemplateModel(div, model); | 2054 templateBind(template).model = model; |
1922 }).then(endOfMicrotask).then((_) { | 2055 }).then(endOfMicrotask).then((_) { |
1923 expect(div.nodes[1].text, '42'); | 2056 expect(div.nodes[1].text, '42'); |
1924 }); | 2057 }); |
1925 }); | 2058 }); |
1926 | 2059 |
1927 test('BindNested', () { | 2060 test('BindNested', () { |
1928 var div = createTestHtml( | 2061 var div = createTestHtml( |
1929 '<template bind="{{}}">' | 2062 '<template bind="{{}}">' |
1930 'Name: {{ name }}' | 2063 'Name: {{ name }}' |
1931 '<template bind="{{wife}}" if="{{wife}}">' | 2064 '<template bind="{{wife}}" if="{{wife}}">' |
1932 'Wife: {{ name }}' | 2065 'Wife: {{ name }}' |
1933 '</template>' | 2066 '</template>' |
1934 '<template bind="{{child}}" if="{{child}}">' | 2067 '<template bind="{{child}}" if="{{child}}">' |
1935 'Child: {{ name }}' | 2068 'Child: {{ name }}' |
1936 '</template>' | 2069 '</template>' |
1937 '</template>'); | 2070 '</template>'); |
1938 | 2071 var template = div.firstChild; |
1939 var m = toObservable({ | 2072 var m = toObservable({ |
1940 'name': 'Hermes', | 2073 'name': 'Hermes', |
1941 'wife': { | 2074 'wife': { |
1942 'name': 'LaBarbara' | 2075 'name': 'LaBarbara' |
1943 } | 2076 } |
1944 }); | 2077 }); |
1945 recursivelySetTemplateModel(div, m); | 2078 templateBind(template).model = m; |
| 2079 |
1946 return new Future(() { | 2080 return new Future(() { |
1947 expect(div.nodes.length, 5); | 2081 expect(div.nodes.length, 5); |
1948 expect(div.nodes[1].text, 'Name: Hermes'); | 2082 expect(div.nodes[1].text, 'Name: Hermes'); |
1949 expect(div.nodes[3].text, 'Wife: LaBarbara'); | 2083 expect(div.nodes[3].text, 'Wife: LaBarbara'); |
1950 | 2084 |
1951 m['child'] = toObservable({'name': 'Dwight'}); | 2085 m['child'] = toObservable({'name': 'Dwight'}); |
| 2086 |
1952 }).then(endOfMicrotask).then((_) { | 2087 }).then(endOfMicrotask).then((_) { |
1953 expect(div.nodes.length, 6); | 2088 expect(div.nodes.length, 6); |
1954 expect(div.nodes[5].text, 'Child: Dwight'); | 2089 expect(div.nodes[5].text, 'Child: Dwight'); |
1955 | 2090 |
1956 m.remove('wife'); | 2091 m.remove('wife'); |
| 2092 |
1957 }).then(endOfMicrotask).then((_) { | 2093 }).then(endOfMicrotask).then((_) { |
1958 expect(div.nodes.length, 5); | 2094 expect(div.nodes.length, 5); |
1959 expect(div.nodes[4].text, 'Child: Dwight'); | 2095 expect(div.nodes[4].text, 'Child: Dwight'); |
1960 }); | 2096 }); |
1961 }); | 2097 }); |
1962 | 2098 |
1963 test('BindRecursive', () { | 2099 test('BindRecursive', () { |
1964 var div = createTestHtml( | 2100 var div = createTestHtml( |
1965 '<template bind="{{}}" if="{{}}" id="t">' | 2101 '<template bind="{{}}" if="{{}}" id="t">' |
1966 'Name: {{ name }}' | 2102 'Name: {{ name }}' |
1967 '<template bind="{{friend}}" if="{{friend}}" ref="t"></template>' | 2103 '<template bind="{{friend}}" if="{{friend}}" ref="t"></template>' |
1968 '</template>'); | 2104 '</template>'); |
1969 | 2105 var template = div.firstChild; |
1970 var m = toObservable({ | 2106 var m = toObservable({ |
1971 'name': 'Fry', | 2107 'name': 'Fry', |
1972 'friend': { | 2108 'friend': { |
1973 'name': 'Bender' | 2109 'name': 'Bender' |
1974 } | 2110 } |
1975 }); | 2111 }); |
1976 recursivelySetTemplateModel(div, m); | 2112 templateBind(template).model = m; |
1977 return new Future(() { | 2113 return new Future(() { |
1978 expect(div.nodes.length, 5); | 2114 expect(div.nodes.length, 5); |
1979 expect(div.nodes[1].text, 'Name: Fry'); | 2115 expect(div.nodes[1].text, 'Name: Fry'); |
1980 expect(div.nodes[3].text, 'Name: Bender'); | 2116 expect(div.nodes[3].text, 'Name: Bender'); |
1981 | 2117 |
1982 m['friend']['friend'] = toObservable({'name': 'Leela'}); | 2118 m['friend']['friend'] = toObservable({'name': 'Leela'}); |
1983 }).then(endOfMicrotask).then((_) { | 2119 }).then(endOfMicrotask).then((_) { |
1984 expect(div.nodes.length, 7); | 2120 expect(div.nodes.length, 7); |
1985 expect(div.nodes[5].text, 'Name: Leela'); | 2121 expect(div.nodes[5].text, 'Name: Leela'); |
1986 | 2122 |
1987 m['friend'] = toObservable({'name': 'Leela'}); | 2123 m['friend'] = toObservable({'name': 'Leela'}); |
1988 }).then(endOfMicrotask).then((_) { | 2124 }).then(endOfMicrotask).then((_) { |
1989 expect(div.nodes.length, 5); | 2125 expect(div.nodes.length, 5); |
1990 expect(div.nodes[3].text, 'Name: Leela'); | 2126 expect(div.nodes[3].text, 'Name: Leela'); |
1991 }); | 2127 }); |
1992 }); | 2128 }); |
1993 | 2129 |
1994 test('Template - Self is terminator', () { | 2130 test('Template - Self is terminator', () { |
1995 var div = createTestHtml( | 2131 var div = createTestHtml( |
1996 '<template repeat>{{ foo }}' | 2132 '<template repeat>{{ foo }}' |
1997 '<template bind></template>' | 2133 '<template bind></template>' |
1998 '</template>'); | 2134 '</template>'); |
| 2135 var template = div.firstChild; |
1999 | 2136 |
2000 var m = toObservable([{ 'foo': 'bar' }]); | 2137 var m = toObservable([{ 'foo': 'bar' }]); |
2001 recursivelySetTemplateModel(div, m); | 2138 templateBind(template).model = m; |
2002 return new Future(() { | 2139 return new Future(() { |
2003 | 2140 |
2004 m.add(toObservable({ 'foo': 'baz' })); | 2141 m.add(toObservable({ 'foo': 'baz' })); |
2005 recursivelySetTemplateModel(div, m); | 2142 templateBind(template).model = m; |
2006 }).then(endOfMicrotask).then((_) { | 2143 }).then(endOfMicrotask).then((_) { |
2007 | 2144 |
2008 expect(div.nodes.length, 5); | 2145 expect(div.nodes.length, 5); |
2009 expect(div.nodes[1].text, 'bar'); | 2146 expect(div.nodes[1].text, 'bar'); |
2010 expect(div.nodes[3].text, 'baz'); | 2147 expect(div.nodes[3].text, 'baz'); |
2011 }); | 2148 }); |
2012 }); | 2149 }); |
2013 | 2150 |
2014 test('Template - Same Contents, Different Array has no effect', () { | 2151 test('Template - Same Contents, Different Array has no effect', () { |
2015 if (!MutationObserver.supported) return null; | 2152 if (!MutationObserver.supported) return null; |
2016 | 2153 |
2017 var div = createTestHtml('<template repeat>{{ foo }}</template>'); | 2154 var div = createTestHtml('<template repeat>{{ foo }}</template>'); |
| 2155 var template = div.firstChild; |
2018 | 2156 |
2019 var m = toObservable([{ 'foo': 'bar' }, { 'foo': 'bat'}]); | 2157 var m = toObservable([{ 'foo': 'bar' }, { 'foo': 'bat'}]); |
2020 recursivelySetTemplateModel(div, m); | 2158 templateBind(template).model = m; |
2021 var observer = new MutationObserver((x, y) {}); | 2159 var observer = new MutationObserver((x, y) {}); |
2022 return new Future(() { | 2160 return new Future(() { |
2023 observer.observe(div, childList: true); | 2161 observer.observe(div, childList: true); |
2024 | 2162 |
2025 var template = div.firstChild; | 2163 var template = div.firstChild; |
2026 templateBind(template).model = new ObservableList.from(m); | 2164 templateBind(template).model = new ObservableList.from(m); |
2027 }).then(endOfMicrotask).then((_) { | 2165 }).then(endOfMicrotask).then((_) { |
2028 var records = observer.takeRecords(); | 2166 var records = observer.takeRecords(); |
2029 expect(records.length, 0); | 2167 expect(records.length, 0); |
2030 }); | 2168 }); |
2031 }); | 2169 }); |
2032 | 2170 |
2033 test('RecursiveRef', () { | 2171 test('RecursiveRef', () { |
2034 var div = createTestHtml( | 2172 var div = createTestHtml( |
2035 '<template bind>' | 2173 '<template bind>' |
2036 '<template id=src>{{ foo }}</template>' | 2174 '<template id=src>{{ foo }}</template>' |
2037 '<template bind ref=src></template>' | 2175 '<template bind ref=src></template>' |
2038 '</template>'); | 2176 '</template>'); |
2039 | 2177 |
2040 var m = toObservable({'foo': 'bar'}); | 2178 var m = toObservable({'foo': 'bar'}); |
2041 recursivelySetTemplateModel(div, m); | 2179 templateBind(div.firstChild).model = m; |
2042 return new Future(() { | 2180 return new Future(() { |
2043 expect(div.nodes.length, 4); | 2181 expect(div.nodes.length, 4); |
2044 expect(div.nodes[3].text, 'bar'); | 2182 expect(div.nodes[3].text, 'bar'); |
2045 }); | 2183 }); |
2046 }); | 2184 }); |
2047 | 2185 |
| 2186 test('baseURI', () { |
| 2187 // TODO(jmesserly): Dart's setInnerHtml breaks this test -- the template |
| 2188 // URL is created as blank despite the NullTreeSanitizer. |
| 2189 // Use JS interop as a workaround. |
| 2190 //var div = createTestHtml('<template bind>' |
| 2191 // '<div style="background: url(foo.jpg)"></div></template>'); |
| 2192 var div = new DivElement(); |
| 2193 new JsObject.fromBrowserObject(div)['innerHTML'] = '<template bind>' |
| 2194 '<div style="background: url(foo.jpg)"></div></template>'; |
| 2195 testDiv.append(div); |
| 2196 TemplateBindExtension.decorate(div.firstChild); |
| 2197 |
| 2198 var local = document.createElement('div'); |
| 2199 local.attributes['style'] = 'background: url(foo.jpg)'; |
| 2200 div.append(local); |
| 2201 var template = div.firstChild; |
| 2202 templateBind(template).model = {}; |
| 2203 return new Future(() { |
| 2204 expect(div.nodes[1].style.backgroundImage, local.style.backgroundImage); |
| 2205 }); |
| 2206 }); |
| 2207 |
2048 test('ChangeRefId', () { | 2208 test('ChangeRefId', () { |
2049 var div = createTestHtml( | 2209 var div = createTestHtml( |
2050 '<template id="a">a:{{ }}</template>' | 2210 '<template id="a">a:{{ }}</template>' |
2051 '<template id="b">b:{{ }}</template>' | 2211 '<template id="b">b:{{ }}</template>' |
2052 '<template repeat="{{}}">' | 2212 '<template repeat="{{}}">' |
2053 '<template ref="a" bind="{{}}"></template>' | 2213 '<template ref="a" bind="{{}}"></template>' |
2054 '</template>'); | 2214 '</template>'); |
| 2215 var template = div.nodes[2]; |
2055 var model = toObservable([]); | 2216 var model = toObservable([]); |
2056 recursivelySetTemplateModel(div, model); | 2217 templateBind(template).model = model; |
2057 return new Future(() { | 2218 return new Future(() { |
2058 expect(div.nodes.length, 3); | 2219 expect(div.nodes.length, 3); |
2059 | 2220 |
2060 document.getElementById('a').id = 'old-a'; | 2221 document.getElementById('a').id = 'old-a'; |
2061 document.getElementById('b').id = 'a'; | 2222 document.getElementById('b').id = 'a'; |
2062 | 2223 |
2063 model..add(1)..add(2); | 2224 model..add(1)..add(2); |
2064 }).then(endOfMicrotask).then((_) { | 2225 }).then(endOfMicrotask).then((_) { |
2065 | 2226 |
2066 expect(div.nodes.length, 7); | 2227 expect(div.nodes.length, 7); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2111 expect(templateBind(templateB).content.ownerDocument, | 2272 expect(templateBind(templateB).content.ownerDocument, |
2112 templateBind(templateA).content.ownerDocument); | 2273 templateBind(templateA).content.ownerDocument); |
2113 }); | 2274 }); |
2114 | 2275 |
2115 test('BindShadowDOM', () { | 2276 test('BindShadowDOM', () { |
2116 if (!ShadowRoot.supported) return null; | 2277 if (!ShadowRoot.supported) return null; |
2117 | 2278 |
2118 var root = createShadowTestHtml( | 2279 var root = createShadowTestHtml( |
2119 '<template bind="{{}}">Hi {{ name }}</template>'); | 2280 '<template bind="{{}}">Hi {{ name }}</template>'); |
2120 var model = toObservable({'name': 'Leela'}); | 2281 var model = toObservable({'name': 'Leela'}); |
2121 recursivelySetTemplateModel(root, model); | 2282 templateBind(root.firstChild).model = model; |
2122 return new Future(() => expect(root.nodes[1].text, 'Hi Leela')); | 2283 return new Future(() => expect(root.nodes[1].text, 'Hi Leela')); |
2123 }); | 2284 }); |
2124 | 2285 |
2125 // Dart note: this test seems gone from JS. Keeping for posterity sake. | 2286 // Dart note: this test seems gone from JS. Keeping for posterity sake. |
2126 test('BindShadowDOM createInstance', () { | 2287 test('BindShadowDOM createInstance', () { |
2127 if (!ShadowRoot.supported) return null; | 2288 if (!ShadowRoot.supported) return null; |
2128 | 2289 |
2129 var model = toObservable({'name': 'Leela'}); | 2290 var model = toObservable({'name': 'Leela'}); |
2130 var template = new Element.html('<template>Hi {{ name }}</template>'); | 2291 var template = new Element.html('<template>Hi {{ name }}</template>'); |
2131 var root = createShadowTestHtml(''); | 2292 var root = createShadowTestHtml(''); |
2132 root.nodes.add(templateBind(template).createInstance(model)); | 2293 root.nodes.add(templateBind(template).createInstance(model)); |
2133 | 2294 |
2134 return new Future(() { | 2295 return new Future(() { |
2135 expect(root.text, 'Hi Leela'); | 2296 expect(root.text, 'Hi Leela'); |
2136 | 2297 |
2137 model['name'] = 'Fry'; | 2298 model['name'] = 'Fry'; |
2138 }).then(endOfMicrotask).then((_) { | 2299 }).then(endOfMicrotask).then((_) { |
2139 expect(root.text, 'Hi Fry'); | 2300 expect(root.text, 'Hi Fry'); |
2140 }); | 2301 }); |
2141 }); | 2302 }); |
2142 | 2303 |
2143 test('BindShadowDOM Template Ref', () { | 2304 test('BindShadowDOM Template Ref', () { |
2144 if (!ShadowRoot.supported) return null; | 2305 if (!ShadowRoot.supported) return null; |
2145 var root = createShadowTestHtml( | 2306 var root = createShadowTestHtml( |
2146 '<template id=foo>Hi</template><template bind ref=foo></template>'); | 2307 '<template id=foo>Hi</template><template bind ref=foo></template>'); |
2147 recursivelySetTemplateModel(root, toObservable({})); | 2308 var template = root.nodes[1]; |
2148 return new Future(() => expect(root.nodes.length, 3)); | 2309 templateBind(template).model = toObservable({}); |
| 2310 return new Future(() { |
| 2311 expect(root.nodes.length, 3); |
| 2312 clearAllTemplates(root); |
| 2313 }); |
2149 }); | 2314 }); |
2150 | 2315 |
2151 // https://github.com/Polymer/TemplateBinding/issues/8 | 2316 // https://github.com/Polymer/TemplateBinding/issues/8 |
2152 test('UnbindingInNestedBind', () { | 2317 test('UnbindingInNestedBind', () { |
2153 var div = createTestHtml( | 2318 var div = createTestHtml( |
2154 '<template bind="{{outer}}" if="{{outer}}" syntax="testHelper">' | 2319 '<template bind="{{outer}}" if="{{outer}}" syntax="testHelper">' |
2155 '<template bind="{{inner}}" if="{{inner}}">' | 2320 '<template bind="{{inner}}" if="{{inner}}">' |
2156 '{{ age }}' | 2321 '{{ age }}' |
2157 '</template>' | 2322 '</template>' |
2158 '</template>'); | 2323 '</template>'); |
2159 | 2324 var template = div.firstChild; |
2160 var syntax = new UnbindingInNestedBindSyntax(); | 2325 var syntax = new UnbindingInNestedBindSyntax(); |
2161 var model = toObservable({'outer': {'inner': {'age': 42}}}); | 2326 var model = toObservable({'outer': {'inner': {'age': 42}}}); |
2162 | 2327 |
2163 recursivelySetTemplateModel(div, model, syntax); | 2328 templateBind(template)..model = model..bindingDelegate = syntax; |
2164 | 2329 |
2165 return new Future(() { | 2330 return new Future(() { |
2166 expect(syntax.count, 1); | 2331 expect(syntax.count, 1); |
2167 | 2332 |
2168 var inner = model['outer']['inner']; | 2333 var inner = model['outer']['inner']; |
2169 model['outer'] = null; | 2334 model['outer'] = null; |
2170 | 2335 |
2171 }).then(endOfMicrotask).then((_) { | 2336 }).then(endOfMicrotask).then((_) { |
2172 expect(syntax.count, 1); | 2337 expect(syntax.count, 1); |
2173 | 2338 |
2174 model['outer'] = toObservable({'inner': {'age': 2}}); | 2339 model['outer'] = toObservable({'inner': {'age': 2}}); |
2175 syntax.expectedAge = 2; | 2340 syntax.expectedAge = 2; |
2176 | 2341 |
2177 }).then(endOfMicrotask).then((_) { | 2342 }).then(endOfMicrotask).then((_) { |
2178 expect(syntax.count, 2); | 2343 expect(syntax.count, 2); |
2179 }); | 2344 }); |
2180 }); | 2345 }); |
2181 | 2346 |
2182 // https://github.com/toolkitchen/mdv/issues/8 | 2347 // https://github.com/toolkitchen/mdv/issues/8 |
2183 test('DontCreateInstancesForAbandonedIterators', () { | 2348 test('DontCreateInstancesForAbandonedIterators', () { |
2184 var div = createTestHtml( | 2349 var div = createTestHtml( |
2185 '<template bind="{{}} {{}}">' | 2350 '<template bind="{{}} {{}}">' |
2186 '<template bind="{{}}">Foo</template>' | 2351 '<template bind="{{}}">Foo</template>' |
2187 '</template>'); | 2352 '</template>'); |
2188 recursivelySetTemplateModel(div, null); | 2353 var template = div.firstChild; |
| 2354 templateBind(template).model = null; |
2189 return nextMicrotask; | 2355 return nextMicrotask; |
2190 }); | 2356 }); |
2191 | 2357 |
2192 test('CreateInstance', () { | 2358 test('CreateInstance', () { |
2193 var div = createTestHtml( | 2359 var div = createTestHtml( |
2194 '<template bind="{{a}}">' | 2360 '<template bind="{{a}}">' |
2195 '<template bind="{{b}}">' | 2361 '<template bind="{{b}}">' |
2196 '{{ foo }}:{{ replaceme }}' | 2362 '{{ foo }}:{{ replaceme }}' |
2197 '</template>' | 2363 '</template>' |
2198 '</template>'); | 2364 '</template>'); |
2199 var outer = templateBind(div.nodes.first); | 2365 var outer = templateBind(div.nodes.first); |
2200 var model = toObservable({'b': {'foo': 'bar'}}); | 2366 var model = toObservable({'b': {'foo': 'bar'}}); |
2201 | 2367 |
2202 var host = new DivElement(); | |
2203 var instance = outer.createInstance(model, new TestBindingSyntax()); | 2368 var instance = outer.createInstance(model, new TestBindingSyntax()); |
2204 expect(outer.content.nodes.first, | 2369 expect(instance.firstChild.nextNode.text, 'bar:replaced'); |
2205 templateBind(instance.nodes.first).ref); | |
2206 | 2370 |
2207 host.append(instance); | 2371 clearAllTemplates(instance); |
2208 return new Future(() { | |
2209 expect(host.firstChild.nextNode.text, 'bar:replaced'); | |
2210 }); | |
2211 }); | 2372 }); |
2212 | 2373 |
2213 test('CreateInstance - sync error', () { | 2374 test('CreateInstance - sync error', () { |
2214 var div = createTestHtml('<template>{{foo}}</template>'); | 2375 var div = createTestHtml('<template>{{foo}}</template>'); |
2215 var outer = templateBind(div.nodes.first); | 2376 var outer = templateBind(div.nodes.first); |
2216 var model = 1; // model is missing 'foo' should throw. | 2377 var model = 1; // model is missing 'foo' should throw. |
2217 expect(() => outer.createInstance(model, new TestBindingSyntax()), | 2378 expect(() => outer.createInstance(model, new TestBindingSyntax()), |
2218 throwsA(isNoSuchMethodError)); | 2379 throwsA(isNoSuchMethodError)); |
2219 }); | 2380 }); |
2220 | 2381 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2317 return new Future(() { | 2478 return new Future(() { |
2318 expect(template.nextNode.nextNode.nextNode.text, '2'); | 2479 expect(template.nextNode.nextNode.nextNode.text, '2'); |
2319 model['show'] = false; | 2480 model['show'] = false; |
2320 }).then(endOfMicrotask).then((_) { | 2481 }).then(endOfMicrotask).then((_) { |
2321 model['show'] = true; | 2482 model['show'] = true; |
2322 }).then(endOfMicrotask).then((_) { | 2483 }).then(endOfMicrotask).then((_) { |
2323 expect(template.nextNode.nextNode.nextNode.text, '2'); | 2484 expect(template.nextNode.nextNode.nextNode.text, '2'); |
2324 }); | 2485 }); |
2325 }); | 2486 }); |
2326 | 2487 |
| 2488 test('Accessor value retrieval count', () { |
| 2489 var div = createTestHtml( |
| 2490 '<template bind>{{ prop }}</template>'); |
| 2491 |
| 2492 var model = new TestAccessorModel(); |
| 2493 |
| 2494 templateBind(div.firstChild).model = model; |
| 2495 |
| 2496 return new Future(() { |
| 2497 expect(model.count, 1); |
| 2498 |
| 2499 model.value++; |
| 2500 // Dart note: we don't handle getters in @observable, so we need to |
| 2501 // notify regardless. |
| 2502 model.notifyPropertyChange(#prop, 1, model.value); |
| 2503 |
| 2504 }).then(endOfMicrotask).then((_) { |
| 2505 expect(model.count, 2); |
| 2506 }); |
| 2507 }); |
| 2508 |
2327 test('issue-141', () { | 2509 test('issue-141', () { |
2328 var div = createTestHtml( | 2510 var div = createTestHtml( |
2329 '<template bind>' | 2511 '<template bind>' |
2330 '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>' | 2512 '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>' |
2331 '</template>'); | 2513 '</template>'); |
2332 | 2514 |
| 2515 var template = div.firstChild; |
2333 var model = toObservable({ | 2516 var model = toObservable({ |
2334 'foo1': 'foo1Value', | 2517 'foo1': 'foo1Value', |
2335 'foo2': 'foo2Value', | 2518 'foo2': 'foo2Value', |
2336 'bar': 'barValue' | 2519 'bar': 'barValue' |
2337 }); | 2520 }); |
2338 | 2521 |
2339 recursivelySetTemplateModel(div, model); | 2522 templateBind(template).model = model; |
2340 return new Future(() { | 2523 return new Future(() { |
2341 expect(div.lastChild.attributes['bar'], 'barValue'); | 2524 expect(div.lastChild.attributes['bar'], 'barValue'); |
2342 }); | 2525 }); |
2343 }); | 2526 }); |
2344 | 2527 |
2345 test('issue-18', () { | 2528 test('issue-18', () { |
2346 var delegate = new Issue18Syntax(); | 2529 var delegate = new Issue18Syntax(); |
2347 | 2530 |
2348 var div = createTestHtml( | 2531 var div = createTestHtml( |
2349 '<template bind>' | 2532 '<template bind>' |
2350 '<div class="foo: {{ bar }}"></div>' | 2533 '<div class="foo: {{ bar }}"></div>' |
2351 '</template>'); | 2534 '</template>'); |
2352 | 2535 |
| 2536 var template = div.firstChild; |
2353 var model = toObservable({'bar': 2}); | 2537 var model = toObservable({'bar': 2}); |
2354 | 2538 |
2355 recursivelySetTemplateModel(div, model, delegate); | 2539 templateBind(template)..model = model..bindingDelegate = delegate; |
2356 | 2540 |
2357 return new Future(() { | 2541 return new Future(() { |
2358 expect(div.lastChild.attributes['class'], 'foo: 2'); | 2542 expect(div.lastChild.attributes['class'], 'foo: 2'); |
2359 }); | 2543 }); |
2360 }); | 2544 }); |
2361 | 2545 |
2362 test('issue-152', () { | 2546 test('issue-152', () { |
2363 var div = createTestHtml('<template ref=notThere></template>'); | 2547 var div = createTestHtml( |
| 2548 '<template ref=notThere bind>XXX</template>'); |
| 2549 |
2364 var template = div.firstChild; | 2550 var template = div.firstChild; |
| 2551 templateBind(template).model = {}; |
2365 | 2552 |
2366 // if a ref cannot be located, a template will continue to use itself | 2553 return new Future(() { |
2367 // as the source of template instances. | 2554 // if a ref cannot be located, a template will continue to use itself |
2368 expect(template, templateBind(template).ref); | 2555 // as the source of template instances. |
| 2556 expect(div.nodes[1].text, 'XXX'); |
| 2557 }); |
2369 }); | 2558 }); |
2370 } | 2559 } |
2371 | 2560 |
2372 compatTests() { | 2561 compatTests() { |
2373 test('underbar bindings', () { | 2562 test('underbar bindings', () { |
2374 var div = createTestHtml( | 2563 var div = createTestHtml( |
2375 '<template bind>' | 2564 '<template bind>' |
2376 '<div _style="color: {{ color }};"></div>' | 2565 '<div _style="color: {{ color }};"></div>' |
2377 '<img _src="{{ url }}">' | 2566 '<img _src="{{ url }}">' |
2378 '<a _href="{{ url2 }}">Link</a>' | 2567 '<a _href="{{ url2 }}">Link</a>' |
2379 '<input type="number" _value="{{ number }}">' | 2568 '<input type="number" _value="{{ number }}">' |
2380 '</template>'); | 2569 '</template>'); |
2381 | 2570 |
| 2571 var template = div.firstChild; |
2382 var model = toObservable({ | 2572 var model = toObservable({ |
2383 'color': 'red', | 2573 'color': 'red', |
2384 'url': 'pic.jpg', | 2574 'url': 'pic.jpg', |
2385 'url2': 'link.html', | 2575 'url2': 'link.html', |
2386 'number': 4 | 2576 'number': 4 |
2387 }); | 2577 }); |
2388 | 2578 |
2389 recursivelySetTemplateModel(div, model); | 2579 templateBind(template).model = model; |
2390 return new Future(() { | 2580 return new Future(() { |
2391 var subDiv = div.firstChild.nextNode; | 2581 var subDiv = div.firstChild.nextNode; |
2392 expect(subDiv.attributes['style'], 'color: red;'); | 2582 expect(subDiv.attributes['style'], 'color: red;'); |
2393 | 2583 |
2394 var img = subDiv.nextNode; | 2584 var img = subDiv.nextNode; |
2395 expect(img.attributes['src'], 'pic.jpg'); | 2585 expect(img.attributes['src'], 'pic.jpg'); |
2396 | 2586 |
2397 var a = img.nextNode; | 2587 var a = img.nextNode; |
2398 expect(a.attributes['href'], 'link.html'); | 2588 expect(a.attributes['href'], 'link.html'); |
2399 | 2589 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2433 } | 2623 } |
2434 } | 2624 } |
2435 | 2625 |
2436 class Issue18Syntax extends BindingDelegate { | 2626 class Issue18Syntax extends BindingDelegate { |
2437 prepareBinding(path, name, node) { | 2627 prepareBinding(path, name, node) { |
2438 if (name != 'class') return null; | 2628 if (name != 'class') return null; |
2439 | 2629 |
2440 return (model, _, oneTime) => new PathObserver(model, path); | 2630 return (model, _, oneTime) => new PathObserver(model, path); |
2441 } | 2631 } |
2442 } | 2632 } |
| 2633 |
| 2634 class TestAccessorModel extends Observable { |
| 2635 @observable var value = 1; |
| 2636 var count = 0; |
| 2637 |
| 2638 @reflectable |
| 2639 get prop { |
| 2640 count++; |
| 2641 return value; |
| 2642 } |
| 2643 } |
OLD | NEW |