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

Unified Diff: third_party/pkg/angular/lib/directive/ng_repeat.dart

Issue 176943008: Update the Angular/DI tests to latest from github. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 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
Index: third_party/pkg/angular/lib/directive/ng_repeat.dart
diff --git a/third_party/pkg/angular/lib/directive/ng_repeat.dart b/third_party/pkg/angular/lib/directive/ng_repeat.dart
index 60885e615dd697abc41f583790d1ad8777f7af27..603b413c1f6a89e02da5c4e8173971523ebe5734 100644
--- a/third_party/pkg/angular/lib/directive/ng_repeat.dart
+++ b/third_party/pkg/angular/lib/directive/ng_repeat.dart
@@ -12,11 +12,13 @@ class _Row {
}
/**
- * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
- * instance gets its own scope, where the given loop variable is set to the current collection item,
- * and `$index` is set to the item index or key.
+ * The `ngRepeat` directive instantiates a template once per item from a
+ * collection. Each template instance gets its own scope, where the given loop
+ * variable is set to the current collection item, and `$index` is set to the
+ * item index or key.
*
- * Special properties are exposed on the local scope of each template instance, including:
+ * Special properties are exposed on the local scope of each template instance,
+ * including:
*
* <table>
* <tr><th> Variable </th><th> Type </th><th> Details <th></tr>
@@ -29,43 +31,48 @@ class _Row {
* </table>
*
*
- * [repeat_expression] ngRepeat The expression indicating how to enumerate a collection. These
- * formats are currently supported:
+ * [repeat_expression] ngRepeat The expression indicating how to enumerate a
+ * collection. These formats are currently supported:
*
- * * `variable in expression` – where variable is the user defined loop variable and `expression`
- * is a scope expression giving the collection to enumerate.
+ * * `variable in expression` – where variable is the user defined loop
+ * variable and `expression` is a scope expression giving the collection to
+ * enumerate.
*
* For example: `album in artist.albums`.
*
- * * `variable in expression track by tracking_expression` – You can also provide an optional
- * tracking function which can be used to associate the objects in the collection with the DOM
- * elements. If no tracking function is specified the ng-repeat associates elements by identity
- * in the collection. It is an error to have more than one tracking function to resolve to the
- * same key. (This would mean that two distinct objects are mapped to the same DOM element,
- * which is not possible.) Filters should be applied to the expression, before specifying a
- * tracking expression.
+ * * `variable in expression track by tracking_expression` – You can also
+ * provide an optional tracking function which can be used to associate the
+ * objects in the collection with the DOM elements. If no tracking function is
+ * specified the ng-repeat associates elements by identity in the collection.
+ * It is an error to have more than one tracking function to resolve to the
+ * same key. (This would mean that two distinct objects are mapped to the same
+ * DOM element, which is not possible.) Filters should be applied to the
+ * expression, before specifying a tracking expression.
*
- * For example: `item in items` is equivalent to `item in items track by $id(item)'. This
- * implies that the DOM elements will be associated by item identity in the array.
+ * For example: `item in items` is equivalent to `item in items track by
+ * $id(item)`. This implies that the DOM elements will be associated by item
+ * identity in the array.
*
- * For example: `item in items track by $id(item)`. A built in `$id()` function can be used
- * to assign a unique `$$hashKey` property to each item in the array. This property is then
- * used as a key to associated DOM elements with the corresponding item in the array by
- * identity. Moving the same object in array would move the DOM element in the same way ian the
+ * For example: `item in items track by $id(item)`. A built in `$id()`
+ * function can be used to assign a unique `$$hashKey` property to each item
+ * in the array. This property is then used as a key to associated DOM
+ * elements with the corresponding item in the array by identity. Moving the
+ * same object in array would move the DOM element in the same way ian the
* DOM.
*
- * For example: `item in items track by item.id` is a typical pattern when the items come from
- * the database. In this case the object identity does not matter. Two objects are considered
- * equivalent as long as their `id` property is same.
- *
- * For example: `item in items | filter:searchText track by item.id` is a pattern that might be
- * used to apply a filter to items in conjunction with a tracking expression.
+ * For example: `item in items track by item.id` is a typical pattern when
+ * the items come from the database. In this case the object identity does
+ * not matter. Two objects are considered equivalent as long as their `id`
+ * property is same.
*
+ * For example: `item in items | filter:searchText track by item.id` is a
+ * pattern that might be used to apply a filter to items in conjunction with
+ * a tracking expression.
*
* # Example:
*
- * <ul ng-repeat="item in ['foo', 'bar', 'baz']">
- * <li>{{$item}}</li>
+ * <ul>
+ * <li ng-repeat="item in ['foo', 'bar', 'baz']">{{item}}</li>
* </ul>
*/
@@ -76,90 +83,119 @@ class _Row {
class NgRepeatDirective extends AbstractNgRepeatDirective {
NgRepeatDirective(BlockHole blockHole,
BoundBlockFactory boundBlockFactory,
- Scope scope): super(blockHole, boundBlockFactory, scope);
- get _shalow => false;
+ Scope scope,
+ Parser parser,
+ AstParser astParser)
+ : super(blockHole, boundBlockFactory, scope, parser, astParser);
}
/**
- * *EXPERIMENTAL:* This feature is experimental. We reserve the right to change or delete it.
+ * *EXPERIMENTAL:* This feature is experimental. We reserve the right to change
+ * or delete it.
*
- * [ng-shallow-repeat] is same as [ng-repeat] with some tradeoffs designed for speed. Use
- * [ng-shollow-repeat] when you expect that your items you are repeating over do not change
- * during the repeater lifetime.
+ * [ng-shallow-repeat] is same as [ng-repeat] with some tradeoffs designed for
+ * speed. Use [ng-shallow-repeat] when you expect that your items you are
+ * repeating over do not change during the repeater lifetime.
*
* The shallow repeater introduces these changes:
*
- * * The repeater only fires if the identity of the list changes or if the list [length] property
- * changes. This means that the repeater will still see additions and deletions but not changes
- * to the array.
- * * The child scopes for each item are created in the lazy mode (see [Scope.$new]). This means
- * the scopes are effectivly taken out of the digest cycle and will not update on changes
- * to the model.
+ * * The repeater only fires if the identity of the list changes or if the list
+ * [length] property changes. This means that the repeater will still see
+ * additions and deletions but not changes to the array.
+ * * The child scopes for each item are created in the lazy mode
+ * (see [Scope.$new]). This means the scopes are effectively taken out of the
+ * digest cycle and will not update on changes to the model.
*
*/
+@deprecated
@NgDirective(
children: NgAnnotation.TRANSCLUDE_CHILDREN,
selector: '[ng-shallow-repeat]',
map: const {'.': '@expression'})
-class NgShalowRepeatDirective extends AbstractNgRepeatDirective {
- NgShalowRepeatDirective(BlockHole blockHole,
+//TODO(misko): delete me, since we can no longer do shallow digest.
+class NgShallowRepeatDirective extends AbstractNgRepeatDirective {
+ NgShallowRepeatDirective(BlockHole blockHole,
BoundBlockFactory boundBlockFactory,
- Scope scope): super(blockHole, boundBlockFactory, scope);
- get _shalow => true;
+ Scope scope,
+ Parser parser,
+ AstParser astParser)
+ : super(blockHole, boundBlockFactory, scope, parser, astParser)
+ {
+ print('DEPRECATED: [ng-shallow-repeat] use [ng-repeat]');
+ }
}
abstract class AbstractNgRepeatDirective {
static RegExp _SYNTAX = new RegExp(r'^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?(\s+lazily\s*)?$');
static RegExp _LHS_SYNTAX = new RegExp(r'^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$');
- BlockHole _blockHole;
- BoundBlockFactory _boundBlockFactory;
- Scope _scope;
+ final BlockHole _blockHole;
+ final BoundBlockFactory _boundBlockFactory;
+ final Scope _scope;
+ final Parser _parser;
+ final AstParser _astParser;
String _expression;
String _valueIdentifier;
String _keyIdentifier;
String _listExpr;
- Map<Object, _Row> _rows = new Map<dynamic, _Row>();
+ Map<dynamic, _Row> _rows = {};
Function _trackByIdFn = (key, value, index) => value;
- Function _removeWatch = () => null;
+ Watch _watch = null;
Iterable _lastCollection;
- AbstractNgRepeatDirective(BlockHole this._blockHole,
- BoundBlockFactory this._boundBlockFactory,
- Scope this._scope);
-
- get _shalow;
+ AbstractNgRepeatDirective(this._blockHole, this._boundBlockFactory,
+ this._scope, this._parser, this._astParser);
set expression(value) {
_expression = value;
- _removeWatch();
+ if (_watch != null) _watch.remove();
Match match = _SYNTAX.firstMatch(_expression);
if (match == null) {
- throw "[NgErr7] ngRepeat error! Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '$_expression'.";
+ throw "[NgErr7] ngRepeat error! Expected expression in form of '_item_ "
+ "in _collection_[ track by _id_]' but got '$_expression'.";
}
_listExpr = match.group(2);
+ var trackByExpr = match.group(4);
+ if (trackByExpr != null) {
+ Expression trackBy = _parser(trackByExpr);
+ _trackByIdFn = ((key, value, index) {
+ final trackByLocals = <String, Object>{};
+ if (_keyIdentifier != null) trackByLocals[_keyIdentifier] = key;
+ trackByLocals
+ ..[_valueIdentifier] = value
+ ..[r'$index'] = index
+ ..[r'$id'] = (obj) => obj;
+ return relaxFnArgs(trackBy.eval)(new ScopeLocals(_scope.context, trackByLocals));
+ });
+ }
var assignExpr = match.group(1);
match = _LHS_SYNTAX.firstMatch(assignExpr);
if (match == null) {
- throw "[NgErr8] ngRepeat error! '_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '$assignExpr'.";
+ throw "[NgErr8] ngRepeat error! '_item_' in '_item_ in _collection_' "
+ "should be an identifier or '(_key_, _value_)' expression, but got "
+ "'$assignExpr'.";
}
_valueIdentifier = match.group(3);
if (_valueIdentifier == null) _valueIdentifier = match.group(1);
_keyIdentifier = match.group(2);
- _removeWatch = _scope.$watchCollection(_listExpr, _onCollectionChange, value, _shalow);
+ _watch = _scope.watch(
+ _astParser(_listExpr, collection: true),
+ (CollectionChangeRecord collection, _) {
+ //TODO(misko): we should take advantage of the CollectionChangeRecord!
+ _onCollectionChange(collection == null ? [] : collection.iterable);
+ }
+ );
}
List<_Row> _computeNewRows(Iterable collection, trackById) {
- List<_Row> newRowOrder = [];
+ final newRowOrder = new List<_Row>(collection.length);
// Same as lastBlockMap but it has the current state. It will become the
// lastBlockMap on the next iteration.
- Map<dynamic, _Row> newRows = new Map<dynamic, _Row>();
- var arrayLength = collection.length;
+ final newRows = <dynamic, _Row>{};
// locate existing items
- var length = newRowOrder.length = collection.length;
- for (var index = 0; index < length; index++) {
+ for (var index = 0; index < newRowOrder.length; index++) {
var value = collection.elementAt(index);
trackById = _trackByIdFn(index, value, index);
if (_rows.containsKey(trackById)) {
@@ -170,12 +206,12 @@ abstract class AbstractNgRepeatDirective {
} else if (newRows.containsKey(trackById)) {
// restore lastBlockMap
newRowOrder.forEach((row) {
- if (row != null && row.startNode != null) {
- _rows[row.id] = row;
- }
+ if (row != null && row.startNode != null) _rows[row.id] = row;
});
// This is a duplicate and we need to throw an error
- throw "[NgErr50] ngRepeat error! Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: $_expression, Duplicate key: $trackById";
+ throw "[NgErr50] ngRepeat error! Duplicates in a repeater are not "
+ "allowed. Use 'track by' expression to specify unique keys. "
+ "Repeater: $_expression, Duplicate key: $trackById";
} else {
// new never before seen row
newRowOrder[index] = new _Row(trackById);
@@ -183,31 +219,25 @@ abstract class AbstractNgRepeatDirective {
}
}
// remove existing items
- _rows.forEach((key, row){
+ _rows.forEach((key, row) {
row.block.remove();
- row.scope.$destroy();
+ row.scope.destroy();
});
_rows = newRows;
return newRowOrder;
}
_onCollectionChange(Iterable collection) {
- var previousNode = _blockHole.elements[0], // current position of the node
- nextNode,
- childScope,
- trackById,
- cursor = _blockHole,
- arrayChange = _lastCollection != collection;
-
- if (arrayChange) { _lastCollection = collection; }
- if (collection is! Iterable) {
- collection = [];
- }
+ dom.Node previousNode = _blockHole.elements[0]; // current position of the node
+ dom.Node nextNode;
+ Scope childScope;
+ Map childContext;
+ Scope trackById;
+ ElementWrapper cursor = _blockHole;
List<_Row> newRowOrder = _computeNewRows(collection, trackById);
- for (var index = 0, length = collection.length; index < length; index++) {
- var key = index;
+ for (var index = 0; index < collection.length; index++) {
var value = collection.elementAt(index);
_Row row = newRowOrder[index];
@@ -215,46 +245,42 @@ abstract class AbstractNgRepeatDirective {
// if we have already seen this object, then we need to reuse the
// associated scope/element
childScope = row.scope;
+ childContext = childScope.context as Map;
nextNode = previousNode;
do {
nextNode = nextNode.nextNode;
} while(nextNode != null);
- if (row.startNode == nextNode) {
- // do nothing
- } else {
- // existing item which got moved
- row.block.moveAfter(cursor);
- }
+ // existing item which got moved
+ if (row.startNode != nextNode) row.block.moveAfter(cursor);
previousNode = row.endNode;
} else {
// new item which we don't know about
- childScope = _scope.$new(lazy:_shalow);
+ childScope = _scope.createChild(childContext = new PrototypeMap(_scope.context));
}
- if (!identical(childScope[_valueIdentifier], value)) {
- childScope[_valueIdentifier] = value;
- childScope.$dirty();
- }
- childScope[r'$index'] = index;
- childScope[r'$first'] = (index == 0);
- childScope[r'$last'] = (index == (collection.length - 1));
- childScope[r'$middle'] = !(childScope.$first || childScope.$last);
- childScope[r'$odd'] = index & 1 == 1;
- childScope[r'$even'] = index & 1 == 0;
- if (arrayChange && _shalow) {
- childScope.$dirty();
+ if (!identical(childScope.context[_valueIdentifier], value)) {
+ childContext[_valueIdentifier] = value;
}
+ var first = (index == 0);
+ var last = (index == collection.length - 1);
+ childContext
+ ..[r'$index'] = index
+ ..[r'$first'] = first
+ ..[r'$last'] = last
+ ..[r'$middle'] = !first && !last
+ ..[r'$odd'] = index & 1 == 1
+ ..[r'$even'] = index & 1 == 0;
if (row.startNode == null) {
- _rows[row.id] = row;
var block = _boundBlockFactory(childScope);
- row..block = block
- ..scope = childScope
- ..elements = block.elements
- ..startNode = row.elements[0]
- ..endNode = row.elements[row.elements.length - 1];
+ _rows[row.id] = row
+ ..block = block
+ ..scope = childScope
+ ..elements = block.elements
+ ..startNode = row.elements[0]
+ ..endNode = row.elements[row.elements.length - 1];
block.insertAfter(cursor);
}
cursor = row.block;

Powered by Google App Engine
This is Rietveld 408576698