Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit cb9a9d7

Browse files
committed
fix(directive-injector): Fixes for Direcive Injector.
Breaking change: Regular (application) injectors cannot construct DirectiveInjectors (DI). Only compilers create DI as part of view creation process. Deprecation: directive injector parent is now private. New public method on dependency injector - parentGet, which allows to get through the usual chain but skipping itself. TestBed does not need DI in its constructor. Internal changes: - Application Injector reference is passed through view creation and passed into new Directive Injector (instead of using parentInjector.appInjector, which is wrong when used with ng-view). - Unwind recursion from the directive injector for performance. - Remove EventListener from View. - Replace DefaultDirectiveInjector with DirectiveInjector with parent = null. - Component visibility handled outside the visibility enum. - Removed Shadowless and ShadowDirectiveInjector subclasses. Prepares for ComponentInjectors breaking the resolution chain, unless directly called. Does not land that change because it is used by clients. Closes #1111
1 parent 665e121 commit cb9a9d7

29 files changed

+341
-234
lines changed

lib/application.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ abstract class Application {
189189
DirectiveMap directiveMap = injector.getByKey(DIRECTIVE_MAP_KEY);
190190
RootScope rootScope = injector.getByKey(ROOT_SCOPE_KEY);
191191
ViewFactory viewFactory = compiler(rootElements, directiveMap);
192-
viewFactory(rootScope, injector.get(DirectiveInjector), rootElements);
192+
viewFactory(rootScope, null, rootElements);
193193
} catch (e, s) {
194194
exceptionHandler(e, s);
195195
}

lib/core_dom/common.dart

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,3 @@ class DirectiveRef {
4545
}
4646
}
4747

48-
/**
49-
* Creates a child injector that allows loading new directives, formatters and
50-
* services from the provided modules.
51-
*/
52-
Injector forceNewDirectivesAndFormatters(Injector injector, DirectiveInjector dirInjector,
53-
List<Module> modules) {
54-
modules.add(new Module()
55-
..bind(Scope, toFactory: (Injector injector) {
56-
var scope = injector.parent.getByKey(SCOPE_KEY);
57-
return scope.createChild(new PrototypeMap(scope.context));
58-
}, inject: [INJECTOR_KEY])
59-
..bind(DirectiveMap)
60-
..bind(FormatterMap)
61-
..bind(DirectiveInjector,
62-
toFactory: () => new DefaultDirectiveInjector.newAppInjector(dirInjector, injector)));
63-
64-
return new ModuleInjector(modules, injector);
65-
}

lib/core_dom/directive_injector.dart

Lines changed: 84 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,11 @@ final CONTENT_PORT_KEY = new Key(ContentPort);
2424
final TEMPLATE_LOADER_KEY = new Key(TemplateLoader);
2525
final SHADOW_ROOT_KEY = new Key(ShadowRoot);
2626

27+
final num MAX_DEPTH = 1 << 30;
28+
2729
const int VISIBILITY_LOCAL = -1;
2830
const int VISIBILITY_DIRECT_CHILD = -2;
2931
const int VISIBILITY_CHILDREN = -3;
30-
const int VISIBILITY_COMPONENT_OFFSET = VISIBILITY_CHILDREN;
31-
const int VISIBILITY_COMPONENT_LOCAL = VISIBILITY_LOCAL + VISIBILITY_COMPONENT_OFFSET;
32-
const int VISIBILITY_COMPONENT_DIRECT_CHILD = VISIBILITY_DIRECT_CHILD + VISIBILITY_COMPONENT_OFFSET;
33-
const int VISIBILITY_COMPONENT_CHILDREN = VISIBILITY_CHILDREN + VISIBILITY_COMPONENT_OFFSET;
3432

3533
const int UNDEFINED_ID = 0;
3634
const int INJECTOR_KEY_ID = 1;
@@ -52,6 +50,8 @@ const int CONTENT_PORT_KEY_ID = 16;
5250
const int EVENT_HANDLER_KEY_ID = 17;
5351
const int KEEP_ME_LAST = 18;
5452

53+
EventHandler eventHandler(DirectiveInjector di) => di._eventHandler;
54+
5555
class DirectiveInjector implements DirectiveBinder {
5656
static bool _isInit = false;
5757
static initUID() {
@@ -99,9 +99,9 @@ class DirectiveInjector implements DirectiveBinder {
9999
, EVENT_HANDLER_KEY
100100
, KEEP_ME_LAST
101101
];
102-
102+
103103
final DirectiveInjector _parent;
104-
final Injector appInjector;
104+
final Injector _appInjector;
105105
final Node _node;
106106
final NodeAttrs _nodeAttrs;
107107
final Animate _animate;
@@ -134,21 +134,17 @@ class DirectiveInjector implements DirectiveBinder {
134134
case VISIBILITY_LOCAL: return Visibility.LOCAL;
135135
case VISIBILITY_DIRECT_CHILD: return Visibility.DIRECT_CHILD;
136136
case VISIBILITY_CHILDREN: return Visibility.CHILDREN;
137-
case VISIBILITY_COMPONENT_LOCAL: return Visibility.LOCAL;
138-
case VISIBILITY_COMPONENT_DIRECT_CHILD: return Visibility.DIRECT_CHILD;
139-
case VISIBILITY_COMPONENT_CHILDREN: return Visibility.CHILDREN;
140137
default: return null;
141138
}
142139
}
143140

144141
static Binding _tempBinding = new Binding();
145142

146-
DirectiveInjector(DirectiveInjector parent, Injector appInjector, this._node, this._nodeAttrs,
143+
DirectiveInjector(this._parent, appInjector, this._node, this._nodeAttrs,
147144
this._eventHandler, this.scope, this._animate)
148-
: appInjector = appInjector,
149-
_parent = parent == null ? new DefaultDirectiveInjector(appInjector) : parent;
145+
: _appInjector = appInjector;
150146

151-
DirectiveInjector._default(this._parent, this.appInjector)
147+
DirectiveInjector._default(this._parent, this._appInjector)
152148
: _node = null,
153149
_nodeAttrs = null,
154150
_eventHandler = null,
@@ -195,54 +191,72 @@ class DirectiveInjector implements DirectiveBinder {
195191
else { throw 'Maximum number of directives per element reached.'; }
196192
}
197193

194+
// Get a key from the directive injector chain. When it is exhausted, get from
195+
// the current application injector chain.
198196
Object get(Type type) => getByKey(new Key(type));
199-
Object getFromParent(Type type) => _parent.get(type);
197+
Object getFromParent(Type type) => getFromParentByKey(new Key(type));
200198

201199
Object getByKey(Key key) {
202200
var oldTag = _TAG_GET.makeCurrent();
203201
try {
204-
return _getByKey(key);
202+
return _getByKey(key, _appInjector);
205203
} on ResolvingError catch (e, s) {
206204
e.appendKey(key);
207205
rethrow;
208206
} finally {
209207
oldTag.makeCurrent();
210208
}
211209
}
212-
Object getFromParentByKey(Key key) => _parent.getByKey(key);
213210

214-
Object _getByKey(Key key) {
211+
Object getFromParentByKey(Key key) {
212+
if (_parent == null) {
213+
return _appInjector.getByKey(key);
214+
} else {
215+
return _parent._getByKey(key, _appInjector);
216+
}
217+
}
218+
219+
Object _getByKey(Key key, Injector appInjector) {
215220
int uid = key.uid;
216221
if (uid == null || uid == UNDEFINED_ID) return appInjector.getByKey(key);
217222
bool isDirective = uid < 0;
218223
return isDirective ? _getDirectiveByKey(key, uid, appInjector) : _getById(uid);
219224
}
220225

221-
Object _getDirectiveByKey(Key k, int visType, Injector i) {
222-
do {
223-
if (_key0 == null) break; if (identical(_key0, k)) return _obj0 == null ? _obj0 = _new(_pKeys0, _factory0) : _obj0;
224-
if (_key1 == null) break; if (identical(_key1, k)) return _obj1 == null ? _obj1 = _new(_pKeys1, _factory1) : _obj1;
225-
if (_key2 == null) break; if (identical(_key2, k)) return _obj2 == null ? _obj2 = _new(_pKeys2, _factory2) : _obj2;
226-
if (_key3 == null) break; if (identical(_key3, k)) return _obj3 == null ? _obj3 = _new(_pKeys3, _factory3) : _obj3;
227-
if (_key4 == null) break; if (identical(_key4, k)) return _obj4 == null ? _obj4 = _new(_pKeys4, _factory4) : _obj4;
228-
if (_key5 == null) break; if (identical(_key5, k)) return _obj5 == null ? _obj5 = _new(_pKeys5, _factory5) : _obj5;
229-
if (_key6 == null) break; if (identical(_key6, k)) return _obj6 == null ? _obj6 = _new(_pKeys6, _factory6) : _obj6;
230-
if (_key7 == null) break; if (identical(_key7, k)) return _obj7 == null ? _obj7 = _new(_pKeys7, _factory7) : _obj7;
231-
if (_key8 == null) break; if (identical(_key8, k)) return _obj8 == null ? _obj8 = _new(_pKeys8, _factory8) : _obj8;
232-
if (_key9 == null) break; if (identical(_key9, k)) return _obj9 == null ? _obj9 = _new(_pKeys9, _factory9) : _obj9;
233-
} while (false);
234-
switch (visType) {
235-
case VISIBILITY_LOCAL: return appInjector.getByKey(k);
236-
case VISIBILITY_DIRECT_CHILD: return _parent._getDirectiveByKey(k, VISIBILITY_LOCAL, i);
237-
case VISIBILITY_CHILDREN: return _parent._getDirectiveByKey(k, VISIBILITY_CHILDREN, i);
238-
// SHADOW
239-
case VISIBILITY_COMPONENT_LOCAL: return _parent._getDirectiveByKey(k, VISIBILITY_LOCAL, i);
240-
case VISIBILITY_COMPONENT_DIRECT_CHILD: return _parent._getDirectiveByKey(k, VISIBILITY_DIRECT_CHILD, i);
241-
case VISIBILITY_COMPONENT_CHILDREN: return _parent._getDirectiveByKey(k, VISIBILITY_CHILDREN, i);
226+
num _getDepth(int visType) {
227+
switch(visType) {
228+
case VISIBILITY_LOCAL: return 0;
229+
case VISIBILITY_DIRECT_CHILD: return 1;
230+
case VISIBILITY_CHILDREN: return MAX_DEPTH;
242231
default: throw null;
243232
}
244233
}
245234

235+
_getDirectiveByKey(Key k, int visType, Injector appInjector) {
236+
num depth = _getDepth(visType);
237+
// ci stands for currentInjector, abbreviated for readability.
238+
var ci = this;
239+
while (ci != null && depth >= 0) {
240+
do {
241+
if (ci._key0 == null) break; if (identical(ci._key0, k)) return ci._obj0 == null ? ci._obj0 = ci._new(ci._pKeys0, ci._factory0) : ci._obj0;
242+
if (ci._key1 == null) break; if (identical(ci._key1, k)) return ci._obj1 == null ? ci._obj1 = ci._new(ci._pKeys1, ci._factory1) : ci._obj1;
243+
if (ci._key2 == null) break; if (identical(ci._key2, k)) return ci._obj2 == null ? ci._obj2 = ci._new(ci._pKeys2, ci._factory2) : ci._obj2;
244+
if (ci._key3 == null) break; if (identical(ci._key3, k)) return ci._obj3 == null ? ci._obj3 = ci._new(ci._pKeys3, ci._factory3) : ci._obj3;
245+
if (ci._key4 == null) break; if (identical(ci._key4, k)) return ci._obj4 == null ? ci._obj4 = ci._new(ci._pKeys4, ci._factory4) : ci._obj4;
246+
if (ci._key5 == null) break; if (identical(ci._key5, k)) return ci._obj5 == null ? ci._obj5 = ci._new(ci._pKeys5, ci._factory5) : ci._obj5;
247+
if (ci._key6 == null) break; if (identical(ci._key6, k)) return ci._obj6 == null ? ci._obj6 = ci._new(ci._pKeys6, ci._factory6) : ci._obj6;
248+
if (ci._key7 == null) break; if (identical(ci._key7, k)) return ci._obj7 == null ? ci._obj7 = ci._new(ci._pKeys7, ci._factory7) : ci._obj7;
249+
if (ci._key8 == null) break; if (identical(ci._key8, k)) return ci._obj8 == null ? ci._obj8 = ci._new(ci._pKeys8, ci._factory8) : ci._obj8;
250+
if (ci._key9 == null) break; if (identical(ci._key9, k)) return ci._obj9 == null ? ci._obj9 = ci._new(ci._pKeys9, ci._factory9) : ci._obj9;
251+
} while (false);
252+
// Future feature: Component Injectors fall-through only if directly called.
253+
// if ((ci is ComponentDirectiveInjector) && !identical(ci, this)) break;
254+
ci = ci._parent;
255+
depth--;
256+
}
257+
return appInjector.getByKey(k);
258+
}
259+
246260
List get directives {
247261
var directives = [];
248262
if (_obj0 != null) directives.add(_obj0);
@@ -260,7 +274,7 @@ class DirectiveInjector implements DirectiveBinder {
260274

261275
Object _getById(int keyId) {
262276
switch(keyId) {
263-
case INJECTOR_KEY_ID: return appInjector;
277+
case INJECTOR_KEY_ID: return _appInjector;
264278
case DIRECTIVE_INJECTOR_KEY_ID: return this;
265279
case NODE_KEY_ID: return _node;
266280
case ELEMENT_KEY_ID: return _node;
@@ -270,7 +284,13 @@ class DirectiveInjector implements DirectiveBinder {
270284
case ELEMENT_PROBE_KEY_ID: return elementProbe;
271285
case NG_ELEMENT_KEY_ID: return ngElement;
272286
case EVENT_HANDLER_KEY_ID: return _eventHandler;
273-
case CONTENT_PORT_KEY_ID: return _parent._getById(keyId);
287+
case CONTENT_PORT_KEY_ID:
288+
var currentInjector = _parent;
289+
while (currentInjector != null) {
290+
if (currentInjector is ComponentDirectiveInjector) return currentInjector._contentPort;
291+
currentInjector = currentInjector._parent;
292+
}
293+
return null;
274294
default: new NoProviderError(_KEYS[keyId]);
275295
}
276296
}
@@ -279,29 +299,30 @@ class DirectiveInjector implements DirectiveBinder {
279299
var oldTag = _TAG_GET.makeCurrent();
280300
int size = paramKeys.length;
281301
var obj;
302+
var appInjector = this._appInjector;
282303
if (size > 15) {
283304
var params = new List(paramKeys.length);
284305
for(var i = 0; i < paramKeys.length; i++) {
285-
params[i] = _getByKey(paramKeys[i]);
306+
params[i] = _getByKey(paramKeys[i], appInjector);
286307
}
287308
_TAG_INSTANTIATE.makeCurrent();
288309
obj = Function.apply(fn, params);
289310
} else {
290-
var a01 = size >= 01 ? _getByKey(paramKeys[00]) : null;
291-
var a02 = size >= 02 ? _getByKey(paramKeys[01]) : null;
292-
var a03 = size >= 03 ? _getByKey(paramKeys[02]) : null;
293-
var a04 = size >= 04 ? _getByKey(paramKeys[03]) : null;
294-
var a05 = size >= 05 ? _getByKey(paramKeys[04]) : null;
295-
var a06 = size >= 06 ? _getByKey(paramKeys[05]) : null;
296-
var a07 = size >= 07 ? _getByKey(paramKeys[06]) : null;
297-
var a08 = size >= 08 ? _getByKey(paramKeys[07]) : null;
298-
var a09 = size >= 09 ? _getByKey(paramKeys[08]) : null;
299-
var a10 = size >= 10 ? _getByKey(paramKeys[09]) : null;
300-
var a11 = size >= 11 ? _getByKey(paramKeys[10]) : null;
301-
var a12 = size >= 12 ? _getByKey(paramKeys[11]) : null;
302-
var a13 = size >= 13 ? _getByKey(paramKeys[12]) : null;
303-
var a14 = size >= 14 ? _getByKey(paramKeys[13]) : null;
304-
var a15 = size >= 15 ? _getByKey(paramKeys[14]) : null;
311+
var a01 = size >= 01 ? _getByKey(paramKeys[00], appInjector) : null;
312+
var a02 = size >= 02 ? _getByKey(paramKeys[01], appInjector) : null;
313+
var a03 = size >= 03 ? _getByKey(paramKeys[02], appInjector) : null;
314+
var a04 = size >= 04 ? _getByKey(paramKeys[03], appInjector) : null;
315+
var a05 = size >= 05 ? _getByKey(paramKeys[04], appInjector) : null;
316+
var a06 = size >= 06 ? _getByKey(paramKeys[05], appInjector) : null;
317+
var a07 = size >= 07 ? _getByKey(paramKeys[06], appInjector) : null;
318+
var a08 = size >= 08 ? _getByKey(paramKeys[07], appInjector) : null;
319+
var a09 = size >= 09 ? _getByKey(paramKeys[08], appInjector) : null;
320+
var a10 = size >= 10 ? _getByKey(paramKeys[09], appInjector) : null;
321+
var a11 = size >= 11 ? _getByKey(paramKeys[10], appInjector) : null;
322+
var a12 = size >= 12 ? _getByKey(paramKeys[11], appInjector) : null;
323+
var a13 = size >= 13 ? _getByKey(paramKeys[12], appInjector) : null;
324+
var a14 = size >= 14 ? _getByKey(paramKeys[13], appInjector) : null;
325+
var a15 = size >= 15 ? _getByKey(paramKeys[14], appInjector) : null;
305326
_TAG_INSTANTIATE.makeCurrent();
306327
switch(size) {
307328
case 00: obj = fn(); break;
@@ -367,14 +388,15 @@ class TemplateDirectiveInjector extends DirectiveInjector {
367388

368389
}
369390

370-
abstract class ComponentDirectiveInjector extends DirectiveInjector {
391+
class ComponentDirectiveInjector extends DirectiveInjector {
371392

372393
final TemplateLoader _templateLoader;
373394
final ShadowRoot _shadowRoot;
395+
final ContentPort _contentPort;
374396

375397
ComponentDirectiveInjector(DirectiveInjector parent, Injector appInjector,
376398
EventHandler eventHandler, Scope scope,
377-
this._templateLoader, this._shadowRoot)
399+
this._templateLoader, this._shadowRoot, this._contentPort)
378400
: super(parent, appInjector, parent._node, parent._nodeAttrs, eventHandler, scope,
379401
parent._animate);
380402

@@ -386,56 +408,16 @@ abstract class ComponentDirectiveInjector extends DirectiveInjector {
386408
}
387409
}
388410

389-
_getDirectiveByKey(Key k, int visType, Injector i) =>
390-
super._getDirectiveByKey(k, visType + VISIBILITY_COMPONENT_OFFSET, i);
391-
}
392-
393-
class ShadowlessComponentDirectiveInjector extends ComponentDirectiveInjector {
394-
final ContentPort _contentPort;
395-
396-
ShadowlessComponentDirectiveInjector(DirectiveInjector parent, Injector appInjector,
397-
EventHandler eventHandler, Scope scope,
398-
templateLoader, shadowRoot, this._contentPort)
399-
: super(parent, appInjector, eventHandler, scope, templateLoader, shadowRoot);
400-
401-
Object _getById(int keyId) {
402-
switch(keyId) {
403-
case CONTENT_PORT_KEY_ID: return _contentPort;
404-
default: return super._getById(keyId);
405-
}
406-
}
407-
}
408-
409-
class ShadowDomComponentDirectiveInjector extends ComponentDirectiveInjector {
410-
ShadowDomComponentDirectiveInjector(DirectiveInjector parent, Injector appInjector,
411-
Scope scope, templateLoader, shadowRoot)
412-
: super(parent, appInjector, new ShadowRootEventHandler(shadowRoot,
413-
parent.getByKey(EXPANDO_KEY),
414-
parent.getByKey(EXCEPTION_HANDLER_KEY)),
415-
scope, templateLoader, shadowRoot);
416-
417411
ElementProbe get elementProbe {
418412
if (_elementProbe == null) {
419413
ElementProbe parentProbe = _parent == null ? null : _parent.elementProbe;
420414
_elementProbe = new ElementProbe(parentProbe, _shadowRoot, this, scope);
421415
}
422416
return _elementProbe;
423417
}
424-
}
425418

426-
@Injectable()
427-
class DefaultDirectiveInjector extends DirectiveInjector {
428-
DefaultDirectiveInjector(Injector appInjector): super._default(null, appInjector);
429-
DefaultDirectiveInjector.newAppInjector(DirectiveInjector parent, Injector appInjector)
430-
: super._default(parent, appInjector);
431-
432-
Object getByKey(Key key) => appInjector.getByKey(key);
433-
_getDirectiveByKey(Key key, int visType, Injector i) =>
434-
_parent == null ? i.getByKey(key) : _parent._getDirectiveByKey(key, visType, i);
435-
_getById(int keyId) {
436-
switch (keyId) {
437-
case CONTENT_PORT_KEY_ID: return null;
438-
default: throw new NoProviderError(DirectiveInjector._KEYS[keyId]);
439-
}
440-
}
419+
// Add 1 to visibility to allow to skip over current component injector.
420+
// For example, a local directive is visible from its component injector children.
421+
num _getDepth(int visType) => super._getDepth(visType) + 1;
441422
}
423+

lib/core_dom/directive_map.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ class DirectiveMap {
1313
final DirectiveSelectorFactory _directiveSelectorFactory;
1414
FormatterMap _formatters;
1515
DirectiveSelector _selector;
16+
Injector _injector;
1617

17-
DirectiveMap(Injector injector,
18+
DirectiveMap(Injector this._injector,
1819
this._formatters,
1920
MetadataExtractor metadataExtractor,
2021
this._directiveSelectorFactory) {
21-
(injector as ModuleInjector).types.forEach((type) {
22+
(_injector as ModuleInjector).types.forEach((type) {
2223
metadataExtractor(type)
2324
.where((annotation) => annotation is Directive)
2425
.forEach((Directive dir) {
@@ -29,7 +30,7 @@ class DirectiveMap {
2930

3031
DirectiveSelector get selector {
3132
if (_selector != null) return _selector;
32-
return _selector = _directiveSelectorFactory.selector(this, _formatters);
33+
return _selector = _directiveSelectorFactory.selector(this, _injector, _formatters);
3334
}
3435

3536
List<DirectiveTypeTuple> operator[](String key) {

0 commit comments

Comments
 (0)