From c8046a254fba97dbdb8394c5ae468ea74f0f492d Mon Sep 17 00:00:00 2001 From: Sential Date: Sun, 4 Aug 2019 23:28:33 +0200 Subject: [PATCH] chore: remove unnecessary code --- src/api/index.ts | 46 +- src/background/extension.ts | 40 +- src/background/messenger.ts | 3 +- src/background/user-storage.ts | 218 +++------- src/background/utils/extension-api.ts | 21 - src/definitions.d.ts | 9 - src/generators/css-filter.ts | 393 +++++++++-------- src/generators/static-theme.ts | 578 ++++++++++++++++---------- src/generators/text-style.ts | 20 - src/inject/dynamic-theme/index.ts | 7 +- src/utils/url.ts | 149 +++---- 11 files changed, 709 insertions(+), 775 deletions(-) delete mode 100644 src/generators/text-style.ts diff --git a/src/api/index.ts b/src/api/index.ts index 9a66c0c..407aa96 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,31 +1,35 @@ -import './chrome'; -import {FilterConfig as Theme, DynamicThemeFix} from '../definitions'; -import ThemeEngines from '../generators/theme-engines'; -import {createOrUpdateDynamicTheme, removeDynamicTheme} from '../inject/dynamic-theme'; +import "./chrome"; +import { FilterConfig as Theme, DynamicThemeFix } from "../definitions"; +import ThemeEngines from "../generators/theme-engines"; +import { + createOrUpdateDynamicTheme, + removeDynamicTheme +} from "../inject/dynamic-theme"; const defaultTheme: Theme = { - mode: 1, - brightness: 100, - contrast: 100, - grayscale: 0, - sepia: 0, - useFont: false, - fontFamily: '', - textStroke: 0, - engine: ThemeEngines.dynamicTheme, - stylesheet: '', + mode: 1, + brightness: 100, + contrast: 100, + grayscale: 0, + sepia: 0, + engine: ThemeEngines.dynamicTheme, + stylesheet: "" }; -export function enable(themeOptions: Partial, fixes: DynamicThemeFix = null, isIFrame = false) { - const theme = {...defaultTheme, ...themeOptions}; +export function enable( + themeOptions: Partial, + fixes: DynamicThemeFix = null, + isIFrame = false +) { + const theme = { ...defaultTheme, ...themeOptions }; - if (theme.engine !== ThemeEngines.dynamicTheme) { - throw new Error('Theme engine is not supported'); - } + if (theme.engine !== ThemeEngines.dynamicTheme) { + throw new Error("Theme engine is not supported"); + } - createOrUpdateDynamicTheme(theme, fixes, isIFrame); + createOrUpdateDynamicTheme(theme, fixes, isIFrame); } export function disable() { - removeDynamicTheme(); + removeDynamicTheme(); } diff --git a/src/background/extension.ts b/src/background/extension.ts index 1a44115..021e99f 100644 --- a/src/background/extension.ts +++ b/src/background/extension.ts @@ -3,12 +3,10 @@ import Messenger from "./messenger"; import TabManager from "./tab-manager"; import UserStorage from "./user-storage"; import { - getFontList, getCommands, setShortcut, canInjectScript } from "./utils/extension-api"; -import { isInTimeInterval, getDuration } from "../utils/time"; import { isURLInList, getURLHost, isURLEnabled } from "../utils/url"; import ThemeEngines from "../generators/theme-engines"; import createCSSFilterStylesheet from "../generators/css-filter"; @@ -27,13 +25,10 @@ import { TabInfo } from "../definitions"; -const AUTO_TIME_CHECK_INTERVAL = getDuration({ seconds: 10 }); - export class Extension { ready: boolean; config: ConfigManager; - fonts: string[]; messenger: Messenger; tabs: TabManager; user: UserStorage; @@ -52,14 +47,6 @@ export class Extension { } isEnabled() { - if (this.user.settings.automation === "time") { - const now = new Date(); - return isInTimeInterval( - now, - this.user.settings.time.activation, - this.user.settings.time.deactivation - ); - } return this.user.settings.enabled; } @@ -67,9 +54,7 @@ export class Extension { async start() { await this.config.load({ local: true }); - this.fonts = await getFontList(); - await this.user.loadSettings(); this.changeSettings(this.user.settings); console.log("loaded", this.user.settings); @@ -81,7 +66,6 @@ export class Extension { this.awaiting.forEach(ready => ready()); this.awaiting = null; - this.startAutoTimeCheck(); this.user.cleanup(); } @@ -121,8 +105,7 @@ export class Extension { if (command === "toggle") { console.log("Toggle command entered"); this.changeSettings({ - enabled: !this.isEnabled(), - automation: "" + enabled: !this.isEnabled() }); } if (command === "addSite") { @@ -157,7 +140,6 @@ export class Extension { isEnabled: this.isEnabled(), isReady: this.ready, settings: this.user.settings, - fonts: this.fonts, shortcuts: await this.getShortcuts() }; } @@ -174,25 +156,7 @@ export class Extension { } } - private wasEnabledOnLastCheck: boolean; - - private startAutoTimeCheck() { - setInterval(() => { - if (!this.ready || this.user.settings.automation !== "time") { - return; - } - const isEnabled = this.isEnabled(); - if (this.wasEnabledOnLastCheck !== isEnabled) { - this.wasEnabledOnLastCheck = isEnabled; - this.tabs.sendMessage(this.getTabMessage); - this.reportChanges(); - } - }, AUTO_TIME_CHECK_INTERVAL); - } - changeSettings($settings: Partial) { - const prev = { ...this.user.settings }; - this.user.set($settings); this.onSettingsChanged(); } @@ -239,7 +203,6 @@ export class Extension { return; } - this.wasEnabledOnLastCheck = this.isEnabled(); this.tabs.sendMessage(this.getTabMessage); this.saveUserSettings(); this.reportChanges(); @@ -342,7 +305,6 @@ export class Extension { // User settings private async saveUserSettings() { - await this.user.saveSettings(); console.log("saved", this.user.settings); } } diff --git a/src/background/messenger.ts b/src/background/messenger.ts index fa3ebb5..26e6e0d 100644 --- a/src/background/messenger.ts +++ b/src/background/messenger.ts @@ -33,8 +33,7 @@ export default class Messenger { chrome.runtime.onMessage.addListener(msg => { if (msg.name === "toggle") { this.adapter.changeSettings({ - enabled: msg.toggle, - automation: "" + enabled: msg.toggle }); } }); diff --git a/src/background/user-storage.ts b/src/background/user-storage.ts index 7106b66..16266cd 100644 --- a/src/background/user-storage.ts +++ b/src/background/user-storage.ts @@ -1,177 +1,57 @@ -import {isMacOS, isWindows} from '../utils/platform'; -import ThemeEngines from '../generators/theme-engines'; -import {isURLMatched} from '../utils/url'; -import {UserSettings} from '../definitions'; - -const SAVE_TIMEOUT = 1000; +import ThemeEngines from "../generators/theme-engines"; +import { isURLMatched } from "../utils/url"; +import { UserSettings } from "../definitions"; export default class UserStorage { - private defaultSettings: UserSettings; - - constructor() { - this.defaultSettings = { - enabled: true, - 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: ThemeEngines.dynamicTheme, - stylesheet: '', - }, - customThemes: [], - siteList: [], - applyToListedOnly: false, - changeBrowserTheme: false, - notifyOfNews: false, - syncSettings: true, - automation: '', - time: { - activation: '18:00', - deactivation: '9:00', - }, - }; - this.settings = null; - } - - settings: Readonly; - - async loadSettings() { - this.settings = await this.loadSettingsFromStorage(); - } - - cleanup() { - chrome.storage.local.remove(['activationTime', 'deactivationTime']); - chrome.storage.sync.remove(['activationTime', 'deactivationTime']); - } - - private loadSettingsFromStorage() { - return new Promise((resolve) => { - chrome.storage.local.get(this.defaultSettings, (local: UserSettings) => { - if (!local.syncSettings) { - local.theme = {...this.defaultSettings.theme, ...local.theme}; - local.time = {...this.defaultSettings.time, ...local.time}; - resolve(local); - return; - } - - chrome.storage.sync.get({...this.defaultSettings, config: 'empty'}, ($sync: UserSettings & {config: any}) => { - let sync: UserSettings; - if ($sync.config === 'empty') { - delete $sync.config; - sync = $sync; - } else { - sync = this.migrateSettings_4_6_2($sync) as UserSettings; - } - sync.theme = {...this.defaultSettings.theme, ...sync.theme}; - sync.time = {...this.defaultSettings.time, ...sync.time}; - resolve(sync); - }); - }); - }); - } - - async saveSettings() { - const saved = await this.saveSettingsIntoStorage(this.settings); - this.settings = saved; - } - - private saveSettingsIntoStorage(settings: UserSettings) { - if (this.timeout) { - clearInterval(this.timeout); + constructor() { + this.settings = null; + } + + settings: Readonly = { + enabled: false, + theme: { + mode: 1, + brightness: 100, + contrast: 100, + grayscale: 0, + sepia: 0, + engine: ThemeEngines.dynamicTheme, + stylesheet: "" + }, + customThemes: [], + siteList: [], + applyToListedOnly: false + }; + + cleanup() { + chrome.storage.local.remove(["activationTime", "deactivationTime"]); + chrome.storage.sync.remove(["activationTime", "deactivationTime"]); + } + + set($settings: Partial) { + if ($settings.siteList) { + if (!Array.isArray($settings.siteList)) { + const list = []; + for (let key in $settings.siteList as any) { + const index = Number(key); + if (!isNaN(index)) { + list[index] = $settings.siteList[key]; + } } - return new Promise((resolve) => { - this.timeout = setTimeout(() => { - this.timeout = null; - if (settings.syncSettings) { - chrome.storage.sync.set(settings, () => { - if (chrome.runtime.lastError) { - console.warn('Settings synchronization was disabled due to error:', chrome.runtime.lastError); - const local: UserSettings = {...settings, syncSettings: false}; - chrome.storage.local.set(local, () => resolve(local)); - } else { - resolve(settings); - } - }); - } else { - chrome.storage.local.set(settings, () => resolve(settings)); - } - }, SAVE_TIMEOUT); - }); - } - - private timeout: number = null; - - set($settings: Partial) { - if ($settings.siteList) { - if (!Array.isArray($settings.siteList)) { - const list = []; - for (let key in ($settings.siteList as any)) { - const index = Number(key); - if (!isNaN(index)) { - list[index] = $settings.siteList[key]; - } - } - $settings.siteList = list; - } - const siteList = $settings.siteList.filter((pattern) => { - let isOK = false; - try { - isURLMatched('https://google.com/', pattern); - isOK = true; - } catch (err) { - console.warn(`Pattern "${pattern}" excluded`); - } - return isOK && pattern !== '/'; - }); - $settings = {...$settings, siteList}; - } - this.settings = {...this.settings, ...$settings}; - } - - private migrateSettings_4_6_2(settings_4_6_2: any) { - function migrateTheme(filterConfig_4_6_2: any) { - const f = filterConfig_4_6_2; - return { - mode: f.mode, - brightness: f.brightness, - contrast: f.contrast, - grayscale: f.grayscale, - sepia: f.sepia, - useFont: f.useFont, - fontFamily: f.fontFamily, - textStroke: f.textStroke, - engine: f.engine, - stylesheet: f.stylesheet, - }; - } - + $settings.siteList = list; + } + const siteList = $settings.siteList.filter(pattern => { + let isOK = false; try { - const s = settings_4_6_2; - const settings: UserSettings = { - ...this.defaultSettings, - enabled: s.enabled, - theme: migrateTheme(s.config), - customThemes: s.config.custom ? s.config.custom.map((c) => { - return { - url: c.url, - theme: migrateTheme(c.config), - }; - }) : [], - siteList: s.config.siteList, - applyToListedOnly: s.config.invertListed, - changeBrowserTheme: s.config.changeBrowserTheme, - }; - chrome.storage.sync.remove('config'); - chrome.storage.sync.set(settings); - return settings; + isURLMatched("https://google.com/", pattern); + isOK = true; } catch (err) { - console.error('Settings migration error:', err, 'Loaded settings:', settings_4_6_2); - return this.defaultSettings; + console.warn(`Pattern "${pattern}" excluded`); } + return isOK && pattern !== "/"; + }); + $settings = { ...$settings, siteList }; } + this.settings = { ...this.settings, ...$settings }; + } } diff --git a/src/background/utils/extension-api.ts b/src/background/utils/extension-api.ts index e44aa9b..d2f4988 100644 --- a/src/background/utils/extension-api.ts +++ b/src/background/utils/extension-api.ts @@ -12,27 +12,6 @@ export function canInjectScript(url: string) { ); } -export function getFontList() { - return new Promise(resolve => { - if (!chrome.fontSettings) { - // Todo: Remove it as soon as Firefox and Edge get support. - resolve([ - "serif", - "sans-serif", - "monospace", - "cursive", - "fantasy", - "system-ui" - ]); - return; - } - chrome.fontSettings.getFontList(list => { - const fonts = list.map(f => f.fontId); - resolve(fonts); - }); - }); -} - export function getCommands() { return new Promise(resolve => { if (!chrome.commands) { diff --git a/src/definitions.d.ts b/src/definitions.d.ts index add3d21..16ec810 100644 --- a/src/definitions.d.ts +++ b/src/definitions.d.ts @@ -4,7 +4,6 @@ export interface ExtensionData { isEnabled: boolean; isReady: boolean; settings: UserSettings; - fonts: string[]; shortcuts: Shortcuts; } @@ -33,9 +32,6 @@ export interface FilterConfig { contrast: number; grayscale: number; sepia: number; - useFont: boolean; - fontFamily: string; - textStroke: number; engine: string; stylesheet: string; } @@ -51,11 +47,6 @@ export interface UserSettings { customThemes: CustomSiteConfig[]; siteList: string[]; applyToListedOnly: boolean; - changeBrowserTheme: boolean; - notifyOfNews: boolean; - syncSettings: boolean; - automation: string; - time: TimeSettings; } export interface TimeSettings { diff --git a/src/generators/css-filter.ts b/src/generators/css-filter.ts index 4b6c7b7..65089da 100644 --- a/src/generators/css-filter.ts +++ b/src/generators/css-filter.ts @@ -1,233 +1,258 @@ -import {formatSitesFixesConfig} from './utils/format'; -import {applyColorMatrix, createFilterMatrix} from './utils/matrix'; -import {parseSitesFixesConfig} from './utils/parse'; -import {parseArray, formatArray} from '../utils/text'; -import {compareURLPatterns, isURLInList} from '../utils/url'; -import {createTextStyle} from './text-style'; -import {FilterConfig, InversionFix} from '../definitions'; +import { formatSitesFixesConfig } from "./utils/format"; +import { applyColorMatrix, createFilterMatrix } from "./utils/matrix"; +import { parseSitesFixesConfig } from "./utils/parse"; +import { parseArray, formatArray } from "../utils/text"; +import { compareURLPatterns, isURLInList } from "../utils/url"; +import { FilterConfig, InversionFix } from "../definitions"; export enum FilterMode { - light = 0, - dark = 1 + light = 0, + dark = 1 } -export default function createCSSFilterStyleheet(config: FilterConfig, url: string, frameURL: string, inversionFixes: InversionFix[]) { - const filterValue = getCSSFilterValue(config); - const reverseFilterValue = 'invert(100%) hue-rotate(180deg)'; - return cssFilterStyleheetTemplate(filterValue, reverseFilterValue, config, url, frameURL, inversionFixes); +export default function createCSSFilterStyleheet( + config: FilterConfig, + url: string, + frameURL: string, + inversionFixes: InversionFix[] +) { + const filterValue = getCSSFilterValue(config); + const reverseFilterValue = "invert(100%) hue-rotate(180deg)"; + return cssFilterStyleheetTemplate( + filterValue, + reverseFilterValue, + config, + url, + frameURL, + inversionFixes + ); } -export function cssFilterStyleheetTemplate(filterValue: string, reverseFilterValue: string, config: FilterConfig, url: string, frameURL: string, inversionFixes: InversionFix[]) { - const fix = getInversionFixesFor(frameURL || url, inversionFixes); +export function cssFilterStyleheetTemplate( + filterValue: string, + reverseFilterValue: string, + config: FilterConfig, + url: string, + frameURL: string, + inversionFixes: InversionFix[] +) { + const fix = getInversionFixesFor(frameURL || url, inversionFixes); - const lines: string[] = []; + const lines: string[] = []; - lines.push('@media screen {'); + lines.push("@media screen {"); - // Add leading rule - if (filterValue && !frameURL) { - lines.push(''); - lines.push('/* Leading rule */'); - lines.push(createLeadingRule(filterValue)); - } + // Add leading rule + if (filterValue && !frameURL) { + lines.push(""); + lines.push("/* Leading rule */"); + lines.push(createLeadingRule(filterValue)); + } - if (config.mode === FilterMode.dark) { - // Add reverse rule - lines.push(''); - lines.push('/* Reverse rule */'); - lines.push(createReverseRule(reverseFilterValue, fix)); - } + if (config.mode === FilterMode.dark) { + // Add reverse rule + lines.push(""); + lines.push("/* Reverse rule */"); + lines.push(createReverseRule(reverseFilterValue, fix)); + } - if (config.useFont || config.textStroke > 0) { - // Add text rule - lines.push(''); - lines.push('/* Font */'); - lines.push(createTextStyle(config)); - } + // Fix bad font hinting after inversion + lines.push(""); + lines.push("/* Text contrast */"); + lines.push("html {"); + lines.push(" text-shadow: 0 0 0 !important;"); + lines.push("}"); - // Fix bad font hinting after inversion - lines.push(''); - lines.push('/* Text contrast */'); - lines.push('html {'); - lines.push(' text-shadow: 0 0 0 !important;'); - lines.push('}'); - - // Full screen fix - lines.push(''); - lines.push('/* Full screen */'); - [':-webkit-full-screen', ':-moz-full-screen', ':fullscreen'].forEach((fullScreen) => { - lines.push(`${fullScreen}, ${fullScreen} * {`); - lines.push(' -webkit-filter: none !important;'); - lines.push(' filter: none !important;'); - lines.push('}'); - }); - - if (!frameURL) { - const [r, g, b] = applyColorMatrix([255, 255, 255], createFilterMatrix(config)); - const bgColor = { - r: Math.round(r), - g: Math.round(g), - b: Math.round(b), - toString() { - return `rgb(${this.r},${this.g},${this.b})`; - }, - }; - lines.push(''); - lines.push('/* Page background */'); - lines.push('html {'); - lines.push(` background: ${bgColor} !important;`); - lines.push('}'); + // Full screen fix + lines.push(""); + lines.push("/* Full screen */"); + [":-webkit-full-screen", ":-moz-full-screen", ":fullscreen"].forEach( + fullScreen => { + lines.push(`${fullScreen}, ${fullScreen} * {`); + lines.push(" -webkit-filter: none !important;"); + lines.push(" filter: none !important;"); + lines.push("}"); } + ); - if (fix.css && fix.css.length > 0 && config.mode === FilterMode.dark) { - lines.push(''); - lines.push('/* Custom rules */'); - lines.push(fix.css); - } + if (!frameURL) { + const [r, g, b] = applyColorMatrix( + [255, 255, 255], + createFilterMatrix(config) + ); + const bgColor = { + r: Math.round(r), + g: Math.round(g), + b: Math.round(b), + toString() { + return `rgb(${this.r},${this.g},${this.b})`; + } + }; + lines.push(""); + lines.push("/* Page background */"); + lines.push("html {"); + lines.push(` background: ${bgColor} !important;`); + lines.push("}"); + } - lines.push(''); - lines.push('}'); + if (fix.css && fix.css.length > 0 && config.mode === FilterMode.dark) { + lines.push(""); + lines.push("/* Custom rules */"); + lines.push(fix.css); + } - return lines.join('\n'); + lines.push(""); + lines.push("}"); + + return lines.join("\n"); } export function getCSSFilterValue(config: FilterConfig) { - const filters: string[] = []; + const filters: string[] = []; - 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 (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; - } + if (filters.length === 0) { + return null; + } - return filters.join(' '); + return filters.join(" "); } function createLeadingRule(filterValue: string): string { - return [ - 'html {', - ` -webkit-filter: ${filterValue} !important;`, - ` filter: ${filterValue} !important;`, - '}' - ].join('\n'); + return [ + "html {", + ` -webkit-filter: ${filterValue} !important;`, + ` filter: ${filterValue} !important;`, + "}" + ].join("\n"); } function joinSelectors(selectors: string[]) { - return selectors.map((s) => s.replace(/\,$/, '')).join(',\n'); + return selectors.map(s => s.replace(/\,$/, "")).join(",\n"); } -function createReverseRule(reverseFilterValue: string, fix: InversionFix): string { - const lines: string[] = []; +function createReverseRule( + reverseFilterValue: string, + fix: InversionFix +): string { + const lines: string[] = []; - if (fix.invert.length > 0) { - lines.push(`${joinSelectors(fix.invert)} {`); - lines.push(` -webkit-filter: ${reverseFilterValue} !important;`); - lines.push(` filter: ${reverseFilterValue} !important;`); - lines.push('}'); - } + if (fix.invert.length > 0) { + lines.push(`${joinSelectors(fix.invert)} {`); + lines.push(` -webkit-filter: ${reverseFilterValue} !important;`); + lines.push(` filter: ${reverseFilterValue} !important;`); + lines.push("}"); + } - if (fix.noinvert.length > 0) { - lines.push(`${joinSelectors(fix.noinvert)} {`); - lines.push(' -webkit-filter: none !important;'); - lines.push(' filter: none !important;'); - lines.push('}'); - } + if (fix.noinvert.length > 0) { + lines.push(`${joinSelectors(fix.noinvert)} {`); + lines.push(" -webkit-filter: none !important;"); + lines.push(" filter: none !important;"); + lines.push("}"); + } - if (fix.removebg.length > 0) { - lines.push(`${joinSelectors(fix.removebg)} {`); - lines.push(' background: white !important;'); - lines.push('}'); - } + if (fix.removebg.length > 0) { + lines.push(`${joinSelectors(fix.removebg)} {`); + lines.push(" background: white !important;"); + lines.push("}"); + } - return lines.join('\n'); + return lines.join("\n"); } /** -* Returns fixes for a given URL. -* If no matches found, common fixes will be returned. -* @param url Site URL. -* @param inversionFixes List of inversion fixes. -*/ -export function getInversionFixesFor(url: string, inversionFixes: InversionFix[]): InversionFix { - const common = { - url: inversionFixes[0].url, - invert: inversionFixes[0].invert || [], - noinvert: inversionFixes[0].noinvert || [], - removebg: inversionFixes[0].removebg || [], - css: inversionFixes[0].css || '', - }; + * Returns fixes for a given URL. + * If no matches found, common fixes will be returned. + * @param url Site URL. + * @param inversionFixes List of inversion fixes. + */ +export function getInversionFixesFor( + url: string, + inversionFixes: InversionFix[] +): InversionFix { + const common = { + url: inversionFixes[0].url, + invert: inversionFixes[0].invert || [], + noinvert: inversionFixes[0].noinvert || [], + removebg: inversionFixes[0].removebg || [], + css: inversionFixes[0].css || "" + }; - if (url) { - // Search for match with given URL - const matches = inversionFixes - .slice(1) - .filter((s) => isURLInList(url, s.url)) - .sort((a, b) => b.url[0].length - a.url[0].length); - if (matches.length > 0) { - const found = matches[0]; - return { - url: found.url, - invert: common.invert.concat(found.invert || []), - noinvert: common.noinvert.concat(found.noinvert || []), - removebg: common.removebg.concat(found.removebg || []), - css: [common.css, found.css].filter((s) => s).join('\n'), - }; - } + if (url) { + // Search for match with given URL + const matches = inversionFixes + .slice(1) + .filter(s => isURLInList(url, s.url)) + .sort((a, b) => b.url[0].length - a.url[0].length); + if (matches.length > 0) { + const found = matches[0]; + return { + url: found.url, + invert: common.invert.concat(found.invert || []), + noinvert: common.noinvert.concat(found.noinvert || []), + removebg: common.removebg.concat(found.removebg || []), + css: [common.css, found.css].filter(s => s).join("\n") + }; } - return common; + } + return common; } const inversionFixesCommands = { - 'INVERT': 'invert', - 'NO INVERT': 'noinvert', - 'REMOVE BG': 'removebg', - 'CSS': 'css', + INVERT: "invert", + "NO INVERT": "noinvert", + "REMOVE BG": "removebg", + CSS: "css" }; export function parseInversionFixes(text: string) { - return parseSitesFixesConfig(text, { - commands: Object.keys(inversionFixesCommands), - getCommandPropName: (command) => inversionFixesCommands[command] || null, - parseCommandValue: (command, value) => { - if (command === 'CSS') { - return value.trim(); - } - return parseArray(value); - }, - }); + return parseSitesFixesConfig(text, { + commands: Object.keys(inversionFixesCommands), + getCommandPropName: command => inversionFixesCommands[command] || null, + parseCommandValue: (command, value) => { + if (command === "CSS") { + return value.trim(); + } + return parseArray(value); + } + }); } export function formatInversionFixes(inversionFixes: InversionFix[]) { - const fixes = inversionFixes.slice().sort((a, b) => compareURLPatterns(a.url[0], b.url[0])); - - return formatSitesFixesConfig(fixes, { - props: Object.values(inversionFixesCommands), - getPropCommandName: (prop) => Object.entries(inversionFixesCommands).find(([, p]) => p === prop)[0], - formatPropValue: (prop, value) => { - if (prop === 'css') { - return value.trim(); - } - return formatArray(value).trim(); - }, - shouldIgnoreProp: (prop, value) => { - if (prop === 'css') { - return !value; - } - return !(Array.isArray(value) && value.length > 0); - } - }); + const fixes = inversionFixes + .slice() + .sort((a, b) => compareURLPatterns(a.url[0], b.url[0])); + + return formatSitesFixesConfig(fixes, { + props: Object.values(inversionFixesCommands), + getPropCommandName: prop => + Object.entries(inversionFixesCommands).find(([, p]) => p === prop)[0], + formatPropValue: (prop, value) => { + if (prop === "css") { + return value.trim(); + } + return formatArray(value).trim(); + }, + shouldIgnoreProp: (prop, value) => { + if (prop === "css") { + return !value; + } + return !(Array.isArray(value) && value.length > 0); + } + }); } diff --git a/src/generators/static-theme.ts b/src/generators/static-theme.ts index 9d4be03..3e95d51 100644 --- a/src/generators/static-theme.ts +++ b/src/generators/static-theme.ts @@ -1,282 +1,398 @@ -import {isURLInList} from '../utils/url'; -import {createTextStyle} from './text-style'; -import {formatSitesFixesConfig} from './utils/format'; -import {applyColorMatrix, createFilterMatrix} from './utils/matrix'; -import {parseSitesFixesConfig} from './utils/parse'; -import {parseArray, formatArray} from '../utils/text'; -import {compareURLPatterns} from '../utils/url'; -import {FilterConfig, StaticTheme} from '../definitions'; +import { isURLInList } from "../utils/url"; +import { formatSitesFixesConfig } from "./utils/format"; +import { applyColorMatrix, createFilterMatrix } from "./utils/matrix"; +import { parseSitesFixesConfig } from "./utils/parse"; +import { parseArray, formatArray } from "../utils/text"; +import { compareURLPatterns } from "../utils/url"; +import { FilterConfig, StaticTheme } from "../definitions"; interface ThemeColors { - [prop: string]: number[]; - neutralBg: number[]; - neutralText: number[]; - redBg: number[]; - redText: number[]; - greenBg: number[]; - greenText: number[]; - blueBg: number[]; - blueText: number[]; - fadeBg: number[]; - fadeText: number[]; + [prop: string]: number[]; + neutralBg: number[]; + neutralText: number[]; + redBg: number[]; + redText: number[]; + greenBg: number[]; + greenText: number[]; + blueBg: number[]; + blueText: number[]; + fadeBg: number[]; + fadeText: number[]; } const darkTheme: ThemeColors = { - neutralBg: [16, 20, 23], - neutralText: [167, 158, 139], - redBg: [64, 12, 32], - redText: [247, 142, 102], - greenBg: [32, 64, 48], - greenText: [128, 204, 148], - blueBg: [32, 48, 64], - blueText: [128, 182, 204], - fadeBg: [16, 20, 23, 0.5], - fadeText: [167, 158, 139, 0.5], + neutralBg: [16, 20, 23], + neutralText: [167, 158, 139], + redBg: [64, 12, 32], + redText: [247, 142, 102], + greenBg: [32, 64, 48], + greenText: [128, 204, 148], + blueBg: [32, 48, 64], + blueText: [128, 182, 204], + fadeBg: [16, 20, 23, 0.5], + fadeText: [167, 158, 139, 0.5] }; const lightTheme: ThemeColors = { - neutralBg: [255, 242, 228], - neutralText: [0, 0, 0], - redBg: [255, 85, 170], - redText: [140, 14, 48], - greenBg: [192, 255, 170], - greenText: [0, 128, 0], - blueBg: [173, 215, 229], - blueText: [28, 16, 171], - fadeBg: [0, 0, 0, 0.5], - fadeText: [0, 0, 0, 0.5], + neutralBg: [255, 242, 228], + neutralText: [0, 0, 0], + redBg: [255, 85, 170], + redText: [140, 14, 48], + greenBg: [192, 255, 170], + greenText: [0, 128, 0], + blueBg: [173, 215, 229], + blueText: [28, 16, 171], + fadeBg: [0, 0, 0, 0.5], + fadeText: [0, 0, 0, 0.5] }; function rgb([r, g, b, a]: number[]) { - if (typeof a === 'number') { - return `rgba(${r}, ${g}, ${b}, ${a})`; - } - return `rgb(${r}, ${g}, ${b})`; + if (typeof a === "number") { + return `rgba(${r}, ${g}, ${b}, ${a})`; + } + return `rgb(${r}, ${g}, ${b})`; } function mix(color1: number[], color2: number[], t: number) { - return color1.map((c, i) => Math.round(c * (1 - t) + color2[i] * t)); + return color1.map((c, i) => Math.round(c * (1 - t) + color2[i] * t)); } -export default function createStaticStylesheet(config: FilterConfig, url: string, frameURL: string, staticThemes: StaticTheme[]) { - const srcTheme = config.mode === 1 ? darkTheme : lightTheme; - const theme = Object.entries(srcTheme).reduce((t, [prop, color]) => { - t[prop] = applyColorMatrix(color, createFilterMatrix({...config, mode: 0})); - return t; - }, {} as ThemeColors); +export default function createStaticStylesheet( + config: FilterConfig, + url: string, + frameURL: string, + staticThemes: StaticTheme[] +) { + const srcTheme = config.mode === 1 ? darkTheme : lightTheme; + const theme = Object.entries(srcTheme).reduce( + (t, [prop, color]) => { + t[prop] = applyColorMatrix( + color, + createFilterMatrix({ ...config, mode: 0 }) + ); + return t; + }, + {} as ThemeColors + ); - const commonTheme = getCommonTheme(staticThemes); - const siteTheme = getThemeFor(frameURL || url, staticThemes); + const commonTheme = getCommonTheme(staticThemes); + const siteTheme = getThemeFor(frameURL || url, staticThemes); - const lines: string[] = []; - - if (!siteTheme || !siteTheme.noCommon) { - lines.push('/* Common theme */'); - lines.push(...ruleGenerators.map((gen) => gen(commonTheme, theme))); - } + const lines: string[] = []; - if (siteTheme) { - lines.push(`/* Theme for ${siteTheme.url.join(' ')} */`); - lines.push(...ruleGenerators.map((gen) => gen(siteTheme, theme))); - } + if (!siteTheme || !siteTheme.noCommon) { + lines.push("/* Common theme */"); + lines.push(...ruleGenerators.map(gen => gen(commonTheme, theme))); + } - if (config.useFont || config.textStroke > 0) { - lines.push('/* Font */'); - lines.push(createTextStyle(config)); - } + if (siteTheme) { + lines.push(`/* Theme for ${siteTheme.url.join(" ")} */`); + lines.push(...ruleGenerators.map(gen => gen(siteTheme, theme))); + } - return lines - .filter((ln) => ln) - .join('\n'); + return lines.filter(ln => ln).join("\n"); } -function createRuleGen(getSelectors: (siteTheme: StaticTheme) => string[], generateDeclarations: (theme: ThemeColors) => string[], modifySelector: ((s: string) => string) = (s) => s) { - return (siteTheme: StaticTheme, themeColors: ThemeColors) => { - const selectors = getSelectors(siteTheme); - if (selectors == null || selectors.length === 0) { - return null; - } - const lines: string[] = []; - selectors.forEach((s, i) => { - let ln = modifySelector(s); - if (i < selectors.length - 1) { - ln += ',' - } else { - ln += ' {'; - } - lines.push(ln); - }); - const declarations = generateDeclarations(themeColors); - declarations.forEach((d) => lines.push(` ${d} !important;`)); - lines.push('}'); - return lines.join('\n'); - }; +function createRuleGen( + getSelectors: (siteTheme: StaticTheme) => string[], + generateDeclarations: (theme: ThemeColors) => string[], + modifySelector: (s: string) => string = s => s +) { + return (siteTheme: StaticTheme, themeColors: ThemeColors) => { + const selectors = getSelectors(siteTheme); + if (selectors == null || selectors.length === 0) { + return null; + } + const lines: string[] = []; + selectors.forEach((s, i) => { + let ln = modifySelector(s); + if (i < selectors.length - 1) { + ln += ","; + } else { + ln += " {"; + } + lines.push(ln); + }); + const declarations = generateDeclarations(themeColors); + declarations.forEach(d => lines.push(` ${d} !important;`)); + lines.push("}"); + return lines.join("\n"); + }; } const mx = { - bg: { - hover: 0.075, - active: 0.1, - }, - fg: { - hover: 0.25, - active: 0.5, - }, - border: 0.5, + bg: { + hover: 0.075, + active: 0.1 + }, + fg: { + hover: 0.25, + active: 0.5 + }, + border: 0.5 }; const ruleGenerators = [ - createRuleGen((t) => t.neutralBg, (t) => [`background-color: ${rgb(t.neutralBg)}`]), - createRuleGen((t) => t.neutralBgActive, (t) => [`background-color: ${rgb(t.neutralBg)}`]), - createRuleGen((t) => t.neutralBgActive, (t) => [`background-color: ${rgb(mix(t.neutralBg, [255, 255, 255], mx.bg.hover))}`], (s) => `${s}:hover`), - createRuleGen((t) => t.neutralBgActive, (t) => [`background-color: ${rgb(mix(t.neutralBg, [255, 255, 255], mx.bg.active))}`], (s) => `${s}:active, ${s}:focus`), - createRuleGen((t) => t.neutralText, (t) => [`color: ${rgb(t.neutralText)}`]), - createRuleGen((t) => t.neutralTextActive, (t) => [`color: ${rgb(t.neutralText)}`]), - createRuleGen((t) => t.neutralTextActive, (t) => [`color: ${rgb(mix(t.neutralText, [255, 255, 255], mx.fg.hover))}`], (s) => `${s}:hover`), - createRuleGen((t) => t.neutralTextActive, (t) => [`color: ${rgb(mix(t.neutralText, [255, 255, 255], mx.fg.active))}`], (s) => `${s}:active, ${s}:focus`), - createRuleGen((t) => t.neutralBorder, (t) => [`border-color: ${rgb(mix(t.neutralBg, t.neutralText, mx.border))}`]), - - createRuleGen((t) => t.redBg, (t) => [`background-color: ${rgb(t.redBg)}`]), - createRuleGen((t) => t.redBgActive, (t) => [`background-color: ${rgb(t.redBg)}`]), - createRuleGen((t) => t.redBgActive, (t) => [`background-color: ${rgb(mix(t.redBg, [255, 0, 64], mx.bg.hover))}`], (s) => `${s}:hover`), - createRuleGen((t) => t.redBgActive, (t) => [`background-color: ${rgb(mix(t.redBg, [255, 0, 64], mx.bg.active))}`], (s) => `${s}:active, ${s}:focus`), - createRuleGen((t) => t.redText, (t) => [`color: ${rgb(t.redText)}`]), - createRuleGen((t) => t.redTextActive, (t) => [`color: ${rgb(t.redText)}`]), - createRuleGen((t) => t.redTextActive, (t) => [`color: ${rgb(mix(t.redText, [255, 255, 0], mx.fg.hover))}`], (s) => `${s}:hover`), - createRuleGen((t) => t.redTextActive, (t) => [`color: ${rgb(mix(t.redText, [255, 255, 0], mx.fg.active))}`], (s) => `${s}:active, ${s}:focus`), - createRuleGen((t) => t.redBorder, (t) => [`border-color: ${rgb(mix(t.redBg, t.redText, mx.border))}`]), - - createRuleGen((t) => t.greenBg, (t) => [`background-color: ${rgb(t.greenBg)}`]), - createRuleGen((t) => t.greenBgActive, (t) => [`background-color: ${rgb(t.greenBg)}`]), - createRuleGen((t) => t.greenBgActive, (t) => [`background-color: ${rgb(mix(t.greenBg, [128, 255, 182], mx.bg.hover))}`], (s) => `${s}:hover`), - createRuleGen((t) => t.greenBgActive, (t) => [`background-color: ${rgb(mix(t.greenBg, [128, 255, 182], mx.bg.active))}`], (s) => `${s}:active, ${s}:focus`), - createRuleGen((t) => t.greenText, (t) => [`color: ${rgb(t.greenText)}`]), - createRuleGen((t) => t.greenTextActive, (t) => [`color: ${rgb(t.greenText)}`]), - createRuleGen((t) => t.greenTextActive, (t) => [`color: ${rgb(mix(t.greenText, [182, 255, 224], mx.fg.hover))}`], (s) => `${s}:hover`), - createRuleGen((t) => t.greenTextActive, (t) => [`color: ${rgb(mix(t.greenText, [182, 255, 224], mx.fg.active))}`], (s) => `${s}:active, ${s}:focus`), - createRuleGen((t) => t.greenBorder, (t) => [`border-color: ${rgb(mix(t.greenBg, t.greenText, mx.border))}`]), - - createRuleGen((t) => t.blueBg, (t) => [`background-color: ${rgb(t.blueBg)}`]), - createRuleGen((t) => t.blueBgActive, (t) => [`background-color: ${rgb(t.blueBg)}`]), - createRuleGen((t) => t.blueBgActive, (t) => [`background-color: ${rgb(mix(t.blueBg, [0, 128, 255], mx.bg.hover))}`], (s) => `${s}:hover`), - createRuleGen((t) => t.blueBgActive, (t) => [`background-color: ${rgb(mix(t.blueBg, [0, 128, 255], mx.bg.active))}`], (s) => `${s}:active, ${s}:focus`), - createRuleGen((t) => t.blueText, (t) => [`color: ${rgb(t.blueText)}`]), - createRuleGen((t) => t.blueTextActive, (t) => [`color: ${rgb(t.blueText)}`]), - createRuleGen((t) => t.blueTextActive, (t) => [`color: ${rgb(mix(t.blueText, [182, 224, 255], mx.fg.hover))}`], (s) => `${s}:hover`), - createRuleGen((t) => t.blueTextActive, (t) => [`color: ${rgb(mix(t.blueText, [182, 224, 255], mx.fg.active))}`], (s) => `${s}:active, ${s}:focus`), - createRuleGen((t) => t.blueBorder, (t) => [`border-color: ${rgb(mix(t.blueBg, t.blueText, mx.border))}`]), - - createRuleGen((t) => t.fadeBg, (t) => [`background-color: ${rgb(t.fadeBg)}`]), - createRuleGen((t) => t.fadeText, (t) => [`color: ${rgb(t.fadeText)}`]), - createRuleGen((t) => t.transparentBg, () => ['background-color: transparent']), - createRuleGen((t) => t.noImage, () => ['background-image: none']), - createRuleGen((t) => t.invert, () => ['filter: invert(100%) hue-rotate(180deg)']), + createRuleGen( + t => t.neutralBg, + t => [`background-color: ${rgb(t.neutralBg)}`] + ), + createRuleGen( + t => t.neutralBgActive, + t => [`background-color: ${rgb(t.neutralBg)}`] + ), + createRuleGen( + t => t.neutralBgActive, + t => [ + `background-color: ${rgb(mix(t.neutralBg, [255, 255, 255], mx.bg.hover))}` + ], + s => `${s}:hover` + ), + createRuleGen( + t => t.neutralBgActive, + t => [ + `background-color: ${rgb( + mix(t.neutralBg, [255, 255, 255], mx.bg.active) + )}` + ], + s => `${s}:active, ${s}:focus` + ), + createRuleGen(t => t.neutralText, t => [`color: ${rgb(t.neutralText)}`]), + createRuleGen( + t => t.neutralTextActive, + t => [`color: ${rgb(t.neutralText)}`] + ), + createRuleGen( + t => t.neutralTextActive, + t => [`color: ${rgb(mix(t.neutralText, [255, 255, 255], mx.fg.hover))}`], + s => `${s}:hover` + ), + createRuleGen( + t => t.neutralTextActive, + t => [`color: ${rgb(mix(t.neutralText, [255, 255, 255], mx.fg.active))}`], + s => `${s}:active, ${s}:focus` + ), + createRuleGen( + t => t.neutralBorder, + t => [`border-color: ${rgb(mix(t.neutralBg, t.neutralText, mx.border))}`] + ), + + createRuleGen(t => t.redBg, t => [`background-color: ${rgb(t.redBg)}`]), + createRuleGen(t => t.redBgActive, t => [`background-color: ${rgb(t.redBg)}`]), + createRuleGen( + t => t.redBgActive, + t => [`background-color: ${rgb(mix(t.redBg, [255, 0, 64], mx.bg.hover))}`], + s => `${s}:hover` + ), + createRuleGen( + t => t.redBgActive, + t => [`background-color: ${rgb(mix(t.redBg, [255, 0, 64], mx.bg.active))}`], + s => `${s}:active, ${s}:focus` + ), + createRuleGen(t => t.redText, t => [`color: ${rgb(t.redText)}`]), + createRuleGen(t => t.redTextActive, t => [`color: ${rgb(t.redText)}`]), + createRuleGen( + t => t.redTextActive, + t => [`color: ${rgb(mix(t.redText, [255, 255, 0], mx.fg.hover))}`], + s => `${s}:hover` + ), + createRuleGen( + t => t.redTextActive, + t => [`color: ${rgb(mix(t.redText, [255, 255, 0], mx.fg.active))}`], + s => `${s}:active, ${s}:focus` + ), + createRuleGen( + t => t.redBorder, + t => [`border-color: ${rgb(mix(t.redBg, t.redText, mx.border))}`] + ), + + createRuleGen(t => t.greenBg, t => [`background-color: ${rgb(t.greenBg)}`]), + createRuleGen( + t => t.greenBgActive, + t => [`background-color: ${rgb(t.greenBg)}`] + ), + createRuleGen( + t => t.greenBgActive, + t => [ + `background-color: ${rgb(mix(t.greenBg, [128, 255, 182], mx.bg.hover))}` + ], + s => `${s}:hover` + ), + createRuleGen( + t => t.greenBgActive, + t => [ + `background-color: ${rgb(mix(t.greenBg, [128, 255, 182], mx.bg.active))}` + ], + s => `${s}:active, ${s}:focus` + ), + createRuleGen(t => t.greenText, t => [`color: ${rgb(t.greenText)}`]), + createRuleGen(t => t.greenTextActive, t => [`color: ${rgb(t.greenText)}`]), + createRuleGen( + t => t.greenTextActive, + t => [`color: ${rgb(mix(t.greenText, [182, 255, 224], mx.fg.hover))}`], + s => `${s}:hover` + ), + createRuleGen( + t => t.greenTextActive, + t => [`color: ${rgb(mix(t.greenText, [182, 255, 224], mx.fg.active))}`], + s => `${s}:active, ${s}:focus` + ), + createRuleGen( + t => t.greenBorder, + t => [`border-color: ${rgb(mix(t.greenBg, t.greenText, mx.border))}`] + ), + + createRuleGen(t => t.blueBg, t => [`background-color: ${rgb(t.blueBg)}`]), + createRuleGen( + t => t.blueBgActive, + t => [`background-color: ${rgb(t.blueBg)}`] + ), + createRuleGen( + t => t.blueBgActive, + t => [ + `background-color: ${rgb(mix(t.blueBg, [0, 128, 255], mx.bg.hover))}` + ], + s => `${s}:hover` + ), + createRuleGen( + t => t.blueBgActive, + t => [ + `background-color: ${rgb(mix(t.blueBg, [0, 128, 255], mx.bg.active))}` + ], + s => `${s}:active, ${s}:focus` + ), + createRuleGen(t => t.blueText, t => [`color: ${rgb(t.blueText)}`]), + createRuleGen(t => t.blueTextActive, t => [`color: ${rgb(t.blueText)}`]), + createRuleGen( + t => t.blueTextActive, + t => [`color: ${rgb(mix(t.blueText, [182, 224, 255], mx.fg.hover))}`], + s => `${s}:hover` + ), + createRuleGen( + t => t.blueTextActive, + t => [`color: ${rgb(mix(t.blueText, [182, 224, 255], mx.fg.active))}`], + s => `${s}:active, ${s}:focus` + ), + createRuleGen( + t => t.blueBorder, + t => [`border-color: ${rgb(mix(t.blueBg, t.blueText, mx.border))}`] + ), + + createRuleGen(t => t.fadeBg, t => [`background-color: ${rgb(t.fadeBg)}`]), + createRuleGen(t => t.fadeText, t => [`color: ${rgb(t.fadeText)}`]), + createRuleGen(t => t.transparentBg, () => ["background-color: transparent"]), + createRuleGen(t => t.noImage, () => ["background-image: none"]), + createRuleGen( + t => t.invert, + () => ["filter: invert(100%) hue-rotate(180deg)"] + ) ]; const staticThemeCommands = [ - 'NO COMMON', - - 'NEUTRAL BG', - 'NEUTRAL BG ACTIVE', - 'NEUTRAL TEXT', - 'NEUTRAL TEXT ACTIVE', - 'NEUTRAL BORDER', - - 'RED BG', - 'RED BG ACTIVE', - 'RED TEXT', - 'RED TEXT ACTIVE', - 'RED BORDER', - - 'GREEN BG', - 'GREEN BG ACTIVE', - 'GREEN TEXT', - 'GREEN TEXT ACTIVE', - 'GREEN BORDER', - - 'BLUE BG', - 'BLUE BG ACTIVE', - 'BLUE TEXT', - 'BLUE TEXT ACTIVE', - 'BLUE BORDER', - - 'FADE BG', - 'FADE TEXT', - 'TRANSPARENT BG', - - 'NO IMAGE', - 'INVERT', + "NO COMMON", + + "NEUTRAL BG", + "NEUTRAL BG ACTIVE", + "NEUTRAL TEXT", + "NEUTRAL TEXT ACTIVE", + "NEUTRAL BORDER", + + "RED BG", + "RED BG ACTIVE", + "RED TEXT", + "RED TEXT ACTIVE", + "RED BORDER", + + "GREEN BG", + "GREEN BG ACTIVE", + "GREEN TEXT", + "GREEN TEXT ACTIVE", + "GREEN BORDER", + + "BLUE BG", + "BLUE BG ACTIVE", + "BLUE TEXT", + "BLUE TEXT ACTIVE", + "BLUE BORDER", + + "FADE BG", + "FADE TEXT", + "TRANSPARENT BG", + + "NO IMAGE", + "INVERT" ]; function upperCaseToCamelCase(text: string) { - return text - .split(' ') - .map((word, i) => { - return (i === 0 - ? word.toLowerCase() - : (word.charAt(0).toUpperCase() + word.substr(1).toLowerCase()) - ); - }) - .join(''); + return text + .split(" ") + .map((word, i) => { + return i === 0 + ? word.toLowerCase() + : word.charAt(0).toUpperCase() + word.substr(1).toLowerCase(); + }) + .join(""); } export function parseStaticThemes($themes: string) { - return parseSitesFixesConfig($themes, { - commands: staticThemeCommands, - getCommandPropName: upperCaseToCamelCase, - parseCommandValue: (command, value) => { - if (command === 'NO COMMON') { - return true; - } - return parseArray(value); - } - }); + return parseSitesFixesConfig($themes, { + commands: staticThemeCommands, + getCommandPropName: upperCaseToCamelCase, + parseCommandValue: (command, value) => { + if (command === "NO COMMON") { + return true; + } + return parseArray(value); + } + }); } function camelCaseToUpperCase(text: string) { - return text.replace(/([a-z])([A-Z])/g, '$1 $2').toUpperCase(); + return text.replace(/([a-z])([A-Z])/g, "$1 $2").toUpperCase(); } export function formatStaticThemes(staticThemes: StaticTheme[]) { - const themes = staticThemes.slice().sort((a, b) => compareURLPatterns(a.url[0], b.url[0])); - - return formatSitesFixesConfig(themes, { - props: staticThemeCommands.map(upperCaseToCamelCase), - getPropCommandName: camelCaseToUpperCase, - formatPropValue: (prop, value) => { - if (prop === 'noCommon') { - return ''; - } - return formatArray(value).trim(); - }, - shouldIgnoreProp: (prop, value) => { - if (prop === 'noCommon') { - return !value; - } - return !(Array.isArray(value) && value.length > 0); - } - }); + const themes = staticThemes + .slice() + .sort((a, b) => compareURLPatterns(a.url[0], b.url[0])); + + return formatSitesFixesConfig(themes, { + props: staticThemeCommands.map(upperCaseToCamelCase), + getPropCommandName: camelCaseToUpperCase, + formatPropValue: (prop, value) => { + if (prop === "noCommon") { + return ""; + } + return formatArray(value).trim(); + }, + shouldIgnoreProp: (prop, value) => { + if (prop === "noCommon") { + return !value; + } + return !(Array.isArray(value) && value.length > 0); + } + }); } function getCommonTheme(themes: StaticTheme[]) { - return themes[0]; + return themes[0]; } function getThemeFor(url: string, themes: StaticTheme[]) { - const sortedBySpecificity = themes - .slice(1) - .map((theme) => { - return { - specificity: isURLInList(url, theme.url) ? theme.url[0].length : 0, - theme - }; - }) - .filter(({specificity}) => specificity > 0) - .sort((a, b) => b.specificity - a.specificity); - - if (sortedBySpecificity.length === 0) { - return null; - } - - return sortedBySpecificity[0].theme; + const sortedBySpecificity = themes + .slice(1) + .map(theme => { + return { + specificity: isURLInList(url, theme.url) ? theme.url[0].length : 0, + theme + }; + }) + .filter(({ specificity }) => specificity > 0) + .sort((a, b) => b.specificity - a.specificity); + + if (sortedBySpecificity.length === 0) { + return null; + } + + return sortedBySpecificity[0].theme; } diff --git a/src/generators/text-style.ts b/src/generators/text-style.ts deleted file mode 100644 index 26e0a34..0000000 --- a/src/generators/text-style.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {FilterConfig} from '../definitions' - -export function createTextStyle(config: FilterConfig): string { - const lines: string[] = []; - lines.push('* {'); - - if (config.useFont && config.fontFamily) { - // TODO: Validate... - 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'); -} diff --git a/src/inject/dynamic-theme/index.ts b/src/inject/dynamic-theme/index.ts index e235724..6fb462c 100644 --- a/src/inject/dynamic-theme/index.ts +++ b/src/inject/dynamic-theme/index.ts @@ -29,7 +29,6 @@ import { throttle } from "../utils/throttle"; import { clamp } from "../../utils/math"; import { getCSSFilterValue } from "../../generators/css-filter"; import { modifyColor } from "../../generators/modify-colors"; -import { createTextStyle } from "../../generators/text-style"; import { FilterConfig, DynamicThemeFix } from "../../definitions"; const styleManagers = new Map< @@ -84,11 +83,7 @@ function createStaticStyleOverrides() { const textStyle = createOrUpdateStyle("darkreader--text"); document.head.insertBefore(textStyle, fallbackStyle.nextSibling); - if (filter.useFont || filter.textStroke > 0) { - textStyle.textContent = createTextStyle(filter); - } else { - textStyle.textContent = ""; - } + textStyle.textContent = ""; setupStylePositionWatcher(textStyle, "text"); const invertStyle = createOrUpdateStyle("darkreader--invert"); diff --git a/src/utils/url.ts b/src/utils/url.ts index f44fffc..a09aa53 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -1,11 +1,11 @@ -import {UserSettings} from '../definitions'; +import { UserSettings } from "../definitions"; export function getURLHost(url: string) { - return url.match(/^(.*?\/{2,3})?(.+?)(\/|$)/)[2]; + return url.match(/^(.*?\/{2,3})?(.+?)(\/|$)/)[2]; } export function compareURLPatterns(a: string, b: string) { - return a.localeCompare(b); + return a.localeCompare(b); } /** @@ -14,12 +14,12 @@ export function compareURLPatterns(a: string, b: string) { * @paramlist List to search into. */ export function isURLInList(url: string, list: string[]) { - for (let i = 0; i < list.length; i++) { - if (isURLMatched(url, list[i])) { - return true; - } + for (let i = 0; i < list.length; i++) { + if (isURLMatched(url, list[i])) { + return true; } - return false; + } + return false; } /** @@ -28,81 +28,84 @@ export function isURLInList(url: string, list: string[]) { * @param urlTemplate URL template ("google.*", "youtube.com" etc). */ export function isURLMatched(url: string, urlTemplate: string): boolean { - const regex = createUrlRegex(urlTemplate); - return Boolean(url.match(regex)); + const regex = createUrlRegex(urlTemplate); + return Boolean(url.match(regex)); } function createUrlRegex(urlTemplate: string): RegExp { - urlTemplate = urlTemplate.trim(); - const exactBeginning = (urlTemplate[0] === '^'); - const exactEnding = (urlTemplate[urlTemplate.length - 1] === '$'); - - urlTemplate = (urlTemplate - .replace(/^\^/, '') // Remove ^ at start - .replace(/\$$/, '') // Remove $ at end - .replace(/^.*?\/{2,3}/, '') // Remove scheme - .replace(/\?.*$/, '') // Remove query - .replace(/\/$/, '') // Remove last slash - ); - - let slashIndex: number; - let beforeSlash: string; - let afterSlash: string; - if ((slashIndex = urlTemplate.indexOf('/')) >= 0) { - beforeSlash = urlTemplate.substring(0, slashIndex); // google.* - afterSlash = urlTemplate.replace('$', '').substring(slashIndex); // /login/abc - } else { - beforeSlash = urlTemplate.replace('$', ''); + urlTemplate = urlTemplate.trim(); + const exactBeginning = urlTemplate[0] === "^"; + const exactEnding = urlTemplate[urlTemplate.length - 1] === "$"; + + urlTemplate = urlTemplate + .replace(/^\^/, "") // Remove ^ at start + .replace(/\$$/, "") // Remove $ at end + .replace(/^.*?\/{2,3}/, "") // Remove scheme + .replace(/\?.*$/, "") // Remove query + .replace(/\/$/, ""); // Remove last slash + + let slashIndex: number; + let beforeSlash: string; + let afterSlash: string; + if ((slashIndex = urlTemplate.indexOf("/")) >= 0) { + beforeSlash = urlTemplate.substring(0, slashIndex); // google.* + afterSlash = urlTemplate.replace("$", "").substring(slashIndex); // /login/abc + } else { + beforeSlash = urlTemplate.replace("$", ""); + } + + // + // SCHEME and SUBDOMAINS + + let result = exactBeginning + ? "^(.*?\\:\\/{2,3})?" // Scheme + : "^(.*?\\:\\/{2,3})?([^/]*?\\.)?"; // Scheme and subdomains + + // + // HOST and PORT + + const hostParts = beforeSlash.split("."); + result += "("; + for (let i = 0; i < hostParts.length; i++) { + if (hostParts[i] === "*") { + hostParts[i] = "[^\\.\\/]+?"; } + } + result += hostParts.join("\\."); + result += ")"; - // - // SCHEME and SUBDOMAINS - - let result = (exactBeginning ? - '^(.*?\\:\\/{2,3})?' // Scheme - : '^(.*?\\:\\/{2,3})?([^\/]*?\\.)?' // Scheme and subdomains - ); + // + // PATH and QUERY - // - // HOST and PORT + if (afterSlash) { + result += "("; + result += afterSlash.replace("/", "\\/"); + result += ")"; + } - const hostParts = beforeSlash.split('.'); - result += '('; - for (let i = 0; i < hostParts.length; i++) { - if (hostParts[i] === '*') { - hostParts[i] = '[^\\.\\/]+?'; - } - } - result += hostParts.join('\\.'); - result += ')'; + result += exactEnding + ? "(\\/?(\\?[^/]*?)?)$" // All following queries + : "(\\/?.*?)$"; // All following paths and queries - // - // PATH and QUERY - - if (afterSlash) { - result += '('; - result += afterSlash.replace('/', '\\/'); - result += ')'; - } + // + // Result - result += (exactEnding ? - '(\\/?(\\?[^\/]*?)?)$' // All following queries - : '(\\/?.*?)$' // All following paths and queries - ); + return new RegExp(result, "i"); +} - // - // Result +export function isURLEnabled( + url: string, + userSettings: UserSettings, + { isProtected, isInDarkList } +) { + if (isProtected) { + return false; + } + const isURLInUserList = isURLInList(url, userSettings.siteList); - return new RegExp(result, 'i'); -} + if (userSettings.applyToListedOnly) { + return isURLInUserList; + } -export function isURLEnabled(url: string, userSettings: UserSettings, {isProtected, isInDarkList}) { - if (isProtected) { - return false; - } - const isURLInUserList = isURLInList(url, userSettings.siteList); - if (userSettings.applyToListedOnly) { - return isURLInUserList; - } - return (!isInDarkList && !isURLInUserList); + return !isInDarkList && !isURLInUserList; }