| Index: third_party/pkg/angular/lib/core_dom/view_factory.dart
|
| diff --git a/third_party/pkg/angular/lib/core_dom/view_factory.dart b/third_party/pkg/angular/lib/core_dom/view_factory.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..97a525fa62de1b6b59acdd06e389f054b9caca08
|
| --- /dev/null
|
| +++ b/third_party/pkg/angular/lib/core_dom/view_factory.dart
|
| @@ -0,0 +1,188 @@
|
| +part of angular.core.dom_internal;
|
| +
|
| +
|
| +/**
|
| + * BoundViewFactory is a [ViewFactory] which does not need Injector because
|
| + * it is pre-bound to an injector from the parent. This means that this
|
| + * BoundViewFactory can only be used from within a specific Directive such
|
| + * as [NgRepeat], but it can not be stored in a cache.
|
| + *
|
| + * The BoundViewFactory needs [Scope] to be created.
|
| + */
|
| +class BoundViewFactory {
|
| + ViewFactory viewFactory;
|
| + Injector injector;
|
| +
|
| + BoundViewFactory(this.viewFactory, this.injector);
|
| +
|
| + View call(Scope scope) =>
|
| + viewFactory(injector.createChild([new Module()..value(Scope, scope)]));
|
| +}
|
| +
|
| +abstract class ViewFactory implements Function {
|
| + BoundViewFactory bind(Injector injector);
|
| +
|
| + View call(Injector injector, [List<dom.Node> elements]);
|
| +}
|
| +
|
| +/**
|
| + * [WalkingViewFactory] is used to create new [View]s. WalkingViewFactory is
|
| + * created by the [Compiler] as a result of compiling a template.
|
| + */
|
| +class WalkingViewFactory implements ViewFactory {
|
| + final List<ElementBinderTreeRef> elementBinders;
|
| + final List<dom.Node> templateElements;
|
| + final Profiler _perf;
|
| + final Expando _expando;
|
| +
|
| + WalkingViewFactory(this.templateElements, this.elementBinders, this._perf,
|
| + this._expando) {
|
| + assert(elementBinders.every((ElementBinderTreeRef eb) =>
|
| + eb is ElementBinderTreeRef));
|
| + }
|
| +
|
| + BoundViewFactory bind(Injector injector) =>
|
| + new BoundViewFactory(this, injector);
|
| +
|
| + View call(Injector injector, [List<dom.Node> nodes]) {
|
| + if (nodes == null) nodes = cloneElements(templateElements);
|
| + var timerId;
|
| + try {
|
| + assert((timerId = _perf.startTimer('ng.view')) != false);
|
| + var view = new View(nodes, injector.get(EventHandler));
|
| + _link(view, nodes, elementBinders, injector);
|
| + return view;
|
| + } finally {
|
| + assert(_perf.stopTimer(timerId) != false);
|
| + }
|
| + }
|
| +
|
| + 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;
|
| +
|
| + ElementBinderTree tree = eb.subtree;
|
| +
|
| + //List childElementBinders = eb.childElementBinders;
|
| + int nodeListIndex = index + preRenderedIndexOffset;
|
| + dom.Node node = nodeList[nodeListIndex];
|
| + var binder = tree.binder;
|
| +
|
| + var timerId;
|
| + try {
|
| + assert((timerId = _perf.startTimer('ng.view.link', _html(node))) != false);
|
| + // 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()..append(node);
|
| + }
|
| +
|
| + var childInjector = binder != null ?
|
| + binder.bind(view, parentInjector, node) :
|
| + parentInjector;
|
| +
|
| + if (fakeParent) {
|
| + // extract the node from the parentNode.
|
| + nodeList[nodeListIndex] = parentNode.nodes[0];
|
| + }
|
| +
|
| + if (tree.subtrees != null) {
|
| + _link(view, node.nodes, tree.subtrees, childInjector);
|
| + }
|
| + } finally {
|
| + assert(_perf.stopTimer(timerId) != false);
|
| + }
|
| + }
|
| + return view;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * 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
|
| + * template HTML needs to be looked up from the URL.
|
| + */
|
| +@Injectable()
|
| +class ViewCache {
|
| + // _viewFactoryCache is unbounded
|
| + final _viewFactoryCache = new LruCache<String, ViewFactory>(capacity: 0);
|
| + final Http http;
|
| + final TemplateCache templateCache;
|
| + final Compiler compiler;
|
| + final dom.NodeTreeSanitizer treeSanitizer;
|
| +
|
| + ViewCache(this.http, this.templateCache, this.compiler, this.treeSanitizer);
|
| +
|
| + ViewFactory fromHtml(String html, DirectiveMap directives) {
|
| + ViewFactory viewFactory = _viewFactoryCache.get(html);
|
| + if (viewFactory == null) {
|
| + var div = new dom.DivElement();
|
| + div.setInnerHtml(html, treeSanitizer: treeSanitizer);
|
| + viewFactory = compiler(div.nodes, directives);
|
| + _viewFactoryCache.put(html, viewFactory);
|
| + }
|
| + return viewFactory;
|
| + }
|
| +
|
| + async.Future<ViewFactory> fromUrl(String url, DirectiveMap directives) {
|
| + return http.get(url, cache: templateCache).then(
|
| + (resp) => fromHtml(resp.responseText, directives));
|
| + }
|
| +}
|
| +
|
| +class _AnchorAttrs extends NodeAttrs {
|
| + DirectiveRef _directiveRef;
|
| +
|
| + _AnchorAttrs(DirectiveRef this._directiveRef): super(null);
|
| +
|
| + String operator [](name) => name == '.' ? _directiveRef.value : null;
|
| +
|
| + void observe(String attributeName, _AttributeChanged notifyFn) {
|
| + notifyFn(attributeName == '.' ? _directiveRef.value : null);
|
| + }
|
| +}
|
| +
|
| +String _html(obj) {
|
| + if (obj is String) {
|
| + return obj;
|
| + }
|
| + if (obj is List) {
|
| + return (obj as List).map((e) => _html(e)).join();
|
| + }
|
| + if (obj is dom.Element) {
|
| + var text = (obj as dom.Element).outerHtml;
|
| + return text.substring(0, text.indexOf('>') + 1);
|
| + }
|
| + return obj.nodeName;
|
| +}
|
| +
|
| +/**
|
| + * [ElementProbe] is attached to each [Element] in the DOM. Its sole purpose is
|
| + * to allow access to the [Injector], [Scope], and Directives for debugging and
|
| + * automated test purposes. The information here is not used by Angular in any
|
| + * way.
|
| + *
|
| + * see: [ngInjector], [ngScope], [ngDirectives]
|
| + */
|
| +class ElementProbe {
|
| + final ElementProbe parent;
|
| + final dom.Node element;
|
| + final Injector injector;
|
| + final Scope scope;
|
| + final directives = [];
|
| +
|
| + ElementProbe(this.parent, this.element, this.injector, this.scope);
|
| +}
|
|
|