-
Notifications
You must be signed in to change notification settings - Fork 30
/
inject-css-in-shadow-dom.js
88 lines (79 loc) · 2.84 KB
/
inject-css-in-shadow-dom.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { hit, logMessage, hijackAttachShadow } from '../helpers';
/* eslint-disable max-len */
/**
* @scriptlet inject-css-in-shadow-dom
*
* @description
* Injects CSS rule into selected Shadow DOM subtrees on a page
*
* ### Syntax
*
* ```text
* example.org#%#//scriptlet('inject-css-in-shadow-dom', cssRule[, hostSelector])
* ```
*
* - `cssRule` — required, string representing a single css rule
* - `hostSelector` — optional, string, selector to match shadow host elements.
* CSS rule will be only applied to shadow roots inside these elements.
* Defaults to injecting css rule into all available roots.
*
* ### Examples
*
* 1. Apply style to all shadow dom subtrees
*
* ```adblock
* example.org#%#//scriptlet('inject-css-in-shadow-dom', '#advertisement { display: none !important; }')
* ```
*
* 1. Apply style to a specific shadow dom subtree
*
* ```adblock
* example.org#%#//scriptlet('inject-css-in-shadow-dom', '#content { margin-top: 0 !important; }', '#banner')
* ```
*
* @added v1.8.2.
*/
/* eslint-enable max-len */
export function injectCssInShadowDom(source, cssRule, hostSelector = '') {
// do nothing if browser does not support ShadowRoot, Proxy or Reflect
// https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot
if (!Element.prototype.attachShadow || typeof Proxy === 'undefined' || typeof Reflect === 'undefined') {
return;
}
// Prevent url() and image-set() styles from being applied
if (cssRule.match(/(url|image-set)\(.*\)/i)) {
logMessage(source, '"url()" function is not allowed for css rules');
return;
}
const callback = (shadowRoot) => {
try {
// adoptedStyleSheets and CSSStyleSheet constructor are not yet supported by Safari
// https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet
const stylesheet = new CSSStyleSheet();
try {
stylesheet.insertRule(cssRule);
} catch (e) {
logMessage(source, `Unable to apply the rule '${cssRule}' due to: \n'${e.message}'`);
return;
}
shadowRoot.adoptedStyleSheets = [...shadowRoot.adoptedStyleSheets, stylesheet];
} catch {
const styleTag = document.createElement('style');
styleTag.innerText = cssRule;
shadowRoot.appendChild(styleTag);
}
hit(source);
};
hijackAttachShadow(window, hostSelector, callback);
}
export const injectCssInShadowDomNames = [
'inject-css-in-shadow-dom',
];
// eslint-disable-next-line prefer-destructuring
injectCssInShadowDom.primaryName = injectCssInShadowDomNames[0];
injectCssInShadowDom.injections = [
hit,
logMessage,
hijackAttachShadow,
];