@@ -17,6 +17,10 @@ import { hit, logMessage, hijackAttachShadow } from '../helpers';
17
17
* - `hostSelector` — optional, string, selector to match shadow host elements.
18
18
* CSS rule will be only applied to shadow roots inside these elements.
19
19
* Defaults to injecting css rule into all available roots.
20
+ * - `cssInjectionMethod` — optional, string, method to inject css rule into shadow dom.
21
+ * Available methods are:
22
+ * - `adoptedStyleSheets` — injects the CSS rule using adopted style sheets (default option).
23
+ * - `styleTag` — injects the CSS rule using a `style` tag.
20
24
*
21
25
* ### Examples
22
26
*
@@ -32,26 +36,64 @@ import { hit, logMessage, hijackAttachShadow } from '../helpers';
32
36
* example.org#%#//scriptlet('inject-css-in-shadow-dom', '#content { margin-top: 0 !important; }', '#banner')
33
37
* ```
34
38
*
39
+ * 1. Apply style to all shadow dom subtrees using style tag
40
+ *
41
+ * ```adblock
42
+ * example.org#%#//scriptlet('inject-css-in-shadow-dom', '.ads { display: none !important; }', '', 'styleTag')
43
+ * ```
44
+ *
35
45
* @added v1.8.2.
36
46
*/
37
47
/* eslint-enable max-len */
38
48
39
- export function injectCssInShadowDom ( source , cssRule , hostSelector = '' ) {
49
+ export function injectCssInShadowDom (
50
+ source ,
51
+ cssRule ,
52
+ hostSelector = '' ,
53
+ cssInjectionMethod = 'adoptedStyleSheets' ,
54
+ ) {
40
55
// do nothing if browser does not support ShadowRoot, Proxy or Reflect
41
56
// https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot
42
57
if ( ! Element . prototype . attachShadow || typeof Proxy === 'undefined' || typeof Reflect === 'undefined' ) {
43
58
return ;
44
59
}
45
60
61
+ if ( cssInjectionMethod !== 'adoptedStyleSheets' && cssInjectionMethod !== 'styleTag' ) {
62
+ logMessage ( source , `Unknown cssInjectionMethod: ${ cssInjectionMethod } ` ) ;
63
+ return ;
64
+ }
65
+
46
66
// Prevent url() and image-set() styles from being applied
47
67
if ( cssRule . match ( / ( u r l | i m a g e - s e t ) \( .* \) / i) ) {
48
68
logMessage ( source , '"url()" function is not allowed for css rules' ) ;
49
69
return ;
50
70
}
51
71
52
- const callback = ( shadowRoot ) => {
72
+ const injectStyleTag = ( shadowRoot ) => {
53
73
try {
54
- // adoptedStyleSheets and CSSStyleSheet constructor are not yet supported by Safari
74
+ const styleTag = document . createElement ( 'style' ) ;
75
+ styleTag . innerText = cssRule ;
76
+ shadowRoot . appendChild ( styleTag ) ;
77
+ hit ( source ) ;
78
+ } catch ( error ) {
79
+ logMessage ( source , `Unable to inject style tag due to: \n'${ error . message } '` ) ;
80
+ }
81
+ } ;
82
+
83
+ /**
84
+ * Injects CSS rules into a shadow root using the adoptedStyleSheets API
85
+ *
86
+ * @param {ShadowRoot } shadowRoot - The shadow root to inject styles into
87
+ * @private
88
+ *
89
+ * @description
90
+ * This function attempts to inject CSS using adoptedStyleSheets API.
91
+ * If successful, it adds the stylesheet to the shadow root's adoptedStyleSheets array.
92
+ * On failure, it falls back to using the injectStyleTag method.
93
+ */
94
+ const injectAdoptedStyleSheets = ( shadowRoot ) => {
95
+ try {
96
+ // adoptedStyleSheets and CSSStyleSheet constructor are not supported by old browsers
55
97
// https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets
56
98
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet
57
99
const stylesheet = new CSSStyleSheet ( ) ;
@@ -62,13 +104,19 @@ export function injectCssInShadowDom(source, cssRule, hostSelector = '') {
62
104
return ;
63
105
}
64
106
shadowRoot . adoptedStyleSheets = [ ...shadowRoot . adoptedStyleSheets , stylesheet ] ;
65
- } catch {
66
- const styleTag = document . createElement ( 'style' ) ;
67
- styleTag . innerText = cssRule ;
68
- shadowRoot . appendChild ( styleTag ) ;
107
+ hit ( source ) ;
108
+ } catch ( error ) {
109
+ logMessage ( source , `Unable to inject adopted style sheet due to: \n' ${ error . message } '` ) ;
110
+ injectStyleTag ( shadowRoot ) ;
69
111
}
112
+ } ;
70
113
71
- hit ( source ) ;
114
+ const callback = ( shadowRoot ) => {
115
+ if ( cssInjectionMethod === 'adoptedStyleSheets' ) {
116
+ injectAdoptedStyleSheets ( shadowRoot ) ;
117
+ } else if ( cssInjectionMethod === 'styleTag' ) {
118
+ injectStyleTag ( shadowRoot ) ;
119
+ }
72
120
} ;
73
121
74
122
hijackAttachShadow ( window , hostSelector , callback ) ;
0 commit comments