Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Side by Side Diff: tests/html/custom_element_bindings_test.dart

Issue 17552019: Reorganize mdv and observe packages (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merged Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tests/html/binding_syntax_test.dart ('k') | tests/html/element_bindings_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library custom_element_bindings_test;
6
7 import 'dart:async';
8 import 'dart:html';
9 import 'package:mdv_observe/mdv_observe.dart';
10 import 'package:unittest/html_config.dart';
11 import 'package:unittest/unittest.dart';
12 import 'mdv_observe_utils.dart';
13
14 main() {
15 useHtmlConfiguration();
16 group('Custom Element Bindings', customElementBindingsTest);
17 }
18
19 sym(x) => new Symbol(x);
20
21 customElementBindingsTest() {
22 var testDiv;
23
24 setUp(() {
25 document.body.append(testDiv = new DivElement());
26 });
27
28 tearDown(() {
29 testDiv.remove();
30 testDiv = null;
31 });
32
33 createTestHtml(s) {
34 var div = new DivElement();
35 div.innerHtml = s;
36 testDiv.append(div);
37
38 for (var node in div.queryAll('*')) {
39 if (node.isTemplate) TemplateElement.decorate(node);
40 }
41
42 return div;
43 }
44
45
46 test('override bind/unbind/unbindAll', () {
47 var element = new MyCustomElement();
48 var model = toSymbolMap({'a': new Point(123, 444), 'b': new Monster(100)});
49
50 element.bind('my-point', model, 'a');
51 element.bind('scary-monster', model, 'b');
52
53 expect(element.attributes, isNot(contains('my-point')));
54 expect(element.attributes, isNot(contains('scary-monster')));
55
56 expect(element.myPoint, model[sym('a')]);
57 expect(element.scaryMonster, model[sym('b')]);
58
59 model[sym('a')] = null;
60 deliverChangeRecords();
61 expect(element.myPoint, null);
62 element.unbind('my-point');
63
64 model[sym('a')] = new Point(1, 2);
65 model[sym('b')] = new Monster(200);
66 deliverChangeRecords();
67 expect(element.scaryMonster, model[sym('b')]);
68 expect(element.myPoint, null, reason: 'a was unbound');
69
70 element.unbindAll();
71 model[sym('b')] = null;
72 deliverChangeRecords();
73 expect(element.scaryMonster.health, 200);
74 });
75
76 test('override attribute setter', () {
77 var element = new WithAttrsCustomElement().real;
78 var model = toSymbolMap({'a': 1, 'b': 2});
79 element.bind('hidden?', model, 'a');
80 element.bind('id', model, 'b');
81
82 expect(element.attributes, contains('hidden'));
83 expect(element.attributes['hidden'], '');
84 expect(element.id, '2');
85
86 model[sym('a')] = null;
87 deliverChangeRecords();
88 expect(element.attributes, isNot(contains('hidden')),
89 reason: 'null is false-y');
90
91 model[sym('a')] = false;
92 deliverChangeRecords();
93 expect(element.attributes, isNot(contains('hidden')));
94
95 model[sym('a')] = 'foo';
96 model[sym('b')] = 'x';
97 deliverChangeRecords();
98 expect(element.attributes, contains('hidden'));
99 expect(element.attributes['hidden'], '');
100 expect(element.id, 'x');
101
102 expect(element.xtag.attributes.log, [
103 ['remove', 'hidden?'],
104 ['[]=', 'hidden', ''],
105 ['remove', 'id'],
106 ['[]=', 'id', '2'],
107 ['remove', 'hidden'],
108 ['remove', 'hidden'],
109 ['[]=', 'hidden', ''],
110 ['[]=', 'id', 'x'],
111 ]);
112 });
113
114 test('template bind uses overridden custom element bind', () {
115
116 var model = toSymbolMap({'a': new Point(123, 444), 'b': new Monster(100)});
117
118 var div = createTestHtml('<template bind>'
119 '<my-custom-element my-point="{{a}}" scary-monster="{{b}}">'
120 '</my-custom-element>'
121 '</template>');
122
123 TemplateElement.instanceCreated.listen((fragment) {
124 for (var e in fragment.queryAll('my-custom-element')) {
125 new MyCustomElement.attach(e);
126 }
127 });
128
129 div.query('template').model = model;
130 deliverChangeRecords();
131
132 var element = div.nodes[1];
133
134 expect(element.xtag is MyCustomElement, true,
135 reason: '${element.xtag} should be a MyCustomElement');
136
137 expect(element.xtag.myPoint, model[sym('a')]);
138 expect(element.xtag.scaryMonster, model[sym('b')]);
139
140 expect(element.attributes, isNot(contains('my-point')));
141 expect(element.attributes, isNot(contains('scary-monster')));
142
143 model[sym('a')] = null;
144 deliverChangeRecords();
145 expect(element.xtag.myPoint, null);
146
147 div.query('template').model = null;
148 deliverChangeRecords();
149
150 expect(element.parentNode, null, reason: 'element was detached');
151
152 model[sym('a')] = new Point(1, 2);
153 model[sym('b')] = new Monster(200);
154 deliverChangeRecords();
155
156 expect(element.xtag.myPoint, null, reason: 'model was unbound');
157 expect(element.xtag.scaryMonster.health, 100, reason: 'model was unbound');
158 });
159
160 }
161
162 class Monster {
163 int health;
164 Monster(this.health);
165 }
166
167 /** Demonstrates a custom element overriding bind/unbind/unbindAll. */
168 class MyCustomElement implements Element {
169 final Element real;
170
171 Point myPoint;
172 Monster scaryMonster;
173
174 StreamSubscription _sub1, _sub2;
175
176 MyCustomElement() : this.attach(new Element.tag('my-custom-element'));
177
178 MyCustomElement.attach(this.real) {
179 real.xtag = this;
180 }
181
182
183 get attributes => real.attributes;
184
185 void bind(String name, model, String path) {
186 switch (name) {
187 case 'my-point':
188 unbind('my-point');
189 attributes.remove('my-point');
190
191 _sub1 = new PathObserver(model, path).bindSync((v) {
192 myPoint = v;
193 });
194 return;
195 case 'scary-monster':
196 unbind('scary-monster');
197 attributes.remove('scary-monster');
198
199 _sub2 = new PathObserver(model, path).bindSync((v) {
200 scaryMonster = v;
201 });
202 return;
203 }
204 real.bind(name, model, path);
205 }
206
207 void unbind(String name) {
208 switch (name) {
209 case 'my-point':
210 if (_sub1 != null) {
211 print('!!! unbind $name');
212 _sub1.cancel();
213 _sub1 = null;
214 }
215 return;
216 case 'scary-monster':
217 if (_sub2 != null) {
218 print('!!! unbind $name');
219 _sub2.cancel();
220 _sub2 = null;
221 }
222 return;
223 }
224 real.unbind(name);
225 }
226
227 void unbindAll() {
228 unbind('my-point');
229 unbind('scary-monster');
230 real.unbindAll();
231 }
232 }
233
234 /**
235 * Demonstrates a custom element can override attributes []= and remove.
236 * and see changes that the data binding system is making to the attributes.
237 */
238 class WithAttrsCustomElement implements Element {
239 final Element real;
240 final AttributeMapWrapper<String, String> attributes;
241
242 factory WithAttrsCustomElement() {
243 var real = new Element.tag('with-attrs-custom-element');
244 var attributes = new AttributeMapWrapper(real.attributes);
245 return new WithAttrsCustomElement._(real, attributes);
246 }
247
248 WithAttrsCustomElement._(this.real, this.attributes) {
249 real.xtag = this;
250 }
251
252 void bind(String name, model, String path) => real.bind(name, model, path);
253 void unbind(String name) => real.unbind(name);
254 void unbindAll() => real.unbindAll();
255 }
256
257 // TODO(jmesserly): would be nice to use mocks when mirrors work on dart2js.
258 class AttributeMapWrapper<K, V> implements Map<K, V> {
259 final List log = [];
260 Map<K, V> _map;
261
262 AttributeMapWrapper(this._map);
263
264 bool containsValue(Object value) => _map.containsValue(value);
265 bool containsKey(Object key) => _map.containsKey(key);
266 V operator [](Object key) => _map[key];
267
268 void operator []=(K key, V value) {
269 log.add(['[]=', key, value]);
270 _map[key] = value;
271 }
272
273 V putIfAbsent(K key, V ifAbsent()) => _map.putIfAbsent(key, ifAbsent);
274
275 V remove(Object key) {
276 log.add(['remove', key]);
277 _map.remove(key);
278 }
279
280 void clear() => _map.clear();
281 void forEach(void f(K key, V value)) => _map.forEach(f);
282 Iterable<K> get keys => _map.keys;
283 Iterable<V> get values => _map.values;
284 int get length => _map.length;
285 bool get isEmpty => _map.isEmpty;
286 bool get isNotEmpty => _map.isNotEmpty;
287 }
OLDNEW
« no previous file with comments | « tests/html/binding_syntax_test.dart ('k') | tests/html/element_bindings_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698