diff --git a/lib/core/annotation_src.dart b/lib/core/annotation_src.dart
index 1c1796d12..ee5270362 100644
--- a/lib/core/annotation_src.dart
+++ b/lib/core/annotation_src.dart
@@ -308,6 +308,13 @@ class Component extends Directive {
@deprecated
final String publishAs;
+ /**
+ * If set to true, this component will always use shadow DOM.
+ * If set to false, this component will never use shadow DOM.
+ * If unset, the compiler's default construction strategy will be used
+ */
+ final bool useShadowDom;
+
const Component({
this.template,
this.templateUrl,
@@ -320,7 +327,8 @@ class Component extends Directive {
selector,
visibility,
exportExpressions,
- exportExpressionAttrs})
+ exportExpressionAttrs,
+ this.useShadowDom})
: _cssUrls = cssUrl,
_applyAuthorStyles = applyAuthorStyles,
_resetStyleInheritance = resetStyleInheritance,
@@ -349,7 +357,8 @@ class Component extends Directive {
selector: selector,
visibility: visibility,
exportExpressions: exportExpressions,
- exportExpressionAttrs: exportExpressionAttrs);
+ exportExpressionAttrs: exportExpressionAttrs,
+ useShadowDom: useShadowDom);
}
/**
diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart
index 13035f6fc..dd01377ac 100644
--- a/lib/core_dom/element_binder.dart
+++ b/lib/core_dom/element_binder.dart
@@ -14,9 +14,13 @@ class TemplateElementBinder extends ElementBinder {
return _directiveCache = [template];
}
- TemplateElementBinder(_perf, _expando, _parser, _componentFactory, this.template, this.templateBinder,
+ TemplateElementBinder(perf, expando, parser, componentFactory,
+ transcludingComponentFactory, shadowDomComponentFactory,
+ this.template, this.templateBinder,
onEvents, bindAttrs, childMode)
- : super(_perf, _expando, _parser, _componentFactory, null, null, onEvents, bindAttrs, childMode);
+ : super(perf, expando, parser, componentFactory,
+ transcludingComponentFactory, shadowDomComponentFactory,
+ null, null, onEvents, bindAttrs, childMode);
String toString() => "[TemplateElementBinder template:$template]";
@@ -41,7 +45,11 @@ class ElementBinder {
final Profiler _perf;
final Expando _expando;
final Parser _parser;
+
+ // The default component factory
final ComponentFactory _componentFactory;
+ final TranscludingComponentFactory _transcludingComponentFactory;
+ final ShadowDomComponentFactory _shadowDomComponentFactory;
final Map onEvents;
final Map bindAttrs;
@@ -53,7 +61,11 @@ class ElementBinder {
// Can be either COMPILE_CHILDREN or IGNORE_CHILDREN
final String childMode;
- ElementBinder(this._perf, this._expando, this._parser, this._componentFactory, this.component, this.decorators,
+ ElementBinder(this._perf, this._expando, this._parser,
+ this._componentFactory,
+ this._transcludingComponentFactory,
+ this._shadowDomComponentFactory,
+ this.component, this.decorators,
this.onEvents, this.bindAttrs, this.childMode);
final bool hasTemplate = false;
@@ -215,7 +227,16 @@ class ElementBinder {
}
nodesAttrsDirectives.add(ref);
} else if (ref.annotation is Component) {
- nodeModule.factory(ref.type, _componentFactory.call(node, ref), visibility: visibility);
+ var factory;
+ var annotation = ref.annotation as Component;
+ if (annotation.useShadowDom == true) {
+ factory = _shadowDomComponentFactory;
+ } else if (annotation.useShadowDom == false) {
+ factory = _transcludingComponentFactory;
+ } else {
+ factory = _componentFactory;
+ }
+ nodeModule.factory(ref.type, factory.call(node, ref), visibility: visibility);
} else {
nodeModule.type(ref.type, visibility: visibility);
}
diff --git a/lib/core_dom/element_binder_builder.dart b/lib/core_dom/element_binder_builder.dart
index 12c4fbcb5..050c53c18 100644
--- a/lib/core_dom/element_binder_builder.dart
+++ b/lib/core_dom/element_binder_builder.dart
@@ -6,17 +6,22 @@ class ElementBinderFactory {
final Profiler _perf;
final Expando _expando;
final ComponentFactory _componentFactory;
+ final TranscludingComponentFactory _transcludingComponentFactory;
+ final ShadowDomComponentFactory _shadowDomComponentFactory;
- ElementBinderFactory(this._parser, this._perf, this._expando, this._componentFactory);
+ ElementBinderFactory(this._parser, this._perf, this._expando, this._componentFactory,
+ this._transcludingComponentFactory, this._shadowDomComponentFactory);
// TODO: Optimize this to re-use a builder.
ElementBinderBuilder builder() => new ElementBinderBuilder(this);
ElementBinder binder(ElementBinderBuilder b) =>
new ElementBinder(_perf, _expando, _parser, _componentFactory,
+ _transcludingComponentFactory, _shadowDomComponentFactory,
b.component, b.decorators, b.onEvents, b.bindAttrs, b.childMode);
TemplateElementBinder templateBinder(ElementBinderBuilder b, ElementBinder transclude) =>
new TemplateElementBinder(_perf, _expando, _parser, _componentFactory,
+ _transcludingComponentFactory, _shadowDomComponentFactory,
b.template, transclude, b.onEvents, b.bindAttrs, b.childMode);
}
diff --git a/lib/core_dom/module_internal.dart b/lib/core_dom/module_internal.dart
index a94445170..810f2f6a7 100644
--- a/lib/core_dom/module_internal.dart
+++ b/lib/core_dom/module_internal.dart
@@ -57,6 +57,8 @@ class CoreDomModule extends Module {
type(Compiler, implementedBy: TaggingCompiler);
type(ComponentFactory, implementedBy: ShadowDomComponentFactory);
+ type(ShadowDomComponentFactory);
+ type(TranscludingComponentFactory);
type(Content);
value(ContentPort, null);
diff --git a/test/core/annotation_src_spec.dart b/test/core/annotation_src_spec.dart
index 4fabc414d..c3d7f8e44 100644
--- a/test/core/annotation_src_spec.dart
+++ b/test/core/annotation_src_spec.dart
@@ -45,7 +45,8 @@ void main() => describe('annotations', () {
selector: '',
visibility: Directive.LOCAL_VISIBILITY,
exportExpressions: [],
- exportExpressionAttrs: []
+ exportExpressionAttrs: [],
+ useShadowDom: true
);
// Check that no fields are null
diff --git a/test/core_dom/compiler_spec.dart b/test/core_dom/compiler_spec.dart
index 5fb4002ac..f86eea9aa 100644
--- a/test/core_dom/compiler_spec.dart
+++ b/test/core_dom/compiler_spec.dart
@@ -618,6 +618,35 @@ void main() {
}).toThrow('Unknown selector format \'buttonbar button\' for InvalidSelector');
});
});
+
+ describe('useShadowDom option', () {
+ beforeEachModule((Module m) {
+ m.type(ShadowyComponent);
+ m.type(ShadowlessComponent);
+ });
+
+ it('should create shadowy components', async((Logger log) {
+ _.compile('');
+ expect(log).toEqual(['shadowy']);
+ expect(_.rootElement.shadowRoot).toBeNotNull();
+ }));
+
+ it('should create shadowless components', async((Logger log) {
+ _.compile('');
+ expect(log).toEqual(['shadowless']);
+ expect(_.rootElement.shadowRoot).toBeNull();
+ }));
+
+ it('should create other components with the default strategy', async((ComponentFactory factory) {
+ _.compile('');
+ if (factory is TranscludingComponentFactory) {
+ expect(_.rootElement.shadowRoot).toBeNull();
+ } else {
+ expect(factory is ShadowDomComponentFactory).toBeTruthy();
+ expect(_.rootElement.shadowRoot).toBeNotNull();
+ }
+ }));
+ });
});
@@ -807,6 +836,27 @@ class SimpleComponent {
}
}
+@Component(
+ selector: 'shadowy',
+ template: r'With shadow DOM',
+ useShadowDom: true
+)
+class ShadowyComponent {
+ ShadowyComponent(Logger log) {
+ log('shadowy');
+ }
+}
+
+@Component(
+ selector: 'shadowless',
+ template: r'Without shadow DOM',
+ useShadowDom: false
+)
+class ShadowlessComponent {
+ ShadowlessComponent(Logger log) {
+ log('shadowless');
+ }
+}
@Component(
selector: 'sometimes',