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

Side by Side Diff: pkg/mdv/test/custom_element_bindings_test.dart

Issue 34453003: Rename mdv -> template_binding, remove experiemntal apis from dart:html (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 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 | « pkg/mdv/test/binding_syntax_test.dart ('k') | pkg/mdv/test/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:html';
8 import 'package:mdv/mdv.dart' as mdv;
9 import 'package:observe/observe.dart' show toObservable;
10 import 'package:unittest/html_config.dart';
11 import 'package:unittest/unittest.dart';
12 import 'mdv_test_utils.dart';
13
14 main() {
15 mdv.initialize();
16 useHtmlConfiguration();
17 group('Custom Element Bindings', customElementBindingsTest);
18 }
19
20 customElementBindingsTest() {
21 var testDiv;
22
23 setUp(() {
24 document.body.append(testDiv = new DivElement());
25 });
26
27 tearDown(() {
28 testDiv.remove();
29 testDiv = null;
30 });
31
32 createTestHtml(s) {
33 var div = new DivElement();
34 div.setInnerHtml(s, treeSanitizer: new NullTreeSanitizer());
35 testDiv.append(div);
36
37 for (var node in div.queryAll('*')) {
38 if (node.isTemplate) TemplateElement.decorate(node);
39 }
40
41 return div;
42 }
43
44
45 observeTest('override bind/unbind/unbindAll', () {
46 var element = new MyCustomElement();
47 var model = toObservable({'a': new Point(123, 444), 'b': new Monster(100)});
48
49 element.bind('my-point', model, 'a');
50 element.bind('scary-monster', model, 'b');
51
52 expect(element.attributes, isNot(contains('my-point')));
53 expect(element.attributes, isNot(contains('scary-monster')));
54
55 expect(element.myPoint, model['a']);
56 expect(element.scaryMonster, model['b']);
57
58 model['a'] = null;
59 performMicrotaskCheckpoint();
60 expect(element.myPoint, null);
61 element.unbind('my-point');
62
63 model['a'] = new Point(1, 2);
64 model['b'] = new Monster(200);
65 performMicrotaskCheckpoint();
66 expect(element.scaryMonster, model['b']);
67 expect(element.myPoint, null, reason: 'a was unbound');
68
69 element.unbindAll();
70 model['b'] = null;
71 performMicrotaskCheckpoint();
72 expect(element.scaryMonster.health, 200);
73 });
74
75 observeTest('override attribute setter', () {
76 var element = new WithAttrsCustomElement().real;
77 var model = toObservable({'a': 1, 'b': 2});
78 element.bind('hidden?', model, 'a');
79 element.bind('id', model, 'b');
80
81 expect(element.attributes, contains('hidden'));
82 expect(element.attributes['hidden'], '');
83 expect(element.id, '2');
84
85 model['a'] = null;
86 performMicrotaskCheckpoint();
87 expect(element.attributes, isNot(contains('hidden')),
88 reason: 'null is false-y');
89
90 model['a'] = false;
91 performMicrotaskCheckpoint();
92 expect(element.attributes, isNot(contains('hidden')));
93
94 model['a'] = 'foo';
95 // TODO(jmesserly): this is here to force an ordering between the two
96 // changes. Otherwise the order depends on what order StreamController
97 // chooses to fire the two listeners in.
98 performMicrotaskCheckpoint();
99
100 model['b'] = 'x';
101 performMicrotaskCheckpoint();
102 expect(element.attributes, contains('hidden'));
103 expect(element.attributes['hidden'], '');
104 expect(element.id, 'x');
105
106 expect(element.xtag.attributes.log, [
107 ['remove', 'hidden?'],
108 ['[]=', 'hidden', ''],
109 ['[]=', 'id', '2'],
110 ['remove', 'hidden'],
111 ['remove', 'hidden'],
112 ['[]=', 'hidden', ''],
113 ['[]=', 'id', 'x'],
114 ]);
115 });
116
117 observeTest('template bind uses overridden custom element bind', () {
118
119 var model = toObservable({'a': new Point(123, 444), 'b': new Monster(100)});
120
121 var div = createTestHtml('<template bind>'
122 '<my-custom-element my-point="{{a}}" scary-monster="{{b}}">'
123 '</my-custom-element>'
124 '</template>');
125
126 callback(fragment) {
127 for (var e in fragment.queryAll('my-custom-element')) {
128 new MyCustomElement.attach(e);
129 }
130 }
131 mdv.instanceCreated.add(callback);
132
133 div.query('template').model = model;
134 performMicrotaskCheckpoint();
135
136 var element = div.nodes[1];
137
138 expect(element.xtag is MyCustomElement, true,
139 reason: '${element.xtag} should be a MyCustomElement');
140
141 expect(element.xtag.myPoint, model['a']);
142 expect(element.xtag.scaryMonster, model['b']);
143
144 expect(element.attributes, isNot(contains('my-point')));
145 expect(element.attributes, isNot(contains('scary-monster')));
146
147 model['a'] = null;
148 performMicrotaskCheckpoint();
149 expect(element.xtag.myPoint, null);
150
151 div.query('template').model = null;
152 performMicrotaskCheckpoint();
153
154 expect(element.parentNode, null, reason: 'element was detached');
155
156 model['a'] = new Point(1, 2);
157 model['b'] = new Monster(200);
158 performMicrotaskCheckpoint();
159
160 expect(element.xtag.myPoint, null, reason: 'model was unbound');
161 expect(element.xtag.scaryMonster.health, 100, reason: 'model was unbound');
162
163 mdv.instanceCreated.remove(callback);
164 });
165
166 }
167
168 class Monster {
169 int health;
170 Monster(this.health);
171 }
172
173 /** Demonstrates a custom element overriding bind/unbind/unbindAll. */
174 class MyCustomElement implements Element {
175 final Element real;
176
177 Point myPoint;
178 Monster scaryMonster;
179
180 MyCustomElement() : this.attach(new Element.tag('my-custom-element'));
181
182 MyCustomElement.attach(this.real) {
183 real.xtag = this;
184 }
185
186 get attributes => real.attributes;
187 get bindings => real.bindings;
188
189 NodeBinding createBinding(String name, model, String path) {
190 switch (name) {
191 case 'my-point':
192 case 'scary-monster':
193 return new _MyCustomBinding(this, name, model, path);
194 }
195 return real.createBinding(name, model, path);
196 }
197
198 bind(String name, model, String path) => real.bind(name, model, path);
199 void unbind(String name) => real.unbind(name);
200 void unbindAll() => real.unbindAll();
201 }
202
203 class _MyCustomBinding extends mdv.NodeBinding {
204 _MyCustomBinding(MyCustomElement node, property, model, path)
205 : super(node, property, model, path) {
206
207 node.attributes.remove(property);
208 }
209
210 MyCustomElement get node => super.node;
211
212 void boundValueChanged(newValue) {
213 if (property == 'my-point') node.myPoint = newValue;
214 if (property == 'scary-monster') node.scaryMonster = newValue;
215 }
216 }
217
218
219 /**
220 * Demonstrates a custom element can override attributes []= and remove.
221 * and see changes that the data binding system is making to the attributes.
222 */
223 class WithAttrsCustomElement implements Element {
224 final Element real;
225 final AttributeMapWrapper<String, String> attributes;
226
227 factory WithAttrsCustomElement() {
228 var real = new Element.tag('with-attrs-custom-element');
229 var attributes = new AttributeMapWrapper(real.attributes);
230 return new WithAttrsCustomElement._(real, attributes);
231 }
232
233 WithAttrsCustomElement._(this.real, this.attributes) {
234 real.xtag = this;
235 }
236
237 createBinding(String name, model, String path) =>
238 real.createBinding(name, model, path);
239 bind(String name, model, String path) => real.bind(name, model, path);
240 void unbind(String name) => real.unbind(name);
241 void unbindAll() => real.unbindAll();
242 }
243
244 // TODO(jmesserly): would be nice to use mocks when mirrors work on dart2js.
245 class AttributeMapWrapper<K, V> implements Map<K, V> {
246 final List log = [];
247 Map<K, V> _map;
248
249 AttributeMapWrapper(this._map);
250
251 bool containsValue(Object value) => _map.containsValue(value);
252 bool containsKey(Object key) => _map.containsKey(key);
253 V operator [](Object key) => _map[key];
254
255 void operator []=(K key, V value) {
256 log.add(['[]=', key, value]);
257 _map[key] = value;
258 }
259
260 V putIfAbsent(K key, V ifAbsent()) => _map.putIfAbsent(key, ifAbsent);
261
262 V remove(Object key) {
263 log.add(['remove', key]);
264 _map.remove(key);
265 }
266
267 void clear() => _map.clear();
268 void forEach(void f(K key, V value)) => _map.forEach(f);
269 Iterable<K> get keys => _map.keys;
270 Iterable<V> get values => _map.values;
271 int get length => _map.length;
272 bool get isEmpty => _map.isEmpty;
273 bool get isNotEmpty => _map.isNotEmpty;
274 }
275
276 /**
277 * Sanitizer which does nothing.
278 */
279 class NullTreeSanitizer implements NodeTreeSanitizer {
280 void sanitizeTree(Node node) {}
281 }
OLDNEW
« no previous file with comments | « pkg/mdv/test/binding_syntax_test.dart ('k') | pkg/mdv/test/element_bindings_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698