Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(751)

Unified Diff: pkg/observe/lib/src/path_observer.dart

Issue 50203004: port TemplateBinding to ed3266266e751b5ab1f75f8e0509d0d5f0ef35d8 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/observe/lib/src/compound_path_observer.dart ('k') | pkg/pkg.status » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 f99fed98c652c6980ef92d595d171a139c644aba..6384f6ee4735851af401ca70b290b348f9a9b7d0 100644
--- a/pkg/observe/lib/src/path_observer.dart
+++ b/pkg/observe/lib/src/path_observer.dart
@@ -29,6 +29,10 @@ import 'package:observe/src/observable.dart' show objectType;
*
* This class is used to implement [Node.bind] and similar functionality.
*/
+// TODO(jmesserly): consider specialized subclasses for:
+// * empty path
+// * "value"
+// * single token in path, e.g. "foo"
class PathObserver extends ChangeNotifier {
/** The path string. */
final String path;
@@ -40,13 +44,22 @@ class PathObserver extends ChangeNotifier {
List<Object> _values;
List<StreamSubscription> _subs;
+ final Function _computeValue;
+
/**
* Observes [path] on [object] for changes. This returns an object that can be
* used to get the changes and get/set the value at this path.
+ *
+ * You can optionally use [computeValue] to apply a function to the result of
+ * evaluating the path. The function should be pure, as PathObserver will not
+ * know to observe any of its dependencies. If you need to observe mutliple
+ * values, use [CompoundPathObserver] instead.
+ *
* See [PathObserver.bindSync] and [PathObserver.value].
*/
- PathObserver(Object object, String path)
+ PathObserver(Object object, String path, {computeValue(newValue)})
: path = path,
+ _computeValue = computeValue,
_isValid = _isPathValid(path),
_segments = <Object>[] {
@@ -62,11 +75,19 @@ class PathObserver extends ChangeNotifier {
// Note that the path itself can't change after it is initially
// constructed, even though the objects along the path can change.
_values = new List<Object>(_segments.length + 1);
+
+ // If we have an empty path, we need to apply the transformation function
+ // to the value. The "value" property should always show the transformed
+ // value.
+ if (_segments.isEmpty && computeValue != null) {
+ object = computeValue(object);
+ }
+
_values[0] = object;
_subs = new List<StreamSubscription>(_segments.length);
}
- /** The object being observed. */
+ /** The object being observed. If the path is empty this will be [value]. */
get object => _values[0];
/** Gets the last reported value at this path. */
@@ -77,7 +98,7 @@ class PathObserver extends ChangeNotifier {
}
/** Sets the value at this path. */
- @reflectable void set value(Object value) {
+ @reflectable void set value(Object newValue) {
int len = _segments.length;
// TODO(jmesserly): throw if property cannot be set?
@@ -85,11 +106,11 @@ class PathObserver extends ChangeNotifier {
if (len == 0) return;
if (!hasObservers) _updateValues(end: len - 1);
- if (_setObjectProperty(_values[len - 1], _segments[len - 1], value)) {
+ if (_setObjectProperty(_values[len - 1], _segments[len - 1], newValue)) {
// Technically, this would get updated asynchronously via a change record.
// However, it is nice if calling the getter will yield the same value
// that was just set. So we use this opportunity to update our cache.
- _values[len] = value;
+ _values[len] = newValue;
}
}
@@ -123,16 +144,24 @@ class PathObserver extends ChangeNotifier {
// TODO(jmesserly): should we be caching these values if not observing?
void _updateValues({int end}) {
if (end == null) end = _segments.length;
+ int last = _segments.length - 1;
for (int i = 0; i < end; i++) {
- _values[i + 1] = _getObjectProperty(_values[i], _segments[i]);
+ var newValue = _getObjectProperty(_values[i], _segments[i]);
+ if (i == last && _computeValue != null) {
+ newValue = _computeValue(newValue);
+ }
+ _values[i + 1] = newValue;
}
}
void _updateObservedValues({int start: 0}) {
var oldValue, newValue;
- for (int i = start; i < _segments.length; i++) {
+ for (int i = start, last = _segments.length - 1; i <= last; i++) {
oldValue = _values[i + 1];
newValue = _getObjectProperty(_values[i], _segments[i]);
+ if (i == last && _computeValue != null) {
+ newValue = _computeValue(newValue);
+ }
if (identical(oldValue, newValue)) {
_observePath(start, i);
return;
@@ -157,16 +186,11 @@ class PathObserver extends ChangeNotifier {
final object = _values[i];
if (object is Observable) {
// TODO(jmesserly): rather than allocating a new closure for each
- // property, we could try and have one for the entire path. In that case,
- // we would lose information about which object changed (note: unless
- // PropertyChangeRecord is modified to includes the sender object), so
- // we would need to re-evaluate the entire path. Need to evaluate perf.
+ // property, we could try and have one for the entire path. However we'd
+ // need to do a linear scan to find the index as soon as we got a change.
+ // Also we need to fix ListChangeRecord and MapChangeRecord to contain
+ // the target. Not sure if it's worth it.
_subs[i] = object.changes.listen((List<ChangeRecord> records) {
- if (!identical(_values[i], object)) {
- // Ignore this object if we're now tracking something else.
- return;
- }
-
for (var record in records) {
if (_changeRecordMatches(record, _segments[i])) {
_updateObservedValues(start: i);
« no previous file with comments | « pkg/observe/lib/src/compound_path_observer.dart ('k') | pkg/pkg.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698