| 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 /** Extensions to the [SelectElement] API. */ | 7 /** Extensions to the [SelectElement] API. */ |
| 8 class _SelectElementExtension extends _ElementExtension { | 8 class _SelectElementExtension extends _ElementExtension { |
| 9 _SelectedIndexBinding _valueBinding; |
| 10 |
| 9 _SelectElementExtension(SelectElement node) : super(node); | 11 _SelectElementExtension(SelectElement node) : super(node); |
| 10 | 12 |
| 11 SelectElement get node => super.node; | 13 SelectElement get node => super.node; |
| 12 | 14 |
| 13 _SelectedIndexBinding _valueBinding; | |
| 14 | |
| 15 void bind(String name, model, String path) { | 15 void bind(String name, model, String path) { |
| 16 if (name.toLowerCase() == 'selectedindex') { | 16 if (name.toLowerCase() == 'selectedindex') { |
| 17 unbind('selectedindex'); | 17 unbind('selectedindex'); |
| 18 node.attributes.remove('selectedindex'); | 18 node.attributes.remove('selectedindex'); |
| 19 _valueBinding = new _SelectedIndexBinding(node, model, path); | 19 _valueBinding = new _SelectedIndexBinding(node, model, path); |
| 20 return; | 20 return; |
| 21 } | 21 } |
| 22 super.bind(name, model, path); | 22 super.bind(name, model, path); |
| 23 } | 23 } |
| 24 | 24 |
| 25 void unbind(String name) { | 25 void unbind(String name) { |
| 26 if (name.toLowerCase() == 'selectedindex' && _valueBinding != null) { | 26 if (name.toLowerCase() == 'selectedindex' && _valueBinding != null) { |
| 27 _valueBinding.unbind(); | 27 _valueBinding.unbind(); |
| 28 _valueBinding = null; | 28 _valueBinding = null; |
| 29 return; | 29 return; |
| 30 } | 30 } |
| 31 super.unbind(name); | 31 super.unbind(name); |
| 32 } | 32 } |
| 33 | 33 |
| 34 void unbindAll() { | 34 void unbindAll() { |
| 35 unbind('selectedindex'); | 35 unbind('selectedindex'); |
| 36 super.unbindAll(); | 36 super.unbindAll(); |
| 37 } | 37 } |
| 38 } | 38 } |
| 39 | |
| 40 | |
| 41 class _SelectedIndexBinding extends _InputBinding { | |
| 42 _SelectedIndexBinding(element, model, path) : super(element, model, path); | |
| 43 | |
| 44 SelectElement get element => super.element; | |
| 45 | |
| 46 void valueChanged(value) { | |
| 47 var newValue = _toInt(value); | |
| 48 if (newValue <= element.length) { | |
| 49 element.selectedIndex = newValue; | |
| 50 return; | |
| 51 } | |
| 52 | |
| 53 // The binding may wish to bind to an <option> which has not yet been | |
| 54 // produced by a child <template>. Furthermore, we may need to wait for | |
| 55 // <optgroup> iterating and then for <option>. | |
| 56 // | |
| 57 // Unlike the JavaScript MDV, we don't have a special "Object.observe" event | |
| 58 // loop to schedule on. (See the the "ensureScheduled" function: | |
| 59 // https://github.com/Polymer/mdv/commit/9a51ad7ed74a292bf71662cea28acbd151f
f65c8) | |
| 60 // | |
| 61 // Instead we use runAsync. Each <template repeat> needs a delay of 3: | |
| 62 // * once to happen after the child _TemplateIterator is created | |
| 63 // * once to be after _TemplateIterator.inputs CompoundBinding resolve | |
| 64 // * once to be after _TemplateIterator._valueBinding PathObserver fires | |
| 65 // And then we need to do this delay sequence twice: | |
| 66 // * once for OPTGROUP | |
| 67 // * once for OPTION. | |
| 68 // The resulting 2 * 3 is our maxRetries. | |
| 69 var maxRetries = 6; | |
| 70 delaySetSelectedIndex() { | |
| 71 if (newValue > element.length && --maxRetries >= 0) { | |
| 72 runAsync(delaySetSelectedIndex); | |
| 73 } else { | |
| 74 element.selectedIndex = newValue; | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 runAsync(delaySetSelectedIndex); | |
| 79 } | |
| 80 | |
| 81 void updateBinding(e) { | |
| 82 binding.value = element.selectedIndex; | |
| 83 } | |
| 84 | |
| 85 // TODO(jmesserly,sigmund): I wonder how many bindings typically convert from | |
| 86 // one type to another (e.g. value-as-number) and whether it is useful to | |
| 87 // have something like a int/num binding converter (either as a base class or | |
| 88 // a wrapper). | |
| 89 static int _toInt(value) { | |
| 90 if (value is String) return int.parse(value, onError: (_) => null); | |
| 91 return value is int ? value : null; | |
| 92 } | |
| 93 } | |
| OLD | NEW |