Chromium Code Reviews| 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 part of mdv; | 5 part of mdv; |
| 6 | 6 |
| 7 // This code is a port of Model-Driven-Views: | 7 // This code is a port of Model-Driven-Views: |
| 8 // https://github.com/polymer-project/mdv | 8 // https://github.com/polymer-project/mdv |
| 9 // The code mostly comes from src/template_element.js | 9 // The code mostly comes from src/template_element.js |
| 10 | 10 |
| 11 typedef void _ChangeHandler(value); | 11 typedef void _ChangeHandler(value); |
| 12 | 12 |
| 13 abstract class _InputBinding { | 13 abstract class _InputBinding { |
| 14 final InputElement element; | 14 // InputElement or SelectElement |
| 15 final element; | |
| 15 PathObserver binding; | 16 PathObserver binding; |
| 16 StreamSubscription _pathSub; | 17 StreamSubscription _pathSub; |
| 17 StreamSubscription _eventSub; | 18 StreamSubscription _eventSub; |
| 18 | 19 |
| 19 _InputBinding(this.element, model, String path) { | 20 _InputBinding(this.element, model, String path) { |
| 20 binding = new PathObserver(model, path); | 21 binding = new PathObserver(model, path); |
| 21 _pathSub = binding.bindSync(valueChanged); | 22 _pathSub = binding.bindSync(valueChanged); |
| 22 _eventSub = _getStreamForInputType(element).listen(updateBinding); | 23 _eventSub = _getStreamForInputType(element).listen(updateBinding); |
| 23 } | 24 } |
| 24 | 25 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 44 }); | 45 }); |
| 45 checkbox.onChange.listen((e) { | 46 checkbox.onChange.listen((e) { |
| 46 fired.add(Element.changeEvent); | 47 fired.add(Element.changeEvent); |
| 47 }); | 48 }); |
| 48 checkbox.dispatchEvent(new MouseEvent('click', view: window)); | 49 checkbox.dispatchEvent(new MouseEvent('click', view: window)); |
| 49 // WebKit/Blink don't fire the change event if the element is outside the | 50 // WebKit/Blink don't fire the change event if the element is outside the |
| 50 // document, so assume 'change' for that case. | 51 // document, so assume 'change' for that case. |
| 51 return fired.length == 1 ? Element.changeEvent : fired.first; | 52 return fired.length == 1 ? Element.changeEvent : fired.first; |
| 52 }(); | 53 }(); |
| 53 | 54 |
| 54 static Stream<Event> _getStreamForInputType(InputElement element) { | 55 static Stream<Event> _getStreamForInputType(element) { |
| 55 switch (element.type) { | 56 switch (element.type) { |
| 56 case 'checkbox': | 57 case 'checkbox': |
| 57 return _checkboxEventType.forTarget(element); | 58 return _checkboxEventType.forTarget(element); |
| 58 case 'radio': | 59 case 'radio': |
| 59 case 'select-multiple': | 60 case 'select-multiple': |
| 60 case 'select-one': | 61 case 'select-one': |
| 61 return element.onChange; | 62 return element.onChange; |
| 62 default: | 63 default: |
| 63 return element.onInput; | 64 return element.onInput; |
| 64 } | 65 } |
| 65 } | 66 } |
| 66 } | 67 } |
| 67 | 68 |
| 68 class _ValueBinding extends _InputBinding { | |
|
Jennifer Messerly
2013/06/27 23:59:48
these just moved to input_element
| |
| 69 _ValueBinding(element, model, path) : super(element, model, path); | |
| 70 | |
| 71 void valueChanged(value) { | |
| 72 element.value = value == null ? '' : '$value'; | |
| 73 } | |
| 74 | |
| 75 void updateBinding(e) { | |
| 76 binding.value = element.value; | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 class _CheckedBinding extends _InputBinding { | |
| 81 _CheckedBinding(element, model, path) : super(element, model, path); | |
| 82 | |
| 83 void valueChanged(value) { | |
| 84 element.checked = _Bindings._toBoolean(value); | |
| 85 } | |
| 86 | |
| 87 void updateBinding(e) { | |
| 88 binding.value = element.checked; | |
| 89 | |
| 90 // Only the radio button that is getting checked gets an event. We | |
| 91 // therefore find all the associated radio buttons and update their | |
| 92 // CheckedBinding manually. | |
| 93 if (element is InputElement && element.type == 'radio') { | |
| 94 for (var r in _getAssociatedRadioButtons(element)) { | |
| 95 var checkedBinding = _mdv(r)._checkedBinding; | |
| 96 if (checkedBinding != null) { | |
| 97 // Set the value directly to avoid an infinite call stack. | |
| 98 checkedBinding.binding.value = false; | |
| 99 } | |
| 100 } | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 // |element| is assumed to be an HTMLInputElement with |type| == 'radio'. | |
| 105 // Returns an array containing all radio buttons other than |element| that | |
| 106 // have the same |name|, either in the form that |element| belongs to or, | |
| 107 // if no form, in the document tree to which |element| belongs. | |
| 108 // | |
| 109 // This implementation is based upon the HTML spec definition of a | |
| 110 // "radio button group": | |
| 111 // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state. html#radio-button-group | |
| 112 // | |
| 113 static Iterable _getAssociatedRadioButtons(element) { | |
| 114 if (!_isNodeInDocument(element)) return []; | |
| 115 if (element.form != null) { | |
| 116 return element.form.nodes.where((el) { | |
| 117 return el != element && | |
| 118 el is InputElement && | |
| 119 el.type == 'radio' && | |
| 120 el.name == element.name; | |
| 121 }); | |
| 122 } else { | |
| 123 var radios = element.document.queryAll( | |
| 124 'input[type="radio"][name="${element.name}"]'); | |
| 125 return radios.where((el) => el != element && el.form == null); | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 // TODO(jmesserly): polyfill document.contains API instead of doing it here | |
| 130 static bool _isNodeInDocument(Node node) { | |
| 131 // On non-IE this works: | |
| 132 // return node.document.contains(node); | |
| 133 var document = node.document; | |
| 134 if (node == document || node.parentNode == document) return true; | |
| 135 return document.documentElement.contains(node); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 class _Bindings { | 69 class _Bindings { |
| 140 // TODO(jmesserly): not sure what kind of boolean conversion rules to | 70 // TODO(jmesserly): not sure what kind of boolean conversion rules to |
| 141 // apply for template data-binding. HTML attributes are true if they're | 71 // apply for template data-binding. HTML attributes are true if they're |
| 142 // present. However Dart only treats "true" as true. Since this is HTML we'll | 72 // present. However Dart only treats "true" as true. Since this is HTML we'll |
| 143 // use something closer to the HTML rules: null (missing) and false are false, | 73 // use something closer to the HTML rules: null (missing) and false are false, |
| 144 // everything else is true. See: https://github.com/polymer-project/mdv/issues /59 | 74 // everything else is true. See: https://github.com/polymer-project/mdv/issues /59 |
| 145 static bool _toBoolean(value) => null != value && false != value; | 75 static bool _toBoolean(value) => null != value && false != value; |
| 146 | 76 |
| 147 static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) { | 77 static Node _createDeepCloneAndDecorateTemplates(Node node, String syntax) { |
| 148 var clone = node.clone(false); // Shallow clone. | 78 var clone = node.clone(false); // Shallow clone. |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 504 nodeExt._templateIterator = null; | 434 nodeExt._templateIterator = null; |
| 505 } | 435 } |
| 506 } | 436 } |
| 507 | 437 |
| 508 _Bindings._nodeOrCustom(node).unbindAll(); | 438 _Bindings._nodeOrCustom(node).unbindAll(); |
| 509 for (var c = node.firstChild; c != null; c = c.nextNode) { | 439 for (var c = node.firstChild; c != null; c = c.nextNode) { |
| 510 _unbindAllRecursively(c); | 440 _unbindAllRecursively(c); |
| 511 } | 441 } |
| 512 } | 442 } |
| 513 } | 443 } |
| OLD | NEW |