Skip to content

Commit 9a81af3

Browse files
committed
1 parent dbce753 commit 9a81af3

17 files changed

+177
-194
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
@@ -64,8 +64,8 @@ export "package:angular/core/module_internal.dart" show
6464
FilterMap,
6565
Interpolate,
6666
VmTurnZone,
67-
PrototypeMap,
6867
RootScope,
68+
LocalContext,
6969
Scope,
7070
ScopeDigestTTL,
7171
ScopeEvent,

lib/core/module_internal.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class CoreModule extends Module {
4444
type(ScopeStats);
4545
type(ScopeStatsEmitter);
4646
factory(ScopeStatsConfig, (i) => new ScopeStatsConfig());
47+
// todo (vicb)
4748
value(Object, {}); // RootScope context
4849
type(VmTurnZone);
4950

lib/core/scope.dart

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

141150
/**
142151
* The [RootScope] of the application.
@@ -182,9 +191,12 @@ class Scope {
182191
/// Do not use. Exposes internal state for testing.
183192
bool get hasOwnStreams => _streams != null && _streams._scope == this;
184193

185-
Scope(Object this.context, this.rootScope, this._parentScope,
194+
// todo(vicb) this.context
195+
Scope(Object _context, this.rootScope, this._parentScope,
186196
this._readWriteGroup, this._readOnlyGroup, this.id,
187-
this._stats);
197+
this._stats) {
198+
context = _context;
199+
}
188200

189201
/**
190202
* Use [watch] to set up change detection on an expression.
@@ -204,7 +216,7 @@ class Scope {
204216
* by reference. When watching a collection, the reaction function receives a
205217
* [CollectionChangeItem] that lists all the changes.
206218
*/
207-
Watch watch(String expression, ReactionFn reactionFn, {context,
219+
Watch watch(String expression, ReactionFn reactionFn, {context,
208220
FormatterMap formatters, bool canChangeModel: true, bool collection: false}) {
209221
assert(isAttached);
210222
assert(expression is String);
@@ -244,8 +256,8 @@ class Scope {
244256
expression is String ||
245257
expression is Function);
246258
if (expression is String && expression.isNotEmpty) {
247-
var obj = locals == null ? context : new ScopeLocals(context, locals);
248-
return rootScope._parser(expression).eval(obj);
259+
var ctx = locals == null ? context : new LocalContext(context, locals);
260+
return rootScope._parser(expression).eval(ctx);
249261
}
250262

251263
assert(locals == null);
@@ -321,7 +333,7 @@ class Scope {
321333
_parentScope = null;
322334
}
323335

324-
_assertInternalStateConsistency() {
336+
void _assertInternalStateConsistency() {
325337
assert((() {
326338
rootScope._verifyStreams(null, '', []);
327339
return true;
@@ -358,7 +370,7 @@ class Scope {
358370
}
359371
}
360372

361-
_mapEqual(Map a, Map b) => a.length == b.length &&
373+
bool _mapEqual(Map a, Map b) => a.length == b.length &&
362374
a.keys.every((k) => b.containsKey(k) && a[k] == b[k]);
363375

364376
/**
@@ -399,7 +411,7 @@ class ScopeStats {
399411
processStopwatch.elapsedMicroseconds;
400412
}
401413

402-
_stopwatchReset() {
414+
void _stopwatchReset() {
403415
fieldStopwatch.reset();
404416
evalStopwatch.reset();
405417
processStopwatch.reset();
@@ -464,9 +476,9 @@ class ScopeStatsEmitter {
464476

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

467-
_ms(num value) => '${pad(_nfDec.format(value), 9)} ms';
468-
_us(num value) => _ms(value / 1000);
469-
_tally(num value) => '${pad(_nfInt.format(value), 6)}';
479+
String _ms(num value) => '${pad(_nfDec.format(value), 9)} ms';
480+
String _us(num value) => _ms(value / 1000);
481+
String _tally(num value) => '${pad(_nfInt.format(value), 6)}';
470482

471483
/**
472484
* Emit a message based on the phase and state of stopwatches.
@@ -490,9 +502,8 @@ class ScopeStatsEmitter {
490502
return (prefix == '1' ? _HEADER_ : '') + ' #$prefix:';
491503
}
492504

493-
String _stat(AvgStopwatch s) {
494-
return '${_tally(s.count)} / ${_us(s.elapsedMicroseconds)} @(${_tally(s.ratePerMs)} #/ms)';
495-
}
505+
String _stat(AvgStopwatch s) =>
506+
'${_tally(s.count)} / ${_us(s.elapsedMicroseconds)} @(${_tally(s.ratePerMs)} #/ms)';
496507
}
497508

498509
/**
@@ -503,6 +514,7 @@ class ScopeStatsConfig {
503514
var emit = false;
504515

505516
ScopeStatsConfig();
517+
506518
ScopeStatsConfig.enabled() {
507519
emit = true;
508520
}
@@ -568,8 +580,8 @@ class RootScope extends Scope {
568580
* followed by change detection
569581
* on non-DOM listeners. Any changes detected are process using the reaction function. The digest
570582
* phase is repeated as long as at least one change has been detected. By default, after 5
571-
* iterations the model is considered unstable and angular exists with an exception. (See
572-
* ScopeDigestTTL)
583+
* iterations the model is considered unstable and angular exits with an exception. (See
584+
* [ScopeDigestTTL])
573585
*
574586
* ##flush
575587
*

lib/core_dom/common.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ Injector forceNewDirectivesAndFilters(Injector injector, List<Module> modules) {
3939
modules.add(new Module()
4040
..factory(Scope, (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: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,16 @@ class ElementBinder {
174174
probe.directives.add(controller);
175175
assert((linkMapTimer = _perf.startTimer('ng.view.link.map', ref.type)) != false);
176176

177+
177178
if (ref.annotation is Controller) {
178-
scope.context[(ref.annotation as Controller).publishAs] = controller;
179+
// todo(vicb)
180+
print("_link context = $controller");
181+
scope.context = controller;
179182
}
180183

181-
var tasks = new _TaskList(controller is AttachAware ? () {
182-
if (scope.isAttached) controller.attach();
183-
} : null);
184+
var tasks = new _TaskList(controller is AttachAware ?
185+
() {if (scope.isAttached) controller.attach();} :
186+
null);
184187

185188
_createAttrMappings(controller, scope, ref, nodeAttrs, formatters, tasks);
186189

@@ -273,16 +276,17 @@ class ElementBinder {
273276

274277
directiveRefs.forEach((DirectiveRef ref) {
275278
Directive annotation = ref.annotation;
276-
var visibility = ref.annotation.visibility;
277-
if (ref.annotation is Controller) {
278-
scope = scope.createChild(new PrototypeMap(scope.context));
279+
280+
if (annotation is Controller) {
281+
//todo(vicb)
282+
scope = scope.createChild(scope.context);
279283
nodeModule.value(Scope, scope);
280284
}
281285

282286
_createDirectiveFactories(ref, nodeModule, node, nodesAttrsDirectives, nodeAttrs,
283-
visibility);
284-
if (ref.annotation.module != null) {
285-
nodeModule.install(ref.annotation.module());
287+
annotation.visibility);
288+
if (annotation.module != null) {
289+
nodeModule.install(annotation.module());
286290
}
287291
});
288292

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;
@@ -61,7 +62,7 @@ class CoreDomModule extends Module {
6162
type(TranscludingComponentFactory);
6263
type(Content);
6364
value(ContentPort, null);
64-
65+
6566
type(Http);
6667
type(UrlRewriter);
6768
type(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
@@ -32,19 +32,19 @@ class ShadowDomComponentFactory implements ComponentFactory {
3232
FactoryFn call(dom.Node node, DirectiveRef ref) {
3333
return (Injector injector) {
3434
var component = ref.annotation as Component;
35-
Scope scope = injector.get(Scope);
36-
ViewCache viewCache = injector.get(ViewCache);
37-
Http http = injector.get(Http);
38-
TemplateCache templateCache = injector.get(TemplateCache);
39-
DirectiveMap directives = injector.get(DirectiveMap);
40-
NgBaseCss baseCss = injector.get(NgBaseCss);
35+
final scope = injector.get(Scope);
36+
final viewCache = injector.get(ViewCache);
37+
final http = injector.get(Http);
38+
final templateCache = injector.get(TemplateCache);
39+
final directives = injector.get(DirectiveMap);
40+
final baseCss = injector.get(NgBaseCss);
4141
// This is a bit of a hack since we are returning different type then we are.
4242
var componentFactory = new _ComponentFactory(node, ref.type, component,
4343
injector.get(dom.NodeTreeSanitizer), _expando, baseCss);
4444
var controller = componentFactory.call(injector, scope, viewCache, http, templateCache,
4545
directives);
4646

47-
componentFactory.shadowScope.context[component.publishAs] = controller;
47+
componentFactory.shadowScope.context = controller;
4848
return controller;
4949
};
5050
}

lib/core_dom/transcluding_component_factory.dart

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

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

0 commit comments

Comments
 (0)