darkreader 4.9.80 → 4.9.82

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.
Files changed (3) hide show
  1. package/README.md +0 -1
  2. package/darkreader.js +390 -245
  3. package/package.json +8 -11
package/README.md CHANGED
@@ -155,7 +155,6 @@ Step 2: change Firefox's settings.
155
155
  A warning page may appear. Click `Accept the Risk and Continue` to proceed.
156
156
  - Search for and set `extensions.webextensions.restrictedDomains` to an empty value.
157
157
  - Create `extensions.webextensions.addons-restricted-domains@mozilla.com.disabled` with `boolean` as type and set its value to `true`.
158
- - Set `extensions.quarantinedDomains.enabled` to `false`.
159
158
  - Set `privacy.resistFingerprinting.block_mozAddonManager` to `true`.
160
159
  - Restart Firefox.
161
160
 
package/darkreader.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Dark Reader v4.9.80
2
+ * Dark Reader v4.9.82
3
3
  * https://darkreader.org/
4
4
  */
5
5
 
@@ -777,6 +777,98 @@
777
777
  };
778
778
  }
779
779
 
780
+ function getMatches(regex, input, group = 0) {
781
+ const matches = [];
782
+ let m;
783
+ while ((m = regex.exec(input))) {
784
+ matches.push(m[group]);
785
+ }
786
+ return matches;
787
+ }
788
+ function escapeRegExpSpecialChars(input) {
789
+ return input.replaceAll(/[\^$.*+?\(\)\[\]{}|\-\\]/g, "\\$&");
790
+ }
791
+ function getParenthesesRange(input, searchStartIndex = 0) {
792
+ return getOpenCloseRange(input, searchStartIndex, "(", ")", []);
793
+ }
794
+ function getOpenCloseRange(
795
+ input,
796
+ searchStartIndex,
797
+ openToken,
798
+ closeToken,
799
+ excludeRanges
800
+ ) {
801
+ let indexOf;
802
+ if (excludeRanges.length === 0) {
803
+ indexOf = (token, pos) => input.indexOf(token, pos);
804
+ } else {
805
+ indexOf = (token, pos) =>
806
+ indexOfExcluding(input, token, pos, excludeRanges);
807
+ }
808
+ const {length} = input;
809
+ let depth = 0;
810
+ let firstOpenIndex = -1;
811
+ for (let i = searchStartIndex; i < length; i++) {
812
+ if (depth === 0) {
813
+ const openIndex = indexOf(openToken, i);
814
+ if (openIndex < 0) {
815
+ break;
816
+ }
817
+ firstOpenIndex = openIndex;
818
+ depth++;
819
+ i = openIndex;
820
+ } else {
821
+ const closeIndex = indexOf(closeToken, i);
822
+ if (closeIndex < 0) {
823
+ break;
824
+ }
825
+ const openIndex = indexOf(openToken, i);
826
+ if (openIndex < 0 || closeIndex <= openIndex) {
827
+ depth--;
828
+ if (depth === 0) {
829
+ return {start: firstOpenIndex, end: closeIndex + 1};
830
+ }
831
+ i = closeIndex;
832
+ } else {
833
+ depth++;
834
+ i = openIndex;
835
+ }
836
+ }
837
+ }
838
+ return null;
839
+ }
840
+ function indexOfExcluding(input, search, position, excludeRanges) {
841
+ const i = input.indexOf(search, position);
842
+ const exclusion = excludeRanges.find((r) => i >= r.start && i < r.end);
843
+ if (exclusion) {
844
+ return indexOfExcluding(
845
+ input,
846
+ search,
847
+ exclusion.end,
848
+ excludeRanges
849
+ );
850
+ }
851
+ return i;
852
+ }
853
+ function splitExcluding(input, separator, excludeRanges) {
854
+ const parts = [];
855
+ let commaIndex = -1;
856
+ let currIndex = 0;
857
+ while (
858
+ (commaIndex = indexOfExcluding(
859
+ input,
860
+ separator,
861
+ currIndex,
862
+ excludeRanges
863
+ )) >= 0
864
+ ) {
865
+ parts.push(input.substring(currIndex, commaIndex).trim());
866
+ currIndex = commaIndex + 1;
867
+ }
868
+ parts.push(input.substring(currIndex).trim());
869
+ return parts;
870
+ }
871
+
780
872
  let anchor;
781
873
  const parsedURLCache = new Map();
782
874
  function fixBaseURL($url) {
@@ -828,21 +920,21 @@
828
920
  return url.pathname === location.pathname;
829
921
  }
830
922
 
831
- function iterateCSSRules(rules, iterate, onMediaRuleError) {
923
+ function iterateCSSRules(rules, iterate, onImportError) {
832
924
  forEach(rules, (rule) => {
833
- if (rule.selectorText) {
925
+ if (isStyleRule(rule)) {
834
926
  iterate(rule);
835
- } else if (rule.href) {
927
+ } else if (isImportRule(rule)) {
836
928
  try {
837
929
  iterateCSSRules(
838
930
  rule.styleSheet.cssRules,
839
931
  iterate,
840
- onMediaRuleError
932
+ onImportError
841
933
  );
842
934
  } catch (err) {
843
- onMediaRuleError && onMediaRuleError();
935
+ onImportError?.();
844
936
  }
845
- } else if (rule.media) {
937
+ } else if (isMediaRule(rule)) {
846
938
  const media = Array.from(rule.media);
847
939
  const isScreenOrAllOrQuery = media.some(
848
940
  (m) =>
@@ -854,12 +946,14 @@
854
946
  (m) => m.startsWith("print") || m.startsWith("speech")
855
947
  );
856
948
  if (isScreenOrAllOrQuery || !isPrintOrSpeech) {
857
- iterateCSSRules(rule.cssRules, iterate, onMediaRuleError);
949
+ iterateCSSRules(rule.cssRules, iterate, onImportError);
858
950
  }
859
- } else if (rule.conditionText) {
951
+ } else if (isSupportsRule(rule)) {
860
952
  if (CSS.supports(rule.conditionText)) {
861
- iterateCSSRules(rule.cssRules, iterate, onMediaRuleError);
953
+ iterateCSSRules(rule.cssRules, iterate, onImportError);
862
954
  }
955
+ } else if (isLayerRule(rule)) {
956
+ iterateCSSRules(rule.cssRules, iterate, onImportError);
863
957
  } else;
864
958
  });
865
959
  }
@@ -907,6 +1001,40 @@
907
1001
  });
908
1002
  }
909
1003
  }
1004
+ if (
1005
+ cssText.includes("background-color: ;") &&
1006
+ !style.getPropertyValue("background")
1007
+ ) {
1008
+ handleEmptyShorthand("background", style, iterate);
1009
+ }
1010
+ if (
1011
+ cssText.includes("border-") &&
1012
+ cssText.includes("-color: ;") &&
1013
+ !style.getPropertyValue("border")
1014
+ ) {
1015
+ handleEmptyShorthand("border", style, iterate);
1016
+ }
1017
+ }
1018
+ function handleEmptyShorthand(shorthand, style, iterate) {
1019
+ const parentRule = style.parentRule;
1020
+ if (isStyleRule(parentRule)) {
1021
+ const sourceCSSText =
1022
+ parentRule.parentStyleSheet?.ownerNode?.textContent;
1023
+ if (sourceCSSText) {
1024
+ let escapedSelector = escapeRegExpSpecialChars(
1025
+ parentRule.selectorText
1026
+ );
1027
+ escapedSelector = escapedSelector.replaceAll(/\s+/g, "\\s*");
1028
+ escapedSelector = escapedSelector.replaceAll(/::/g, "::?");
1029
+ const regexp = new RegExp(
1030
+ `${escapedSelector}\\s*{[^}]*?${shorthand}:\\s*([^;}]+)`
1031
+ );
1032
+ const match = sourceCSSText.match(regexp);
1033
+ if (match) {
1034
+ iterate(shorthand, match[1]);
1035
+ }
1036
+ }
1037
+ }
910
1038
  }
911
1039
  const cssURLRegex = /url\((('.*?')|(".*?")|([^\)]*?))\)/g;
912
1040
  const cssImportRegex =
@@ -935,14 +1063,92 @@
935
1063
  }
936
1064
  });
937
1065
  }
938
- const cssCommentsRegex = /\/\*[\s\S]*?\*\//g;
939
- function removeCSSComments$1($css) {
940
- return $css.replace(cssCommentsRegex, "");
941
- }
942
1066
  const fontFaceRegex = /@font-face\s*{[^}]*}/g;
943
1067
  function replaceCSSFontFace($css) {
944
1068
  return $css.replace(fontFaceRegex, "");
945
1069
  }
1070
+ const styleRules = new WeakSet();
1071
+ const importRules = new WeakSet();
1072
+ const mediaRules = new WeakSet();
1073
+ const supportsRules = new WeakSet();
1074
+ const layerRules = new WeakSet();
1075
+ function isStyleRule(rule) {
1076
+ if (!rule) {
1077
+ return false;
1078
+ }
1079
+ if (styleRules.has(rule)) {
1080
+ return true;
1081
+ }
1082
+ if (rule.selectorText) {
1083
+ styleRules.add(rule);
1084
+ return true;
1085
+ }
1086
+ return false;
1087
+ }
1088
+ function isImportRule(rule) {
1089
+ if (!rule) {
1090
+ return false;
1091
+ }
1092
+ if (styleRules.has(rule)) {
1093
+ return false;
1094
+ }
1095
+ if (importRules.has(rule)) {
1096
+ return true;
1097
+ }
1098
+ if (rule.href) {
1099
+ importRules.add(rule);
1100
+ return true;
1101
+ }
1102
+ return false;
1103
+ }
1104
+ function isMediaRule(rule) {
1105
+ if (!rule) {
1106
+ return false;
1107
+ }
1108
+ if (styleRules.has(rule)) {
1109
+ return false;
1110
+ }
1111
+ if (mediaRules.has(rule)) {
1112
+ return true;
1113
+ }
1114
+ if (rule.media) {
1115
+ mediaRules.add(rule);
1116
+ return true;
1117
+ }
1118
+ return false;
1119
+ }
1120
+ function isSupportsRule(rule) {
1121
+ if (!rule) {
1122
+ return false;
1123
+ }
1124
+ if (styleRules.has(rule)) {
1125
+ return false;
1126
+ }
1127
+ if (supportsRules.has(rule)) {
1128
+ return true;
1129
+ }
1130
+ if (rule instanceof CSSSupportsRule) {
1131
+ supportsRules.add(rule);
1132
+ return true;
1133
+ }
1134
+ return false;
1135
+ }
1136
+ function isLayerRule(rule) {
1137
+ if (!rule) {
1138
+ return false;
1139
+ }
1140
+ if (styleRules.has(rule)) {
1141
+ return false;
1142
+ }
1143
+ if (layerRules.has(rule)) {
1144
+ return true;
1145
+ }
1146
+ if (rule instanceof CSSLayerBlockRule) {
1147
+ layerRules.add(rule);
1148
+ return true;
1149
+ }
1150
+ return false;
1151
+ }
946
1152
 
947
1153
  function evalMath(expression) {
948
1154
  const rpnStack = [];
@@ -1006,94 +1212,8 @@
1006
1212
  ["/", new Operator(2, (left, right) => left / right)]
1007
1213
  ]);
1008
1214
 
1009
- function getMatches(regex, input, group = 0) {
1010
- const matches = [];
1011
- let m;
1012
- while ((m = regex.exec(input))) {
1013
- matches.push(m[group]);
1014
- }
1015
- return matches;
1016
- }
1017
- function getParenthesesRange(input, searchStartIndex = 0) {
1018
- return getOpenCloseRange(input, searchStartIndex, "(", ")", []);
1019
- }
1020
- function getOpenCloseRange(
1021
- input,
1022
- searchStartIndex,
1023
- openToken,
1024
- closeToken,
1025
- excludeRanges
1026
- ) {
1027
- let indexOf;
1028
- if (excludeRanges.length === 0) {
1029
- indexOf = (token, pos) => input.indexOf(token, pos);
1030
- } else {
1031
- indexOf = (token, pos) =>
1032
- indexOfExcluding(input, token, pos, excludeRanges);
1033
- }
1034
- const {length} = input;
1035
- let depth = 0;
1036
- let firstOpenIndex = -1;
1037
- for (let i = searchStartIndex; i < length; i++) {
1038
- if (depth === 0) {
1039
- const openIndex = indexOf(openToken, i);
1040
- if (openIndex < 0) {
1041
- break;
1042
- }
1043
- firstOpenIndex = openIndex;
1044
- depth++;
1045
- i = openIndex;
1046
- } else {
1047
- const closeIndex = indexOf(closeToken, i);
1048
- if (closeIndex < 0) {
1049
- break;
1050
- }
1051
- const openIndex = indexOf(openToken, i);
1052
- if (openIndex < 0 || closeIndex <= openIndex) {
1053
- depth--;
1054
- if (depth === 0) {
1055
- return {start: firstOpenIndex, end: closeIndex + 1};
1056
- }
1057
- i = closeIndex;
1058
- } else {
1059
- depth++;
1060
- i = openIndex;
1061
- }
1062
- }
1063
- }
1064
- return null;
1065
- }
1066
- function indexOfExcluding(input, search, position, excludeRanges) {
1067
- const i = input.indexOf(search, position);
1068
- const exclusion = excludeRanges.find((r) => i >= r.start && i < r.end);
1069
- if (exclusion) {
1070
- return indexOfExcluding(
1071
- input,
1072
- search,
1073
- exclusion.end,
1074
- excludeRanges
1075
- );
1076
- }
1077
- return i;
1078
- }
1079
- function splitExcluding(input, separator, excludeRanges) {
1080
- const parts = [];
1081
- let commaIndex = -1;
1082
- let currIndex = 0;
1083
- while (
1084
- (commaIndex = indexOfExcluding(
1085
- input,
1086
- separator,
1087
- currIndex,
1088
- excludeRanges
1089
- )) >= 0
1090
- ) {
1091
- parts.push(input.substring(currIndex, commaIndex).trim());
1092
- currIndex = commaIndex + 1;
1093
- }
1094
- parts.push(input.substring(currIndex).trim());
1095
- return parts;
1096
- }
1215
+ const isSystemDarkModeEnabled = () =>
1216
+ matchMedia("(prefers-color-scheme: dark)").matches;
1097
1217
 
1098
1218
  const hslaParseCache = new Map();
1099
1219
  const rgbaParseCache = new Map();
@@ -1235,6 +1355,23 @@
1235
1355
  if ($color === "transparent") {
1236
1356
  return {r: 0, g: 0, b: 0, a: 0};
1237
1357
  }
1358
+ if (
1359
+ (c.startsWith("color(") || c.startsWith("color-mix(")) &&
1360
+ c.endsWith(")")
1361
+ ) {
1362
+ return domParseColor(c);
1363
+ }
1364
+ if (c.startsWith("light-dark(") && c.endsWith(")")) {
1365
+ const match = c.match(
1366
+ /^light-dark\(\s*([a-z]+(\(.*\))?),\s*([a-z]+(\(.*\))?)\s*\)$/
1367
+ );
1368
+ if (match) {
1369
+ const schemeColor = isSystemDarkModeEnabled()
1370
+ ? match[3]
1371
+ : match[1];
1372
+ return parse(schemeColor);
1373
+ }
1374
+ }
1238
1375
  return null;
1239
1376
  }
1240
1377
  function getNumbers($color) {
@@ -1548,6 +1685,21 @@
1548
1685
  function getSRGBLightness(r, g, b) {
1549
1686
  return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
1550
1687
  }
1688
+ let canvas$1;
1689
+ let context$1;
1690
+ function domParseColor($color) {
1691
+ if (!context$1) {
1692
+ canvas$1 = document.createElement("canvas");
1693
+ canvas$1.width = 1;
1694
+ canvas$1.height = 1;
1695
+ context$1 = canvas$1.getContext("2d", {willReadFrequently: true});
1696
+ }
1697
+ context$1.fillStyle = $color;
1698
+ context$1.fillRect(0, 0, 1, 1);
1699
+ const d = context$1.getImageData(0, 0, 1, 1).data;
1700
+ const color = `rgba(${d[0]}, ${d[1]}, ${d[2]}, ${(d[3] / 255).toFixed(2)})`;
1701
+ return parseRGB(color);
1702
+ }
1551
1703
 
1552
1704
  function scale(x, inLow, inHigh, outLow, outHigh) {
1553
1705
  return ((x - inLow) * (outHigh - outLow)) / (inHigh - inLow) + outLow;
@@ -2456,8 +2608,9 @@
2456
2608
  ignoreImageSelectors,
2457
2609
  isCancelled
2458
2610
  ) {
2611
+ let modifier = null;
2459
2612
  if (property.startsWith("--")) {
2460
- const modifier = getVariableModifier(
2613
+ modifier = getVariableModifier(
2461
2614
  variablesStore,
2462
2615
  property,
2463
2616
  value,
@@ -2465,30 +2618,16 @@
2465
2618
  ignoreImageSelectors,
2466
2619
  isCancelled
2467
2620
  );
2468
- if (modifier) {
2469
- return {
2470
- property,
2471
- value: modifier,
2472
- important: getPriority(rule.style, property),
2473
- sourceValue: value
2474
- };
2475
- }
2476
2621
  } else if (value.includes("var(")) {
2477
- const modifier = getVariableDependantModifier(
2622
+ modifier = getVariableDependantModifier(
2478
2623
  variablesStore,
2479
2624
  property,
2480
2625
  value
2481
2626
  );
2482
- if (modifier) {
2483
- return {
2484
- property,
2485
- value: modifier,
2486
- important: getPriority(rule.style, property),
2487
- sourceValue: value
2488
- };
2489
- }
2490
2627
  } else if (property === "color-scheme") {
2491
- return null;
2628
+ modifier = getColorSchemeModifier();
2629
+ } else if (property === "scrollbar-color") {
2630
+ modifier = getScrollbarColorModifier(value);
2492
2631
  } else if (
2493
2632
  (property.includes("color") &&
2494
2633
  property !== "-webkit-print-color-adjust") ||
@@ -2496,45 +2635,51 @@
2496
2635
  property === "stroke" ||
2497
2636
  property === "stop-color"
2498
2637
  ) {
2499
- const modifier = getColorModifier(property, value, rule);
2500
- if (modifier) {
2501
- return {
2502
- property,
2503
- value: modifier,
2504
- important: getPriority(rule.style, property),
2505
- sourceValue: value
2506
- };
2638
+ if (
2639
+ property.startsWith("border") &&
2640
+ property !== "border-color" &&
2641
+ value === "initial"
2642
+ ) {
2643
+ const borderSideProp = property.substring(
2644
+ 0,
2645
+ property.length - 6
2646
+ );
2647
+ const borderSideVal =
2648
+ rule.style.getPropertyValue(borderSideProp);
2649
+ if (
2650
+ borderSideVal.startsWith("0px") ||
2651
+ borderSideVal === "none"
2652
+ ) {
2653
+ property = borderSideProp;
2654
+ modifier = borderSideVal;
2655
+ } else {
2656
+ modifier = value;
2657
+ }
2658
+ } else {
2659
+ modifier = getColorModifier(property, value, rule);
2507
2660
  }
2508
2661
  } else if (
2509
2662
  property === "background-image" ||
2510
2663
  property === "list-style-image"
2511
2664
  ) {
2512
- const modifier = getBgImageModifier(
2665
+ modifier = getBgImageModifier(
2513
2666
  value,
2514
2667
  rule,
2515
2668
  ignoreImageSelectors,
2516
2669
  isCancelled
2517
2670
  );
2518
- if (modifier) {
2519
- return {
2520
- property,
2521
- value: modifier,
2522
- important: getPriority(rule.style, property),
2523
- sourceValue: value
2524
- };
2525
- }
2526
2671
  } else if (property.includes("shadow")) {
2527
- const modifier = getShadowModifier(value);
2528
- if (modifier) {
2529
- return {
2530
- property,
2531
- value: modifier,
2532
- important: getPriority(rule.style, property),
2533
- sourceValue: value
2534
- };
2535
- }
2672
+ modifier = getShadowModifier(value);
2536
2673
  }
2537
- return null;
2674
+ if (!modifier) {
2675
+ return null;
2676
+ }
2677
+ return {
2678
+ property,
2679
+ value: modifier,
2680
+ important: getPriority(rule.style, property),
2681
+ sourceValue: value
2682
+ };
2538
2683
  }
2539
2684
  function joinSelectors(...selectors) {
2540
2685
  return selectors.filter(Boolean).join(", ");
@@ -2548,11 +2693,12 @@
2548
2693
  );
2549
2694
  lines.push("}");
2550
2695
  }
2551
- if (isCSSColorSchemePropSupported) {
2696
+ if (isCSSColorSchemePropSupported && !isIFrame && theme.mode === 1) {
2552
2697
  lines.push("html {");
2553
- lines.push(
2554
- ` color-scheme: ${theme.mode === 1 ? "dark" : "dark light"} !important;`
2555
- );
2698
+ lines.push(` color-scheme: dark !important;`);
2699
+ lines.push("}");
2700
+ lines.push("iframe {");
2701
+ lines.push(` color-scheme: initial;`);
2556
2702
  lines.push("}");
2557
2703
  }
2558
2704
  const bgSelectors = joinSelectors(
@@ -2746,7 +2892,8 @@
2746
2892
  "initial",
2747
2893
  "currentcolor",
2748
2894
  "none",
2749
- "unset"
2895
+ "unset",
2896
+ "auto"
2750
2897
  ]);
2751
2898
  function getColorModifier(prop, value, rule) {
2752
2899
  if (unparsableColors.has(value.toLowerCase())) {
@@ -2766,14 +2913,14 @@
2766
2913
  (rule.style.getPropertyValue("mask-image") &&
2767
2914
  rule.style.getPropertyValue("mask-image") !== "none")
2768
2915
  ) {
2769
- return (filter) => modifyForegroundColor(rgb, filter);
2916
+ return (theme) => modifyForegroundColor(rgb, theme);
2770
2917
  }
2771
- return (filter) => modifyBackgroundColor(rgb, filter);
2918
+ return (theme) => modifyBackgroundColor(rgb, theme);
2772
2919
  }
2773
2920
  if (prop.includes("border") || prop.includes("outline")) {
2774
- return (filter) => modifyBorderColor(rgb, filter);
2921
+ return (theme) => modifyBorderColor(rgb, theme);
2775
2922
  }
2776
- return (filter) => modifyForegroundColor(rgb, filter);
2923
+ return (theme) => modifyForegroundColor(rgb, theme);
2777
2924
  }
2778
2925
  const imageDetailsCache = new Map();
2779
2926
  const awaitingForImageLoading = new Map();
@@ -3081,6 +3228,24 @@
3081
3228
  }
3082
3229
  return (theme) => shadowModifier(theme).result;
3083
3230
  }
3231
+ function getScrollbarColorModifier(value) {
3232
+ const colorsMatch = value.match(
3233
+ /^\s*([a-z]+(\(.*\))?)\s+([a-z]+(\(.*\))?)\s*$/
3234
+ );
3235
+ if (!colorsMatch) {
3236
+ return value;
3237
+ }
3238
+ const thumb = parseColorWithCache(colorsMatch[1]);
3239
+ const track = parseColorWithCache(colorsMatch[3]);
3240
+ if (!thumb || !track) {
3241
+ return null;
3242
+ }
3243
+ return (theme) =>
3244
+ `${modifyForegroundColor(thumb, theme)} ${modifyBackgroundColor(thumb, theme)}`;
3245
+ }
3246
+ function getColorSchemeModifier() {
3247
+ return (theme) => (theme.mode === 0 ? "dark light" : "dark");
3248
+ }
3084
3249
  function getVariableModifier(
3085
3250
  variablesStore,
3086
3251
  prop,
@@ -3196,7 +3361,9 @@
3196
3361
  this.unknownColorVars.has(ref) ||
3197
3362
  this.isVarType(
3198
3363
  ref,
3199
- VAR_TYPE_TEXTCOLOR | VAR_TYPE_BORDERCOLOR
3364
+ VAR_TYPE_BGCOLOR |
3365
+ VAR_TYPE_TEXTCOLOR |
3366
+ VAR_TYPE_BORDERCOLOR
3200
3367
  )
3201
3368
  );
3202
3369
  }) != null;
@@ -3419,21 +3586,20 @@
3419
3586
  return modified;
3420
3587
  }
3421
3588
  return new Promise((resolve) => {
3422
- const firstUnknownVar = unknownVars
3423
- .values()
3424
- .next().value;
3425
- const callback = () => {
3426
- this.unsubscribeFromVariableTypeChanges(
3427
- firstUnknownVar,
3589
+ for (const unknownVar of unknownVars.values()) {
3590
+ const callback = () => {
3591
+ this.unsubscribeFromVariableTypeChanges(
3592
+ unknownVar,
3593
+ callback
3594
+ );
3595
+ const newValue = modify();
3596
+ resolve(newValue);
3597
+ };
3598
+ this.subscribeForVarTypeChange(
3599
+ unknownVar,
3428
3600
  callback
3429
3601
  );
3430
- const newValue = modify();
3431
- resolve(newValue);
3432
- };
3433
- this.subscribeForVarTypeChange(
3434
- firstUnknownVar,
3435
- callback
3436
- );
3602
+ }
3437
3603
  });
3438
3604
  }
3439
3605
  return modified;
@@ -3520,8 +3686,11 @@
3520
3686
  return;
3521
3687
  }
3522
3688
  this.definedVars.add(varName);
3523
- const isColor =
3524
- rawValueRegex.test(value) || parseColorWithCache(value);
3689
+ const isColor = Boolean(
3690
+ value.match(rawRGBSpaceRegex) ||
3691
+ value.match(rawRGBCommaRegex) ||
3692
+ parseColorWithCache(value)
3693
+ );
3525
3694
  if (isColor) {
3526
3695
  this.unknownColorVars.add(varName);
3527
3696
  } else if (
@@ -3597,7 +3766,9 @@
3597
3766
  this.unknownColorVars.has(ref) ||
3598
3767
  this.isVarType(
3599
3768
  ref,
3600
- VAR_TYPE_TEXTCOLOR | VAR_TYPE_BORDERCOLOR
3769
+ VAR_TYPE_BGCOLOR |
3770
+ VAR_TYPE_TEXTCOLOR |
3771
+ VAR_TYPE_BORDERCOLOR
3601
3772
  )
3602
3773
  );
3603
3774
  }) != null;
@@ -3802,23 +3973,20 @@
3802
3973
  property === "-webkit-text-fill-color"
3803
3974
  );
3804
3975
  }
3805
- const rawValueRegex = /^\d{1,3}, ?\d{1,3}, ?\d{1,3}$/;
3806
- function parseRawValue(color) {
3807
- if (rawValueRegex.test(color)) {
3808
- const splitted = color.split(",");
3809
- let resultInRGB = "rgb(";
3810
- splitted.forEach((number) => {
3811
- resultInRGB += `${number.trim()}, `;
3812
- });
3813
- resultInRGB = resultInRGB.substring(0, resultInRGB.length - 2);
3814
- resultInRGB += ")";
3815
- return {isRaw: true, color: resultInRGB};
3976
+ const rawRGBSpaceRegex = /^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})$/;
3977
+ const rawRGBCommaRegex = /^(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})$/;
3978
+ function parseRawColorValue(input) {
3979
+ const match =
3980
+ input.match(rawRGBSpaceRegex) ?? input.match(rawRGBCommaRegex);
3981
+ if (match) {
3982
+ const color = `rgb(${match[1]}, ${match[2]}, ${match[3]})`;
3983
+ return {isRaw: true, color};
3816
3984
  }
3817
- return {isRaw: false, color: color};
3985
+ return {isRaw: false, color: input};
3818
3986
  }
3819
- function handleRawValue(color, theme, modifyFunction) {
3820
- const {isRaw, color: newColor} = parseRawValue(color);
3821
- const rgb = parseColorWithCache(newColor);
3987
+ function handleRawColorValue(input, theme, modifyFunction) {
3988
+ const {isRaw, color} = parseRawColorValue(input);
3989
+ const rgb = parseColorWithCache(color);
3822
3990
  if (rgb) {
3823
3991
  const outputColor = modifyFunction(rgb, theme);
3824
3992
  if (isRaw) {
@@ -3829,16 +3997,16 @@
3829
3997
  }
3830
3998
  return outputColor;
3831
3999
  }
3832
- return newColor;
4000
+ return color;
3833
4001
  }
3834
4002
  function tryModifyBgColor(color, theme) {
3835
- return handleRawValue(color, theme, modifyBackgroundColor);
4003
+ return handleRawColorValue(color, theme, modifyBackgroundColor);
3836
4004
  }
3837
4005
  function tryModifyTextColor(color, theme) {
3838
- return handleRawValue(color, theme, modifyForegroundColor);
4006
+ return handleRawColorValue(color, theme, modifyForegroundColor);
3839
4007
  }
3840
4008
  function tryModifyBorderColor(color, theme) {
3841
- return handleRawValue(color, theme, modifyBorderColor);
4009
+ return handleRawColorValue(color, theme, modifyBorderColor);
3842
4010
  }
3843
4011
  function insertVarValues(source, varValues, stack = new Set()) {
3844
4012
  let containsUnresolvedVar = false;
@@ -4408,6 +4576,11 @@
4408
4576
  }
4409
4577
  }
4410
4578
 
4579
+ const cssCommentsRegex = /\/\*[\s\S]*?\*\//g;
4580
+ function removeCSSComments(cssText) {
4581
+ return cssText.replace(cssCommentsRegex, "");
4582
+ }
4583
+
4411
4584
  const themeCacheKeys = [
4412
4585
  "mode",
4413
4586
  "brightness",
@@ -4461,9 +4634,12 @@
4461
4634
  let cssText = rule.cssText;
4462
4635
  let textDiffersFromPrev = false;
4463
4636
  notFoundCacheKeys.delete(cssText);
4464
- if (rule.parentRule instanceof CSSMediaRule) {
4637
+ if (isMediaRule(rule.parentRule)) {
4465
4638
  cssText += `;${rule.parentRule.media.mediaText}`;
4466
4639
  }
4640
+ if (isLayerRule(rule.parentRule)) {
4641
+ cssText += `;${rule.parentRule.name}`;
4642
+ }
4467
4643
  if (!rulesTextCache.has(cssText)) {
4468
4644
  rulesTextCache.add(cssText);
4469
4645
  textDiffersFromPrev = true;
@@ -4728,7 +4904,7 @@
4728
4904
  function buildStyleSheet() {
4729
4905
  function createTarget(group, parent) {
4730
4906
  const {rule} = group;
4731
- if (rule instanceof CSSMediaRule) {
4907
+ if (isMediaRule(rule)) {
4732
4908
  const {media} = rule;
4733
4909
  const index = parent.cssRules.length;
4734
4910
  parent.insertRule(
@@ -4737,6 +4913,12 @@
4737
4913
  );
4738
4914
  return parent.cssRules[index];
4739
4915
  }
4916
+ if (isLayerRule(rule)) {
4917
+ const {name} = rule;
4918
+ const index = parent.cssRules.length;
4919
+ parent.insertRule(`@layer ${name} {}`, index);
4920
+ return parent.cssRules[index];
4921
+ }
4740
4922
  return parent;
4741
4923
  }
4742
4924
  function iterateReadyRules(group, target, styleIterator) {
@@ -4991,9 +5173,7 @@
4991
5173
  if (!(element instanceof HTMLStyleElement)) {
4992
5174
  return false;
4993
5175
  }
4994
- const cssText = removeCSSComments$1(
4995
- element.textContent ?? ""
4996
- ).trim();
5176
+ const cssText = removeCSSComments(element.textContent ?? "").trim();
4997
5177
  return cssText.match(cssImportRegex);
4998
5178
  }
4999
5179
  function hasImports(cssRules, checkCrossOrigin) {
@@ -5367,7 +5547,7 @@
5367
5547
  });
5368
5548
  }
5369
5549
  async function replaceCSSImports(cssText, basePath, cache = new Map()) {
5370
- cssText = removeCSSComments$1(cssText);
5550
+ cssText = removeCSSComments(cssText);
5371
5551
  cssText = replaceCSSFontFace(cssText);
5372
5552
  cssText = replaceCSSRelativeURLsWithAbsolute(cssText, basePath);
5373
5553
  const importMatches = getMatches(cssImportRegex, cssText);
@@ -6589,6 +6769,7 @@
6589
6769
  const enableCustomElementRegistryProxy = !(
6590
6770
  fixes && fixes.disableCustomElementRegistryProxy
6591
6771
  );
6772
+ document.dispatchEvent(new CustomEvent("__darkreader__cleanUp"));
6592
6773
  {
6593
6774
  const proxyScript = createOrUpdateScript("darkreader--proxy");
6594
6775
  proxyScript.append(
@@ -6846,7 +7027,6 @@
6846
7027
  }
6847
7028
  changeMetaThemeColorWhenAvailable(theme);
6848
7029
  }
6849
- let pendingAdoptedVarMatch = false;
6850
7030
  function handleAdoptedStyleSheets(node) {
6851
7031
  if (isFirefox) {
6852
7032
  const fallback = getAdoptedStyleSheetFallback(node);
@@ -6864,42 +7044,9 @@
6864
7044
  sheets.forEach((s) => {
6865
7045
  variablesStore.addRulesForMatching(s.cssRules);
6866
7046
  });
7047
+ variablesStore.matchVariablesAndDependents();
6867
7048
  newManger.render(theme, ignoredImageAnalysisSelectors);
6868
- pendingAdoptedVarMatch = true;
6869
7049
  });
6870
- potentialAdoptedStyleNodes.delete(node);
6871
- } else if (!potentialAdoptedStyleNodes.has(node)) {
6872
- potentialAdoptedStyleNodes.add(node);
6873
- }
6874
- }
6875
- const potentialAdoptedStyleNodes = new Set();
6876
- let potentialAdoptedStyleFrameId = null;
6877
- function watchPotentialAdoptedStyleNodes() {
6878
- potentialAdoptedStyleFrameId = requestAnimationFrame(() => {
6879
- let changed = false;
6880
- potentialAdoptedStyleNodes.forEach((node) => {
6881
- if (node.isConnected) {
6882
- handleAdoptedStyleSheets(node);
6883
- changed = true;
6884
- } else {
6885
- potentialAdoptedStyleNodes.delete(node);
6886
- }
6887
- });
6888
- if (changed || pendingAdoptedVarMatch) {
6889
- variablesStore.matchVariablesAndDependents();
6890
- pendingAdoptedVarMatch = false;
6891
- }
6892
- watchPotentialAdoptedStyleNodes();
6893
- });
6894
- }
6895
- function stopWatchingPotentialAdoptedStyleNodes() {
6896
- potentialAdoptedStyleFrameId &&
6897
- cancelAnimationFrame(potentialAdoptedStyleFrameId);
6898
- potentialAdoptedStyleNodes.clear();
6899
- if (isFirefox) {
6900
- document.dispatchEvent(
6901
- new CustomEvent("__darkreader__stopAdoptedStyleSheetsWatcher")
6902
- );
6903
7050
  }
6904
7051
  }
6905
7052
  function getAdoptedStyleChangeToken(node) {
@@ -6971,7 +7118,6 @@
6971
7118
  handleAdoptedStyleSheets(shadowRoot);
6972
7119
  }
6973
7120
  );
6974
- watchPotentialAdoptedStyleNodes();
6975
7121
  watchForInlineStyles(
6976
7122
  (element) => {
6977
7123
  overrideInlineStyle(
@@ -7147,7 +7293,6 @@
7147
7293
  adoptedStyleManagers.splice(0);
7148
7294
  adoptedStyleFallbacks.forEach((fallback) => fallback.destroy());
7149
7295
  adoptedStyleFallbacks.clear();
7150
- stopWatchingPotentialAdoptedStyleNodes();
7151
7296
  metaObserver && metaObserver.disconnect();
7152
7297
  cleaners.forEach((clean) => clean());
7153
7298
  cleaners.splice(0);
@@ -7202,7 +7347,7 @@
7202
7347
  };
7203
7348
  rules.push(rule);
7204
7349
  }
7205
- ruleStart = brackets.end + 1;
7350
+ ruleStart = brackets.end;
7206
7351
  });
7207
7352
  return rules;
7208
7353
  }
@@ -7229,9 +7374,6 @@
7229
7374
  }
7230
7375
  return ranges;
7231
7376
  }
7232
- function removeCSSComments(cssText) {
7233
- return cssText.trim().replace(/\/\*.*?\*\//g, "");
7234
- }
7235
7377
  function getTokenExclusionRanges(cssText) {
7236
7378
  const singleQuoteGoesFirst =
7237
7379
  cssText.indexOf("'") < cssText.indexOf('"');
@@ -7287,13 +7429,19 @@
7287
7429
  );
7288
7430
  return declarations;
7289
7431
  }
7432
+ function isParsedStyleRule(rule) {
7433
+ return "selectors" in rule;
7434
+ }
7290
7435
 
7291
7436
  function formatCSS(cssText) {
7292
7437
  const parsed = parseCSS(cssText);
7438
+ return formatParsedCSS(parsed);
7439
+ }
7440
+ function formatParsedCSS(parsed) {
7293
7441
  const lines = [];
7294
7442
  const tab = " ";
7295
7443
  function formatRule(rule, indent) {
7296
- if (isStyleRule(rule)) {
7444
+ if (isParsedStyleRule(rule)) {
7297
7445
  formatStyleRule(rule, indent);
7298
7446
  } else {
7299
7447
  formatAtRule(rule, indent);
@@ -7338,13 +7486,10 @@
7338
7486
  return aNorm.localeCompare(bNorm);
7339
7487
  });
7340
7488
  }
7341
- function isStyleRule(rule) {
7342
- return "selectors" in rule;
7343
- }
7344
7489
  function clearEmptyRules(rules) {
7345
7490
  for (let i = rules.length - 1; i >= 0; i--) {
7346
7491
  const rule = rules[i];
7347
- if (isStyleRule(rule)) {
7492
+ if (isParsedStyleRule(rule)) {
7348
7493
  if (rule.declarations.length === 0) {
7349
7494
  rules.splice(i, 1);
7350
7495
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "darkreader",
3
- "version": "4.9.80",
3
+ "version": "4.9.82",
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",
@@ -58,24 +58,21 @@
58
58
  "@rollup/plugin-node-resolve": "15.2.3",
59
59
  "@rollup/plugin-replace": "5.0.5",
60
60
  "@rollup/plugin-typescript": "11.1.6",
61
- "@rollup/pluginutils": "5.1.0",
62
61
  "@types/chrome": "0.0.263",
63
- "@types/eslint": "8.56.5",
62
+ "@types/eslint": "8.56.6",
64
63
  "@types/jasmine": "5.1.4",
65
64
  "@types/jest": "29.5.12",
66
65
  "@types/karma": "6.3.8",
67
66
  "@types/karma-coverage": "2.0.3",
68
- "@types/node": "20.11.25",
69
- "@types/offscreencanvas": "2019.7.3",
67
+ "@types/node": "20.12.2",
70
68
  "@types/ws": "8.5.10",
71
- "@typescript-eslint/eslint-plugin": "7.1.1",
72
- "@typescript-eslint/parser": "7.1.1",
69
+ "@typescript-eslint/eslint-plugin": "7.4.0",
70
+ "@typescript-eslint/parser": "7.4.0",
73
71
  "chokidar": "3.6.0",
74
72
  "eslint": "8.57.0",
75
73
  "eslint-plugin-compat": "4.2.0",
76
74
  "eslint-plugin-import": "2.29.1",
77
75
  "eslint-plugin-local": "4.2.1",
78
- "get-stream": "8.0.1",
79
76
  "globby": "14.0.1",
80
77
  "jasmine-core": "5.1.2",
81
78
  "jest": "29.7.0",
@@ -91,12 +88,12 @@
91
88
  "less": "4.2.0",
92
89
  "malevic": "0.20.1",
93
90
  "prettier": "3.2.5",
94
- "puppeteer-core": "22.4.1",
95
- "rollup": "4.12.1",
91
+ "puppeteer-core": "22.6.1",
92
+ "rollup": "4.13.2",
96
93
  "rollup-plugin-istanbul": "5.0.0",
97
94
  "ts-jest": "29.1.2",
98
95
  "tslib": "2.6.2",
99
- "typescript": "5.4.2",
96
+ "typescript": "5.4.3",
100
97
  "web-ext": "7.11.0",
101
98
  "ws": "8.16.0",
102
99
  "yazl": "2.5.1"