| Index: third_party/pkg/angular/lib/core_dom/tagging_compiler.dart
|
| diff --git a/third_party/pkg/angular/lib/core_dom/tagging_compiler.dart b/third_party/pkg/angular/lib/core_dom/tagging_compiler.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a0300742868c68179e5d9187ad0bbbe1235f22a4
|
| --- /dev/null
|
| +++ b/third_party/pkg/angular/lib/core_dom/tagging_compiler.dart
|
| @@ -0,0 +1,185 @@
|
| +part of angular.core.dom_internal;
|
| +
|
| +TaggedElementBinder _addBinder(List list, TaggedElementBinder binder) {
|
| + assert(binder.parentBinderOffset != list.length); // Do not point to yourself!
|
| + list.add(binder);
|
| + return binder;
|
| +}
|
| +
|
| +@Injectable()
|
| +class TaggingCompiler implements Compiler {
|
| + final Profiler _perf;
|
| + final Expando _expando;
|
| +
|
| + TaggingCompiler(this._perf, this._expando);
|
| +
|
| + ElementBinder _elementBinderForNode(NodeCursor domCursor,
|
| + ElementBinder useExistingElementBinder,
|
| + DirectiveMap directives,
|
| + List elementBinders) {
|
| + var node = domCursor.current;
|
| +
|
| + if (node.nodeType == 1) {
|
| + // If nodetype is a element, call selector matchElement.
|
| + // If text, call selector.matchText
|
| +
|
| + ElementBinder elementBinder = useExistingElementBinder == null ?
|
| + directives.selector.matchElement(node) : useExistingElementBinder;
|
| +
|
| + if (elementBinder.hasTemplate) {
|
| + var templateBinder = elementBinder as TemplateElementBinder;
|
| + templateBinder.templateViewFactory = _compileTransclusion(
|
| + domCursor, templateBinder.template,
|
| + templateBinder.templateBinder, directives);
|
| + }
|
| + return elementBinder;
|
| + } else if (node.nodeType == dom.Node.TEXT_NODE) {
|
| + return directives.selector.matchText(node);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + _compileNode(NodeCursor domCursor,
|
| + ElementBinder elementBinder,
|
| + DirectiveMap directives,
|
| + List elementBinders,
|
| + int parentElementBinderOffset,
|
| + bool isTopLevel,
|
| + TaggedElementBinder directParentElementBinder) {
|
| + var node = domCursor.current;
|
| + if (node.nodeType == dom.Node.ELEMENT_NODE) {
|
| + TaggedElementBinder taggedElementBinder;
|
| + int taggedElementBinderIndex;
|
| + if (elementBinder.hasDirectivesOrEvents || elementBinder.hasTemplate) {
|
| + taggedElementBinder = _addBinder(elementBinders,
|
| + new TaggedElementBinder(elementBinder, parentElementBinderOffset, isTopLevel));
|
| + taggedElementBinderIndex = elementBinders.length - 1;
|
| + node.classes.add('ng-binding');
|
| + } else {
|
| + taggedElementBinder = null;
|
| + taggedElementBinderIndex = parentElementBinderOffset;
|
| + }
|
| +
|
| + if (elementBinder.shouldCompileChildren) {
|
| + if (domCursor.descend()) {
|
| + var addedDummy = false;
|
| + if (taggedElementBinder == null) {
|
| + addedDummy = true;
|
| + // add a dummy to the list which may be removed later.
|
| + taggedElementBinder = _addBinder(elementBinders,
|
| + new TaggedElementBinder(null, parentElementBinderOffset, isTopLevel));
|
| + }
|
| +
|
| + _compileView(domCursor, null, directives, taggedElementBinderIndex,
|
| + taggedElementBinder, elementBinders, false);
|
| +
|
| + if (addedDummy && !_isDummyBinder(taggedElementBinder)) {
|
| + // We are keeping the element binder, so add the class
|
| + // to the DOM node as well.
|
| + //
|
| + // To avoid array chrun, we remove all dummy binders at the
|
| + // end of the compilation process.
|
| + node.classes.add('ng-binding');
|
| + }
|
| + domCursor.ascend();
|
| + }
|
| + }
|
| + } else if (node.nodeType == dom.Node.TEXT_NODE ||
|
| + node.nodeType == dom.Node.COMMENT_NODE) {
|
| + if (elementBinder != null &&
|
| + elementBinder.hasDirectivesOrEvents &&
|
| + directParentElementBinder != null) {
|
| + directParentElementBinder.addText(
|
| + new TaggedTextBinder(elementBinder, domCursor.index));
|
| + } else if (isTopLevel) {
|
| + // Always add an elementBinder for top-level text.
|
| + _addBinder(elementBinders,
|
| + new TaggedElementBinder(elementBinder, parentElementBinderOffset, isTopLevel));
|
| + }
|
| + } else {
|
| + throw "Unsupported node type for $node: [${node.nodeType}]";
|
| + }
|
| + }
|
| +
|
| + List _compileView(NodeCursor domCursor,
|
| + ElementBinder useExistingElementBinder,
|
| + DirectiveMap directives,
|
| + int parentElementBinderOffset,
|
| + TaggedElementBinder directParentElementBinder,
|
| + List<TaggedElementBinder> elementBinders,
|
| + bool isTopLevel) {
|
| + assert(parentElementBinderOffset != null);
|
| + assert(parentElementBinderOffset < elementBinders.length);
|
| + if (domCursor.current == null) return null;
|
| +
|
| + do {
|
| + _compileNode(domCursor,
|
| + _elementBinderForNode(domCursor, useExistingElementBinder, directives, elementBinders),
|
| + directives, elementBinders, parentElementBinderOffset,
|
| + isTopLevel, directParentElementBinder);
|
| + } while (domCursor.moveNext());
|
| +
|
| + return elementBinders;
|
| + }
|
| +
|
| + TaggingViewFactory _compileTransclusion(
|
| + NodeCursor templateCursor,
|
| + DirectiveRef directiveRef,
|
| + ElementBinder transcludedElementBinder,
|
| + DirectiveMap directives) {
|
| + var anchorName = directiveRef.annotation.selector +
|
| + (directiveRef.value != null ? '=' + directiveRef.value : '');
|
| +
|
| + var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
|
| + var elementBinders = [];
|
| + _compileView(transcludeCursor, transcludedElementBinder,
|
| + directives, -1, null, elementBinders, true);
|
| +
|
| + var viewFactory = new TaggingViewFactory(transcludeCursor.elements,
|
| + _removeUnusedBinders(elementBinders), _perf);
|
| +
|
| + return viewFactory;
|
| + }
|
| +
|
| + TaggingViewFactory call(List<dom.Node> elements, DirectiveMap directives) {
|
| + var timerId;
|
| + assert((timerId = _perf.startTimer('ng.compile', _html(elements))) != false);
|
| + final elementBinders = <TaggedElementBinder>[];
|
| + _compileView(
|
| + new NodeCursor(elements),
|
| + null, directives, -1, null, elementBinders, true);
|
| +
|
| + var viewFactory = new TaggingViewFactory(
|
| + elements, _removeUnusedBinders(elementBinders), _perf);
|
| +
|
| + assert(_perf.stopTimer(timerId) != false);
|
| + return viewFactory;
|
| + }
|
| +
|
| + _isDummyBinder(TaggedElementBinder binder) =>
|
| + binder.binder == null && binder.textBinders == null && !binder.isTopLevel;
|
| +
|
| + _removeUnusedBinders(List<TaggedElementBinder> binders) {
|
| + // In order to support text nodes with directiveless parents, we
|
| + // add dummy ElementBinders to the list. After the entire template
|
| + // has been compiled, we remove the dummies and update the offset indices
|
| + final output = [];
|
| + final List<int> offsetMap = [];
|
| + int outputIndex = 0;
|
| +
|
| + for (var i = 0, ii = binders.length; i < ii; i++) {
|
| + TaggedElementBinder binder = binders[i];
|
| + if (_isDummyBinder(binder)) {
|
| + offsetMap.add(-2);
|
| + } else {
|
| + if (binder.parentBinderOffset != -1) {
|
| + binder.parentBinderOffset = offsetMap[binder.parentBinderOffset];
|
| + }
|
| + assert(binder.parentBinderOffset != -2);
|
| + output.add(binder);
|
| + offsetMap.add(outputIndex++);
|
| + }
|
| + }
|
| + return output;
|
| + }
|
| +}
|
|
|