Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions demo/bouncing_balls/bouncy_balls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class BounceController {

timeDigest() {
var start = window.performance.now();
scope.$evalAsync(() {
scope.runAsync(() {
digestTime = (window.performance.now() - start).round();
}, outsideDigest: true);
}
Expand Down Expand Up @@ -109,7 +109,7 @@ class BallPositionDirective {

set position(BallModel model) {
element.style.backgroundColor = model.color;
scope.$watch(() {
scope.watch(() {
element.style.left = '${model.x + 10}px';
element.style.top = '${model.y + 10}px';
});
Expand Down
49 changes: 27 additions & 22 deletions lib/change_detection/ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ part of angular.watch_group;
abstract class AST {
static final String _CONTEXT = '#';
final String expression;
AST(this.expression) { assert(expression!=null); }
AST(expression)
: expression = expression.startsWith('#.') ?
expression.substring(2) :
expression {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the { on the new line in this case. It is hard to tell where the body starts otherwise. I know it is not consistent with the rest of the style, but to me it is more readable. What do you think?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I think this is easier to read

foo 
  ? true
  : false

then

foo ?
  true :
  false

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really care for the {, new line might indeed be more readable, will change.

about the ternary op, the core Dart team seem to prefer ops at the end of line but I also found ops at strart of line more readable, will change also.

assert(expression!=null);
}
WatchRecord<_Handler> setupWatch(WatchGroup watchGroup);
toString() => expression;
}
Expand All @@ -21,8 +26,8 @@ abstract class AST {
*/
class ContextReferenceAST extends AST {
ContextReferenceAST(): super(AST._CONTEXT);
WatchRecord<_Handler> setupWatch(WatchGroup watchGroup)
=> new _ConstantWatchRecord(watchGroup, expression, watchGroup.context);
WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) =>
new _ConstantWatchRecord(watchGroup, expression, watchGroup.context);
}

/**
Expand All @@ -33,12 +38,14 @@ class ContextReferenceAST extends AST {
class ConstantAST extends AST {
final constant;

ConstantAST(dynamic constant):
super('$constant'),
constant = constant;
ConstantAST(constant, [String expression])
: constant = constant,
super(expression == null ?
constant is String ? '"$constant"' : '$constant' :
expression);

WatchRecord<_Handler> setupWatch(WatchGroup watchGroup)
=> new _ConstantWatchRecord(watchGroup, expression, constant);
WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) =>
new _ConstantWatchRecord(watchGroup, expression, constant);
}

/**
Expand All @@ -51,13 +58,12 @@ class FieldReadAST extends AST {
final String name;

FieldReadAST(lhs, name)
: super(lhs.expression == AST._CONTEXT ? name : '$lhs.$name'),
: super('$lhs.$name'),
lhs = lhs,
name = name;

WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) =>
watchGroup.addFieldWatch(lhs, name, expression);

watchGroup.addFieldWatch(lhs, name, expression);
}

/**
Expand All @@ -77,7 +83,7 @@ class PureFunctionAST extends AST {
name = name;

WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) =>
watchGroup.addFunctionWatch(fn, argsAST, expression);
watchGroup.addFunctionWatch(fn, argsAST, expression);
}

/**
Expand All @@ -97,19 +103,18 @@ class MethodAST extends AST {
argsAST = argsAST;

WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) =>
watchGroup.addMethodWatch(lhsAST, name, argsAST, expression);
watchGroup.addMethodWatch(lhsAST, name, argsAST, expression);
}


class CollectionAST extends AST {
final AST valueAST;
CollectionAST(valueAST):
super('#collection($valueAST)'),
valueAST = valueAST;
CollectionAST(valueAST)
: super('#collection($valueAST)'),
valueAST = valueAST;

WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) {
return watchGroup.addCollectionWatch(valueAST);
}
WatchRecord<_Handler> setupWatch(WatchGroup watchGroup) =>
watchGroup.addCollectionWatch(valueAST);
}

_argList(List<AST> items) => items.join(', ');
Expand All @@ -124,9 +129,9 @@ class _ConstantWatchRecord extends WatchRecord<_Handler> {
final currentValue;
final _Handler handler;

_ConstantWatchRecord(WatchGroup watchGroup, String expression, dynamic currentValue):
currentValue = currentValue,
handler = new _ConstantHandler(watchGroup, expression, currentValue);
_ConstantWatchRecord(WatchGroup watchGroup, String expression, currentValue)
: currentValue = currentValue,
handler = new _ConstantHandler(watchGroup, expression, currentValue);

ChangeRecord<_Handler> check() => null;
void remove() => null;
Expand Down
76 changes: 69 additions & 7 deletions lib/change_detection/change_detection.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
library change_detection;

typedef EvalExceptionHandler(error, stack);

/**
* An interface for [ChangeDetectorGroup] groups related watches together. It
* guarentees that within the group all watches will be reported in the order in
* guarantees that within the group all watches will be reported in the order in
* which they were registered. It also provides an efficient way of removing the
* watch group.
*/
Expand All @@ -25,7 +27,6 @@ abstract class ChangeDetectorGroup<H> {
*/
WatchRecord<H> watch(Object object, String field, H handler);


/** Use to remove all watches in the group in an efficient manner. */
void remove();

Expand Down Expand Up @@ -53,7 +54,7 @@ abstract class ChangeDetector<H> extends ChangeDetectorGroup<H> {
* linked list of [ChangeRecord]s. The [ChangeRecord]s are to be returned in
* the same order as they were registered.
*/
ChangeRecord<H> collectChanges();
ChangeRecord<H> collectChanges([EvalExceptionHandler exceptionHandler]);
}

abstract class Record<H> {
Expand Down Expand Up @@ -110,7 +111,64 @@ abstract class ChangeRecord<H> extends Record<H> {
}

/**
* If [ChangeDetector] is watching a collection (an [Iterable]) then the
* If [ChangeDetector] is watching a an [Map] then the
* [currentValue] of [Record] will contain this object. The object contains a
* summary of changes to the map since the last execution. The changes
* are reported as a list of [MapKeyValue]s which contain the current
* and previous value in the list as well as the key.
*/
abstract class MapChangeRecord<K, V> {
/// The underlying iterable object
Map get map;

/// A list of [CollectionKeyValue]s which are in the iteration order. */
KeyValue<K, V> get mapHead;
/// A list of changed items.
ChangedKeyValue<K, V> get changesHead;
/// A list of new added items.
AddedKeyValue<K, V> get additionsHead;
/// A list of removed items
RemovedKeyValue<K, V> get removalsHead;

void forEachChange(void f(ChangedKeyValue<K, V> change));
void forEachAddition(void f(AddedKeyValue<K, V> addition));
void forEachRemoval(void f(RemovedKeyValue<K, V> removal));
}

/**
* Each item in map is wrapped in [MapKeyValue], which can track
* the [item]s [currentValue] and [previousValue] location.
*/
abstract class MapKeyValue<K, V> {
/// The item.
K get key;

/// Previous item location in the list or [null] if addition.
V get previousValue;

/// Current item location in the list or [null] if removal.
V get currentValue;
}

abstract class KeyValue<K, V> extends MapKeyValue<K, V> {
KeyValue<K, V> get nextKeyValue;
}

abstract class AddedKeyValue<K, V> extends MapKeyValue<K, V> {
AddedKeyValue<K, V> get nextAddedKeyValue;
}

abstract class RemovedKeyValue<K, V> extends MapKeyValue<K, V> {
RemovedKeyValue<K, V> get nextRemovedKeyValue;
}

abstract class ChangedKeyValue<K, V> extends MapKeyValue<K, V> {
ChangedKeyValue<K, V> get nextChangedKeyValue;
}


/**
* If [ChangeDetector] is watching a an [Iterable] then the
* [currentValue] of [Record] will contain this object. The object contains a
* summary of changes to the collection since the last execution. The changes
* are reported as a list of [CollectionChangeItem]s which contain the current
Expand All @@ -128,18 +186,22 @@ abstract class CollectionChangeRecord<K, V> {
MovedItem<K, V> get movesHead;
/** A list of [RemovedItem]s. */
RemovedItem<K, V> get removalsHead;

void forEachAddition(void f(AddedItem<K, V> addition));
void forEachMove(void f(MovedItem<K, V> move));
void forEachRemoval(void f(RemovedItem<K, V> removal));
}

/**
* Each item in collection is wrapped in [CollectionChangeItem], which can track
* the [item]s [currentKey] and [previousKey] location.
*/
abstract class CollectionChangeItem<K, V> {
abstract class CollectionChangeItem<K, V> { // TODO(misko): change <K,V> to <V> since K is int.
/** Previous item location in the list or [null] if addition. */
K get previousKey;
K get previousKey; // TODO(misko): rename to previousIndex

/** Current item location in the list or [null] if removal. */
K get currentKey;
K get currentKey; // TODO(misko): rename to CurrentIndex

/** The item. */
V get item;
Expand Down
Loading