| Index: third_party/pkg/angular/lib/core_dom/compiler.dart
|
| diff --git a/third_party/pkg/angular/lib/core_dom/compiler.dart b/third_party/pkg/angular/lib/core_dom/compiler.dart
|
| index dec51caa3f4bf14b8f7fdfa90d5ea3f7924a5e73..6a52ac8d1ceed75eb0ed728f72f150833bd00042 100644
|
| --- a/third_party/pkg/angular/lib/core_dom/compiler.dart
|
| +++ b/third_party/pkg/angular/lib/core_dom/compiler.dart
|
| @@ -1,5 +1,234 @@
|
| -part of angular.core.dom_internal;
|
| +part of angular.core.dom;
|
|
|
| -abstract class Compiler implements Function {
|
| - ViewFactory call(List<dom.Node> elements, DirectiveMap directives);
|
| +@NgInjectableService()
|
| +class Compiler {
|
| + final Profiler _perf;
|
| + final Parser _parser;
|
| + final Expando _expando;
|
| +
|
| + Compiler(this._perf, this._parser, this._expando);
|
| +
|
| + _compileBlock(NodeCursor domCursor, NodeCursor templateCursor,
|
| + List<DirectiveRef> useExistingDirectiveRefs,
|
| + DirectiveMap directives) {
|
| + if (domCursor.nodeList().length == 0) return null;
|
| +
|
| + var directivePositions = null; // don't pre-create to create sparse tree and prevent GC pressure.
|
| + var cursorAlreadyAdvanced;
|
| +
|
| + do {
|
| + var declaredDirectiveRefs = useExistingDirectiveRefs == null
|
| + ? directives.selector(domCursor.nodeList()[0])
|
| + : useExistingDirectiveRefs;
|
| + var children = NgAnnotation.COMPILE_CHILDREN;
|
| + var childDirectivePositions = null;
|
| + List<DirectiveRef> usableDirectiveRefs = null;
|
| +
|
| + cursorAlreadyAdvanced = false;
|
| +
|
| + for (var j = 0; j < declaredDirectiveRefs.length; j++) {
|
| + DirectiveRef directiveRef = declaredDirectiveRefs[j];
|
| + NgAnnotation annotation = directiveRef.annotation;
|
| + var blockFactory = null;
|
| +
|
| + if (annotation.children != children &&
|
| + children == NgAnnotation.COMPILE_CHILDREN) {
|
| + children = annotation.children;
|
| + }
|
| +
|
| + if (children == NgAnnotation.TRANSCLUDE_CHILDREN) {
|
| + var remainingDirectives = declaredDirectiveRefs.sublist(j + 1);
|
| + blockFactory = compileTransclusion(
|
| + domCursor, templateCursor,
|
| + directiveRef, remainingDirectives, directives);
|
| +
|
| + // stop processing further directives since they belong to
|
| + // transclusion
|
| + j = declaredDirectiveRefs.length;
|
| + }
|
| + if (usableDirectiveRefs == null) usableDirectiveRefs = [];
|
| + directiveRef.blockFactory = blockFactory;
|
| + createMappings(directiveRef);
|
| + usableDirectiveRefs.add(directiveRef);
|
| + }
|
| +
|
| + if (children == NgAnnotation.COMPILE_CHILDREN && domCursor.descend()) {
|
| + templateCursor.descend();
|
| +
|
| + childDirectivePositions =
|
| + _compileBlock(domCursor, templateCursor, null, directives);
|
| +
|
| + domCursor.ascend();
|
| + templateCursor.ascend();
|
| + }
|
| +
|
| + if (childDirectivePositions != null || usableDirectiveRefs != null) {
|
| + if (directivePositions == null) directivePositions = [];
|
| + var directiveOffsetIndex = templateCursor.index;
|
| +
|
| + directivePositions
|
| + ..add(directiveOffsetIndex)
|
| + ..add(usableDirectiveRefs)
|
| + ..add(childDirectivePositions);
|
| + }
|
| + } while (templateCursor.microNext() && domCursor.microNext());
|
| +
|
| + return directivePositions;
|
| + }
|
| +
|
| + BlockFactory compileTransclusion(
|
| + NodeCursor domCursor, NodeCursor templateCursor,
|
| + DirectiveRef directiveRef,
|
| + List<DirectiveRef> transcludedDirectiveRefs,
|
| + DirectiveMap directives) {
|
| + var anchorName = directiveRef.annotation.selector + (directiveRef.value != null ? '=' + directiveRef.value : '');
|
| + var blockFactory;
|
| + var blocks;
|
| +
|
| + var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
|
| + var domCursorIndex = domCursor.index;
|
| + var directivePositions =
|
| + _compileBlock(domCursor, transcludeCursor, transcludedDirectiveRefs, directives);
|
| + if (directivePositions == null) directivePositions = [];
|
| +
|
| + blockFactory = new BlockFactory(transcludeCursor.elements, directivePositions, _perf, _expando);
|
| + domCursor.index = domCursorIndex;
|
| +
|
| + if (domCursor.isInstance()) {
|
| + domCursor.insertAnchorBefore(anchorName);
|
| + blocks = [blockFactory(domCursor.nodeList())];
|
| + domCursor.macroNext();
|
| + templateCursor.macroNext();
|
| + while (domCursor.isValid() && domCursor.isInstance()) {
|
| + blocks.add(blockFactory(domCursor.nodeList()));
|
| + domCursor.macroNext();
|
| + templateCursor.remove();
|
| + }
|
| + } else {
|
| + domCursor.replaceWithAnchor(anchorName);
|
| + }
|
| +
|
| + return blockFactory;
|
| + }
|
| +
|
| + BlockFactory 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);
|
| + var directivePositions = _compileBlock(
|
| + new NodeCursor(domElements), new NodeCursor(templateElements),
|
| + null, directives);
|
| +
|
| + var blockFactory = new BlockFactory(templateElements,
|
| + directivePositions == null ? [] : directivePositions, _perf, _expando);
|
| +
|
| + assert(_perf.stopTimer(timerId) != false);
|
| + return blockFactory;
|
| + }
|
| +
|
| + static RegExp _MAPPING = new RegExp(r'^(\@|=\>\!|\=\>|\<\=\>|\&)\s*(.*)$');
|
| +
|
| + createMappings(DirectiveRef ref) {
|
| + NgAnnotation annotation = ref.annotation;
|
| + if (annotation.map != null) annotation.map.forEach((attrName, mapping) {
|
| + Match match = _MAPPING.firstMatch(mapping);
|
| + if (match == null) {
|
| + throw "Unknown mapping '$mapping' for attribute '$attrName'.";
|
| + }
|
| + var mode = match[1];
|
| + var dstPath = match[2];
|
| +
|
| + String dstExpression = dstPath.isEmpty ? attrName : dstPath;
|
| + Expression dstPathFn = _parser(dstExpression);
|
| + if (!dstPathFn.isAssignable) {
|
| + throw "Expression '$dstPath' is not assignable in mapping '$mapping' for attribute '$attrName'.";
|
| + }
|
| + ApplyMapping mappingFn;
|
| + switch (mode) {
|
| + case '@':
|
| + mappingFn = (NodeAttrs attrs, Scope scope, Object controller, FilterMap filters, notify()) {
|
| + attrs.observe(attrName, (value) {
|
| + dstPathFn.assign(controller, value);
|
| + notify();
|
| + });
|
| + };
|
| + break;
|
| + case '<=>':
|
| + mappingFn = (NodeAttrs attrs, Scope scope, Object controller, FilterMap filters, notify()) {
|
| + if (attrs[attrName] == null) return notify();
|
| + String expression = attrs[attrName];
|
| + Expression expressionFn = _parser(expression);
|
| + var blockOutbound = false;
|
| + var blockInbound = false;
|
| + scope.watch(
|
| + expression,
|
| + (inboundValue, _) {
|
| + if (!blockInbound) {
|
| + blockOutbound = true;
|
| + scope.rootScope.runAsync(() => blockOutbound = false);
|
| + var value = dstPathFn.assign(controller, inboundValue);
|
| + notify();
|
| + return value;
|
| + }
|
| + },
|
| + filters: filters
|
| + );
|
| + if (expressionFn.isAssignable) {
|
| + scope.watch(
|
| + dstExpression,
|
| + (outboundValue, _) {
|
| + if (!blockOutbound) {
|
| + blockInbound = true;
|
| + scope.rootScope.runAsync(() => blockInbound = false);
|
| + expressionFn.assign(scope.context, outboundValue);
|
| + notify();
|
| + }
|
| + },
|
| + context: controller,
|
| + filters: filters
|
| + );
|
| + }
|
| + };
|
| + break;
|
| + case '=>':
|
| + mappingFn = (NodeAttrs attrs, Scope scope, Object controller, FilterMap filters, notify()) {
|
| + if (attrs[attrName] == null) return notify();
|
| + Expression attrExprFn = _parser(attrs[attrName]);
|
| + var shadowValue = null;
|
| + scope.watch(attrs[attrName],
|
| + (v, _) {
|
| + dstPathFn.assign(controller, shadowValue = v);
|
| + notify();
|
| + },
|
| + filters: filters);
|
| + };
|
| + break;
|
| + case '=>!':
|
| + mappingFn = (NodeAttrs attrs, Scope scope, Object controller, FilterMap filters, notify()) {
|
| + if (attrs[attrName] == null) return notify();
|
| + Expression attrExprFn = _parser(attrs[attrName]);
|
| + var watch;
|
| + watch = scope.watch(
|
| + attrs[attrName],
|
| + (value, _) {
|
| + if (dstPathFn.assign(controller, value) != null) {
|
| + watch.remove();
|
| + }
|
| + },
|
| + filters: filters);
|
| + notify();
|
| + };
|
| + break;
|
| + case '&':
|
| + mappingFn = (NodeAttrs attrs, Scope scope, Object dst, FilterMap filters, notify()) {
|
| + dstPathFn.assign(dst, _parser(attrs[attrName]).bind(scope.context, ScopeLocals.wrapper));
|
| + notify();
|
| + };
|
| + break;
|
| + }
|
| + ref.mappings.add(mappingFn);
|
| + });
|
| + }
|
| }
|
| +
|
|
|