@@ -2,12 +2,14 @@ part of angular.core.dom;
2
2
3
3
@NgInjectableService ()
4
4
class ElementBinderFactory {
5
- Parser _parser;
5
+ final Parser _parser;
6
+ final Profiler _perf;
7
+ final Expando _expando;
6
8
7
- ElementBinderFactory (Parser this ._parser);
9
+ ElementBinderFactory (this ._parser, this ._perf, this ._expando );
8
10
9
- binder ([ int templateIndex] ) {
10
- return new ElementBinder (_parser);
11
+ binder () {
12
+ return new ElementBinder (_parser, _perf, _expando );
11
13
}
12
14
}
13
15
@@ -17,31 +19,38 @@ class ElementBinderFactory {
17
19
*/
18
20
19
21
class ElementBinder {
22
+ // DI Services
20
23
Parser _parser;
24
+ Profiler _perf;
25
+ Expando _expando;
21
26
22
- ElementBinder (this ._parser);
23
-
24
- ElementBinder .forTransclusion (ElementBinder other) {
25
- _parser = other._parser;
26
- decorators = other.decorators;
27
- component = other.component;
28
- childMode = other.childMode;
29
- childElementBinders = other.childElementBinders;
30
- }
31
-
27
+ // Member fields
32
28
List <DirectiveRef > decorators = [];
33
-
34
29
DirectiveRef template;
30
+ ViewFactory templateViewFactory;
35
31
36
32
DirectiveRef component;
37
-
38
33
var childElementBinders;
39
-
40
34
var offsetIndex;
41
35
42
36
// Can be either COMPILE_CHILDREN or IGNORE_CHILDREN
43
37
String childMode = NgAnnotation .COMPILE_CHILDREN ;
44
38
39
+
40
+ ElementBinder (this ._parser, this ._perf, this ._expando);
41
+
42
+ ElementBinder .forTransclusion (ElementBinder other) {
43
+ _parser = other._parser;
44
+ _perf = other._perf;
45
+ _expando = other._expando;
46
+
47
+ decorators = other.decorators;
48
+ component = other.component;
49
+ childElementBinders = other.childElementBinders;
50
+ offsetIndex = other.offsetIndex;
51
+ childMode = other.childMode;
52
+ }
53
+
45
54
addDirective (DirectiveRef ref) {
46
55
var annotation = ref.annotation;
47
56
var children = annotation.children;
@@ -61,15 +70,19 @@ class ElementBinder {
61
70
createMappings (ref);
62
71
}
63
72
64
- List <DirectiveRef > walkDOM (compileTransclusionCallback, compileChildrenCallback) {
65
- if (template != null ) {
66
- template.viewFactory = compileTransclusionCallback (new ElementBinder .forTransclusion (this ));
67
- } else if (childMode == NgAnnotation .COMPILE_CHILDREN ) {
68
- childElementBinders = compileChildrenCallback ();
69
- }
73
+ bool get hasTemplate {
74
+ return template != null ;
70
75
}
71
76
72
- List <DirectiveRef > get usableDirectiveRefs {
77
+ bool get shouldCompileChildren {
78
+ return childMode == NgAnnotation .COMPILE_CHILDREN ;
79
+ }
80
+
81
+ ElementBinder get templateBinder {
82
+ return new ElementBinder .forTransclusion (this );
83
+ }
84
+
85
+ List <DirectiveRef > get _usableDirectiveRefs {
73
86
if (template != null ) {
74
87
return [template];
75
88
}
@@ -79,9 +92,185 @@ class ElementBinder {
79
92
return decorators;
80
93
}
81
94
95
+ bool get isUseful {
96
+ return (_usableDirectiveRefs != null && _usableDirectiveRefs.length != 0 ) || childElementBinders != null ;
97
+ }
98
+
99
+ // DI visibility callback allowing node-local visibility.
100
+
101
+ static final Function _elementOnly = (Injector requesting, Injector defining) {
102
+ if (requesting.name == _SHADOW ) {
103
+ requesting = requesting.parent;
104
+ }
105
+ return identical (requesting, defining);
106
+ };
107
+
108
+ // DI visibility callback allowing visibility from direct child into parent.
109
+
110
+ static final Function _elementDirectChildren = (Injector requesting, Injector defining) {
111
+ if (requesting.name == _SHADOW ) {
112
+ requesting = requesting.parent;
113
+ }
114
+ return _elementOnly (requesting, defining) || identical (requesting.parent, defining);
115
+ };
116
+
117
+ Injector bind (View view, Injector parentInjector, dom.Node node) {
118
+ var timerId;
119
+ assert ((timerId = _perf.startTimer ('ng.view.link.setUp' , _html (node))) != false );
120
+ Injector nodeInjector;
121
+ Scope scope = parentInjector.get (Scope );
122
+ FilterMap filters = parentInjector.get (FilterMap );
123
+ Map <Type , _ComponentFactory > fctrs;
124
+ var nodeAttrs = node is dom.Element ? new NodeAttrs (node) : null ;
125
+ ElementProbe probe;
126
+
127
+ var directiveRefs = _usableDirectiveRefs;
128
+ try {
129
+ if (directiveRefs == null || directiveRefs.length == 0 ) return parentInjector;
130
+ var nodeModule = new Module ();
131
+ var viewPortFactory = (_) => null ;
132
+ var viewFactory = (_) => null ;
133
+ var boundViewFactory = (_) => null ;
134
+ var nodesAttrsDirectives = null ;
82
135
83
- bool isUseful () {
84
- return (usableDirectiveRefs != null && usableDirectiveRefs.length != 0 ) || childElementBinders != null ;
136
+ nodeModule.value (View , view);
137
+ nodeModule.value (dom.Element , node);
138
+ nodeModule.value (dom.Node , node);
139
+ nodeModule.value (NodeAttrs , nodeAttrs);
140
+ directiveRefs.forEach ((DirectiveRef ref) {
141
+ NgAnnotation annotation = ref.annotation;
142
+ var visibility = _elementOnly;
143
+ if (ref.annotation is NgController ) {
144
+ scope = scope.createChild (new PrototypeMap (scope.context));
145
+ nodeModule.value (Scope , scope);
146
+ }
147
+ if (ref.annotation.visibility == NgDirective .CHILDREN_VISIBILITY ) {
148
+ visibility = null ;
149
+ } else if (ref.annotation.visibility == NgDirective .DIRECT_CHILDREN_VISIBILITY ) {
150
+ visibility = _elementDirectChildren;
151
+ }
152
+ if (ref.type == NgTextMustacheDirective ) {
153
+ nodeModule.factory (NgTextMustacheDirective , (Injector injector) {
154
+ return new NgTextMustacheDirective (
155
+ node, ref.value, injector.get (Interpolate ), injector.get (Scope ),
156
+ injector.get (AstParser ), injector.get (FilterMap ));
157
+ });
158
+ } else if (ref.type == NgAttrMustacheDirective ) {
159
+ if (nodesAttrsDirectives == null ) {
160
+ nodesAttrsDirectives = [];
161
+ nodeModule.factory (NgAttrMustacheDirective , (Injector injector) {
162
+ var scope = injector.get (Scope );
163
+ var interpolate = injector.get (Interpolate );
164
+ for (var ref in nodesAttrsDirectives) {
165
+ new NgAttrMustacheDirective (nodeAttrs, ref.value, interpolate,
166
+ scope, injector.get (AstParser ), injector.get (FilterMap ));
167
+ }
168
+ });
169
+ }
170
+ nodesAttrsDirectives.add (ref);
171
+ } else if (ref.annotation is NgComponent ) {
172
+ //nodeModule.factory(type, new ComponentFactory(node, ref.directive), visibility: visibility);
173
+ // TODO(misko): there should be no need to wrap function like this.
174
+ nodeModule.factory (ref.type, (Injector injector) {
175
+ Compiler compiler = injector.get (Compiler );
176
+ Scope scope = injector.get (Scope );
177
+ ViewCache viewCache = injector.get (ViewCache );
178
+ Http http = injector.get (Http );
179
+ TemplateCache templateCache = injector.get (TemplateCache );
180
+ DirectiveMap directives = injector.get (DirectiveMap );
181
+ // This is a bit of a hack since we are returning different type then we are.
182
+ var componentFactory = new _ComponentFactory (node, ref.type,
183
+ ref.annotation as NgComponent ,
184
+ injector.get (dom.NodeTreeSanitizer ), _expando);
185
+ if (fctrs == null ) fctrs = new Map <Type , _ComponentFactory >();
186
+ fctrs[ref.type] = componentFactory;
187
+ return componentFactory.call (injector, compiler, scope, viewCache, http, templateCache, directives);
188
+ }, visibility: visibility);
189
+ } else {
190
+ nodeModule.type (ref.type, visibility: visibility);
191
+ }
192
+ for (var publishType in ref.annotation.publishTypes) {
193
+ nodeModule.factory (publishType, (Injector injector) => injector.get (ref.type), visibility: visibility);
194
+ }
195
+ if (annotation.children == NgAnnotation .TRANSCLUDE_CHILDREN ) {
196
+ // Currently, transclude is only supported for NgDirective.
197
+ assert (annotation is NgDirective );
198
+ viewPortFactory = (_) => new ViewPort (node,
199
+ parentInjector.get (NgAnimate ));
200
+ viewFactory = (_) => templateViewFactory;
201
+ boundViewFactory = (Injector injector) => templateViewFactory.bind (injector);
202
+ }
203
+ });
204
+ nodeModule
205
+ ..factory (ViewPort , viewPortFactory)
206
+ ..factory (ViewFactory , viewFactory)
207
+ ..factory (BoundViewFactory , boundViewFactory)
208
+ ..factory (ElementProbe , (_) => probe);
209
+ nodeInjector = parentInjector.createChild ([nodeModule]);
210
+ probe = _expando[node] = new ElementProbe (
211
+ parentInjector.get (ElementProbe ), node, nodeInjector, scope);
212
+ } finally {
213
+ assert (_perf.stopTimer (timerId) != false );
214
+ }
215
+ directiveRefs.forEach ((DirectiveRef ref) {
216
+ var linkTimer;
217
+ try {
218
+ var linkMapTimer;
219
+ assert ((linkTimer = _perf.startTimer ('ng.view.link' , ref.type)) != false );
220
+ var controller = nodeInjector.get (ref.type);
221
+ probe.directives.add (controller);
222
+ assert ((linkMapTimer = _perf.startTimer ('ng.view.link.map' , ref.type)) != false );
223
+ var shadowScope = (fctrs != null && fctrs.containsKey (ref.type)) ? fctrs[ref.type].shadowScope : null ;
224
+ if (ref.annotation is NgController ) {
225
+ scope.context[(ref.annotation as NgController ).publishAs] = controller;
226
+ } else if (ref.annotation is NgComponent ) {
227
+ shadowScope.context[(ref.annotation as NgComponent ).publishAs] = controller;
228
+ }
229
+ if (nodeAttrs == null ) nodeAttrs = new _AnchorAttrs (ref);
230
+ var attachDelayStatus = controller is NgAttachAware ? [false ] : null ;
231
+ checkAttachReady () {
232
+ if (attachDelayStatus.reduce ((a, b) => a && b)) {
233
+ attachDelayStatus = null ;
234
+ if (scope.isAttached) {
235
+ controller.attach ();
236
+ }
237
+ }
238
+ }
239
+ for (var map in ref.mappings) {
240
+ var notify;
241
+ if (attachDelayStatus != null ) {
242
+ var index = attachDelayStatus.length;
243
+ attachDelayStatus.add (false );
244
+ notify = () {
245
+ if (attachDelayStatus != null ) {
246
+ attachDelayStatus[index] = true ;
247
+ checkAttachReady ();
248
+ }
249
+ };
250
+ } else {
251
+ notify = () => null ;
252
+ }
253
+ map (nodeAttrs, scope, controller, filters, notify);
254
+ }
255
+ if (attachDelayStatus != null ) {
256
+ Watch watch;
257
+ watch = scope.watch (
258
+ '1' , // Cheat a bit.
259
+ (_, __) {
260
+ watch.remove ();
261
+ attachDelayStatus[0 ] = true ;
262
+ checkAttachReady ();
263
+ });
264
+ }
265
+ if (controller is NgDetachAware ) {
266
+ scope.on (ScopeEvent .DESTROY ).listen ((_) => controller.detach ());
267
+ }
268
+ assert (_perf.stopTimer (linkMapTimer) != false );
269
+ } finally {
270
+ assert (_perf.stopTimer (linkTimer) != false );
271
+ }
272
+ });
273
+ return nodeInjector;
85
274
}
86
275
87
276
static RegExp _MAPPING = new RegExp (r'^(\@|=\>\!|\=\>|\<\=\>|\&)\s*(.*)$' );
@@ -188,5 +377,4 @@ class ElementBinder {
188
377
ref.mappings.add (mappingFn);
189
378
});
190
379
}
191
-
192
380
}
0 commit comments