UNPKG

darkreader

Version:

Dark mode for every website

1,637 lines (1,613 loc) 284 kB
/** * Dark Reader v4.9.112 * https://darkreader.org/ */ var MessageTypeUItoBG; (function (MessageTypeUItoBG) { MessageTypeUItoBG["GET_DATA"] = "ui-bg-get-data"; MessageTypeUItoBG["GET_DEVTOOLS_DATA"] = "ui-bg-get-devtools-data"; MessageTypeUItoBG["SUBSCRIBE_TO_CHANGES"] = "ui-bg-subscribe-to-changes"; MessageTypeUItoBG["UNSUBSCRIBE_FROM_CHANGES"] = "ui-bg-unsubscribe-from-changes"; MessageTypeUItoBG["CHANGE_SETTINGS"] = "ui-bg-change-settings"; MessageTypeUItoBG["SET_THEME"] = "ui-bg-set-theme"; MessageTypeUItoBG["TOGGLE_ACTIVE_TAB"] = "ui-bg-toggle-active-tab"; MessageTypeUItoBG["MARK_NEWS_AS_READ"] = "ui-bg-mark-news-as-read"; MessageTypeUItoBG["MARK_NEWS_AS_DISPLAYED"] = "ui-bg-mark-news-as-displayed"; MessageTypeUItoBG["LOAD_CONFIG"] = "ui-bg-load-config"; MessageTypeUItoBG["APPLY_DEV_DYNAMIC_THEME_FIXES"] = "ui-bg-apply-dev-dynamic-theme-fixes"; MessageTypeUItoBG["RESET_DEV_DYNAMIC_THEME_FIXES"] = "ui-bg-reset-dev-dynamic-theme-fixes"; MessageTypeUItoBG["APPLY_DEV_INVERSION_FIXES"] = "ui-bg-apply-dev-inversion-fixes"; MessageTypeUItoBG["RESET_DEV_INVERSION_FIXES"] = "ui-bg-reset-dev-inversion-fixes"; MessageTypeUItoBG["APPLY_DEV_STATIC_THEMES"] = "ui-bg-apply-dev-static-themes"; MessageTypeUItoBG["RESET_DEV_STATIC_THEMES"] = "ui-bg-reset-dev-static-themes"; MessageTypeUItoBG["START_ACTIVATION"] = "ui-bg-start-activation"; MessageTypeUItoBG["RESET_ACTIVATION"] = "ui-bg-reset-activation"; MessageTypeUItoBG["COLOR_SCHEME_CHANGE"] = "ui-bg-color-scheme-change"; MessageTypeUItoBG["HIDE_HIGHLIGHTS"] = "ui-bg-hide-highlights"; })(MessageTypeUItoBG || (MessageTypeUItoBG = {})); var MessageTypeBGtoUI; (function (MessageTypeBGtoUI) { MessageTypeBGtoUI["CHANGES"] = "bg-ui-changes"; })(MessageTypeBGtoUI || (MessageTypeBGtoUI = {})); var DebugMessageTypeBGtoUI; (function (DebugMessageTypeBGtoUI) { DebugMessageTypeBGtoUI["CSS_UPDATE"] = "debug-bg-ui-css-update"; DebugMessageTypeBGtoUI["UPDATE"] = "debug-bg-ui-update"; })(DebugMessageTypeBGtoUI || (DebugMessageTypeBGtoUI = {})); var MessageTypeBGtoCS; (function (MessageTypeBGtoCS) { MessageTypeBGtoCS["ADD_CSS_FILTER"] = "bg-cs-add-css-filter"; MessageTypeBGtoCS["ADD_DYNAMIC_THEME"] = "bg-cs-add-dynamic-theme"; MessageTypeBGtoCS["ADD_STATIC_THEME"] = "bg-cs-add-static-theme"; MessageTypeBGtoCS["ADD_SVG_FILTER"] = "bg-cs-add-svg-filter"; MessageTypeBGtoCS["CLEAN_UP"] = "bg-cs-clean-up"; MessageTypeBGtoCS["FETCH_RESPONSE"] = "bg-cs-fetch-response"; MessageTypeBGtoCS["UNSUPPORTED_SENDER"] = "bg-cs-unsupported-sender"; })(MessageTypeBGtoCS || (MessageTypeBGtoCS = {})); var DebugMessageTypeBGtoCS; (function (DebugMessageTypeBGtoCS) { DebugMessageTypeBGtoCS["RELOAD"] = "debug-bg-cs-reload"; })(DebugMessageTypeBGtoCS || (DebugMessageTypeBGtoCS = {})); var MessageTypeCStoBG; (function (MessageTypeCStoBG) { MessageTypeCStoBG["COLOR_SCHEME_CHANGE"] = "cs-bg-color-scheme-change"; MessageTypeCStoBG["DARK_THEME_DETECTED"] = "cs-bg-dark-theme-detected"; MessageTypeCStoBG["DARK_THEME_NOT_DETECTED"] = "cs-bg-dark-theme-not-detected"; MessageTypeCStoBG["FETCH"] = "cs-bg-fetch"; MessageTypeCStoBG["DOCUMENT_CONNECT"] = "cs-bg-document-connect"; MessageTypeCStoBG["DOCUMENT_FORGET"] = "cs-bg-document-forget"; MessageTypeCStoBG["DOCUMENT_FREEZE"] = "cs-bg-document-freeze"; MessageTypeCStoBG["DOCUMENT_RESUME"] = "cs-bg-document-resume"; })(MessageTypeCStoBG || (MessageTypeCStoBG = {})); var DebugMessageTypeCStoBG; (function (DebugMessageTypeCStoBG) { DebugMessageTypeCStoBG["LOG"] = "debug-cs-bg-log"; })(DebugMessageTypeCStoBG || (DebugMessageTypeCStoBG = {})); var MessageTypeCStoUI; (function (MessageTypeCStoUI) { MessageTypeCStoUI["EXPORT_CSS_RESPONSE"] = "cs-ui-export-css-response"; })(MessageTypeCStoUI || (MessageTypeCStoUI = {})); var MessageTypeUItoCS; (function (MessageTypeUItoCS) { MessageTypeUItoCS["EXPORT_CSS"] = "ui-cs-export-css"; })(MessageTypeUItoCS || (MessageTypeUItoCS = {})); const isNavigatorDefined = typeof navigator !== "undefined"; const userAgent = isNavigatorDefined ? navigator.userAgentData && Array.isArray(navigator.userAgentData.brands) ? navigator.userAgentData.brands .map((brand) => `${brand.brand.toLowerCase()} ${brand.version}`) .join(" ") : navigator.userAgent.toLowerCase() : "some useragent"; const platform = isNavigatorDefined ? navigator.userAgentData && typeof navigator.userAgentData.platform === "string" ? navigator.userAgentData.platform.toLowerCase() : navigator.platform.toLowerCase() : "some platform"; const isChromium = userAgent.includes("chrome") || userAgent.includes("chromium"); const isFirefox = userAgent.includes("firefox") || userAgent.includes("thunderbird") || userAgent.includes("librewolf"); const isSafari = userAgent.includes("safari") && !isChromium; const isWindows = platform.startsWith("win"); const isMacOS = platform.startsWith("mac"); isNavigatorDefined && navigator.userAgentData ? navigator.userAgentData.mobile : userAgent.includes("mobile"); const isShadowDomSupported = typeof ShadowRoot === "function"; const isMatchMediaChangeEventListenerSupported = typeof MediaQueryList === "function" && typeof MediaQueryList.prototype.addEventListener === "function"; const isLayerRuleSupported = typeof CSSLayerBlockRule === "function"; (() => { const m = userAgent.match(/chrom(?:e|ium)(?:\/| )([^ ]+)/); if (m && m[1]) { return m[1]; } return ""; })(); (() => { const m = userAgent.match(/(?:firefox|librewolf)(?:\/| )([^ ]+)/); if (m && m[1]) { return m[1]; } return ""; })(); const isDefinedSelectorSupported = (() => { try { document.querySelector(":defined"); return true; } catch (err) { return false; } })(); const isCSSColorSchemePropSupported = (() => { try { if (typeof document === "undefined") { return false; } const el = document.createElement("div"); if (!el || typeof el.style !== "object") { return false; } if (typeof el.style.colorScheme === "string") { return true; } el.setAttribute("style", "color-scheme: dark"); return el.style.colorScheme === "dark"; } catch (e) { return false; } })(); async function getOKResponse(url, mimeType, origin) { const credentials = origin && url.startsWith(`${origin}/`) ? undefined : "omit"; const response = await fetch(url, { cache: "force-cache", credentials, referrer: origin }); if ( isFirefox && mimeType === "text/css" && url.startsWith("moz-extension://") && url.endsWith(".css") ) { return response; } if ( mimeType && !response.headers.get("Content-Type").startsWith(mimeType) ) { throw new Error(`Mime type mismatch when loading ${url}`); } if (!response.ok) { throw new Error( `Unable to load ${url} ${response.status} ${response.statusText}` ); } return response; } async function loadAsDataURL(url, mimeType) { const response = await getOKResponse(url, mimeType); return await readResponseAsDataURL(response); } async function loadAsBlob(url, mimeType) { const response = await getOKResponse(url, mimeType); return await response.blob(); } async function readResponseAsDataURL(response) { const blob = await response.blob(); const dataURL = await new Promise((resolve) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.readAsDataURL(blob); }); return dataURL; } async function loadAsText(url, mimeType, origin) { const response = await getOKResponse(url, mimeType, origin); return await response.text(); } const throwCORSError = async (url) => { return Promise.reject( new Error( [ "Embedded Dark Reader cannot access a cross-origin resource", url, "Overview your URLs and CORS policies or use", "`DarkReader.setFetchMethod(fetch: (url) => Promise<Response>))`.", "See if using `DarkReader.setFetchMethod(window.fetch)`", "before `DarkReader.enable()` works." ].join(" ") ) ); }; let fetcher = throwCORSError; function setFetchMethod$1(fetch) { if (fetch) { fetcher = fetch; } else { fetcher = throwCORSError; } } async function callFetchMethod(url) { return await fetcher(url); } if (!window.chrome) { window.chrome = {}; } if (!chrome.runtime) { chrome.runtime = {}; } const messageListeners = new Set(); async function sendMessage(...args) { if (args[0] && args[0].type === MessageTypeCStoBG.FETCH) { const {id} = args[0]; try { const {url, responseType} = args[0].data; const response = await callFetchMethod(url); let text; if (responseType === "data-url") { text = await readResponseAsDataURL(response); } else { text = await response.text(); } messageListeners.forEach((cb) => cb({ type: MessageTypeBGtoCS.FETCH_RESPONSE, data: text, error: null, id }) ); } catch (error) { console.error(error); messageListeners.forEach((cb) => cb({ type: MessageTypeBGtoCS.FETCH_RESPONSE, data: null, error, id }) ); } } } function addMessageListener(callback) { messageListeners.add(callback); } if (typeof chrome.runtime.sendMessage === "function") { const nativeSendMessage = chrome.runtime.sendMessage; chrome.runtime.sendMessage = (...args) => { sendMessage(...args); nativeSendMessage.apply(chrome.runtime, args); }; } else { chrome.runtime.sendMessage = sendMessage; } if (!chrome.runtime.onMessage) { chrome.runtime.onMessage = {}; } if (typeof chrome.runtime.onMessage.addListener === "function") { const nativeAddListener = chrome.runtime.onMessage.addListener; chrome.runtime.onMessage.addListener = (...args) => { addMessageListener(args[0]); nativeAddListener.apply(chrome.runtime.onMessage, args); }; } else { chrome.runtime.onMessage.addListener = (...args) => addMessageListener(args[0]); } var ThemeEngine; (function (ThemeEngine) { ThemeEngine["cssFilter"] = "cssFilter"; ThemeEngine["svgFilter"] = "svgFilter"; ThemeEngine["staticTheme"] = "staticTheme"; ThemeEngine["dynamicTheme"] = "dynamicTheme"; })(ThemeEngine || (ThemeEngine = {})); var AutomationMode; (function (AutomationMode) { AutomationMode["NONE"] = ""; AutomationMode["TIME"] = "time"; AutomationMode["SYSTEM"] = "system"; AutomationMode["LOCATION"] = "location"; })(AutomationMode || (AutomationMode = {})); const DEFAULT_COLORS = { darkScheme: { background: "#181a1b", text: "#e8e6e3" }, lightScheme: { background: "#dcdad7", text: "#181a1b" } }; const DEFAULT_THEME = { mode: 1, brightness: 100, contrast: 100, grayscale: 0, sepia: 0, useFont: false, fontFamily: isMacOS ? "Helvetica Neue" : isWindows ? "Segoe UI" : "Open Sans", textStroke: 0, engine: ThemeEngine.dynamicTheme, stylesheet: "", darkSchemeBackgroundColor: DEFAULT_COLORS.darkScheme.background, darkSchemeTextColor: DEFAULT_COLORS.darkScheme.text, lightSchemeBackgroundColor: DEFAULT_COLORS.lightScheme.background, lightSchemeTextColor: DEFAULT_COLORS.lightScheme.text, scrollbarColor: "", selectionColor: "auto", styleSystemControls: !isCSSColorSchemePropSupported, lightColorScheme: "Default", darkColorScheme: "Default", immediateModify: false }; const filterModeSites = [ "*.officeapps.live.com", "*.sharepoint.com", "docs.google.com", "onedrive.live.com" ]; ({ customThemes: filterModeSites.map((url) => { const engine = ThemeEngine.cssFilter; return { url: [url], theme: {...DEFAULT_THEME, engine}, builtIn: true }; }), automation: { mode: AutomationMode.NONE } }); function getMatches(regex, input, group = 0) { const matches = []; let m; while ((m = regex.exec(input))) { matches.push(m[group]); } return matches; } function getMatchesWithOffsets(regex, input, group = 0) { const matches = []; let m; while ((m = regex.exec(input))) { matches.push({text: m[group], offset: m.index}); } return matches; } function getHashCode(text) { const len = text.length; let hash = 0; for (let i = 0; i < len; i++) { const c = text.charCodeAt(i); hash = ((hash << 5) - hash + c) & 4294967295; } return hash; } function escapeRegExpSpecialChars(input) { return input.replaceAll(/[\^$.*+?\(\)\[\]{}|\-\\]/g, "\\$&"); } function getParenthesesRange(input, searchStartIndex = 0) { return getOpenCloseRange(input, searchStartIndex, "(", ")", []); } function getOpenCloseRange( input, searchStartIndex, openToken, closeToken, excludeRanges ) { let indexOf; if (excludeRanges.length === 0) { indexOf = (token, pos) => input.indexOf(token, pos); } else { indexOf = (token, pos) => indexOfExcluding(input, token, pos, excludeRanges); } const {length} = input; let depth = 0; let firstOpenIndex = -1; for (let i = searchStartIndex; i < length; i++) { if (depth === 0) { const openIndex = indexOf(openToken, i); if (openIndex < 0) { break; } firstOpenIndex = openIndex; depth++; i = openIndex; } else { const closeIndex = indexOf(closeToken, i); if (closeIndex < 0) { break; } const openIndex = indexOf(openToken, i); if (openIndex < 0 || closeIndex <= openIndex) { depth--; if (depth === 0) { return {start: firstOpenIndex, end: closeIndex + 1}; } i = closeIndex; } else { depth++; i = openIndex; } } } return null; } function indexOfExcluding(input, search, position, excludeRanges) { const i = input.indexOf(search, position); const exclusion = excludeRanges.find((r) => i >= r.start && i < r.end); if (exclusion) { return indexOfExcluding(input, search, exclusion.end, excludeRanges); } return i; } function splitExcluding(input, separator, excludeRanges) { const parts = []; let commaIndex = -1; let currIndex = 0; while ( (commaIndex = indexOfExcluding( input, separator, currIndex, excludeRanges )) >= 0 ) { parts.push(input.substring(currIndex, commaIndex).trim()); currIndex = commaIndex + 1; } parts.push(input.substring(currIndex).trim()); return parts; } let anchor; const parsedURLCache = new Map(); function fixBaseURL($url) { if (!anchor) { anchor = document.createElement("a"); } anchor.href = $url; return anchor.href; } function parseURL($url, $base = null) { const key = `${$url}${$base ? `;${$base}` : ""}`; if (parsedURLCache.has(key)) { return parsedURLCache.get(key); } if ($base) { const parsedURL = new URL($url, fixBaseURL($base)); parsedURLCache.set(key, parsedURL); return parsedURL; } const parsedURL = new URL(fixBaseURL($url)); parsedURLCache.set($url, parsedURL); return parsedURL; } function getAbsoluteURL($base, $relative) { if ($relative.match(/^data\\?\:/)) { return $relative; } if (/^\/\//.test($relative)) { return `${location.protocol}${$relative}`; } const b = parseURL($base); const a = parseURL($relative, b.href); return a.href; } function isRelativeHrefOnAbsolutePath(href) { if (href.startsWith("data:")) { return true; } const url = parseURL(href); if (url.protocol !== location.protocol) { return false; } if (url.hostname !== location.hostname) { return false; } if (url.port !== location.port) { return false; } return url.pathname === location.pathname; } const excludedSelectors = [ "pre", "pre *", "code", '[aria-hidden="true"]', '[class*="fa-"]', ".fa", ".fab", ".fad", ".fal", ".far", ".fas", ".fass", ".fasr", ".fat", ".icofont", '[style*="font-"]', '[class*="icon"]', '[class*="Icon"]', '[class*="symbol"]', '[class*="Symbol"]', ".glyphicon", '[class*="material-symbol"]', '[class*="material-icon"]', "mu", '[class*="mu-"]', ".typcn", '[class*="vjs-"]' ]; function createTextStyle(config) { const lines = []; lines.push(`*:not(${excludedSelectors.join(", ")}) {`); if (config.useFont && config.fontFamily) { lines.push(` font-family: ${config.fontFamily} !important;`); } if (config.textStroke > 0) { lines.push(` -webkit-text-stroke: ${config.textStroke}px !important;`); lines.push(` text-stroke: ${config.textStroke}px !important;`); } lines.push("}"); return lines.join("\n"); } function isArrayLike(items) { return items.length != null; } function forEach(items, iterator) { if (isArrayLike(items)) { for (let i = 0, len = items.length; i < len; i++) { iterator(items[i]); } } else { for (const item of items) { iterator(item); } } } function push(array, addition) { forEach(addition, (a) => array.push(a)); } function toArray(items) { const results = []; for (let i = 0, len = items.length; i < len; i++) { results.push(items[i]); } return results; } function scale(x, inLow, inHigh, outLow, outHigh) { return ((x - inLow) * (outHigh - outLow)) / (inHigh - inLow) + outLow; } function clamp(x, min, max) { return Math.min(max, Math.max(min, x)); } function multiplyMatrices(m1, m2) { const result = []; for (let i = 0, len = m1.length; i < len; i++) { result[i] = []; for (let j = 0, len2 = m2[0].length; j < len2; j++) { let sum = 0; for (let k = 0, len3 = m1[0].length; k < len3; k++) { sum += m1[i][k] * m2[k][j]; } result[i][j] = sum; } } return result; } function createFilterMatrix(config) { let m = Matrix.identity(); if (config.sepia !== 0) { m = multiplyMatrices(m, Matrix.sepia(config.sepia / 100)); } if (config.grayscale !== 0) { m = multiplyMatrices(m, Matrix.grayscale(config.grayscale / 100)); } if (config.contrast !== 100) { m = multiplyMatrices(m, Matrix.contrast(config.contrast / 100)); } if (config.brightness !== 100) { m = multiplyMatrices(m, Matrix.brightness(config.brightness / 100)); } if (config.mode === 1) { m = multiplyMatrices(m, Matrix.invertNHue()); } return m; } function applyColorMatrix([r, g, b], matrix) { const rgb = [[r / 255], [g / 255], [b / 255], [1], [1]]; const result = multiplyMatrices(matrix, rgb); return [0, 1, 2].map((i) => clamp(Math.round(result[i][0] * 255), 0, 255)); } const Matrix = { identity() { return [ [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1] ]; }, invertNHue() { return [ [0.333, -0.667, -0.667, 0, 1], [-0.667, 0.333, -0.667, 0, 1], [-0.667, -0.667, 0.333, 0, 1], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1] ]; }, brightness(v) { return [ [v, 0, 0, 0, 0], [0, v, 0, 0, 0], [0, 0, v, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1] ]; }, contrast(v) { const t = (1 - v) / 2; return [ [v, 0, 0, 0, t], [0, v, 0, 0, t], [0, 0, v, 0, t], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1] ]; }, sepia(v) { return [ [ 0.393 + 0.607 * (1 - v), 0.769 - 0.769 * (1 - v), 0.189 - 0.189 * (1 - v), 0, 0 ], [ 0.349 - 0.349 * (1 - v), 0.686 + 0.314 * (1 - v), 0.168 - 0.168 * (1 - v), 0, 0 ], [ 0.272 - 0.272 * (1 - v), 0.534 - 0.534 * (1 - v), 0.131 + 0.869 * (1 - v), 0, 0 ], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1] ]; }, grayscale(v) { return [ [ 0.2126 + 0.7874 * (1 - v), 0.7152 - 0.7152 * (1 - v), 0.0722 - 0.0722 * (1 - v), 0, 0 ], [ 0.2126 - 0.2126 * (1 - v), 0.7152 + 0.2848 * (1 - v), 0.0722 - 0.0722 * (1 - v), 0, 0 ], [ 0.2126 - 0.2126 * (1 - v), 0.7152 - 0.7152 * (1 - v), 0.0722 + 0.9278 * (1 - v), 0, 0 ], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1] ]; } }; var FilterMode; (function (FilterMode) { FilterMode[(FilterMode["light"] = 0)] = "light"; FilterMode[(FilterMode["dark"] = 1)] = "dark"; })(FilterMode || (FilterMode = {})); function getCSSFilterValue(config) { const filters = []; if (config.mode === FilterMode.dark) { filters.push("invert(100%) hue-rotate(180deg)"); } if (config.brightness !== 100) { filters.push(`brightness(${config.brightness}%)`); } if (config.contrast !== 100) { filters.push(`contrast(${config.contrast}%)`); } if (config.grayscale !== 0) { filters.push(`grayscale(${config.grayscale}%)`); } if (config.sepia !== 0) { filters.push(`sepia(${config.sepia}%)`); } if (filters.length === 0) { return null; } return filters.join(" "); } function evalMath(expression) { const rpnStack = []; const workingStack = []; let lastToken; for (let i = 0, len = expression.length; i < len; i++) { const token = expression[i]; if (!token || token === " ") { continue; } if (operators.has(token)) { const op = operators.get(token); while (workingStack.length) { const currentOp = operators.get(workingStack[0]); if (!currentOp) { break; } if (op.lessOrEqualThan(currentOp)) { rpnStack.push(workingStack.shift()); } else { break; } } workingStack.unshift(token); } else if (!lastToken || operators.has(lastToken)) { rpnStack.push(token); } else { rpnStack[rpnStack.length - 1] += token; } lastToken = token; } rpnStack.push(...workingStack); const stack = []; for (let i = 0, len = rpnStack.length; i < len; i++) { const op = operators.get(rpnStack[i]); if (op) { const args = stack.splice(0, 2); stack.push(op.exec(args[1], args[0])); } else { stack.unshift(parseFloat(rpnStack[i])); } } return stack[0]; } class Operator { constructor(precedence, method) { this.precendce = precedence; this.execMethod = method; } exec(left, right) { return this.execMethod(left, right); } lessOrEqualThan(op) { return this.precendce <= op.precendce; } } const operators = new Map([ ["+", new Operator(1, (left, right) => left + right)], ["-", new Operator(1, (left, right) => left - right)], ["*", new Operator(2, (left, right) => left * right)], ["/", new Operator(2, (left, right) => left / right)] ]); const isSystemDarkModeEnabled = () => matchMedia("(prefers-color-scheme: dark)").matches; const hslaParseCache = new Map(); const rgbaParseCache = new Map(); function parseColorWithCache($color) { $color = $color.trim(); if (rgbaParseCache.has($color)) { return rgbaParseCache.get($color); } if ($color.includes("calc(")) { $color = lowerCalcExpression($color); } const color = parse($color); if (color) { rgbaParseCache.set($color, color); return color; } return null; } function parseToHSLWithCache(color) { if (hslaParseCache.has(color)) { return hslaParseCache.get(color); } const rgb = parseColorWithCache(color); if (!rgb) { return null; } const hsl = rgbToHSL(rgb); hslaParseCache.set(color, hsl); return hsl; } function clearColorCache() { hslaParseCache.clear(); rgbaParseCache.clear(); } function hslToRGB({h, s, l, a = 1}) { if (s === 0) { const [r, b, g] = [l, l, l].map((x) => Math.round(x * 255)); return {r, g, b, a}; } const c = (1 - Math.abs(2 * l - 1)) * s; const x = c * (1 - Math.abs(((h / 60) % 2) - 1)); const m = l - c / 2; const [r, g, b] = ( h < 60 ? [c, x, 0] : h < 120 ? [x, c, 0] : h < 180 ? [0, c, x] : h < 240 ? [0, x, c] : h < 300 ? [x, 0, c] : [c, 0, x] ).map((n) => Math.round((n + m) * 255)); return {r, g, b, a}; } function rgbToHSL({r: r255, g: g255, b: b255, a = 1}) { const r = r255 / 255; const g = g255 / 255; const b = b255 / 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); const c = max - min; const l = (max + min) / 2; if (c === 0) { return {h: 0, s: 0, l, a}; } let h = (max === r ? ((g - b) / c) % 6 : max === g ? (b - r) / c + 2 : (r - g) / c + 4) * 60; if (h < 0) { h += 360; } const s = c / (1 - Math.abs(2 * l - 1)); return {h, s, l, a}; } function toFixed(n, digits = 0) { const fixed = n.toFixed(digits); if (digits === 0) { return fixed; } const dot = fixed.indexOf("."); if (dot >= 0) { const zerosMatch = fixed.match(/0+$/); if (zerosMatch) { if (zerosMatch.index === dot + 1) { return fixed.substring(0, dot); } return fixed.substring(0, zerosMatch.index); } } return fixed; } function rgbToString(rgb) { const {r, g, b, a} = rgb; if (a != null && a < 1) { return `rgba(${toFixed(r)}, ${toFixed(g)}, ${toFixed(b)}, ${toFixed(a, 2)})`; } return `rgb(${toFixed(r)}, ${toFixed(g)}, ${toFixed(b)})`; } function rgbToHexString({r, g, b, a}) { return `#${(a != null && a < 1 ? [r, g, b, Math.round(a * 255)] : [r, g, b]) .map((x) => { return `${x < 16 ? "0" : ""}${x.toString(16)}`; }) .join("")}`; } function hslToString(hsl) { const {h, s, l, a} = hsl; if (a != null && a < 1) { return `hsla(${toFixed(h)}, ${toFixed(s * 100)}%, ${toFixed(l * 100)}%, ${toFixed(a, 2)})`; } return `hsl(${toFixed(h)}, ${toFixed(s * 100)}%, ${toFixed(l * 100)}%)`; } const rgbMatch = /^rgba?\([^\(\)]+\)$/; const hslMatch = /^hsla?\([^\(\)]+\)$/; const hexMatch = /^#[0-9a-f]+$/i; const supportedColorFuncs = [ "color", "color-mix", "hwb", "lab", "lch", "oklab", "oklch" ]; function parse($color) { const c = $color.trim().toLowerCase(); if (c.includes("(from ")) { if (c.indexOf("(from") !== c.lastIndexOf("(from")) { return null; } return domParseColor(c); } if (c.match(rgbMatch)) { if (c.startsWith("rgb(#") || c.startsWith("rgba(#")) { if (c.lastIndexOf("rgb") > 0) { return null; } return domParseColor(c); } return parseRGB(c); } if (c.match(hslMatch)) { return parseHSL(c); } if (c.match(hexMatch)) { return parseHex(c); } if (knownColors.has(c)) { return getColorByName(c); } if (systemColors.has(c)) { return getSystemColor(c); } if (c === "transparent") { return {r: 0, g: 0, b: 0, a: 0}; } if ( c.endsWith(")") && supportedColorFuncs.some( (fn) => c.startsWith(fn) && c[fn.length] === "(" && c.lastIndexOf(fn) === 0 ) ) { return domParseColor(c); } if (c.startsWith("light-dark(") && c.endsWith(")")) { const match = c.match( /^light-dark\(\s*([a-z]+(\(.*\))?),\s*([a-z]+(\(.*\))?)\s*\)$/ ); if (match) { const schemeColor = isSystemDarkModeEnabled() ? match[3] : match[1]; return parse(schemeColor); } } return null; } function getNumbers($color) { const numbers = []; let prevPos = 0; let isMining = false; const startIndex = $color.indexOf("("); $color = $color.substring(startIndex + 1, $color.length - 1); for (let i = 0; i < $color.length; i++) { const c = $color[i]; if ((c >= "0" && c <= "9") || c === "." || c === "+" || c === "-") { isMining = true; } else if (isMining && (c === " " || c === "," || c === "/")) { numbers.push($color.substring(prevPos, i)); isMining = false; prevPos = i + 1; } else if (!isMining) { prevPos = i + 1; } } if (isMining) { numbers.push($color.substring(prevPos, $color.length)); } return numbers; } function getNumbersFromString(str, range, units) { const raw = getNumbers(str); const unitsList = Object.entries(units); const numbers = raw .map((r) => r.trim()) .map((r, i) => { let n; const unit = unitsList.find(([u]) => r.endsWith(u)); if (unit) { n = (parseFloat(r.substring(0, r.length - unit[0].length)) / unit[1]) * range[i]; } else { n = parseFloat(r); } if (range[i] > 1) { return Math.round(n); } return n; }); return numbers; } const rgbRange = [255, 255, 255, 1]; const rgbUnits = {"%": 100}; function parseRGB($rgb) { const [r, g, b, a = 1] = getNumbersFromString($rgb, rgbRange, rgbUnits); if (r == null || g == null || b == null || a == null) { return null; } return {r, g, b, a}; } const hslRange = [360, 1, 1, 1]; const hslUnits = {"%": 100, "deg": 360, "rad": 2 * Math.PI, "turn": 1}; function parseHSL($hsl) { const [h, s, l, a = 1] = getNumbersFromString($hsl, hslRange, hslUnits); if (h == null || s == null || l == null || a == null) { return null; } return hslToRGB({h, s, l, a}); } function parseHex($hex) { const h = $hex.substring(1); switch (h.length) { case 3: case 4: { const [r, g, b] = [0, 1, 2].map((i) => parseInt(`${h[i]}${h[i]}`, 16) ); const a = h.length === 3 ? 1 : parseInt(`${h[3]}${h[3]}`, 16) / 255; return {r, g, b, a}; } case 6: case 8: { const [r, g, b] = [0, 2, 4].map((i) => parseInt(h.substring(i, i + 2), 16) ); const a = h.length === 6 ? 1 : parseInt(h.substring(6, 8), 16) / 255; return {r, g, b, a}; } } return null; } function getColorByName($color) { const n = knownColors.get($color); return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: (n >> 0) & 255, a: 1 }; } function getSystemColor($color) { const n = systemColors.get($color); return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: (n >> 0) & 255, a: 1 }; } function lowerCalcExpression(color) { let searchIndex = 0; const replaceBetweenIndices = (start, end, replacement) => { color = color.substring(0, start) + replacement + color.substring(end); }; while ((searchIndex = color.indexOf("calc(")) !== -1) { const range = getParenthesesRange(color, searchIndex); if (!range) { break; } let slice = color.slice(range.start + 1, range.end - 1); const includesPercentage = slice.includes("%"); slice = slice.split("%").join(""); const output = Math.round(evalMath(slice)); replaceBetweenIndices( range.start - 4, range.end, output + (includesPercentage ? "%" : "") ); } return color; } const knownColors = new Map( Object.entries({ aliceblue: 0xf0f8ff, antiquewhite: 0xfaebd7, aqua: 0x00ffff, aquamarine: 0x7fffd4, azure: 0xf0ffff, beige: 0xf5f5dc, bisque: 0xffe4c4, black: 0x000000, blanchedalmond: 0xffebcd, blue: 0x0000ff, blueviolet: 0x8a2be2, brown: 0xa52a2a, burlywood: 0xdeb887, cadetblue: 0x5f9ea0, chartreuse: 0x7fff00, chocolate: 0xd2691e, coral: 0xff7f50, cornflowerblue: 0x6495ed, cornsilk: 0xfff8dc, crimson: 0xdc143c, cyan: 0x00ffff, darkblue: 0x00008b, darkcyan: 0x008b8b, darkgoldenrod: 0xb8860b, darkgray: 0xa9a9a9, darkgrey: 0xa9a9a9, darkgreen: 0x006400, darkkhaki: 0xbdb76b, darkmagenta: 0x8b008b, darkolivegreen: 0x556b2f, darkorange: 0xff8c00, darkorchid: 0x9932cc, darkred: 0x8b0000, darksalmon: 0xe9967a, darkseagreen: 0x8fbc8f, darkslateblue: 0x483d8b, darkslategray: 0x2f4f4f, darkslategrey: 0x2f4f4f, darkturquoise: 0x00ced1, darkviolet: 0x9400d3, deeppink: 0xff1493, deepskyblue: 0x00bfff, dimgray: 0x696969, dimgrey: 0x696969, dodgerblue: 0x1e90ff, firebrick: 0xb22222, floralwhite: 0xfffaf0, forestgreen: 0x228b22, fuchsia: 0xff00ff, gainsboro: 0xdcdcdc, ghostwhite: 0xf8f8ff, gold: 0xffd700, goldenrod: 0xdaa520, gray: 0x808080, grey: 0x808080, green: 0x008000, greenyellow: 0xadff2f, honeydew: 0xf0fff0, hotpink: 0xff69b4, indianred: 0xcd5c5c, indigo: 0x4b0082, ivory: 0xfffff0, khaki: 0xf0e68c, lavender: 0xe6e6fa, lavenderblush: 0xfff0f5, lawngreen: 0x7cfc00, lemonchiffon: 0xfffacd, lightblue: 0xadd8e6, lightcoral: 0xf08080, lightcyan: 0xe0ffff, lightgoldenrodyellow: 0xfafad2, lightgray: 0xd3d3d3, lightgrey: 0xd3d3d3, lightgreen: 0x90ee90, lightpink: 0xffb6c1, lightsalmon: 0xffa07a, lightseagreen: 0x20b2aa, lightskyblue: 0x87cefa, lightslategray: 0x778899, lightslategrey: 0x778899, lightsteelblue: 0xb0c4de, lightyellow: 0xffffe0, lime: 0x00ff00, limegreen: 0x32cd32, linen: 0xfaf0e6, magenta: 0xff00ff, maroon: 0x800000, mediumaquamarine: 0x66cdaa, mediumblue: 0x0000cd, mediumorchid: 0xba55d3, mediumpurple: 0x9370db, mediumseagreen: 0x3cb371, mediumslateblue: 0x7b68ee, mediumspringgreen: 0x00fa9a, mediumturquoise: 0x48d1cc, mediumvioletred: 0xc71585, midnightblue: 0x191970, mintcream: 0xf5fffa, mistyrose: 0xffe4e1, moccasin: 0xffe4b5, navajowhite: 0xffdead, navy: 0x000080, oldlace: 0xfdf5e6, olive: 0x808000, olivedrab: 0x6b8e23, orange: 0xffa500, orangered: 0xff4500, orchid: 0xda70d6, palegoldenrod: 0xeee8aa, palegreen: 0x98fb98, paleturquoise: 0xafeeee, palevioletred: 0xdb7093, papayawhip: 0xffefd5, peachpuff: 0xffdab9, peru: 0xcd853f, pink: 0xffc0cb, plum: 0xdda0dd, powderblue: 0xb0e0e6, purple: 0x800080, rebeccapurple: 0x663399, red: 0xff0000, rosybrown: 0xbc8f8f, royalblue: 0x4169e1, saddlebrown: 0x8b4513, salmon: 0xfa8072, sandybrown: 0xf4a460, seagreen: 0x2e8b57, seashell: 0xfff5ee, sienna: 0xa0522d, silver: 0xc0c0c0, skyblue: 0x87ceeb, slateblue: 0x6a5acd, slategray: 0x708090, slategrey: 0x708090, snow: 0xfffafa, springgreen: 0x00ff7f, steelblue: 0x4682b4, tan: 0xd2b48c, teal: 0x008080, thistle: 0xd8bfd8, tomato: 0xff6347, turquoise: 0x40e0d0, violet: 0xee82ee, wheat: 0xf5deb3, white: 0xffffff, whitesmoke: 0xf5f5f5, yellow: 0xffff00, yellowgreen: 0x9acd32 }) ); const systemColors = new Map( Object.entries({ "ActiveBorder": 0x3b99fc, "ActiveCaption": 0x000000, "AppWorkspace": 0xaaaaaa, "Background": 0x6363ce, "ButtonFace": 0xffffff, "ButtonHighlight": 0xe9e9e9, "ButtonShadow": 0x9fa09f, "ButtonText": 0x000000, "CaptionText": 0x000000, "GrayText": 0x7f7f7f, "Highlight": 0xb2d7ff, "HighlightText": 0x000000, "InactiveBorder": 0xffffff, "InactiveCaption": 0xffffff, "InactiveCaptionText": 0x000000, "InfoBackground": 0xfbfcc5, "InfoText": 0x000000, "Menu": 0xf6f6f6, "MenuText": 0xffffff, "Scrollbar": 0xaaaaaa, "ThreeDDarkShadow": 0x000000, "ThreeDFace": 0xc0c0c0, "ThreeDHighlight": 0xffffff, "ThreeDLightShadow": 0xffffff, "ThreeDShadow": 0x000000, "Window": 0xececec, "WindowFrame": 0xaaaaaa, "WindowText": 0x000000, "-webkit-focus-ring-color": 0xe59700 }).map(([key, value]) => [key.toLowerCase(), value]) ); function getSRGBLightness(r, g, b) { return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255; } let canvas$1; let context$1; function domParseColor($color) { if (!context$1) { canvas$1 = document.createElement("canvas"); canvas$1.width = 1; canvas$1.height = 1; context$1 = canvas$1.getContext("2d", {willReadFrequently: true}); } context$1.fillStyle = $color; context$1.fillRect(0, 0, 1, 1); const d = context$1.getImageData(0, 0, 1, 1).data; const color = `rgba(${d[0]}, ${d[1]}, ${d[2]}, ${(d[3] / 255).toFixed(2)})`; return parseRGB(color); } function throttle(callback) { let pending = false; let frameId = null; let lastArgs; const throttled = (...args) => { lastArgs = args; if (frameId) { pending = true; } else { callback(...lastArgs); frameId = requestAnimationFrame(() => { frameId = null; if (pending) { callback(...lastArgs); pending = false; } }); } }; const cancel = () => { cancelAnimationFrame(frameId); pending = false; frameId = null; }; return Object.assign(throttled, {cancel}); } function createAsyncTasksQueue() { const tasks = []; let frameId = null; function runTasks() { let task; while ((task = tasks.shift())) { task(); } frameId = null; } function add(task) { tasks.push(task); if (!frameId) { frameId = requestAnimationFrame(runTasks); } } function cancel() { tasks.splice(0); cancelAnimationFrame(frameId); frameId = null; } return {add, cancel}; } const delayTokens = new Set(); function requestAnimationFrameOnce(token, callback) { if (delayTokens.has(token)) { return; } delayTokens.add(token); requestAnimationFrame(() => { delayTokens.delete(token); callback(); }); } function hexify(number) { return (number < 16 ? "0" : "") + number.toString(16); } function generateUID() { if ("randomUUID" in crypto) { const uuid = crypto.randomUUID(); return ( uuid.substring(0, 8) + uuid.substring(9, 13) + uuid.substring(14, 18) + uuid.substring(19, 23) + uuid.substring(24) ); } if ("getRandomValues" in crypto) { return Array.from(crypto.getRandomValues(new Uint8Array(16))) .map((x) => hexify(x)) .join(""); } return Math.floor(Math.random() * 2 ** 55).toString(36); } let documentVisibilityListener = null; let documentIsVisible_ = !document.hidden; const listenerOptions = { capture: true, passive: true }; function watchForDocumentVisibility() { document.addEventListener( "visibilitychange", documentVisibilityListener, listenerOptions ); window.addEventListener( "pageshow", documentVisibilityListener, listenerOptions ); window.addEventListener( "focus", documentVisibilityListener, listenerOptions ); } function stopWatchingForDocumentVisibility() { document.removeEventListener( "visibilitychange", documentVisibilityListener, listenerOptions ); window.removeEventListener( "pageshow", documentVisibilityListener, listenerOptions ); window.removeEventListener( "focus", documentVisibilityListener, listenerOptions ); } function setDocumentVisibilityListener(callback) { const alreadyWatching = Boolean(documentVisibilityListener); documentVisibilityListener = () => { if (!document.hidden) { removeDocumentVisibilityListener(); callback(); documentIsVisible_ = true; } }; if (!alreadyWatching) { watchForDocumentVisibility(); } } function removeDocumentVisibilityListener() { stopWatchingForDocumentVisibility(); documentVisibilityListener = null; } function documentIsVisible() { return documentIsVisible_; } function getDuration(time) { let duration = 0; if (time.seconds) { duration += time.seconds * 1000; } if (time.minutes) { duration += time.minutes * 60 * 1000; } if (time.hours) { duration += time.hours * 60 * 60 * 1000; } if (time.days) { duration += time.days * 24 * 60 * 60 * 1000; } return duration; } function logInfo(...args) {} function logWarn(...args) {} function logAssert(...args) {} function ASSERT(description, condition) { if (!condition) { logAssert(description); } } function removeNode(node) { node && node.parentNode && node.parentNode.removeChild(node); } function watchForNodePosition(node, mode, onRestore = Function.prototype) { const MAX_ATTEMPTS_COUNT = 10; const RETRY_TIMEOUT = getDuration({seconds: 2}); const ATTEMPTS_INTERVAL = getDuration({seconds: 10}); let prevSibling = node.previousSibling; let parent = node.parentNode; if (!parent) { throw new Error( "Unable to watch for node position: parent element not found" ); } if (mode === "prev-sibling" && !prevSibling) { throw new Error( "Unable to watch for node position: there is no previous sibling" ); } let attempts = 0; let start = null; let timeoutId = null; const restore = throttle(() => { if (timeoutId) { return; } attempts++; const now = Date.now(); if (start == null) { start = now; } else if (attempts >= MAX_ATTEMPTS_COUNT) { if (now - start < ATTEMPTS_INTERVAL) { logWarn( `Node position watcher paused: retry in ${RETRY_TIMEOUT}ms`, node, prevSibling ); timeoutId = setTimeout(() => { start = null; attempts = 0; timeoutId = null; restore(); }, RETRY_TIMEOUT); return; } start = now; attempts = 1; } if (mode === "head") { if (prevSibling && prevSibling.parentNode !== parent) { logWarn( "Sibling moved, moving node to the head end", node, prevSibling, parent ); prevSibling = document.head.lastChild; } } if (mode === "prev-sibling") { if (prevSibling.parentNode == null) { logWarn( "Unable to restore node position: sibling was removed", node, prevSibling, parent ); stop(); return; } if (prevSibling.parentNode !== parent) { logWarn( "Style was moved to another parent", node, prevSibling, parent ); updateParent(prevSibling.parentNode); } } if (mode === "head" && !parent.isConnected) { parent = document.head; } logWarn("Restoring node position", node, prevSibling, parent); parent.insertBefore( node, prevSibling && prevSibling.isConnected ? prevSibling.nextSibling : parent.firstChild ); observer.takeRecords(); onRestore && onRestore(); }); const observer = new MutationObserver(() => { if ( (mode === "head" && (node.parentNode !== parent || !node.parentNode.isConnected)) || (mode === "prev-sibling" && node.previousSibling !== prevSibling) ) { restore(); } }); const run = () => { observer.observe(parent, {childList: true}); }; const stop = () => { clearTimeout(timeoutId); observer.disconnect(); restore.cancel(); }; const skip = () => { observer.takeRecords(); }; const updateParent = (parentNode) => { parent = parentNode; stop(); run(); }; run(); return {run, stop, skip}; } function iterateShadowHosts(root, iterator) { if (root == null) { return; } const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, { acceptNode(node) {