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

Commit 59516af

Browse files
committed
feat(compiler): Tagging compiler
1 parent eb4422a commit 59516af

File tree

4 files changed

+127
-76
lines changed

4 files changed

+127
-76
lines changed

lib/core_dom/element_binder.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,27 @@ class ElementBinderTree {
391391
}
392392

393393

394+
class TaggedTextBinder {
395+
ElementBinder binder;
396+
final int offsetIndex;
397+
398+
TaggedTextBinder(this.binder, this.offsetIndex);
399+
}
400+
394401
// Used for the tagging compiler
395402
class TaggedElementBinder {
396403
ElementBinder binder;
397404
int parentBinderOffset;
405+
var injector;
406+
407+
List<TaggedTextBinder> textBinders;
398408

399409
TaggedElementBinder(this.binder, this.parentBinderOffset);
410+
411+
void addText(TaggedTextBinder tagged) {
412+
if (textBinders == null) {
413+
textBinders = [];
414+
}
415+
textBinders.add(tagged);
416+
}
400417
}

lib/core_dom/tagging_compiler.dart

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,48 +11,85 @@ class TaggingCompiler implements Compiler {
1111

1212
NodeCursor domCursor, NodeCursor templateCursor,
1313
ElementBinder useExistingElementBinder,
14-
DirectiveMap directives) {
14+
DirectiveMap directives,
15+
int parentElementBinderOffset,
16+
TaggedElementBinder directParentElementBinder) {
1517
List<TaggedElementBinder> elementBinders = [];
16-
if (domCursor.nodeList().length == 0) return null;
18+
if (domCursor.current == null) return null;
1719

1820

1921
do {
20-
var subtrees, binder;
22+
var node = domCursor.current;
2123

22-
var node = domCursor.nodeList()[0];
24+
ElementBinder elementBinder;
2325

24-
// If nodetype is a element, call selector matchElement. If text, call selector.matchText
26+
if (node.nodeType == 1) {
2527

26-
// TODO: selector will return null for non-useful bindings.
27-
ElementBinder elementBinder = useExistingElementBinder == null
28-
? directives.selector.match(node)
29-
: useExistingElementBinder;
28+
// If nodetype is a element, call selector matchElement. If text, call selector.matchText
3029

31-
if (elementBinder.hasTemplate) {
32-
elementBinder.templateViewFactory = _compileTransclusion(elementBinders,
33-
domCursor, templateCursor,
34-
elementBinder.template, elementBinder.templateBinder, directives);
30+
// TODO: selector will return null for non-useful bindings.
31+
elementBinder = useExistingElementBinder == null
32+
? directives.selector.matchElement(node)
33+
: useExistingElementBinder;
34+
35+
if (elementBinder.hasTemplate) {
36+
elementBinder.templateViewFactory = _compileTransclusion(elementBinders,
37+
domCursor, templateCursor,
38+
elementBinder.template, elementBinder.templateBinder, directives, parentElementBinderOffset);
39+
}
3540
}
3641

37-
if (elementBinder.shouldCompileChildren) {
38-
if (domCursor.descend()) {
39-
templateCursor.descend();
42+
node = domCursor.current;
43+
if (node.nodeType == 1) {
4044

41-
elementBinders.addAll(
42-
_compileView(domCursor, templateCursor, null, directives /*current element list length*/));
45+
var taggedElementBinder = null;
46+
if (elementBinder.hasDirectives || elementBinder.hasTemplate) {
47+
taggedElementBinder = new TaggedElementBinder(elementBinder, parentElementBinderOffset);
48+
elementBinders.add(taggedElementBinder);
49+
parentElementBinderOffset = elementBinders.length - 1;
4350

44-
domCursor.ascend();
45-
templateCursor.ascend();
51+
// TODO(deboer): Hack, this sucks.
52+
(templateCursor.current as dom.Element).classes.add('ng-binding');
53+
node.classes.add('ng-binding');
4654
}
47-
}
4855

49-
// move this up
50-
if (elementBinder.hasDirectives) {
51-
elementBinders.add(new TaggedElementBinder(elementBinder, -1));
52-
node.classes.add('ng-binding');
53-
binder = elementBinder;
56+
if (elementBinder.shouldCompileChildren) {
57+
if (domCursor.descend()) {
58+
templateCursor.descend();
59+
60+
elementBinders.addAll(
61+
_compileView(domCursor, templateCursor, null, directives, parentElementBinderOffset,
62+
taggedElementBinder));
63+
64+
domCursor.ascend();
65+
templateCursor.ascend();
66+
}
67+
}
68+
} else if (node.nodeType == 3 || node.nodeType == 8) {
69+
elementBinder = node.nodeType == 3 ? directives.selector.matchText(node) : elementBinder;
70+
71+
if (elementBinder.hasDirectives && (node.parentNode != null && templateCursor.current.parentNode != null)) {
72+
if (directParentElementBinder == null) {
73+
74+
directParentElementBinder = new TaggedElementBinder(null, parentElementBinderOffset);
75+
elementBinders.add(directParentElementBinder);
76+
77+
assert(templateCursor.current.parentNode is dom.Element);
78+
assert(node.parentNode is dom.Element);
79+
80+
(node.parentNode as dom.Element).classes.add('ng-binding');
81+
(templateCursor.current.parentNode as dom.Element).classes.add('ng-binding');
82+
}
83+
directParentElementBinder.addText(new TaggedTextBinder(elementBinder, 0 /* TODO */));
84+
} else if(!(node.parentNode != null && templateCursor.current.parentNode != null)) { // Always add an elementBinder for top-level text.
85+
elementBinders.add(new TaggedElementBinder(elementBinder, parentElementBinderOffset));
86+
}
87+
// } else if (node.nodeType == 8) { // comment
88+
89+
} else {
90+
throw "wtf";
5491
}
55-
} while (templateCursor.microNext() && domCursor.microNext());
92+
} while (templateCursor.moveNext() && domCursor.moveNext());
5693

5794
return elementBinders;
5895
}
@@ -61,28 +98,28 @@ class TaggingCompiler implements Compiler {
6198
NodeCursor domCursor, NodeCursor templateCursor,
6299
DirectiveRef directiveRef,
63100
ElementBinder transcludedElementBinder,
64-
DirectiveMap directives) {
101+
DirectiveMap directives,
102+
int parentElementBinderOffset) {
65103
var anchorName = directiveRef.annotation.selector + (directiveRef.value != null ? '=' + directiveRef.value : '');
66104
var viewFactory;
67105
var views;
68106

69107
var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
70108
var domCursorIndex = domCursor.index;
71109
var elementBinders =
72-
_compileView(domCursor, transcludeCursor, transcludedElementBinder, directives);
110+
_compileView(domCursor, transcludeCursor, transcludedElementBinder, directives, parentElementBinderOffset, null);
73111
if (elementBinders == null) elementBinders = [];
74112

75113
viewFactory = new TaggingViewFactory(transcludeCursor.elements, elementBinders, _perf, _expando);
76114
domCursor.index = domCursorIndex;
77115

78-
if (domCursor.isInstance()) {
116+
if (domCursor.isInstance) {
79117
domCursor.insertAnchorBefore(anchorName);
80-
views = [viewFactory(domCursor.nodeList())];
81-
domCursor.macroNext();
82-
templateCursor.macroNext();
83-
while (domCursor.isValid() && domCursor.isInstance()) {
84-
views.add(viewFactory(domCursor.nodeList()));
85-
domCursor.macroNext();
118+
views = [viewFactory([domCursor.current])];
119+
domCursor.moveNext();
120+
templateCursor.moveNext();
121+
while (domCursor.moveNext() && domCursor.isInstance) {
122+
views.add(viewFactory([domCursor.current]));
86123
templateCursor.remove();
87124
}
88125
} else {
@@ -99,7 +136,7 @@ class TaggingCompiler implements Compiler {
99136
List<dom.Node> templateElements = cloneElements(domElements);
100137
List<TaggedElementBinder> elementBinders = _compileView(
101138
new NodeCursor(domElements), new NodeCursor(templateElements),
102-
null, directives);
139+
null, directives, -1, null);
103140

104141
var viewFactory = new TaggingViewFactory(templateElements,
105142
elementBinders == null ? [] : elementBinders, _perf, _expando);

lib/core_dom/tagging_view_factory.dart

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,53 @@ part of angular.core.dom;
22

33
class TaggingViewFactory implements ViewFactory {
44
final List<TaggedElementBinder> elementBinders;
5-
final List<dom.Node> templateElements;
5+
final List<dom.Node> templateNodes;
66
final Profiler _perf;
77
final Expando _expando;
88

9-
TaggingViewFactory(this.templateElements, this.elementBinders, this._perf, this._expando);
9+
TaggingViewFactory(this.templateNodes, this.elementBinders, this._perf, this._expando);
1010

1111
BoundViewFactory bind(Injector injector) =>
1212
new BoundViewFactory(this, injector);
1313

14-
View call(Injector injector, [List<dom.Node> elements /* TODO: document fragment */]) {
15-
if (elements == null) {
16-
elements = cloneElements(templateElements);
14+
View call(Injector injector, [List<dom.Node> nodes /* TODO: document fragment */]) {
15+
if (nodes == null) {
16+
nodes = cloneElements(templateNodes);
1717
}
1818
var timerId;
1919
try {
2020
assert((timerId = _perf.startTimer('ng.view')) != false);
21-
var view = new View(elements, injector.get(NgAnimate));
22-
_link(view, elements, elementBinders, injector);
21+
var view = new View(nodes);
22+
_link(view, nodes, elementBinders, injector);
2323
return view;
2424
} finally {
2525
assert(_perf.stopTimer(timerId) != false);
2626
}
2727
}
2828

29-
View _link(View view, List<dom.Node> nodeList, List elementBinders, Injector parentInjector) {
29+
_bindTagged(TaggedElementBinder tagged, rootInjector, elementBinders, View view, boundNode) {
30+
var binder = tagged.binder;
31+
var parentInjector = tagged.parentBinderOffset == -1 ? rootInjector : elementBinders[tagged.parentBinderOffset].injector;
32+
assert(parentInjector != null);
33+
34+
tagged.injector = binder != null ? binder.bind(view, parentInjector, boundNode) : parentInjector;
35+
36+
if (tagged.textBinders != null) {
37+
for (var k = 0, kk = tagged.textBinders.length; k < kk; k++) {
38+
TaggedTextBinder taggedText = tagged.textBinders[k];
39+
taggedText.binder.bind(view, tagged.injector, boundNode.childNodes[taggedText.offsetIndex]);
40+
}
41+
}
42+
}
43+
44+
View _link(View view, List<dom.Node> nodeList, List elementBinders, Injector rootInjector) {
3045

3146

3247
var directiveDefsByName = {};
3348

3449
var elementBinderIndex = 0;
3550
for (int i = 0, ii = nodeList.length; i < ii; i++) {
3651
var node = nodeList[i];
37-
print("node: $node ${node.outerHtml}}");
3852

3953
// if node isn't attached to the DOM, create a parent for it.
4054
var parentNode = node.parentNode;
@@ -45,47 +59,31 @@ class TaggingViewFactory implements ViewFactory {
4559
parentNode.append(node);
4660
}
4761

48-
if (node is dom.Element) {
62+
if (node.nodeType == 1) {
4963
var elts = node.querySelectorAll('.ng-binding');
5064
// HACK: querySelectorAll doesn't return the node.
5165
var startIndex = node.classes.contains('ng-binding') ? -1 : 0;
52-
print("starting at: $startIndex");
5366
for (int j = startIndex, jj = elts.length; j < jj; j++, elementBinderIndex++) {
54-
if (j >= 0) print("elt: ${elts[j]} ${elts[j].outerHtml}");
5567
TaggedElementBinder tagged = elementBinders[elementBinderIndex];
68+
var boundNode = j == -1 ? node : elts[j];
5669

57-
var binder = tagged.binder;
58-
59-
var childInjector = binder != null ? binder.bind(view, parentInjector, j == -1 ? node : elts[j]) : parentInjector;
70+
_bindTagged(tagged, rootInjector, elementBinders, view, boundNode);
6071
}
72+
} else if (node.nodeType == 3 || node.nodeType == 8) {
73+
TaggedElementBinder tagged = elementBinders[elementBinderIndex];
74+
assert(tagged.binder != null);
75+
76+
_bindTagged(tagged, rootInjector, elementBinders, view, node);
77+
78+
elementBinderIndex++;
79+
} else {
80+
throw "nodeType sadness ${node.nodeType}}";
6181
}
6282

6383
if (fakeParent) {
6484
// extract the node from the parentNode.
6585
nodeList[i] = parentNode.nodes[0];
6686
}
67-
68-
// querySelectorAll('.ng-binding') should return a list of nodes in the same order as the elementBinders list.
69-
70-
// keep a injector array --
71-
72-
/*var eb = elementBinders[i];
73-
int index = i;
74-
75-
var binder = eb.binder;
76-
77-
var timerId;
78-
try {
79-
assert((timerId = _perf.startTimer('ng.view.link', _html(node))) != false);
80-
81-
82-
83-
84-
85-
86-
} finally {
87-
assert(_perf.stopTimer(timerId) != false);
88-
}*/
8987
}
9088
return view;
9189
}

test/core_dom/compiler_spec.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ forBothCompilers(fn) {
1212
fn();
1313
});
1414

15-
xdescribe('tagging compiler', () {
15+
describe('tagging compiler', () {
1616
beforeEach(module((Module m) {
1717
m.type(Compiler, implementedBy: TaggingCompiler);
1818
return m;
@@ -591,7 +591,6 @@ void main() {
591591
})));
592592

593593
it('should expose a parent controller to the scope of its children', inject((TestBed _) {
594-
595594
var element = _.compile('<div my-parent-controller>'
596595
' <div my-child-controller>{{ my_parent.data() }}</div>'
597596
'</div>');

0 commit comments

Comments
 (0)