| 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 observe; | 5 part of observe; |
| 6 | 6 |
| 7 /** The callback used in the [CompoundBinding.combinator] field. */ | 7 /** The callback used in the [CompoundBinding.combinator] field. */ |
| 8 typedef Object CompoundBindingCombinator(Map objects); | 8 typedef Object CompoundBindingCombinator(Map objects); |
| 9 | 9 |
| 10 /** | 10 /** |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 * binding.bind('nameN', objN, pathN); | 27 * binding.bind('nameN', objN, pathN); |
| 28 */ | 28 */ |
| 29 // TODO(jmesserly): rename to something that indicates it's a computed value? | 29 // TODO(jmesserly): rename to something that indicates it's a computed value? |
| 30 class CompoundBinding extends ChangeNotifierBase { | 30 class CompoundBinding extends ChangeNotifierBase { |
| 31 CompoundBindingCombinator _combinator; | 31 CompoundBindingCombinator _combinator; |
| 32 | 32 |
| 33 // TODO(jmesserly): ideally these would be String keys, but sometimes we | 33 // TODO(jmesserly): ideally these would be String keys, but sometimes we |
| 34 // use integers. | 34 // use integers. |
| 35 Map<dynamic, StreamSubscription> _observers = new Map(); | 35 Map<dynamic, StreamSubscription> _observers = new Map(); |
| 36 Map _values = new Map(); | 36 Map _values = new Map(); |
| 37 bool _scheduled = false; | |
| 38 Object _value; | 37 Object _value; |
| 39 | 38 |
| 39 /** |
| 40 * True if [resolve] is scheduled. You can set this to true if you plan to |
| 41 * call [resolve] manually, avoiding the need for scheduling an asynchronous |
| 42 * resolve. |
| 43 */ |
| 44 // TODO(jmesserly): I don't like having this public, is the optimization |
| 45 // really needed? "runAsync" in Dart should be pretty cheap. |
| 46 bool scheduled; |
| 47 |
| 48 /** |
| 49 * Creates a new CompoundBinding, optionally proving the [combinator] function |
| 50 * for computing the value. You can also set [schedule] to true if you plan |
| 51 * to invoke [resolve] manually after initial construction of the binding. |
| 52 */ |
| 40 CompoundBinding([CompoundBindingCombinator combinator]) { | 53 CompoundBinding([CompoundBindingCombinator combinator]) { |
| 41 // TODO(jmesserly): this is a tweak to the original code, it seemed to me | 54 // TODO(jmesserly): this is a tweak to the original code, it seemed to me |
| 42 // that passing the combinator to the constructor should be equivalent to | 55 // that passing the combinator to the constructor should be equivalent to |
| 43 // setting it via the property. | 56 // setting it via the property. |
| 44 // I also added a null check to the combinator setter. | 57 // I also added a null check to the combinator setter. |
| 45 this.combinator = combinator; | 58 this.combinator = combinator; |
| 46 } | 59 } |
| 47 | 60 |
| 48 CompoundBindingCombinator get combinator => _combinator; | 61 CompoundBindingCombinator get combinator => _combinator; |
| 49 | 62 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 79 | 92 |
| 80 binding.cancel(); | 93 binding.cancel(); |
| 81 _values.remove(name); | 94 _values.remove(name); |
| 82 if (!suppressResolve) _scheduleResolve(); | 95 if (!suppressResolve) _scheduleResolve(); |
| 83 } | 96 } |
| 84 | 97 |
| 85 // TODO(rafaelw): Is this the right processing model? | 98 // TODO(rafaelw): Is this the right processing model? |
| 86 // TODO(rafaelw): Consider having a seperate ChangeSummary for | 99 // TODO(rafaelw): Consider having a seperate ChangeSummary for |
| 87 // CompoundBindings so to excess dirtyChecks. | 100 // CompoundBindings so to excess dirtyChecks. |
| 88 void _scheduleResolve() { | 101 void _scheduleResolve() { |
| 89 if (_scheduled) return; | 102 if (scheduled) return; |
| 90 _scheduled = true; | 103 scheduled = true; |
| 91 runAsync(resolve); | 104 runAsync(resolve); |
| 92 } | 105 } |
| 93 | 106 |
| 94 void resolve() { | 107 void resolve() { |
| 95 if (_observers.isEmpty) return; | 108 if (_observers.isEmpty) return; |
| 96 _scheduled = false; | 109 scheduled = false; |
| 97 | 110 |
| 98 if (_combinator == null) { | 111 if (_combinator == null) { |
| 99 throw new StateError( | 112 throw new StateError( |
| 100 'CompoundBinding attempted to resolve without a combinator'); | 113 'CompoundBinding attempted to resolve without a combinator'); |
| 101 } | 114 } |
| 102 | 115 |
| 103 value = _combinator(_values); | 116 value = _combinator(_values); |
| 104 } | 117 } |
| 105 | 118 |
| 106 /** | 119 /** |
| 107 * Closes the observer. | 120 * Closes the observer. |
| 108 * | 121 * |
| 109 * This happens automatically if the [value] property is no longer observed, | 122 * This happens automatically if the [value] property is no longer observed, |
| 110 * but this can also be called explicitly. | 123 * but this can also be called explicitly. |
| 111 */ | 124 */ |
| 112 void close() { | 125 void close() { |
| 113 for (var binding in _observers.values) { | 126 for (var binding in _observers.values) { |
| 114 binding.cancel(); | 127 binding.cancel(); |
| 115 } | 128 } |
| 116 _observers.clear(); | 129 _observers.clear(); |
| 117 _values.clear(); | 130 _values.clear(); |
| 118 value = null; | 131 value = null; |
| 119 } | 132 } |
| 120 | 133 |
| 121 _unobserved() => close(); | 134 _unobserved() => close(); |
| 122 } | 135 } |
| OLD | NEW |