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

Commit f4893e0

Browse files
committed
feat(compiler): Shadow DOM-less components
1 parent 0c797cc commit f4893e0

7 files changed

+243
-27
lines changed

lib/core_dom/module_internal.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ part 'mustache.dart';
3434
part 'node_cursor.dart';
3535
part 'selector.dart';
3636
part 'shadow_dom_component_factory.dart';
37+
part 'shadowless_shadow_root.dart';
3738
part 'tagging_compiler.dart';
3839
part 'tagging_view_factory.dart';
3940
part 'template_cache.dart';
41+
part 'transcluding_component_factory.dart';
4042
part 'tree_sanitizer.dart';
4143
part 'walking_compiler.dart';
4244
part 'ng_element.dart';
@@ -53,7 +55,11 @@ class CoreDomModule extends Module {
5355
type(AttrMustache);
5456

5557
type(Compiler, implementedBy: TaggingCompiler);
58+
5659
type(ComponentFactory, implementedBy: ShadowDomComponentFactory);
60+
type(_Content);
61+
value(_ContentPort, null);
62+
5763
type(Http);
5864
type(UrlRewriter);
5965
type(HttpBackend);

lib/core_dom/shadow_dom_component_factory.dart

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,26 @@ part of angular.core.dom_internal;
22

33
abstract class ComponentFactory {
44
FactoryFn call(dom.Node node, DirectiveRef ref);
5+
6+
static async.Future<ViewFactory> _viewFuture(
7+
Component component, ViewCache viewCache, DirectiveMap directives) {
8+
if (component.template != null) {
9+
return new async.Future.value(viewCache.fromHtml(component.template, directives));
10+
}
11+
if (component.templateUrl != null) {
12+
return viewCache.fromUrl(component.templateUrl, directives);
13+
}
14+
return null;
15+
}
16+
17+
static TemplateLoader _setupOnShadowDomAttach(controller, templateLoader, shadowScope) {
18+
if (controller is ShadowRootAware) {
19+
templateLoader.template.then((shadowDom) {
20+
if (!shadowScope.isAttached) return;
21+
(controller as ShadowRootAware).onShadowRoot(shadowDom);
22+
});
23+
}
24+
}
525
}
626

727
class ShadowDomComponentFactory implements ComponentFactory {
@@ -12,7 +32,6 @@ class ShadowDomComponentFactory implements ComponentFactory {
1232
FactoryFn call(dom.Node node, DirectiveRef ref) {
1333
return (Injector injector) {
1434
var component = ref.annotation as Component;
15-
Compiler compiler = injector.get(Compiler);
1635
Scope scope = injector.get(Scope);
1736
ViewCache viewCache = injector.get(ViewCache);
1837
Http http = injector.get(Http);
@@ -78,13 +97,7 @@ class _ComponentFactory implements Function {
7897
} else {
7998
cssFutures.add(new async.Future.value(null));
8099
}
81-
var viewFuture;
82-
if (component.template != null) {
83-
viewFuture = new async.Future.value(viewCache.fromHtml(
84-
component.template, directives));
85-
} else if (component.templateUrl != null) {
86-
viewFuture = viewCache.fromUrl(component.templateUrl, directives);
87-
}
100+
var viewFuture = ComponentFactory._viewFuture(component, viewCache, directives);
88101
TemplateLoader templateLoader = new TemplateLoader(
89102
async.Future.wait(cssFutures).then((Iterable<String> cssList) {
90103
if (cssList != null) {
@@ -98,19 +111,14 @@ class _ComponentFactory implements Function {
98111
if (viewFuture != null) {
99112
return viewFuture.then((ViewFactory viewFactory) {
100113
return (!shadowScope.isAttached) ?
101-
shadowDom :
102-
attachViewToShadowDom(viewFactory);
114+
shadowDom :
115+
attachViewToShadowDom(viewFactory);
103116
});
104117
}
105118
return shadowDom;
106119
}));
107120
controller = createShadowInjector(injector, templateLoader).get(type);
108-
if (controller is ShadowRootAware) {
109-
templateLoader.template.then((_) {
110-
if (!shadowScope.isAttached) return;
111-
(controller as ShadowRootAware).onShadowRoot(shadowDom);
112-
});
113-
}
121+
ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
114122
return controller;
115123
}
116124

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
part of angular.core.dom_internal;
2+
3+
@proxy
4+
class ShadowlessShadowRoot implements dom.ShadowRoot {
5+
dom.Element _element;
6+
7+
ShadowlessShadowRoot(this._element);
8+
9+
noSuchMethod(Invocation invocation) {
10+
throw new UnimplementedError("Not yet implemented in ShadowlessShadowRoot.");
11+
}
12+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
part of angular.core.dom_internal;
2+
3+
@Decorator(
4+
selector: 'content')
5+
class _Content implements AttachAware, DetachAware {
6+
final _ContentPort _port;
7+
final dom.Element _element;
8+
dom.Comment _beginComment;
9+
_Content(this._port, this._element);
10+
11+
void attach() {
12+
if (_port == null) return;
13+
_beginComment = _port.content(_element);
14+
}
15+
16+
void detach() {
17+
if (_port == null) return;
18+
_port.detachContent(_beginComment);
19+
}
20+
}
21+
22+
class _ContentPort {
23+
dom.Element _element;
24+
var _childNodes = [];
25+
26+
_ContentPort(this._element);
27+
28+
void pullNodes() {
29+
_childNodes.addAll(_element.nodes);
30+
_element.nodes = [];
31+
}
32+
33+
content(dom.Element elt) {
34+
var hash = elt.hashCode;
35+
var beginComment = new dom.Comment("content $hash");
36+
37+
if (_childNodes.isNotEmpty) {
38+
elt.parent.insertBefore(beginComment, elt);
39+
elt.parent.insertAllBefore(_childNodes, elt);
40+
elt.parent.insertBefore(new dom.Comment("end-content $hash"), elt);
41+
_childNodes = [];
42+
}
43+
elt.remove();
44+
return beginComment;
45+
}
46+
47+
void detachContent(dom.Comment _beginComment) {
48+
// Search for endComment and extract everything in between.
49+
// TODO optimize -- there may be a better way of pulling out nodes.
50+
51+
var endCommentText = "end-${_beginComment.text}";
52+
53+
var next;
54+
for (next = _beginComment.nextNode;
55+
next.nodeType != dom.Node.COMMENT_NODE && next.text != endCommentText;
56+
next = _beginComment.nextNode) {
57+
_childNodes.add(next);
58+
next.remove();
59+
}
60+
assert(next.nodeType == dom.Node.COMMENT_NODE && next.text == endCommentText);
61+
next.remove();
62+
}
63+
}
64+
65+
class TranscludingComponentFactory implements ComponentFactory {
66+
final Expando _expando;
67+
68+
TranscludingComponentFactory(this._expando);
69+
70+
FactoryFn call(dom.Node node, DirectiveRef ref) {
71+
// CSS is not supported.
72+
assert((ref.annotation as Component).cssUrls == null ||
73+
(ref.annotation as Component).cssUrls.isEmpty);
74+
75+
var element = node as dom.Element;
76+
return (Injector injector) {
77+
var childInjector;
78+
var component = ref.annotation as Component;
79+
Scope scope = injector.get(Scope);
80+
ViewCache viewCache = injector.get(ViewCache);
81+
Http http = injector.get(Http);
82+
TemplateCache templateCache = injector.get(TemplateCache);
83+
DirectiveMap directives = injector.get(DirectiveMap);
84+
NgBaseCss baseCss = injector.get(NgBaseCss);
85+
86+
var contentPort = new _ContentPort(element);
87+
88+
// Append the component's template as children
89+
var viewFuture = ComponentFactory._viewFuture(component, viewCache, directives);
90+
91+
if (viewFuture != null) {
92+
viewFuture = viewFuture.then((ViewFactory viewFactory) {
93+
contentPort.pullNodes();
94+
element.nodes.addAll(viewFactory(childInjector).nodes);
95+
return element;
96+
});
97+
} else {
98+
viewFuture = new async.Future.microtask(() => contentPort.pullNodes());
99+
}
100+
TemplateLoader templateLoader = new TemplateLoader(viewFuture);
101+
102+
Scope shadowScope = scope.createChild({});
103+
104+
var probe;
105+
var childModule = new Module()
106+
..type(ref.type)
107+
..type(NgElement)
108+
..value(_ContentPort, contentPort)
109+
..value(Scope, shadowScope)
110+
..value(TemplateLoader, templateLoader)
111+
..value(dom.ShadowRoot, new ShadowlessShadowRoot(element))
112+
..factory(ElementProbe, (_) => probe);
113+
childInjector = injector.createChild([childModule], name: SHADOW_DOM_INJECTOR_NAME);
114+
115+
var controller = childInjector.get(ref.type);
116+
shadowScope.context[component.publishAs] = controller;
117+
ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
118+
return controller;
119+
};
120+
}
121+
}

lib/directive/ng_template.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ class NgTemplate {
3535
? (element as dom.TemplateElement).content.innerHtml
3636
: element.innerHtml));
3737
}
38+
39+

pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ packages:
1212
barback:
1313
description: barback
1414
source: hosted
15-
version: "0.13.0"
15+
version: "0.12.0"
1616
benchmark_harness:
1717
description: benchmark_harness
1818
source: hosted

0 commit comments

Comments
 (0)