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

Commit

Permalink
feat(compiler): Initial TagggingCompiler implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jbdeboer committed Mar 11, 2014
1 parent 96d46c5 commit 8016340
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 103 deletions.
103 changes: 1 addition & 102 deletions lib/core_dom/compiler.dart
Original file line number Diff line number Diff line change
@@ -1,106 +1,5 @@
part of angular.core.dom;

abstract class Compiler implements Function {
WalkingViewFactory call(List<dom.Node> elements, DirectiveMap directives);
}

@NgInjectableService()
class WalkingCompiler implements Compiler {
final Profiler _perf;
final Expando _expando;

WalkingCompiler(this._perf, this._expando);

List<ElementBinderTreeRef> _compileView(NodeCursor domCursor, NodeCursor templateCursor,
ElementBinder existingElementBinder,
DirectiveMap directives) {
if (domCursor.current == null) return null;

List<ElementBinderTreeRef> elementBinders = null; // don't pre-create to create sparse tree and prevent GC pressure.

do {
var subtrees, binder;

ElementBinder elementBinder = existingElementBinder == null
? directives.selector(domCursor.current)
: existingElementBinder;

if (elementBinder.hasTemplate) {
elementBinder.templateViewFactory = _compileTransclusion(
domCursor, templateCursor,
elementBinder.template, elementBinder.templateBinder, directives);
}

if (elementBinder.shouldCompileChildren) {
if (domCursor.descend()) {
templateCursor.descend();

subtrees =
_compileView(domCursor, templateCursor, null, directives);

domCursor.ascend();
templateCursor.ascend();
}
}

if (elementBinder.hasDirectives) {
binder = elementBinder;
}

if (elementBinders == null) elementBinders = [];
elementBinders.add(new ElementBinderTreeRef(templateCursor.index, new ElementBinderTree(binder, subtrees)));
} while (templateCursor.moveNext() && domCursor.moveNext());

return elementBinders;
}

WalkingViewFactory _compileTransclusion(
NodeCursor domCursor, NodeCursor templateCursor,
DirectiveRef directiveRef,
ElementBinder transcludedElementBinder,
DirectiveMap directives) {
var anchorName = directiveRef.annotation.selector +
(directiveRef.value != null ? '=' + directiveRef.value : '');
var viewFactory;
var views;

var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
var domCursorIndex = domCursor.index;
var elementBinders =
_compileView(domCursor, transcludeCursor, transcludedElementBinder, directives);
if (elementBinders == null) elementBinders = [];

viewFactory = new WalkingViewFactory(transcludeCursor.elements, elementBinders, _perf, _expando);
domCursor.index = domCursorIndex;

if (domCursor.isInstance) {
domCursor.insertAnchorBefore(anchorName);
views = [viewFactory([domCursor.current])];
templateCursor.moveNext();
while (domCursor.moveNext() && domCursor.isInstance) {
views.add(viewFactory([domCursor.current]));
templateCursor.remove();
}
} else {
domCursor.replaceWithAnchor(anchorName);
}

return viewFactory;
}

WalkingViewFactory call(List<dom.Node> elements, DirectiveMap directives) {
var timerId;
assert((timerId = _perf.startTimer('ng.compile', _html(elements))) != false);
final List<dom.Node> domElements = elements;
final List<dom.Node> templateElements = cloneElements(domElements);
var elementBinders = _compileView(
new NodeCursor(domElements), new NodeCursor(templateElements),
null, directives);

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

assert(_perf.stopTimer(timerId) != false);
return viewFactory;
}
ViewFactory call(List<dom.Node> elements, DirectiveMap directives);
}
9 changes: 9 additions & 0 deletions lib/core_dom/element_binder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -389,3 +389,12 @@ class ElementBinderTree {

ElementBinderTree(this.binder, this.subtrees);
}


// Used for the tagging compiler
class TaggedElementBinder {
ElementBinder binder;
int parentBinderOffset;

TaggedElementBinder(this.binder, this.parentBinderOffset);
}
3 changes: 3 additions & 0 deletions lib/core_dom/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ part 'http.dart';
part 'ng_mustache.dart';
part 'node_cursor.dart';
part 'selector.dart';
part 'tagging_compiler.dart';
part 'tagging_view_factory.dart';
part 'template_cache.dart';
part 'tree_sanitizer.dart';
part 'walking_compiler.dart';

class NgCoreDomModule extends Module {
NgCoreDomModule() {
Expand Down
110 changes: 110 additions & 0 deletions lib/core_dom/tagging_compiler.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
part of angular.core.dom;

@NgInjectableService()
class TaggingCompiler implements Compiler {
final Profiler _perf;
final Expando _expando;

TaggingCompiler(this._perf, this._expando);

List _compileView(

NodeCursor domCursor, NodeCursor templateCursor,
ElementBinder useExistingElementBinder,
DirectiveMap directives) {
List<TaggedElementBinder> elementBinders = [];
if (domCursor.nodeList().length == 0) return null;


do {
var subtrees, binder;

var node = domCursor.nodeList()[0];

// If nodetype is a element, call selector matchElement. If text, call selector.matchText

// TODO: selector will return null for non-useful bindings.
ElementBinder elementBinder = useExistingElementBinder == null
? directives.selector(node)
: useExistingElementBinder;

if (elementBinder.hasTemplate) {
elementBinder.templateViewFactory = _compileTransclusion(elementBinders,
domCursor, templateCursor,
elementBinder.template, elementBinder.templateBinder, directives);
}

if (elementBinder.shouldCompileChildren) {
if (domCursor.descend()) {
templateCursor.descend();

elementBinders.addAll(
_compileView(domCursor, templateCursor, null, directives /*current element list length*/));

domCursor.ascend();
templateCursor.ascend();
}
}

// move this up
if (elementBinder.hasDirectives) {
elementBinders.add(new TaggedElementBinder(elementBinder, -1));
node.classes.add('ng-binding');
binder = elementBinder;
}
} while (templateCursor.microNext() && domCursor.microNext());

return elementBinders;
}

TaggingViewFactory _compileTransclusion(List<TaggedElementBinder> tElementBinders,
NodeCursor domCursor, NodeCursor templateCursor,
DirectiveRef directiveRef,
ElementBinder transcludedElementBinder,
DirectiveMap directives) {
var anchorName = directiveRef.annotation.selector + (directiveRef.value != null ? '=' + directiveRef.value : '');
var viewFactory;
var views;

var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
var domCursorIndex = domCursor.index;
var elementBinders =
_compileView(domCursor, transcludeCursor, transcludedElementBinder, directives);
if (elementBinders == null) elementBinders = [];

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

if (domCursor.isInstance()) {
domCursor.insertAnchorBefore(anchorName);
views = [viewFactory(domCursor.nodeList())];
domCursor.macroNext();
templateCursor.macroNext();
while (domCursor.isValid() && domCursor.isInstance()) {
views.add(viewFactory(domCursor.nodeList()));
domCursor.macroNext();
templateCursor.remove();
}
} else {
domCursor.replaceWithAnchor(anchorName);
}

return viewFactory;
}

TaggingViewFactory call(List<dom.Node> elements, DirectiveMap directives) {
var timerId;
assert((timerId = _perf.startTimer('ng.compile', _html(elements))) != false);
List<dom.Node> domElements = elements;
List<dom.Node> templateElements = cloneElements(domElements);
List<TaggedElementBinder> elementBinders = _compileView(
new NodeCursor(domElements), new NodeCursor(templateElements),
null, directives);

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

assert(_perf.stopTimer(timerId) != false);
return viewFactory;
}
}
92 changes: 92 additions & 0 deletions lib/core_dom/tagging_view_factory.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
part of angular.core.dom;

class TaggingViewFactory implements ViewFactory {
final List<TaggedElementBinder> elementBinders;
final List<dom.Node> templateElements;
final Profiler _perf;
final Expando _expando;

TaggingViewFactory(this.templateElements, this.elementBinders, this._perf, this._expando);

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

View call(Injector injector, [List<dom.Node> elements /* TODO: document fragment */]) {
if (elements == null) {
elements = cloneElements(templateElements);
}
var timerId;
try {
assert((timerId = _perf.startTimer('ng.view')) != false);
var view = new View(elements, injector.get(NgAnimate));
_link(view, elements, elementBinders, injector);
return view;
} finally {
assert(_perf.stopTimer(timerId) != false);
}
}

View _link(View view, List<dom.Node> nodeList, List elementBinders, Injector parentInjector) {


var directiveDefsByName = {};

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

// if node isn't attached to the DOM, create a parent for it.
var parentNode = node.parentNode;
var fakeParent = false;
if (parentNode == null) {
fakeParent = true;
parentNode = new dom.DivElement();
parentNode.append(node);
}

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

var binder = tagged.binder;

var childInjector = binder != null ? binder.bind(view, parentInjector, j == -1 ? node : elts[j]) : parentInjector;
}
}

if (fakeParent) {
// extract the node from the parentNode.
nodeList[i] = parentNode.nodes[0];
}

// querySelectorAll('.ng-binding') should return a list of nodes in the same order as the elementBinders list.

// keep a injector array --

/*var eb = elementBinders[i];
int index = i;
var binder = eb.binder;
var timerId;
try {
assert((timerId = _perf.startTimer('ng.view.link', _html(node))) != false);
} finally {
assert(_perf.stopTimer(timerId) != false);
}*/
}
return view;
}
}
9 changes: 9 additions & 0 deletions lib/core_dom/view_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,16 @@ class WalkingViewFactory implements ViewFactory {
}

View _link(View view, List<dom.Node> nodeList, List elementBinders, Injector parentInjector) {


var preRenderedIndexOffset = 0;
var directiveDefsByName = {};

for (int i = 0; i < elementBinders.length; i++) {
// querySelectorAll('.ng-binding') should return a list of nodes in the same order as the elementBinders list.

// keep a injector array --

var eb = elementBinders[i];
int index = eb.offsetIndex;

Expand Down Expand Up @@ -100,6 +106,9 @@ class WalkingViewFactory implements ViewFactory {
}
}




/**
* ViewCache is used to cache the compilation of templates into [View]s.
* It can be used synchronously if HTML is known or asynchronously if the
Expand Down
Loading

0 comments on commit 8016340

Please sign in to comment.