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

Side by Side Diff: pkg/mdv/lib/src/input_bindings.dart

Issue 20149004: [mdv] implement Node.createBinding and Node.createBindings (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
OLDNEW
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 part of mdv; 5 part of mdv;
6 6
7 abstract class _InputBinding { 7 abstract class _InputBinding extends NodeBinding {
8 // InputElement or SelectElement
9 final element;
10 PathObserver binding;
11 StreamSubscription _pathSub;
12 StreamSubscription _eventSub; 8 StreamSubscription _eventSub;
13 9
14 _InputBinding(this.element, model, String path) { 10 _InputBinding(node, name, model, path): super(node, name, model, path) {
15 binding = new PathObserver(model, path); 11 _eventSub = _getStreamForInputType(node).listen(nodeValueChanged);
16 _pathSub = binding.bindSync(valueChanged);
17 _eventSub = _getStreamForInputType(element).listen(updateBinding);
18 } 12 }
19 13
20 void valueChanged(newValue); 14 void boundValueChanged(newValue);
21 15
22 void updateBinding(e); 16 void nodeValueChanged(e);
23 17
24 void unbind() { 18 void close() {
25 binding = null; 19 if (closed) return;
26 _pathSub.cancel();
27 _eventSub.cancel(); 20 _eventSub.cancel();
21 super.close();
28 } 22 }
29 23
30 static EventStreamProvider<Event> _checkboxEventType = () { 24 static EventStreamProvider<Event> _checkboxEventType = () {
31 // Attempt to feature-detect which event (change or click) is fired first 25 // Attempt to feature-detect which event (change or click) is fired first
32 // for checkboxes. 26 // for checkboxes.
33 var div = new DivElement(); 27 var div = new DivElement();
34 var checkbox = div.append(new InputElement()); 28 var checkbox = div.append(new InputElement());
35 checkbox.type = 'checkbox'; 29 checkbox.type = 'checkbox';
36 var fired = []; 30 var fired = [];
37 checkbox.onClick.listen((e) { 31 checkbox.onClick.listen((e) {
(...skipping 16 matching lines...) Expand all
54 case 'select-multiple': 48 case 'select-multiple':
55 case 'select-one': 49 case 'select-one':
56 return element.onChange; 50 return element.onChange;
57 default: 51 default:
58 return element.onInput; 52 return element.onInput;
59 } 53 }
60 } 54 }
61 } 55 }
62 56
63 class _ValueBinding extends _InputBinding { 57 class _ValueBinding extends _InputBinding {
64 _ValueBinding(element, model, path) : super(element, model, path); 58 _ValueBinding(node, model, path) : super(node, 'value', model, path);
65 59
66 void valueChanged(value) { 60 get node => super.node;
Siggi Cherem (dart-lang) 2013/07/25 16:24:12 remove this getter or the 'as dynamic' below?
67 // Note: element can be an InputElement or TextAreaElement. 61
68 element.value = value == null ? '' : '$value'; 62 void boundValueChanged(newValue) {
63 // Note: node can be an InputElement or TextAreaElement. Both have "value".
64 (node as dynamic).value = sanitizeBoundValue(newValue);
69 } 65 }
70 66
71 void updateBinding(e) { 67 void nodeValueChanged(e) {
72 binding.value = element.value; 68 value = (node as dynamic).value;
73 } 69 }
74 } 70 }
75 71
76 class _CheckedBinding extends _InputBinding { 72 class _CheckedBinding extends _InputBinding {
77 _CheckedBinding(element, model, path) : super(element, model, path); 73 _CheckedBinding(node, model, path) : super(node, 'checked', model, path);
78 74
79 InputElement get element => super.element; 75 InputElement get node => super.node;
80 76
81 void valueChanged(value) { 77 void boundValueChanged(newValue) {
82 element.checked = _toBoolean(value); 78 node.checked = _toBoolean(newValue);
83 } 79 }
84 80
85 void updateBinding(e) { 81 void nodeValueChanged(e) {
86 binding.value = element.checked; 82 value = node.checked;
87 83
88 // Only the radio button that is getting checked gets an event. We 84 // Only the radio button that is getting checked gets an event. We
89 // therefore find all the associated radio buttons and update their 85 // therefore find all the associated radio buttons and update their
90 // CheckedBinding manually. 86 // CheckedBinding manually.
91 if (element is InputElement && element.type == 'radio') { 87 if (node is InputElement && node.type == 'radio') {
92 for (var r in _getAssociatedRadioButtons(element)) { 88 for (var r in _getAssociatedRadioButtons(node)) {
93 var checkedBinding = _mdv(r)._checkedBinding; 89 var checkedBinding = r.bindings['checked'];
94 if (checkedBinding != null) { 90 if (checkedBinding != null) {
95 // Set the value directly to avoid an infinite call stack. 91 // Set the value directly to avoid an infinite call stack.
96 checkedBinding.binding.value = false; 92 checkedBinding.value = false;
97 } 93 }
98 } 94 }
99 } 95 }
100 } 96 }
101 97
102 // |element| is assumed to be an HTMLInputElement with |type| == 'radio'. 98 // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
103 // Returns an array containing all radio buttons other than |element| that 99 // Returns an array containing all radio buttons other than |element| that
104 // have the same |name|, either in the form that |element| belongs to or, 100 // have the same |name|, either in the form that |element| belongs to or,
105 // if no form, in the document tree to which |element| belongs. 101 // if no form, in the document tree to which |element| belongs.
106 // 102 //
(...skipping 21 matching lines...) Expand all
128 static bool _isNodeInDocument(Node node) { 124 static bool _isNodeInDocument(Node node) {
129 // On non-IE this works: 125 // On non-IE this works:
130 // return node.document.contains(node); 126 // return node.document.contains(node);
131 var document = node.document; 127 var document = node.document;
132 if (node == document || node.parentNode == document) return true; 128 if (node == document || node.parentNode == document) return true;
133 return document.documentElement.contains(node); 129 return document.documentElement.contains(node);
134 } 130 }
135 } 131 }
136 132
137 class _SelectedIndexBinding extends _InputBinding { 133 class _SelectedIndexBinding extends _InputBinding {
138 _SelectedIndexBinding(element, model, path) : super(element, model, path); 134 _SelectedIndexBinding(node, model, path)
135 : super(node, 'selectedIndex', model, path);
139 136
140 SelectElement get element => super.element; 137 SelectElement get node => super.node;
141 138
142 void valueChanged(value) { 139 void boundValueChanged(value) {
143 var newValue = _toInt(value); 140 var newValue = _toInt(value);
144 if (newValue <= element.length) { 141 if (newValue <= node.length) {
145 element.selectedIndex = newValue; 142 node.selectedIndex = newValue;
146 return; 143 return;
147 } 144 }
148 145
149 // The binding may wish to bind to an <option> which has not yet been 146 // The binding may wish to bind to an <option> which has not yet been
150 // produced by a child <template>. Furthermore, we may need to wait for 147 // produced by a child <template>. Furthermore, we may need to wait for
151 // <optgroup> iterating and then for <option>. 148 // <optgroup> iterating and then for <option>.
152 // 149 //
153 // Unlike the JavaScript MDV, we don't have a special "Object.observe" event 150 // Unlike the JavaScript MDV, we don't have a special "Object.observe" event
154 // loop to schedule on. (See the the "ensureScheduled" function: 151 // loop to schedule on. (See the the "ensureScheduled" function:
155 // https://github.com/Polymer/mdv/commit/9a51ad7ed74a292bf71662cea28acbd151f f65c8) 152 // https://github.com/Polymer/mdv/commit/9a51ad7ed74a292bf71662cea28acbd151f f65c8)
156 // 153 //
157 // Instead we use runAsync. Each <template repeat> needs a delay of 2: 154 // Instead we use runAsync. Each <template repeat> needs a delay of 2:
158 // * once to happen after the child _TemplateIterator is created 155 // * once to happen after the child _TemplateIterator is created
159 // * once to be after _TemplateIterator.inputs CompoundBinding resolve 156 // * once to be after _TemplateIterator.inputs CompoundBinding resolve
160 // And then we need to do this delay sequence twice: 157 // And then we need to do this delay sequence twice:
161 // * once for OPTGROUP 158 // * once for OPTGROUP
162 // * once for OPTION. 159 // * once for OPTION.
163 // The resulting 2 * 2 is our maxRetries. 160 // The resulting 2 * 2 is our maxRetries.
164 var maxRetries = 4; 161 var maxRetries = 4;
165 delaySetSelectedIndex() { 162 delaySetSelectedIndex() {
166 if (newValue > element.length && --maxRetries >= 0) { 163 if (newValue > node.length && --maxRetries >= 0) {
167 runAsync(delaySetSelectedIndex); 164 runAsync(delaySetSelectedIndex);
168 } else { 165 } else {
169 element.selectedIndex = newValue; 166 node.selectedIndex = newValue;
170 } 167 }
171 } 168 }
172 169
173 runAsync(delaySetSelectedIndex); 170 runAsync(delaySetSelectedIndex);
174 } 171 }
175 172
176 void updateBinding(e) { 173 void nodeValueChanged(e) {
177 binding.value = element.selectedIndex; 174 value = node.selectedIndex;
178 } 175 }
179 176
180 // TODO(jmesserly,sigmund): I wonder how many bindings typically convert from 177 // TODO(jmesserly,sigmund): I wonder how many bindings typically convert from
181 // one type to another (e.g. value-as-number) and whether it is useful to 178 // one type to another (e.g. value-as-number) and whether it is useful to
182 // have something like a int/num binding converter (either as a base class or 179 // have something like a int/num binding converter (either as a base class or
183 // a wrapper). 180 // a wrapper).
184 static int _toInt(value) { 181 static int _toInt(value) {
185 if (value is String) return int.parse(value, onError: (_) => null); 182 if (value is String) return int.parse(value, onError: (_) => null);
186 return value is int ? value : null; 183 return value is int ? value : null;
187 } 184 }
188 } 185 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698