darkreader 4.9.117 → 4.9.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/darkreader.js +156 -23
- package/darkreader.mjs +151 -25
- package/package.json +18 -18
package/LICENSE
CHANGED
package/darkreader.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dark Reader v4.9.
|
|
2
|
+
* Dark Reader v4.9.119
|
|
3
3
|
* https://darkreader.org/
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -189,7 +189,10 @@
|
|
|
189
189
|
}
|
|
190
190
|
if (
|
|
191
191
|
mimeType &&
|
|
192
|
-
!
|
|
192
|
+
!(
|
|
193
|
+
response.headers.get("Content-Type") === mimeType ||
|
|
194
|
+
response.headers.get("Content-Type").startsWith(`${mimeType};`)
|
|
195
|
+
)
|
|
193
196
|
) {
|
|
194
197
|
throw new Error(`Mime type mismatch when loading ${url}`);
|
|
195
198
|
}
|
|
@@ -2691,22 +2694,64 @@
|
|
|
2691
2694
|
}
|
|
2692
2695
|
});
|
|
2693
2696
|
const ipV4RegExp = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
|
2694
|
-
const
|
|
2695
|
-
const
|
|
2697
|
+
const MAX_CORS_HOSTS = 16;
|
|
2698
|
+
const corsHosts = new Set();
|
|
2699
|
+
const checkedHosts = new Set();
|
|
2700
|
+
const localAliases = [
|
|
2701
|
+
"127-0-0-1.org.uk",
|
|
2702
|
+
"42foo.com",
|
|
2703
|
+
"domaincontrol.com",
|
|
2704
|
+
"fbi.com",
|
|
2705
|
+
"fuf.me",
|
|
2706
|
+
"lacolhost.com",
|
|
2707
|
+
"local.sisteminha.com",
|
|
2708
|
+
"localfabriek.nl",
|
|
2709
|
+
"localhost",
|
|
2710
|
+
"localhst.co.uk",
|
|
2711
|
+
"localmachine.info",
|
|
2712
|
+
"localmachine.name",
|
|
2713
|
+
"localtest.me",
|
|
2714
|
+
"lvh.me",
|
|
2715
|
+
"mouse-potato.com",
|
|
2716
|
+
"nip.io",
|
|
2717
|
+
"sslip.io",
|
|
2718
|
+
"vcap.me",
|
|
2719
|
+
"xip.io",
|
|
2720
|
+
"yoogle.com"
|
|
2721
|
+
];
|
|
2722
|
+
const localSubDomains = [
|
|
2723
|
+
".corp",
|
|
2724
|
+
".direct",
|
|
2725
|
+
".home",
|
|
2726
|
+
".internal",
|
|
2727
|
+
".intranet",
|
|
2728
|
+
".lan",
|
|
2729
|
+
".local",
|
|
2730
|
+
".localdomain",
|
|
2731
|
+
".test",
|
|
2732
|
+
".zz",
|
|
2733
|
+
...localAliases.map((alias) => `.${alias}`)
|
|
2734
|
+
];
|
|
2696
2735
|
function shouldIgnoreCors(url) {
|
|
2697
|
-
const host = url
|
|
2698
|
-
if (!
|
|
2699
|
-
|
|
2736
|
+
const {host, hostname, port, protocol} = url;
|
|
2737
|
+
if (!corsHosts.has(host)) {
|
|
2738
|
+
corsHosts.add(host);
|
|
2739
|
+
}
|
|
2740
|
+
if (checkedHosts.has(host)) {
|
|
2741
|
+
return false;
|
|
2700
2742
|
}
|
|
2701
2743
|
if (
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2744
|
+
corsHosts.size >= MAX_CORS_HOSTS ||
|
|
2745
|
+
protocol !== "https:" ||
|
|
2746
|
+
port !== "" ||
|
|
2747
|
+
localAliases.includes(hostname) ||
|
|
2748
|
+
localSubDomains.some((sub) => hostname.endsWith(sub)) ||
|
|
2749
|
+
hostname.startsWith("[") ||
|
|
2750
|
+
hostname.match(ipV4RegExp)
|
|
2707
2751
|
) {
|
|
2708
2752
|
return true;
|
|
2709
2753
|
}
|
|
2754
|
+
checkedHosts.add(host);
|
|
2710
2755
|
return false;
|
|
2711
2756
|
}
|
|
2712
2757
|
|
|
@@ -2714,14 +2759,59 @@
|
|
|
2714
2759
|
async function getImageDetails(url) {
|
|
2715
2760
|
return new Promise(async (resolve, reject) => {
|
|
2716
2761
|
try {
|
|
2717
|
-
|
|
2762
|
+
let dataURL = url.startsWith("data:")
|
|
2718
2763
|
? url
|
|
2719
2764
|
: await getDataURL(url);
|
|
2720
2765
|
const blob =
|
|
2721
2766
|
tryConvertDataURLToBlobSync(dataURL) ??
|
|
2722
2767
|
(await loadAsBlob(url));
|
|
2723
2768
|
let image;
|
|
2769
|
+
let useViewBox = false;
|
|
2724
2770
|
if (dataURL.startsWith("data:image/svg+xml")) {
|
|
2771
|
+
const commaIndex = dataURL.indexOf(",");
|
|
2772
|
+
if (commaIndex >= 0) {
|
|
2773
|
+
let svgText = dataURL.slice(commaIndex + 1);
|
|
2774
|
+
const encoding = dataURL
|
|
2775
|
+
.slice(0, commaIndex)
|
|
2776
|
+
.split(";")[1];
|
|
2777
|
+
if (encoding === "base64") {
|
|
2778
|
+
svgText = atob(svgText);
|
|
2779
|
+
}
|
|
2780
|
+
if (svgText.startsWith("<svg ")) {
|
|
2781
|
+
const closingIndex = svgText.indexOf(">");
|
|
2782
|
+
const svgOpening = svgText
|
|
2783
|
+
.slice(0, closingIndex + 1)
|
|
2784
|
+
.toLocaleLowerCase();
|
|
2785
|
+
if (
|
|
2786
|
+
svgOpening.includes("viewbox") &&
|
|
2787
|
+
!svgOpening.includes("width") &&
|
|
2788
|
+
!svgOpening.includes("height")
|
|
2789
|
+
) {
|
|
2790
|
+
useViewBox = true;
|
|
2791
|
+
const viewboxIndex =
|
|
2792
|
+
svgOpening.indexOf('viewbox="');
|
|
2793
|
+
const viewboxCloseIndex = svgOpening.indexOf(
|
|
2794
|
+
'viewbox="',
|
|
2795
|
+
viewboxIndex + 9
|
|
2796
|
+
);
|
|
2797
|
+
const viewBox = svgOpening
|
|
2798
|
+
.slice(
|
|
2799
|
+
viewboxIndex + 9,
|
|
2800
|
+
viewboxCloseIndex - 1
|
|
2801
|
+
)
|
|
2802
|
+
.split(" ")
|
|
2803
|
+
.map((x) => parseFloat(x));
|
|
2804
|
+
if (
|
|
2805
|
+
viewBox.length === 4 &&
|
|
2806
|
+
!viewBox.some((x) => isNaN(x))
|
|
2807
|
+
) {
|
|
2808
|
+
const width = viewBox[2] - viewBox[0];
|
|
2809
|
+
const height = viewBox[3] - viewBox[1];
|
|
2810
|
+
dataURL = `data:image/svg+xml;base64,${btoa(`<svg width="${width}" height="${height}" ${svgText.slice(5)}`)}`;
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2725
2815
|
image = await loadImage(dataURL);
|
|
2726
2816
|
} else {
|
|
2727
2817
|
image =
|
|
@@ -2735,6 +2825,7 @@
|
|
|
2735
2825
|
dataURL: analysis.isLarge ? "" : dataURL,
|
|
2736
2826
|
width: image.width,
|
|
2737
2827
|
height: image.height,
|
|
2828
|
+
useViewBox,
|
|
2738
2829
|
...analysis
|
|
2739
2830
|
});
|
|
2740
2831
|
});
|
|
@@ -2922,13 +3013,16 @@
|
|
|
2922
3013
|
}
|
|
2923
3014
|
document.addEventListener("securitypolicyviolation", onCSPError);
|
|
2924
3015
|
const objectURLs = new Set();
|
|
2925
|
-
function getFilteredImageURL({dataURL, width, height}, theme) {
|
|
3016
|
+
function getFilteredImageURL({dataURL, width, height, useViewBox}, theme) {
|
|
2926
3017
|
if (dataURL.startsWith("data:image/svg+xml")) {
|
|
2927
3018
|
dataURL = escapeXML(dataURL);
|
|
2928
3019
|
}
|
|
2929
3020
|
const matrix = getSVGFilterMatrixValue(theme);
|
|
3021
|
+
const size = useViewBox
|
|
3022
|
+
? `viewBox="0 0 ${width} ${height}"`
|
|
3023
|
+
: `width="${width}" height="${height}"`;
|
|
2930
3024
|
const svg = [
|
|
2931
|
-
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
3025
|
+
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ${size}>`,
|
|
2932
3026
|
"<defs>",
|
|
2933
3027
|
'<filter id="darkreader-image-filter">',
|
|
2934
3028
|
`<feColorMatrix type="matrix" values="${matrix}" />`,
|
|
@@ -4190,8 +4284,8 @@
|
|
|
4190
4284
|
this.definedVars.add(varName);
|
|
4191
4285
|
const isColor = Boolean(
|
|
4192
4286
|
value.match(rawRGBSpaceRegex) ||
|
|
4193
|
-
|
|
4194
|
-
|
|
4287
|
+
value.match(rawRGBCommaRegex) ||
|
|
4288
|
+
parseColorWithCache(value)
|
|
4195
4289
|
);
|
|
4196
4290
|
if (isColor) {
|
|
4197
4291
|
this.unknownColorVars.add(varName);
|
|
@@ -4530,13 +4624,16 @@
|
|
|
4530
4624
|
function isTextColorProperty(property) {
|
|
4531
4625
|
return textColorProps.includes(property);
|
|
4532
4626
|
}
|
|
4533
|
-
const rawRGBSpaceRegex =
|
|
4627
|
+
const rawRGBSpaceRegex =
|
|
4628
|
+
/^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})\s*(\/\s*\d+\.?\d*)?$/;
|
|
4534
4629
|
const rawRGBCommaRegex = /^(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})$/;
|
|
4535
4630
|
function parseRawColorValue(input) {
|
|
4536
4631
|
const match =
|
|
4537
4632
|
input.match(rawRGBSpaceRegex) ?? input.match(rawRGBCommaRegex);
|
|
4538
4633
|
if (match) {
|
|
4539
|
-
const color =
|
|
4634
|
+
const color = match[4]
|
|
4635
|
+
? `rgb(${match[1]} ${match[2]} ${match[3]} / ${match[4]})`
|
|
4636
|
+
: `rgb(${match[1]}, ${match[2]}, ${match[3]})`;
|
|
4540
4637
|
return {isRaw: true, color};
|
|
4541
4638
|
}
|
|
4542
4639
|
return {isRaw: false, color: input};
|
|
@@ -5581,8 +5678,8 @@
|
|
|
5581
5678
|
}
|
|
5582
5679
|
const shouldAnalyze = Boolean(
|
|
5583
5680
|
svg &&
|
|
5584
|
-
|
|
5585
|
-
|
|
5681
|
+
(svg.getAttribute("class")?.includes("logo") ||
|
|
5682
|
+
svg.parentElement?.getAttribute("class")?.includes("logo"))
|
|
5586
5683
|
);
|
|
5587
5684
|
svgAnalysisConditionCache.set(svg, shouldAnalyze);
|
|
5588
5685
|
return shouldAnalyze;
|
|
@@ -5625,6 +5722,7 @@
|
|
|
5625
5722
|
svgNodesRoots.set(svgElement, root);
|
|
5626
5723
|
return root;
|
|
5627
5724
|
}
|
|
5725
|
+
const inlineStringValueCache = new Map();
|
|
5628
5726
|
function overrideInlineStyle(
|
|
5629
5727
|
element,
|
|
5630
5728
|
theme,
|
|
@@ -5652,6 +5750,13 @@
|
|
|
5652
5750
|
}
|
|
5653
5751
|
const unsetProps = new Set(Object.keys(overrides));
|
|
5654
5752
|
function setCustomProp(targetCSSProp, modifierCSSProp, cssVal) {
|
|
5753
|
+
const cachedStringValue = inlineStringValueCache
|
|
5754
|
+
.get(modifierCSSProp)
|
|
5755
|
+
?.get(cssVal);
|
|
5756
|
+
if (cachedStringValue) {
|
|
5757
|
+
setStaticValue(cachedStringValue);
|
|
5758
|
+
return;
|
|
5759
|
+
}
|
|
5655
5760
|
const mod = getModifiableCSSDeclaration(
|
|
5656
5761
|
modifierCSSProp,
|
|
5657
5762
|
cssVal,
|
|
@@ -5718,6 +5823,10 @@
|
|
|
5718
5823
|
typeof mod.value === "function" ? mod.value(theme) : mod.value;
|
|
5719
5824
|
if (typeof value === "string") {
|
|
5720
5825
|
setStaticValue(value);
|
|
5826
|
+
if (!inlineStringValueCache.has(modifierCSSProp)) {
|
|
5827
|
+
inlineStringValueCache.set(modifierCSSProp, new Map());
|
|
5828
|
+
}
|
|
5829
|
+
inlineStringValueCache.get(modifierCSSProp).set(cssVal, value);
|
|
5721
5830
|
} else if (value instanceof Promise) {
|
|
5722
5831
|
setAsyncValue(value, cssVal);
|
|
5723
5832
|
} else if (typeof value === "object") {
|
|
@@ -5804,13 +5913,16 @@
|
|
|
5804
5913
|
value.match(/^[0-9a-f]{6}$/i)
|
|
5805
5914
|
) {
|
|
5806
5915
|
value = `#${value}`;
|
|
5916
|
+
} else if (value.match(/^#?[0-9a-f]{4}$/i)) {
|
|
5917
|
+
const hex = value.startsWith("#") ? value.substring(1) : value;
|
|
5918
|
+
value = `#${hex}00`;
|
|
5807
5919
|
}
|
|
5808
5920
|
setCustomProp("color", "color", value);
|
|
5809
5921
|
}
|
|
5810
5922
|
if (isSVGElement) {
|
|
5811
5923
|
if (element.hasAttribute("fill")) {
|
|
5812
5924
|
const value = element.getAttribute("fill");
|
|
5813
|
-
if (value !== "none") {
|
|
5925
|
+
if (value !== "none" && value !== "currentColor") {
|
|
5814
5926
|
if (!(element instanceof SVGTextElement)) {
|
|
5815
5927
|
const handleSVGElement = () => {
|
|
5816
5928
|
let isSVGSmall = false;
|
|
@@ -6142,7 +6254,7 @@
|
|
|
6142
6254
|
forEach(node.querySelectorAll(STYLE_SELECTOR), (style) =>
|
|
6143
6255
|
getManageableStyles(style, results, false)
|
|
6144
6256
|
);
|
|
6145
|
-
if (deep) {
|
|
6257
|
+
if (deep && (node.children?.length > 0 || node.shadowRoot)) {
|
|
6146
6258
|
iterateShadowHosts(node, (host) =>
|
|
6147
6259
|
getManageableStyles(host.shadowRoot, results, false)
|
|
6148
6260
|
);
|
|
@@ -7310,10 +7422,23 @@
|
|
|
7310
7422
|
removedStyles,
|
|
7311
7423
|
movedStyles
|
|
7312
7424
|
});
|
|
7425
|
+
const potentialHosts = new Set();
|
|
7313
7426
|
additions.forEach((n) => {
|
|
7427
|
+
if (n.parentElement) {
|
|
7428
|
+
potentialHosts.add(n.parentElement);
|
|
7429
|
+
}
|
|
7430
|
+
if (n.previousElementSibling) {
|
|
7431
|
+
potentialHosts.add(n.previousElementSibling);
|
|
7432
|
+
}
|
|
7314
7433
|
deepObserve(n);
|
|
7315
7434
|
collectUndefinedElements(n);
|
|
7316
7435
|
});
|
|
7436
|
+
potentialHosts.forEach((el) => {
|
|
7437
|
+
if (el.shadowRoot && !observedRoots.has(el)) {
|
|
7438
|
+
subscribeForShadowRootChanges(el);
|
|
7439
|
+
deepObserve(el.shadowRoot);
|
|
7440
|
+
}
|
|
7441
|
+
});
|
|
7317
7442
|
additions.forEach(
|
|
7318
7443
|
(node) => isCustomElement(node) && recordUndefinedElement(node)
|
|
7319
7444
|
);
|
|
@@ -7427,6 +7552,14 @@
|
|
|
7427
7552
|
});
|
|
7428
7553
|
document.addEventListener("__darkreader__isDefined", handleIsDefined);
|
|
7429
7554
|
collectUndefinedElements(document);
|
|
7555
|
+
addDOMReadyListener(() => {
|
|
7556
|
+
forEach(document.body.children, (el) => {
|
|
7557
|
+
if (el.shadowRoot && !observedRoots.has(el)) {
|
|
7558
|
+
subscribeForShadowRootChanges(el);
|
|
7559
|
+
deepObserve(el.shadowRoot);
|
|
7560
|
+
}
|
|
7561
|
+
});
|
|
7562
|
+
});
|
|
7430
7563
|
}
|
|
7431
7564
|
function resetObservers() {
|
|
7432
7565
|
observers.forEach((o) => o.disconnect());
|
package/darkreader.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dark Reader v4.9.
|
|
2
|
+
* Dark Reader v4.9.119
|
|
3
3
|
* https://darkreader.org/
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -172,7 +172,10 @@ async function getOKResponse(url, mimeType, origin) {
|
|
|
172
172
|
}
|
|
173
173
|
if (
|
|
174
174
|
mimeType &&
|
|
175
|
-
!
|
|
175
|
+
!(
|
|
176
|
+
response.headers.get("Content-Type") === mimeType ||
|
|
177
|
+
response.headers.get("Content-Type").startsWith(`${mimeType};`)
|
|
178
|
+
)
|
|
176
179
|
) {
|
|
177
180
|
throw new Error(`Mime type mismatch when loading ${url}`);
|
|
178
181
|
}
|
|
@@ -2603,22 +2606,64 @@ chrome.runtime.onMessage.addListener(({type, data, error, id}) => {
|
|
|
2603
2606
|
}
|
|
2604
2607
|
});
|
|
2605
2608
|
const ipV4RegExp = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
|
2606
|
-
const
|
|
2607
|
-
const
|
|
2609
|
+
const MAX_CORS_HOSTS = 16;
|
|
2610
|
+
const corsHosts = new Set();
|
|
2611
|
+
const checkedHosts = new Set();
|
|
2612
|
+
const localAliases = [
|
|
2613
|
+
"127-0-0-1.org.uk",
|
|
2614
|
+
"42foo.com",
|
|
2615
|
+
"domaincontrol.com",
|
|
2616
|
+
"fbi.com",
|
|
2617
|
+
"fuf.me",
|
|
2618
|
+
"lacolhost.com",
|
|
2619
|
+
"local.sisteminha.com",
|
|
2620
|
+
"localfabriek.nl",
|
|
2621
|
+
"localhost",
|
|
2622
|
+
"localhst.co.uk",
|
|
2623
|
+
"localmachine.info",
|
|
2624
|
+
"localmachine.name",
|
|
2625
|
+
"localtest.me",
|
|
2626
|
+
"lvh.me",
|
|
2627
|
+
"mouse-potato.com",
|
|
2628
|
+
"nip.io",
|
|
2629
|
+
"sslip.io",
|
|
2630
|
+
"vcap.me",
|
|
2631
|
+
"xip.io",
|
|
2632
|
+
"yoogle.com"
|
|
2633
|
+
];
|
|
2634
|
+
const localSubDomains = [
|
|
2635
|
+
".corp",
|
|
2636
|
+
".direct",
|
|
2637
|
+
".home",
|
|
2638
|
+
".internal",
|
|
2639
|
+
".intranet",
|
|
2640
|
+
".lan",
|
|
2641
|
+
".local",
|
|
2642
|
+
".localdomain",
|
|
2643
|
+
".test",
|
|
2644
|
+
".zz",
|
|
2645
|
+
...localAliases.map((alias) => `.${alias}`)
|
|
2646
|
+
];
|
|
2608
2647
|
function shouldIgnoreCors(url) {
|
|
2609
|
-
const host = url
|
|
2610
|
-
if (!
|
|
2611
|
-
|
|
2648
|
+
const {host, hostname, port, protocol} = url;
|
|
2649
|
+
if (!corsHosts.has(host)) {
|
|
2650
|
+
corsHosts.add(host);
|
|
2651
|
+
}
|
|
2652
|
+
if (checkedHosts.has(host)) {
|
|
2653
|
+
return false;
|
|
2612
2654
|
}
|
|
2613
2655
|
if (
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2656
|
+
corsHosts.size >= MAX_CORS_HOSTS ||
|
|
2657
|
+
protocol !== "https:" ||
|
|
2658
|
+
port !== "" ||
|
|
2659
|
+
localAliases.includes(hostname) ||
|
|
2660
|
+
localSubDomains.some((sub) => hostname.endsWith(sub)) ||
|
|
2661
|
+
hostname.startsWith("[") ||
|
|
2662
|
+
hostname.match(ipV4RegExp)
|
|
2619
2663
|
) {
|
|
2620
2664
|
return true;
|
|
2621
2665
|
}
|
|
2666
|
+
checkedHosts.add(host);
|
|
2622
2667
|
return false;
|
|
2623
2668
|
}
|
|
2624
2669
|
|
|
@@ -2626,13 +2671,51 @@ const imageManager = new AsyncQueue();
|
|
|
2626
2671
|
async function getImageDetails(url) {
|
|
2627
2672
|
return new Promise(async (resolve, reject) => {
|
|
2628
2673
|
try {
|
|
2629
|
-
|
|
2630
|
-
? url
|
|
2631
|
-
: await getDataURL(url);
|
|
2674
|
+
let dataURL = url.startsWith("data:") ? url : await getDataURL(url);
|
|
2632
2675
|
const blob =
|
|
2633
2676
|
tryConvertDataURLToBlobSync(dataURL) ?? (await loadAsBlob(url));
|
|
2634
2677
|
let image;
|
|
2678
|
+
let useViewBox = false;
|
|
2635
2679
|
if (dataURL.startsWith("data:image/svg+xml")) {
|
|
2680
|
+
const commaIndex = dataURL.indexOf(",");
|
|
2681
|
+
if (commaIndex >= 0) {
|
|
2682
|
+
let svgText = dataURL.slice(commaIndex + 1);
|
|
2683
|
+
const encoding = dataURL.slice(0, commaIndex).split(";")[1];
|
|
2684
|
+
if (encoding === "base64") {
|
|
2685
|
+
svgText = atob(svgText);
|
|
2686
|
+
}
|
|
2687
|
+
if (svgText.startsWith("<svg ")) {
|
|
2688
|
+
const closingIndex = svgText.indexOf(">");
|
|
2689
|
+
const svgOpening = svgText
|
|
2690
|
+
.slice(0, closingIndex + 1)
|
|
2691
|
+
.toLocaleLowerCase();
|
|
2692
|
+
if (
|
|
2693
|
+
svgOpening.includes("viewbox") &&
|
|
2694
|
+
!svgOpening.includes("width") &&
|
|
2695
|
+
!svgOpening.includes("height")
|
|
2696
|
+
) {
|
|
2697
|
+
useViewBox = true;
|
|
2698
|
+
const viewboxIndex =
|
|
2699
|
+
svgOpening.indexOf('viewbox="');
|
|
2700
|
+
const viewboxCloseIndex = svgOpening.indexOf(
|
|
2701
|
+
'viewbox="',
|
|
2702
|
+
viewboxIndex + 9
|
|
2703
|
+
);
|
|
2704
|
+
const viewBox = svgOpening
|
|
2705
|
+
.slice(viewboxIndex + 9, viewboxCloseIndex - 1)
|
|
2706
|
+
.split(" ")
|
|
2707
|
+
.map((x) => parseFloat(x));
|
|
2708
|
+
if (
|
|
2709
|
+
viewBox.length === 4 &&
|
|
2710
|
+
!viewBox.some((x) => isNaN(x))
|
|
2711
|
+
) {
|
|
2712
|
+
const width = viewBox[2] - viewBox[0];
|
|
2713
|
+
const height = viewBox[3] - viewBox[1];
|
|
2714
|
+
dataURL = `data:image/svg+xml;base64,${btoa(`<svg width="${width}" height="${height}" ${svgText.slice(5)}`)}`;
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2636
2719
|
image = await loadImage(dataURL);
|
|
2637
2720
|
} else {
|
|
2638
2721
|
image =
|
|
@@ -2646,6 +2729,7 @@ async function getImageDetails(url) {
|
|
|
2646
2729
|
dataURL: analysis.isLarge ? "" : dataURL,
|
|
2647
2730
|
width: image.width,
|
|
2648
2731
|
height: image.height,
|
|
2732
|
+
useViewBox,
|
|
2649
2733
|
...analysis
|
|
2650
2734
|
});
|
|
2651
2735
|
});
|
|
@@ -2832,13 +2916,16 @@ function onCSPError(err) {
|
|
|
2832
2916
|
}
|
|
2833
2917
|
document.addEventListener("securitypolicyviolation", onCSPError);
|
|
2834
2918
|
const objectURLs = new Set();
|
|
2835
|
-
function getFilteredImageURL({dataURL, width, height}, theme) {
|
|
2919
|
+
function getFilteredImageURL({dataURL, width, height, useViewBox}, theme) {
|
|
2836
2920
|
if (dataURL.startsWith("data:image/svg+xml")) {
|
|
2837
2921
|
dataURL = escapeXML(dataURL);
|
|
2838
2922
|
}
|
|
2839
2923
|
const matrix = getSVGFilterMatrixValue(theme);
|
|
2924
|
+
const size = useViewBox
|
|
2925
|
+
? `viewBox="0 0 ${width} ${height}"`
|
|
2926
|
+
: `width="${width}" height="${height}"`;
|
|
2840
2927
|
const svg = [
|
|
2841
|
-
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
2928
|
+
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ${size}>`,
|
|
2842
2929
|
"<defs>",
|
|
2843
2930
|
'<filter id="darkreader-image-filter">',
|
|
2844
2931
|
`<feColorMatrix type="matrix" values="${matrix}" />`,
|
|
@@ -4049,8 +4136,8 @@ class VariablesStore {
|
|
|
4049
4136
|
this.definedVars.add(varName);
|
|
4050
4137
|
const isColor = Boolean(
|
|
4051
4138
|
value.match(rawRGBSpaceRegex) ||
|
|
4052
|
-
|
|
4053
|
-
|
|
4139
|
+
value.match(rawRGBCommaRegex) ||
|
|
4140
|
+
parseColorWithCache(value)
|
|
4054
4141
|
);
|
|
4055
4142
|
if (isColor) {
|
|
4056
4143
|
this.unknownColorVars.add(varName);
|
|
@@ -4381,13 +4468,16 @@ const textColorProps = [
|
|
|
4381
4468
|
function isTextColorProperty(property) {
|
|
4382
4469
|
return textColorProps.includes(property);
|
|
4383
4470
|
}
|
|
4384
|
-
const rawRGBSpaceRegex =
|
|
4471
|
+
const rawRGBSpaceRegex =
|
|
4472
|
+
/^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})\s*(\/\s*\d+\.?\d*)?$/;
|
|
4385
4473
|
const rawRGBCommaRegex = /^(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})$/;
|
|
4386
4474
|
function parseRawColorValue(input) {
|
|
4387
4475
|
const match =
|
|
4388
4476
|
input.match(rawRGBSpaceRegex) ?? input.match(rawRGBCommaRegex);
|
|
4389
4477
|
if (match) {
|
|
4390
|
-
const color =
|
|
4478
|
+
const color = match[4]
|
|
4479
|
+
? `rgb(${match[1]} ${match[2]} ${match[3]} / ${match[4]})`
|
|
4480
|
+
: `rgb(${match[1]}, ${match[2]}, ${match[3]})`;
|
|
4391
4481
|
return {isRaw: true, color};
|
|
4392
4482
|
}
|
|
4393
4483
|
return {isRaw: false, color: input};
|
|
@@ -5418,8 +5508,8 @@ function shouldAnalyzeSVGAsImage(svg) {
|
|
|
5418
5508
|
}
|
|
5419
5509
|
const shouldAnalyze = Boolean(
|
|
5420
5510
|
svg &&
|
|
5421
|
-
|
|
5422
|
-
|
|
5511
|
+
(svg.getAttribute("class")?.includes("logo") ||
|
|
5512
|
+
svg.parentElement?.getAttribute("class")?.includes("logo"))
|
|
5423
5513
|
);
|
|
5424
5514
|
svgAnalysisConditionCache.set(svg, shouldAnalyze);
|
|
5425
5515
|
return shouldAnalyze;
|
|
@@ -5462,6 +5552,7 @@ function getSVGElementRoot(svgElement) {
|
|
|
5462
5552
|
svgNodesRoots.set(svgElement, root);
|
|
5463
5553
|
return root;
|
|
5464
5554
|
}
|
|
5555
|
+
const inlineStringValueCache = new Map();
|
|
5465
5556
|
function overrideInlineStyle(
|
|
5466
5557
|
element,
|
|
5467
5558
|
theme,
|
|
@@ -5489,6 +5580,13 @@ function overrideInlineStyle(
|
|
|
5489
5580
|
}
|
|
5490
5581
|
const unsetProps = new Set(Object.keys(overrides));
|
|
5491
5582
|
function setCustomProp(targetCSSProp, modifierCSSProp, cssVal) {
|
|
5583
|
+
const cachedStringValue = inlineStringValueCache
|
|
5584
|
+
.get(modifierCSSProp)
|
|
5585
|
+
?.get(cssVal);
|
|
5586
|
+
if (cachedStringValue) {
|
|
5587
|
+
setStaticValue(cachedStringValue);
|
|
5588
|
+
return;
|
|
5589
|
+
}
|
|
5492
5590
|
const mod = getModifiableCSSDeclaration(
|
|
5493
5591
|
modifierCSSProp,
|
|
5494
5592
|
cssVal,
|
|
@@ -5554,6 +5652,10 @@ function overrideInlineStyle(
|
|
|
5554
5652
|
typeof mod.value === "function" ? mod.value(theme) : mod.value;
|
|
5555
5653
|
if (typeof value === "string") {
|
|
5556
5654
|
setStaticValue(value);
|
|
5655
|
+
if (!inlineStringValueCache.has(modifierCSSProp)) {
|
|
5656
|
+
inlineStringValueCache.set(modifierCSSProp, new Map());
|
|
5657
|
+
}
|
|
5658
|
+
inlineStringValueCache.get(modifierCSSProp).set(cssVal, value);
|
|
5557
5659
|
} else if (value instanceof Promise) {
|
|
5558
5660
|
setAsyncValue(value, cssVal);
|
|
5559
5661
|
} else if (typeof value === "object") {
|
|
@@ -5628,13 +5730,16 @@ function overrideInlineStyle(
|
|
|
5628
5730
|
let value = element.getAttribute("color");
|
|
5629
5731
|
if (value.match(/^[0-9a-f]{3}$/i) || value.match(/^[0-9a-f]{6}$/i)) {
|
|
5630
5732
|
value = `#${value}`;
|
|
5733
|
+
} else if (value.match(/^#?[0-9a-f]{4}$/i)) {
|
|
5734
|
+
const hex = value.startsWith("#") ? value.substring(1) : value;
|
|
5735
|
+
value = `#${hex}00`;
|
|
5631
5736
|
}
|
|
5632
5737
|
setCustomProp("color", "color", value);
|
|
5633
5738
|
}
|
|
5634
5739
|
if (isSVGElement) {
|
|
5635
5740
|
if (element.hasAttribute("fill")) {
|
|
5636
5741
|
const value = element.getAttribute("fill");
|
|
5637
|
-
if (value !== "none") {
|
|
5742
|
+
if (value !== "none" && value !== "currentColor") {
|
|
5638
5743
|
if (!(element instanceof SVGTextElement)) {
|
|
5639
5744
|
const handleSVGElement = () => {
|
|
5640
5745
|
let isSVGSmall = false;
|
|
@@ -5946,7 +6051,7 @@ function getManageableStyles(node, results = [], deep = true) {
|
|
|
5946
6051
|
forEach(node.querySelectorAll(STYLE_SELECTOR), (style) =>
|
|
5947
6052
|
getManageableStyles(style, results, false)
|
|
5948
6053
|
);
|
|
5949
|
-
if (deep) {
|
|
6054
|
+
if (deep && (node.children?.length > 0 || node.shadowRoot)) {
|
|
5950
6055
|
iterateShadowHosts(node, (host) =>
|
|
5951
6056
|
getManageableStyles(host.shadowRoot, results, false)
|
|
5952
6057
|
);
|
|
@@ -7072,10 +7177,23 @@ function watchForStylePositions(currentStyles, update, shadowRootDiscovered) {
|
|
|
7072
7177
|
removedStyles,
|
|
7073
7178
|
movedStyles
|
|
7074
7179
|
});
|
|
7180
|
+
const potentialHosts = new Set();
|
|
7075
7181
|
additions.forEach((n) => {
|
|
7182
|
+
if (n.parentElement) {
|
|
7183
|
+
potentialHosts.add(n.parentElement);
|
|
7184
|
+
}
|
|
7185
|
+
if (n.previousElementSibling) {
|
|
7186
|
+
potentialHosts.add(n.previousElementSibling);
|
|
7187
|
+
}
|
|
7076
7188
|
deepObserve(n);
|
|
7077
7189
|
collectUndefinedElements(n);
|
|
7078
7190
|
});
|
|
7191
|
+
potentialHosts.forEach((el) => {
|
|
7192
|
+
if (el.shadowRoot && !observedRoots.has(el)) {
|
|
7193
|
+
subscribeForShadowRootChanges(el);
|
|
7194
|
+
deepObserve(el.shadowRoot);
|
|
7195
|
+
}
|
|
7196
|
+
});
|
|
7079
7197
|
additions.forEach(
|
|
7080
7198
|
(node) => isCustomElement(node) && recordUndefinedElement(node)
|
|
7081
7199
|
);
|
|
@@ -7189,6 +7307,14 @@ function watchForStylePositions(currentStyles, update, shadowRootDiscovered) {
|
|
|
7189
7307
|
});
|
|
7190
7308
|
document.addEventListener("__darkreader__isDefined", handleIsDefined);
|
|
7191
7309
|
collectUndefinedElements(document);
|
|
7310
|
+
addDOMReadyListener(() => {
|
|
7311
|
+
forEach(document.body.children, (el) => {
|
|
7312
|
+
if (el.shadowRoot && !observedRoots.has(el)) {
|
|
7313
|
+
subscribeForShadowRootChanges(el);
|
|
7314
|
+
deepObserve(el.shadowRoot);
|
|
7315
|
+
}
|
|
7316
|
+
});
|
|
7317
|
+
});
|
|
7192
7318
|
}
|
|
7193
7319
|
function resetObservers() {
|
|
7194
7320
|
observers.forEach((o) => o.disconnect());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "darkreader",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.119",
|
|
4
4
|
"description": "Dark mode for every website",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"api": "node --max-old-space-size=3072 tasks/cli.js build --api",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"type": "module",
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
|
44
|
-
"url": "https://github.com/darkreader/darkreader.git"
|
|
44
|
+
"url": "git+https://github.com/darkreader/darkreader.git"
|
|
45
45
|
},
|
|
46
46
|
"author": "Alexander Shutau <darkreaderapp@gmail.com> (https://darkreader.org/)",
|
|
47
47
|
"license": "MIT",
|
|
@@ -67,26 +67,26 @@
|
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@eslint/compat": "2.0.0",
|
|
70
|
-
"@eslint/eslintrc": "3.3.
|
|
71
|
-
"@eslint/js": "9.39.
|
|
70
|
+
"@eslint/eslintrc": "3.3.3",
|
|
71
|
+
"@eslint/js": "9.39.2",
|
|
72
72
|
"@rollup/plugin-node-resolve": "16.0.3",
|
|
73
73
|
"@rollup/plugin-replace": "6.0.3",
|
|
74
74
|
"@rollup/plugin-typescript": "12.3.0",
|
|
75
75
|
"@stylistic/eslint-plugin": "5.6.1",
|
|
76
|
-
"@types/chrome": "0.1.
|
|
76
|
+
"@types/chrome": "0.1.32",
|
|
77
77
|
"@types/eslint": "9.6.1",
|
|
78
78
|
"@types/jasmine": "5.1.13",
|
|
79
79
|
"@types/jest": "30.0.0",
|
|
80
80
|
"@types/karma": "6.3.9",
|
|
81
81
|
"@types/karma-coverage": "2.0.3",
|
|
82
|
-
"@types/node": "
|
|
82
|
+
"@types/node": "25.0.3",
|
|
83
83
|
"@types/ws": "8.18.1",
|
|
84
|
-
"chokidar": "
|
|
84
|
+
"chokidar": "5.0.0",
|
|
85
85
|
"eslint-plugin-compat": "6.0.2",
|
|
86
86
|
"eslint-plugin-import": "2.32.0",
|
|
87
|
-
"globals": "
|
|
88
|
-
"globby": "16.
|
|
89
|
-
"jasmine-core": "5.
|
|
87
|
+
"globals": "17.0.0",
|
|
88
|
+
"globby": "16.1.0",
|
|
89
|
+
"jasmine-core": "5.13.0",
|
|
90
90
|
"jest": "30.2.0",
|
|
91
91
|
"jest-extended": "7.0.0",
|
|
92
92
|
"karma": "6.4.4",
|
|
@@ -97,20 +97,20 @@
|
|
|
97
97
|
"karma-rollup-preprocessor": "7.0.8",
|
|
98
98
|
"karma-safari-launcher": "1.0.0",
|
|
99
99
|
"karma-spec-reporter": "0.0.36",
|
|
100
|
-
"less": "4.
|
|
101
|
-
"prettier": "3.
|
|
102
|
-
"puppeteer-core": "24.
|
|
103
|
-
"rollup": "4.
|
|
100
|
+
"less": "4.5.1",
|
|
101
|
+
"prettier": "3.7.4",
|
|
102
|
+
"puppeteer-core": "24.34.0",
|
|
103
|
+
"rollup": "4.55.1",
|
|
104
104
|
"rollup-plugin-istanbul": "5.0.0",
|
|
105
|
-
"ts-jest": "29.4.
|
|
105
|
+
"ts-jest": "29.4.6",
|
|
106
106
|
"tslib": "2.8.1",
|
|
107
107
|
"typescript": "5.9.3",
|
|
108
|
-
"typescript-eslint": "8.
|
|
108
|
+
"typescript-eslint": "8.51.0",
|
|
109
109
|
"ws": "8.18.3",
|
|
110
110
|
"yazl": "3.3.1"
|
|
111
111
|
},
|
|
112
112
|
"optionalDependencies": {
|
|
113
|
-
"@rollup/rollup-linux-x64-gnu": "4.
|
|
114
|
-
"@rollup/rollup-win32-x64-msvc": "4.
|
|
113
|
+
"@rollup/rollup-linux-x64-gnu": "4.55.1",
|
|
114
|
+
"@rollup/rollup-win32-x64-msvc": "4.55.1"
|
|
115
115
|
}
|
|
116
116
|
}
|