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

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

Issue 19593006: [mdv] Implement two-way binding to HTMLTextArea.value (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 /** Extensions to the [InputElement] API. */ 7 /** Extensions to the [InputElement] API. */
8 class _InputElementExtension extends _ElementExtension { 8 class _InputElementExtension extends _ElementExtension {
9 _ValueBinding _valueBinding;
10 _CheckedBinding _checkedBinding;
11
9 _InputElementExtension(InputElement node) : super(node); 12 _InputElementExtension(InputElement node) : super(node);
10 13
11 InputElement get node => super.node; 14 InputElement get node => super.node;
12 15
13 _ValueBinding _valueBinding;
14
15 _CheckedBinding _checkedBinding;
16
17 void bind(String name, model, String path) { 16 void bind(String name, model, String path) {
18 switch (name) { 17 switch (name.toLowerCase()) {
19 case 'value': 18 case 'value':
20 unbind('value'); 19 unbind('value');
21 node.attributes.remove('value'); 20 node.attributes.remove('value');
22 _valueBinding = new _ValueBinding(node, model, path); 21 _valueBinding = new _ValueBinding(node, model, path);
23 break; 22 break;
24 case 'checked': 23 case 'checked':
25 unbind('checked'); 24 unbind('checked');
26 node.attributes.remove('checked'); 25 node.attributes.remove('checked');
27 _checkedBinding = new _CheckedBinding(node, model, path); 26 _checkedBinding = new _CheckedBinding(node, model, path);
28 break; 27 break;
29 default: 28 default:
30 super.bind(name, model, path); 29 super.bind(name, model, path);
31 break; 30 break;
32 } 31 }
33 } 32 }
34 33
35 void unbind(String name) { 34 void unbind(String name) {
36 switch (name) { 35 switch (name.toLowerCase()) {
37 case 'value': 36 case 'value':
38 if (_valueBinding != null) { 37 if (_valueBinding != null) {
39 _valueBinding.unbind(); 38 _valueBinding.unbind();
40 _valueBinding = null; 39 _valueBinding = null;
41 } 40 }
42 break; 41 break;
43 case 'checked': 42 case 'checked':
44 if (_checkedBinding != null) { 43 if (_checkedBinding != null) {
45 _checkedBinding.unbind(); 44 _checkedBinding.unbind();
46 _checkedBinding = null; 45 _checkedBinding = null;
47 } 46 }
48 break; 47 break;
49 default: 48 default:
50 super.unbind(name); 49 super.unbind(name);
51 break; 50 break;
52 } 51 }
53 } 52 }
54 53
55 void unbindAll() { 54 void unbindAll() {
56 unbind('value'); 55 unbind('value');
57 unbind('checked'); 56 unbind('checked');
58 super.unbindAll(); 57 super.unbindAll();
59 } 58 }
60 } 59 }
61
62 class _ValueBinding extends _InputBinding {
63 _ValueBinding(element, model, path) : super(element, model, path);
64
65 InputElement get element => super.element;
66
67 void valueChanged(value) {
68 element.value = value == null ? '' : '$value';
69 }
70
71 void updateBinding(e) {
72 binding.value = element.value;
73 }
74 }
75
76 class _CheckedBinding extends _InputBinding {
77 _CheckedBinding(element, model, path) : super(element, model, path);
78
79 InputElement get element => super.element;
80
81 void valueChanged(value) {
82 element.checked = _toBoolean(value);
83 }
84
85 void updateBinding(e) {
86 binding.value = element.checked;
87
88 // Only the radio button that is getting checked gets an event. We
89 // therefore find all the associated radio buttons and update their
90 // CheckedBinding manually.
91 if (element is InputElement && element.type == 'radio') {
92 for (var r in _getAssociatedRadioButtons(element)) {
93 var checkedBinding = _mdv(r)._checkedBinding;
94 if (checkedBinding != null) {
95 // Set the value directly to avoid an infinite call stack.
96 checkedBinding.binding.value = false;
97 }
98 }
99 }
100 }
101
102 // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
103 // 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,
105 // if no form, in the document tree to which |element| belongs.
106 //
107 // This implementation is based upon the HTML spec definition of a
108 // "radio button group":
109 // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state. html#radio-button-group
110 //
111 static Iterable _getAssociatedRadioButtons(element) {
112 if (!_isNodeInDocument(element)) return [];
113 if (element.form != null) {
114 return element.form.nodes.where((el) {
115 return el != element &&
116 el is InputElement &&
117 el.type == 'radio' &&
118 el.name == element.name;
119 });
120 } else {
121 var radios = element.document.queryAll(
122 'input[type="radio"][name="${element.name}"]');
123 return radios.where((el) => el != element && el.form == null);
124 }
125 }
126
127 // TODO(jmesserly): polyfill document.contains API instead of doing it here
128 static bool _isNodeInDocument(Node node) {
129 // On non-IE this works:
130 // return node.document.contains(node);
131 var document = node.document;
132 if (node == document || node.parentNode == document) return true;
133 return document.documentElement.contains(node);
134 }
135 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698