@@ -23,15 +23,22 @@ export class ShadowDomStrategy {
2323 shimHostElement ( component : Type , element : Element ) { }
2424}
2525
26- export class EmulatedShadowDomStrategy extends ShadowDomStrategy {
27- _styleInliner : StyleInliner ;
26+ /**
27+ * This strategy emulates the Shadow DOM for the templates, styles **excluded**:
28+ * - components templates are added as children of their component element,
29+ * - styles are moved from the templates to the styleHost (i.e. the document head).
30+ *
31+ * Notes:
32+ * - styles are **not** scoped to their component and will apply to the whole document,
33+ * - you can **not** use shadow DOM specific selectors in the styles
34+ */
35+ export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy {
2836 _styleUrlResolver : StyleUrlResolver ;
29- _styleHost : Element ;
3037 _lastInsertedStyle : StyleElement ;
38+ _styleHost : Element ;
3139
32- constructor ( styleInliner : StyleInliner , styleUrlResolver : StyleUrlResolver , styleHost : Element ) {
40+ constructor ( styleUrlResolver : StyleUrlResolver , styleHost : Element ) {
3341 super ( ) ;
34- this . _styleInliner = styleInliner ;
3542 this . _styleUrlResolver = styleUrlResolver ;
3643 this . _styleHost = styleHost ;
3744 }
@@ -49,6 +56,58 @@ export class EmulatedShadowDomStrategy extends ShadowDomStrategy {
4956 return [ Content ] ;
5057 }
5158
59+ transformStyleText ( cssText : string , baseUrl : string , component : Type ) {
60+ return this . _styleUrlResolver . resolveUrls ( cssText , baseUrl ) ;
61+ }
62+
63+ handleStyleElement ( styleEl : StyleElement ) {
64+ DOM . remove ( styleEl ) ;
65+
66+ var cssText = DOM . getText ( styleEl ) ;
67+
68+ if ( ! MapWrapper . contains ( _sharedStyleTexts , cssText ) ) {
69+ // Styles are unscoped and shared across components, only append them to the head
70+ // when there are not present yet
71+ MapWrapper . set ( _sharedStyleTexts , cssText , true ) ;
72+ this . _insertStyleElement ( this . _styleHost , styleEl ) ;
73+ }
74+ } ;
75+
76+ _insertStyleElement ( host : Element , style : StyleElement ) {
77+ if ( isBlank ( this . _lastInsertedStyle ) ) {
78+ var firstChild = DOM . firstChild ( host ) ;
79+ if ( isPresent ( firstChild ) ) {
80+ DOM . insertBefore ( firstChild , style ) ;
81+ } else {
82+ DOM . appendChild ( host , style ) ;
83+ }
84+ } else {
85+ DOM . insertAfter ( this . _lastInsertedStyle , style ) ;
86+ }
87+ this . _lastInsertedStyle = style ;
88+ }
89+ }
90+
91+ /**
92+ * This strategy emulates the Shadow DOM for the templates, styles **included**:
93+ * - components templates are added as children of their component element,
94+ * - both the template and the styles are modified so that styles are scoped to the component
95+ * they belong to,
96+ * - styles are moved from the templates to the styleHost (i.e. the document head).
97+ *
98+ * Notes:
99+ * - styles are scoped to their component and will apply only to it,
100+ * - a common subset of shadow DOM selectors are supported,
101+ * - see `ShadowCss` for more information and limitations.
102+ */
103+ export class EmulatedScopedShadowDomStrategy extends EmulatedUnscopedShadowDomStrategy {
104+ _styleInliner : StyleInliner ;
105+
106+ constructor ( styleInliner : StyleInliner , styleUrlResolver : StyleUrlResolver , styleHost : Element ) {
107+ super ( styleUrlResolver , styleHost ) ;
108+ this . _styleInliner = styleInliner ;
109+ }
110+
52111 transformStyleText ( cssText : string , baseUrl : string , component : Type ) {
53112 cssText = this . _styleUrlResolver . resolveUrls ( cssText , baseUrl ) ;
54113 var css = this . _styleInliner . inlineImports ( cssText , baseUrl ) ;
@@ -75,22 +134,14 @@ export class EmulatedShadowDomStrategy extends ShadowDomStrategy {
75134 var attrName = _getHostAttribute ( id ) ;
76135 DOM . setAttribute ( element , attrName , '' ) ;
77136 }
78-
79- _insertStyleElement ( host : Element , style : StyleElement ) {
80- if ( isBlank ( this . _lastInsertedStyle ) ) {
81- var firstChild = DOM . firstChild ( host ) ;
82- if ( isPresent ( firstChild ) ) {
83- DOM . insertBefore ( firstChild , style ) ;
84- } else {
85- DOM . appendChild ( host , style ) ;
86- }
87- } else {
88- DOM . insertAfter ( this . _lastInsertedStyle , style ) ;
89- }
90- this . _lastInsertedStyle = style ;
91- }
92137}
93138
139+ /**
140+ * This strategies uses the native Shadow DOM support.
141+ *
142+ * The templates for the component are inserted in a Shadow Root created on the component element.
143+ * Hence they are strictly isolated.
144+ */
94145export class NativeShadowDomStrategy extends ShadowDomStrategy {
95146 _styleUrlResolver : StyleUrlResolver ;
96147
@@ -124,6 +175,7 @@ function _moveViewNodesIntoParent(parent, view) {
124175
125176var _componentUIDs : Map < Type , int > = MapWrapper . create ( ) ;
126177var _nextComponentUID : int = 0 ;
178+ var _sharedStyleTexts : Map < string , boolean > = MapWrapper . create ( ) ;
127179
128180function _getComponentId ( component : Type ) {
129181 var id = MapWrapper . get ( _componentUIDs , component ) ;
@@ -150,8 +202,9 @@ function _shimCssForComponent(cssText: string, component: Type): string {
150202 return shadowCss . shimCssText ( cssText , _getContentAttribute ( id ) , _getHostAttribute ( id ) ) ;
151203}
152204
153- // Reset the component cache - used for tests only
205+ // Reset the caches - used for tests only
154206export function resetShadowDomCache ( ) {
155207 MapWrapper . clear ( _componentUIDs ) ;
156208 _nextComponentUID = 0 ;
209+ MapWrapper . clear ( _sharedStyleTexts ) ;
157210}
0 commit comments