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

Commit

Permalink
feat(compiler): Shadow DOM-less components
Browse files Browse the repository at this point in the history
  • Loading branch information
jbdeboer committed Apr 23, 2014
1 parent c6be443 commit 172afb8
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 27 deletions.
6 changes: 6 additions & 0 deletions lib/core_dom/module_internal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ part 'mustache.dart';
part 'node_cursor.dart';
part 'selector.dart';
part 'shadow_dom_component_factory.dart';
part 'shadowless_shadow_root.dart';
part 'tagging_compiler.dart';
part 'tagging_view_factory.dart';
part 'template_cache.dart';
part 'transcluding_component_factory.dart';
part 'tree_sanitizer.dart';
part 'walking_compiler.dart';
part 'ng_element.dart';
Expand All @@ -53,7 +55,11 @@ class CoreDomModule extends Module {
type(AttrMustache);

type(Compiler, implementedBy: TaggingCompiler);

type(ComponentFactory, implementedBy: ShadowDomComponentFactory);
type(Content);
value(ContentPort, null);

type(Http);
type(UrlRewriter);
type(HttpBackend);
Expand Down
40 changes: 24 additions & 16 deletions lib/core_dom/shadow_dom_component_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ part of angular.core.dom_internal;

abstract class ComponentFactory {
FactoryFn call(dom.Node node, DirectiveRef ref);

static async.Future<ViewFactory> _viewFuture(
Component component, ViewCache viewCache, DirectiveMap directives) {
if (component.template != null) {
return new async.Future.value(viewCache.fromHtml(component.template, directives));
}
if (component.templateUrl != null) {
return viewCache.fromUrl(component.templateUrl, directives);
}
return null;
}

static TemplateLoader _setupOnShadowDomAttach(controller, templateLoader, shadowScope) {
if (controller is ShadowRootAware) {
templateLoader.template.then((shadowDom) {
if (!shadowScope.isAttached) return;
(controller as ShadowRootAware).onShadowRoot(shadowDom);
});
}
}
}

class ShadowDomComponentFactory implements ComponentFactory {
Expand All @@ -12,7 +32,6 @@ class ShadowDomComponentFactory implements ComponentFactory {
FactoryFn call(dom.Node node, DirectiveRef ref) {
return (Injector injector) {
var component = ref.annotation as Component;
Compiler compiler = injector.get(Compiler);
Scope scope = injector.get(Scope);
ViewCache viewCache = injector.get(ViewCache);
Http http = injector.get(Http);
Expand Down Expand Up @@ -78,13 +97,7 @@ class _ComponentFactory implements Function {
} else {
cssFutures.add(new async.Future.value(null));
}
var viewFuture;
if (component.template != null) {
viewFuture = new async.Future.value(viewCache.fromHtml(
component.template, directives));
} else if (component.templateUrl != null) {
viewFuture = viewCache.fromUrl(component.templateUrl, directives);
}
var viewFuture = ComponentFactory._viewFuture(component, viewCache, directives);
TemplateLoader templateLoader = new TemplateLoader(
async.Future.wait(cssFutures).then((Iterable<String> cssList) {
if (cssList != null) {
Expand All @@ -98,19 +111,14 @@ class _ComponentFactory implements Function {
if (viewFuture != null) {
return viewFuture.then((ViewFactory viewFactory) {
return (!shadowScope.isAttached) ?
shadowDom :
attachViewToShadowDom(viewFactory);
shadowDom :
attachViewToShadowDom(viewFactory);
});
}
return shadowDom;
}));
controller = createShadowInjector(injector, templateLoader).get(type);
if (controller is ShadowRootAware) {
templateLoader.template.then((_) {
if (!shadowScope.isAttached) return;
(controller as ShadowRootAware).onShadowRoot(shadowDom);
});
}
ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
return controller;
}

Expand Down
12 changes: 12 additions & 0 deletions lib/core_dom/shadowless_shadow_root.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
part of angular.core.dom_internal;

@proxy
class ShadowlessShadowRoot implements dom.ShadowRoot {
dom.Element _element;

ShadowlessShadowRoot(this._element);

noSuchMethod(Invocation invocation) {
throw new UnimplementedError("Not yet implemented in ShadowlessShadowRoot.");
}
}
121 changes: 121 additions & 0 deletions lib/core_dom/transcluding_component_factory.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
part of angular.core.dom_internal;

@Decorator(
selector: 'content')
class Content implements AttachAware, DetachAware {
final ContentPort _port;
final dom.Element _element;
dom.Comment _beginComment;
Content(this._port, this._element);

void attach() {
if (_port == null) return;
_beginComment = _port.content(_element);
}

void detach() {
if (_port == null) return;
_port.detachContent(_beginComment);
}
}

class ContentPort {
dom.Element _element;
var _childNodes = [];

ContentPort(this._element);

void pullNodes() {
_childNodes.addAll(_element.nodes);
_element.nodes = [];
}

content(dom.Element elt) {
var hash = elt.hashCode;
var beginComment = new dom.Comment("content $hash");

if (_childNodes.isNotEmpty) {
elt.parent.insertBefore(beginComment, elt);
elt.parent.insertAllBefore(_childNodes, elt);
elt.parent.insertBefore(new dom.Comment("end-content $hash"), elt);
_childNodes = [];
}
elt.remove();
return beginComment;
}

void detachContent(dom.Comment _beginComment) {
// Search for endComment and extract everything in between.
// TODO optimize -- there may be a better way of pulling out nodes.

var endCommentText = "end-${_beginComment.text}";

var next;
for (next = _beginComment.nextNode;
next.nodeType != dom.Node.COMMENT_NODE && next.text != endCommentText;
next = _beginComment.nextNode) {
_childNodes.add(next);
next.remove();
}
assert(next.nodeType == dom.Node.COMMENT_NODE && next.text == endCommentText);
next.remove();
}
}

class TranscludingComponentFactory implements ComponentFactory {
final Expando _expando;

TranscludingComponentFactory(this._expando);

FactoryFn call(dom.Node node, DirectiveRef ref) {
// CSS is not supported.
assert((ref.annotation as Component).cssUrls == null ||
(ref.annotation as Component).cssUrls.isEmpty);

var element = node as dom.Element;
return (Injector injector) {
var childInjector;
var component = ref.annotation as Component;
Scope scope = injector.get(Scope);
ViewCache viewCache = injector.get(ViewCache);
Http http = injector.get(Http);
TemplateCache templateCache = injector.get(TemplateCache);
DirectiveMap directives = injector.get(DirectiveMap);
NgBaseCss baseCss = injector.get(NgBaseCss);

var contentPort = new ContentPort(element);

// Append the component's template as children
var viewFuture = ComponentFactory._viewFuture(component, viewCache, directives);

if (viewFuture != null) {
viewFuture = viewFuture.then((ViewFactory viewFactory) {
contentPort.pullNodes();
element.nodes.addAll(viewFactory(childInjector).nodes);
return element;
});
} else {
viewFuture = new async.Future.microtask(() => contentPort.pullNodes());
}
TemplateLoader templateLoader = new TemplateLoader(viewFuture);

Scope shadowScope = scope.createChild({});

var probe;
var childModule = new Module()
..type(ref.type)
..type(NgElement)
..value(ContentPort, contentPort)
..value(Scope, shadowScope)
..value(TemplateLoader, templateLoader)
..value(dom.ShadowRoot, new ShadowlessShadowRoot(element))
..factory(ElementProbe, (_) => probe);
childInjector = injector.createChild([childModule], name: SHADOW_DOM_INJECTOR_NAME);

var controller = childInjector.get(ref.type);
shadowScope.context[component.publishAs] = controller;
ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
return controller;
};
}
}
2 changes: 2 additions & 0 deletions lib/directive/ng_template.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ class NgTemplate {
? (element as dom.TemplateElement).content.innerHtml
: element.innerHtml));
}


2 changes: 1 addition & 1 deletion pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ packages:
barback:
description: barback
source: hosted
version: "0.13.0"
version: "0.12.0"
benchmark_harness:
description: benchmark_harness
source: hosted
Expand Down
Loading

0 comments on commit 172afb8

Please sign in to comment.