Skip to content

Commit e894086

Browse files
committed
1 parent 1c50c6a commit e894086

16 files changed

+173
-182
lines changed

lib/change_detection/dirty_checking_change_detector.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ library dirty_checking_change_detector;
22

33
import 'dart:collection';
44
import 'package:angular/change_detection/change_detection.dart';
5+
import 'package:angular/change_detection/watch_group.dart';
56

67
/**
78
* [DirtyCheckingChangeDetector] determines which object properties have changed
@@ -369,7 +370,7 @@ class _ChangeIterator<H> implements Iterator<Record<H>>{
369370
* removing efficient. [DirtyCheckingRecord] also has a [nextChange] field which
370371
* creates a single linked list of all of the changes for efficient traversal.
371372
*/
372-
class DirtyCheckingRecord<H> implements Record<H>, WatchRecord<H> {
373+
class DirtyCheckingRecord<H> implements WatchRecord<H> {
373374
static const List<String> _MODE_NAMES =
374375
const ['MARKER', 'IDENT', 'GETTER', 'MAP[]', 'ITERABLE', 'MAP'];
375376
static const int _MODE_MARKER_ = 0;
@@ -456,6 +457,19 @@ class DirtyCheckingRecord<H> implements Record<H>, WatchRecord<H> {
456457
return;
457458
}
458459

460+
while (obj is LocalContext) {
461+
var ctx = obj as LocalContext;
462+
if (ctx.hasProperty(field)) {
463+
_object = obj;
464+
_mode = _MODE_MAP_FIELD_;
465+
_getter = null;
466+
return;
467+
}
468+
obj = ctx.parent;
469+
}
470+
471+
if (obj == null) throw "$field property does not exist on $_object";
472+
459473
if (obj is Map) {
460474
_mode = _MODE_MAP_FIELD_;
461475
_getter = null;
Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,27 @@
11
part of angular.watch_group;
22

3-
class PrototypeMap<K, V> implements Map<K,V> {
4-
final Map<K, V> prototype;
5-
final Map<K, V> self = new Map();
3+
// todo(vicb) rename to ContextLocals + rename the file
4+
class LocalContext {
5+
// todo(vicb) _parentContext
6+
final Object parent;
7+
final Map _locals = <String, Object>{};
68

7-
PrototypeMap(this.prototype);
8-
9-
void operator []=(name, value) {
10-
self[name] = value;
9+
LocalContext(this.parent, [Map<String, Object> locals = null]) {
10+
if (locals != null) _locals.addAll(locals);
11+
_locals[r'$parent'] = parent;
1112
}
12-
V operator [](name) => self.containsKey(name) ? self[name] : prototype[name];
1313

14-
bool get isEmpty => self.isEmpty && prototype.isEmpty;
15-
bool get isNotEmpty => self.isNotEmpty || prototype.isNotEmpty;
16-
// todo(vbe) include prototype keys ?
17-
Iterable<K> get keys => self.keys;
18-
// todo(vbe) include prototype values ?
19-
Iterable<V> get values => self.values;
20-
int get length => self.length;
14+
static LocalContext wrapper(context, Map<String, Object> locals) =>
15+
new LocalContext(context, locals);
16+
17+
bool hasProperty(String prop) => _locals.containsKey(prop);
2118

22-
void forEach(fn) {
23-
// todo(vbe) include prototype ?
24-
self.forEach(fn);
19+
void operator[]=(String prop, value) {
20+
_locals[prop] = value;
2521
}
26-
V remove(key) => self.remove(key);
27-
clear() => self.clear;
28-
// todo(vbe) include prototype ?
29-
bool containsKey(key) => self.containsKey(key);
30-
// todo(vbe) include prototype ?
31-
bool containsValue(key) => self.containsValue(key);
32-
void addAll(map) {
33-
self.addAll(map);
22+
23+
dynamic operator[](String prop) {
24+
assert(hasProperty(prop));
25+
return _locals[prop];
3426
}
35-
// todo(vbe) include prototype ?
36-
V putIfAbsent(key, fn) => self.putIfAbsent(key, fn);
3727
}

lib/change_detection/watch_group.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ part 'prototype_map.dart';
1515
* * [value]: The current value of the watched expression.
1616
* * [previousValue]: The previous value of the watched expression.
1717
*
18-
* If the expression is watching a collection (a list or a map), then [value] is wrapped in
19-
* a [CollectionChangeItem] that lists all the changes.
18+
* Notes:
19+
*
20+
* * [value] is a [CollectionChangeRecord] when a Collection is being watched
21+
* * [value] is a [MapChangeRecord] when a [Map] is being watched
2022
*/
2123
typedef void ReactionFn(value, previousValue);
2224
typedef void ChangeLog(String expression, current, previous);

lib/core/module.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ export "package:angular/core/module_internal.dart" show
6363
ExceptionHandler,
6464
Interpolate,
6565
VmTurnZone,
66-
PrototypeMap,
6766
RootScope,
67+
LocalContext,
6868
Scope,
6969
ScopeDigestTTL,
7070
ScopeEvent,

lib/core/scope.dart

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,16 @@ class Scope {
138138
/**
139139
* The default execution context for [watch]es [observe]ers, and [eval]uation.
140140
*/
141-
final context;
141+
// todo(vicb) was final
142+
var _context;
143+
144+
get context => _context;
145+
set context(ctx) {
146+
147+
print("scope: setting context to $ctx");
148+
_context = ctx;
149+
150+
}
142151

143152
/**
144153
* The [RootScope] of the application.
@@ -184,9 +193,12 @@ class Scope {
184193
/// Do not use. Exposes internal state for testing.
185194
bool get hasOwnStreams => _streams != null && _streams._scope == this;
186195

187-
Scope(Object this.context, this.rootScope, this._parentScope,
196+
// todo(vicb) this.context
197+
Scope(Object _context, this.rootScope, this._parentScope,
188198
this._readWriteGroup, this._readOnlyGroup, this.id,
189-
this._stats);
199+
this._stats) {
200+
context = _context;
201+
}
190202

191203
/**
192204
* Use [watch] to set up change detection on an expression.
@@ -206,7 +218,7 @@ class Scope {
206218
* by reference. When watching a collection, the reaction function receives a
207219
* [CollectionChangeItem] that lists all the changes.
208220
*/
209-
Watch watch(String expression, ReactionFn reactionFn, {context,
221+
Watch watch(String expression, ReactionFn reactionFn, {context,
210222
FormatterMap formatters, bool canChangeModel: true, bool collection: false}) {
211223
assert(isAttached);
212224
assert(expression is String);
@@ -246,8 +258,8 @@ class Scope {
246258
expression is String ||
247259
expression is Function);
248260
if (expression is String && expression.isNotEmpty) {
249-
var obj = locals == null ? context : new ScopeLocals(context, locals);
250-
return rootScope._parser(expression).eval(obj);
261+
var ctx = locals == null ? context : new LocalContext(context, locals);
262+
return rootScope._parser(expression).eval(ctx);
251263
}
252264

253265
assert(locals == null);
@@ -323,7 +335,7 @@ class Scope {
323335
_parentScope = null;
324336
}
325337

326-
_assertInternalStateConsistency() {
338+
void _assertInternalStateConsistency() {
327339
assert((() {
328340
rootScope._verifyStreams(null, '', []);
329341
return true;
@@ -360,7 +372,7 @@ class Scope {
360372
}
361373
}
362374

363-
_mapEqual(Map a, Map b) => a.length == b.length &&
375+
bool _mapEqual(Map a, Map b) => a.length == b.length &&
364376
a.keys.every((k) => b.containsKey(k) && a[k] == b[k]);
365377

366378
/**
@@ -401,7 +413,7 @@ class ScopeStats {
401413
processStopwatch.elapsedMicroseconds;
402414
}
403415

404-
_stopwatchReset() {
416+
void _stopwatchReset() {
405417
fieldStopwatch.reset();
406418
evalStopwatch.reset();
407419
processStopwatch.reset();
@@ -466,9 +478,9 @@ class ScopeStatsEmitter {
466478

467479
static pad(String str, int size) => _PAD_.substring(0, max(size - str.length, 0)) + str;
468480

469-
_ms(num value) => '${pad(_nfDec.format(value), 9)} ms';
470-
_us(num value) => _ms(value / 1000);
471-
_tally(num value) => '${pad(_nfInt.format(value), 6)}';
481+
String _ms(num value) => '${pad(_nfDec.format(value), 9)} ms';
482+
String _us(num value) => _ms(value / 1000);
483+
String _tally(num value) => '${pad(_nfInt.format(value), 6)}';
472484

473485
/**
474486
* Emit a message based on the phase and state of stopwatches.
@@ -492,9 +504,8 @@ class ScopeStatsEmitter {
492504
return (prefix == '1' ? _HEADER_ : '') + ' #$prefix:';
493505
}
494506

495-
String _stat(AvgStopwatch s) {
496-
return '${_tally(s.count)} / ${_us(s.elapsedMicroseconds)} @(${_tally(s.ratePerMs)} #/ms)';
497-
}
507+
String _stat(AvgStopwatch s) =>
508+
'${_tally(s.count)} / ${_us(s.elapsedMicroseconds)} @(${_tally(s.ratePerMs)} #/ms)';
498509
}
499510

500511
/**
@@ -505,6 +516,7 @@ class ScopeStatsConfig {
505516
var emit = false;
506517

507518
ScopeStatsConfig();
519+
508520
ScopeStatsConfig.enabled() {
509521
emit = true;
510522
}
@@ -570,8 +582,8 @@ class RootScope extends Scope {
570582
* followed by change detection
571583
* on non-DOM listeners. Any changes detected are process using the reaction function. The digest
572584
* phase is repeated as long as at least one change has been detected. By default, after 5
573-
* iterations the model is considered unstable and angular exists with an exception. (See
574-
* ScopeDigestTTL)
585+
* iterations the model is considered unstable and angular exits with an exception. (See
586+
* [ScopeDigestTTL])
575587
*
576588
* ##flush
577589
*

lib/core_dom/common.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ Injector forceNewDirectivesAndFormatters(Injector injector, List<Module> modules
3939
modules.add(new Module()
4040
..bind(Scope, toFactory: (i) {
4141
var scope = i.parent.get(Scope);
42-
return scope.createChild(new PrototypeMap(scope.context));
42+
//todo(vicb)
43+
return scope.createChild(scope.context);
4344
}));
4445

4546
return injector.createChild(modules,

lib/core_dom/element_binder.dart

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,16 @@ class ElementBinder {
200200
probe.directives.add(controller);
201201
assert((linkMapTimer = _perf.startTimer('ng.view.link.map', ref.type)) != false);
202202

203+
203204
if (ref.annotation is Controller) {
204-
scope.context[(ref.annotation as Controller).publishAs] = controller;
205+
// todo(vicb)
206+
print("_link context = $controller");
207+
scope.context = controller;
205208
}
206209

207-
var tasks = new _TaskList(controller is AttachAware ? () {
208-
if (scope.isAttached) controller.attach();
209-
} : null);
210+
var tasks = new _TaskList(controller is AttachAware ?
211+
() {if (scope.isAttached) controller.attach();} :
212+
null);
210213

211214
if (ref.mappings.isNotEmpty) {
212215
if (nodeAttrs == null) nodeAttrs = new _AnchorAttrs(ref);
@@ -302,16 +305,16 @@ class ElementBinder {
302305

303306
directiveRefs.forEach((DirectiveRef ref) {
304307
Directive annotation = ref.annotation;
305-
var visibility = ref.annotation.visibility;
306-
if (ref.annotation is Controller) {
307-
scope = scope.createChild(new PrototypeMap(scope.context));
308+
if (annotation is Controller) {
309+
//todo(vicb)
310+
scope = scope.createChild(scope.context);
308311
nodeModule.bind(Scope, toValue: scope);
309312
}
310313

311314
_createDirectiveFactories(ref, nodeModule, node, nodesAttrsDirectives, nodeAttrs,
312-
visibility);
313-
if (ref.annotation.module != null) {
314-
nodeModule.install(ref.annotation.module());
315+
annotation.visibility);
316+
if (annotation.module != null) {
317+
nodeModule.install(annotation.module());
315318
}
316319
});
317320

lib/core_dom/module_internal.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import 'package:angular/core/module_internal.dart';
1313
import 'package:angular/core/parser/parser.dart';
1414
import 'package:angular/core_dom/dom_util.dart' as util;
1515

16-
import 'package:angular/change_detection/watch_group.dart' show Watch, PrototypeMap;
16+
// todo vicb
17+
import 'package:angular/change_detection/watch_group.dart' show Watch, LocalContext;
1718
import 'package:angular/core/registry.dart';
1819

1920
import 'package:angular/directive/module.dart' show NgBaseCss;
@@ -62,7 +63,7 @@ class CoreDomModule extends Module {
6263
bind(TranscludingComponentFactory);
6364
bind(Content);
6465
bind(ContentPort, toValue: null);
65-
66+
6667
bind(Http);
6768
bind(UrlRewriter);
6869
bind(HttpBackend);

lib/core_dom/mustache.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ class TextMustache {
1212
FormatterMap formatters) {
1313
String expression = interpolate(template);
1414

15+
print('Mustache: watching $expression');
16+
1517
scope.watch(expression,
1618
_updateMarkup,
1719
canChangeModel: false,
1820
formatters: formatters);
1921
}
2022

2123
void _updateMarkup(text, previousText) {
24+
print('Mustache: changed $previousText -> $text');
2225
_element.text = text;
2326
}
2427
}

lib/core_dom/shadow_dom_component_factory.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ class ShadowDomComponentFactory implements ComponentFactory {
3535
FactoryFn call(dom.Node node, DirectiveRef ref) {
3636
return (Injector injector) {
3737
var component = ref.annotation as Component;
38-
Scope scope = injector.get(Scope);
39-
ViewCache viewCache = injector.get(ViewCache);
40-
Http http = injector.get(Http);
41-
TemplateCache templateCache = injector.get(TemplateCache);
42-
DirectiveMap directives = injector.get(DirectiveMap);
43-
NgBaseCss baseCss = injector.get(NgBaseCss);
38+
final scope = injector.get(Scope);
39+
final viewCache = injector.get(ViewCache);
40+
final http = injector.get(Http);
41+
final templateCache = injector.get(TemplateCache);
42+
final directives = injector.get(DirectiveMap);
43+
final baseCss = injector.get(NgBaseCss);
4444
// This is a bit of a hack since we are returning different type then we are.
4545
var componentFactory = new _ComponentFactory(node, ref.type, component,
4646
injector.get(dom.NodeTreeSanitizer), _expando, baseCss, _styleElementCache);
4747
var controller = componentFactory.call(injector, scope, viewCache, http, templateCache,
4848
directives);
4949

50-
componentFactory.shadowScope.context[component.publishAs] = controller;
50+
componentFactory.shadowScope.context = controller;
5151
return controller;
5252
};
5353
}

lib/core_dom/transcluding_component_factory.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class TranscludingComponentFactory implements ComponentFactory {
114114
childInjector = injector.createChild([childModule], name: SHADOW_DOM_INJECTOR_NAME);
115115

116116
var controller = childInjector.get(ref.type);
117-
shadowScope.context[component.publishAs] = controller;
117+
shadowScope.context = controller;
118118
ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
119119
return controller;
120120
};

0 commit comments

Comments
 (0)