| Index: pkg/observe/lib/src/path_observer.dart
|
| diff --git a/pkg/observe/lib/src/path_observer.dart b/pkg/observe/lib/src/path_observer.dart
|
| index c6e0be02bc30869968f14ca8d61dbf16d5144461..1b6e1a34dc1a80b7638bf918a0897b763616e81a 100644
|
| --- a/pkg/observe/lib/src/path_observer.dart
|
| +++ b/pkg/observe/lib/src/path_observer.dart
|
| @@ -21,7 +21,7 @@ part of observe;
|
| *
|
| * This class is used to implement [Node.bind] and similar functionality.
|
| */
|
| -class PathObserver extends ChangeNotifierBase {
|
| +class PathObserver extends ChangeNotifier {
|
| /** The path string. */
|
| final String path;
|
|
|
| @@ -119,21 +119,19 @@ class PathObserver extends ChangeNotifierBase {
|
| }
|
|
|
| void _updateObservedValues([int start = 0]) {
|
| - bool changed = false;
|
| + var oldValue, newValue;
|
| for (int i = start; i < _segments.length; i++) {
|
| - final newValue = _getObjectProperty(_values[i], _segments[i]);
|
| - if (identical(_values[i + 1], newValue)) {
|
| + oldValue = _values[i + 1];
|
| + newValue = _getObjectProperty(_values[i], _segments[i]);
|
| + if (identical(oldValue, newValue)) {
|
| _observePath(start, i);
|
| return;
|
| }
|
| _values[i + 1] = newValue;
|
| - changed = true;
|
| }
|
|
|
| _observePath(start);
|
| - if (changed) {
|
| - notifyChange(new PropertyChangeRecord(#value));
|
| - }
|
| + notifyPropertyChange(#value, oldValue, newValue);
|
| }
|
|
|
| void _observePath([int start = 0, int end]) {
|
| @@ -160,7 +158,7 @@ class PathObserver extends ChangeNotifierBase {
|
| }
|
|
|
| for (var record in records) {
|
| - if (record.changes(_segments[i])) {
|
| + if (_changeRecordMatches(record, _segments[i])) {
|
| _updateObservedValues(i);
|
| return;
|
| }
|
| @@ -170,6 +168,20 @@ class PathObserver extends ChangeNotifierBase {
|
| }
|
| }
|
|
|
| +bool _changeRecordMatches(record, key) {
|
| + if (record is ListChangeRecord) {
|
| + return key is int && (record as ListChangeRecord).indexChanged(key);
|
| + }
|
| + if (record is PropertyChangeRecord) {
|
| + return (record as PropertyChangeRecord).name == key;
|
| + }
|
| + if (record is MapChangeRecord) {
|
| + if (key is Symbol) key = MirrorSystem.getName(key);
|
| + return (record as MapChangeRecord).key == key;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| _getObjectProperty(object, property) {
|
| if (object == null) {
|
| return null;
|
| @@ -185,12 +197,12 @@ _getObjectProperty(object, property) {
|
|
|
| if (property is Symbol) {
|
| var mirror = reflect(object);
|
| - try {
|
| - return mirror.getField(property).reflectee;
|
| - } catch (e) {}
|
| + var result = _tryGetField(mirror, property);
|
| + if (result != null) return result.reflectee;
|
| }
|
|
|
| if (object is Map) {
|
| + if (property is Symbol) property = MirrorSystem.getName(property);
|
| return object[property];
|
| }
|
|
|
| @@ -209,13 +221,11 @@ bool _setObjectProperty(object, property, value) {
|
|
|
| if (property is Symbol) {
|
| var mirror = reflect(object);
|
| - try {
|
| - mirror.setField(property, value);
|
| - return true;
|
| - } catch (e) {}
|
| + if (_trySetField(mirror, property, value)) return true;
|
| }
|
|
|
| if (object is Map) {
|
| + if (property is Symbol) property = MirrorSystem.getName(property);
|
| object[property] = value;
|
| return true;
|
| }
|
| @@ -223,6 +233,58 @@ bool _setObjectProperty(object, property, value) {
|
| return false;
|
| }
|
|
|
| +InstanceMirror _tryGetField(InstanceMirror mirror, Symbol name) {
|
| + try {
|
| + return mirror.getField(name);
|
| + } on NoSuchMethodError catch (e) {
|
| + if (_hasMember(mirror, name, (m) =>
|
| + m is VariableMirror || m is MethodMirror && m.isGetter)) {
|
| + // The field/getter is there but threw a NoSuchMethod exception.
|
| + // This is a legitimate error in the code so rethrow.
|
| + rethrow;
|
| + }
|
| + // The field isn't there. PathObserver does not treat this as an error.
|
| + return null;
|
| + }
|
| +}
|
| +
|
| +bool _trySetField(InstanceMirror mirror, Symbol name, Object value) {
|
| + try {
|
| + mirror.setField(name, value);
|
| + return true;
|
| + } on NoSuchMethodError catch (e) {
|
| + if (_hasMember(mirror, name, (m) => m is VariableMirror) ||
|
| + _hasMember(mirror, _setterName(name))) {
|
| + // The field/setter is there but threw a NoSuchMethod exception.
|
| + // This is a legitimate error in the code so rethrow.
|
| + rethrow;
|
| + }
|
| + // The field isn't there. PathObserver does not treat this as an error.
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +// TODO(jmesserly): workaround for:
|
| +// https://code.google.com/p/dart/issues/detail?id=10029
|
| +Symbol _setterName(Symbol getter) =>
|
| + new Symbol('${MirrorSystem.getName(getter)}=');
|
| +
|
| +bool _hasMember(InstanceMirror mirror, Symbol name, [bool test(member)]) {
|
| + var type = mirror.type;
|
| + while (type != null) {
|
| + final member = type.members[name];
|
| + if (member != null && (test == null || test(member))) return true;
|
| +
|
| + try {
|
| + type = type.superclass;
|
| + } on UnsupportedError catch (e) {
|
| + // TODO(jmesserly): dart2js throws this error when the type is not
|
| + // reflectable.
|
| + return false;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
|
|
| // From: https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js
|
|
|
|
|