| 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 /** | 7 /** |
| 8 * Use `@observable` to make a field automatically observable. | 8 * Use `@observable` to make a field automatically observable. |
| 9 */ | 9 */ |
| 10 const Object observable = const _ObservableAnnotation(); | 10 const Object observable = const _ObservableAnnotation(); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 * When a field, property, or indexable item is changed, the change record | 90 * When a field, property, or indexable item is changed, the change record |
| 91 * will be sent to [changes]. | 91 * will be sent to [changes]. |
| 92 */ | 92 */ |
| 93 abstract class ObservableMixin implements Observable { | 93 abstract class ObservableMixin implements Observable { |
| 94 StreamController _changes; | 94 StreamController _changes; |
| 95 InstanceMirror _mirror; | 95 InstanceMirror _mirror; |
| 96 | 96 |
| 97 Map<Symbol, Object> _values; | 97 Map<Symbol, Object> _values; |
| 98 List<ChangeRecord> _records; | 98 List<ChangeRecord> _records; |
| 99 | 99 |
| 100 static final _objectType = reflectClass(Object); |
| 101 |
| 100 Stream<List<ChangeRecord>> get changes { | 102 Stream<List<ChangeRecord>> get changes { |
| 101 if (_changes == null) { | 103 if (_changes == null) { |
| 102 _changes = new StreamController.broadcast(sync: true, | 104 _changes = new StreamController.broadcast(sync: true, |
| 103 onListen: _observed, onCancel: _unobserved); | 105 onListen: _observed, onCancel: _unobserved); |
| 104 } | 106 } |
| 105 return _changes.stream; | 107 return _changes.stream; |
| 106 } | 108 } |
| 107 | 109 |
| 108 bool get hasObservers => _changes != null && _changes.hasListener; | 110 bool get hasObservers => _changes != null && _changes.hasListener; |
| 109 | 111 |
| 110 void _observed() { | 112 void _observed() { |
| 111 // Register this object for dirty checking purposes. | 113 // Register this object for dirty checking purposes. |
| 112 registerObservable(this); | 114 registerObservable(this); |
| 113 | 115 |
| 114 var mirror = reflect(this); | 116 var mirror = reflect(this); |
| 115 var values = new Map<Symbol, Object>(); | 117 var values = new Map<Symbol, Object>(); |
| 116 | 118 |
| 117 // TODO(jmesserly): this should consider the superclass. Unfortunately | 119 // Note: we scan for @observable regardless of whether the base type |
| 118 // that is not possible right now because of: | 120 // actually includes this mixin. While perhaps too inclusive, it lets us |
| 119 // http://code.google.com/p/dart/issues/detail?id=9434 | 121 // avoid complex logic that walks "with" and "implements" clauses. |
| 120 for (var field in mirror.type.variables.values) { | 122 for (var type = mirror.type; type != _objectType; type = type.superclass) { |
| 121 if (field.isFinal || field.isStatic || field.isPrivate) continue; | 123 for (var field in type.variables.values) { |
| 124 if (field.isFinal || field.isStatic || field.isPrivate) continue; |
| 122 | 125 |
| 123 for (var meta in field.metadata) { | 126 for (var meta in field.metadata) { |
| 124 if (identical(observable, meta.reflectee)) { | 127 if (identical(observable, meta.reflectee)) { |
| 125 var name = field.simpleName; | 128 var name = field.simpleName; |
| 126 // Note: since this is a field, getting the value shouldn't execute | 129 // Note: since this is a field, getting the value shouldn't execute |
| 127 // user code, so we don't need to worry about errors. | 130 // user code, so we don't need to worry about errors. |
| 128 values[name] = mirror.getField(name).reflectee; | 131 values[name] = mirror.getField(name).reflectee; |
| 129 break; | 132 break; |
| 133 } |
| 130 } | 134 } |
| 131 } | 135 } |
| 132 } | 136 } |
| 133 | 137 |
| 134 _mirror = mirror; | 138 _mirror = mirror; |
| 135 _values = values; | 139 _values = values; |
| 136 } | 140 } |
| 137 | 141 |
| 138 /** Release data associated with observation. */ | 142 /** Release data associated with observation. */ |
| 139 void _unobserved() { | 143 void _unobserved() { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 /** | 222 /** |
| 219 * The type of the `@observable` annotation. | 223 * The type of the `@observable` annotation. |
| 220 * | 224 * |
| 221 * Library private because you should be able to use the [observable] field | 225 * Library private because you should be able to use the [observable] field |
| 222 * to get the one and only instance. We could make it public though, if anyone | 226 * to get the one and only instance. We could make it public though, if anyone |
| 223 * needs it for some reason. | 227 * needs it for some reason. |
| 224 */ | 228 */ |
| 225 class _ObservableAnnotation { | 229 class _ObservableAnnotation { |
| 226 const _ObservableAnnotation(); | 230 const _ObservableAnnotation(); |
| 227 } | 231 } |
| OLD | NEW |