From 013faebca536fab84a17ab24d5a2c776aeb5764a Mon Sep 17 00:00:00 2001 From: Ankit Ahuja <61857+ankit@users.noreply.github.com> Date: Thu, 14 Jul 2022 12:20:54 +0100 Subject: [PATCH 1/8] manifest-v3: configure webpack config and manifest.json --- src/extension/manifest.json | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/extension/manifest.json b/src/extension/manifest.json index d87f5cc5..5278ad9d 100644 --- a/src/extension/manifest.json +++ b/src/extension/manifest.json @@ -1,12 +1,13 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "Stylebot", "version": "3.1.1", "author": "Ankit Ahuja", "description": "__MSG_extension_description__", "default_locale": "en", "background": { - "scripts": ["background/index.js"] + "service_worker": "background/index.js", + "type": "module" }, "options_ui": { "page": "options/index.html", @@ -27,7 +28,7 @@ "run_at": "document_start" } ], - "browser_action": { + "action": { "default_icon": { "16": "img/icon16.png", "24": "img/icon24.png", @@ -46,14 +47,21 @@ "storage", "identity", "contextMenus", - "unlimitedStorage", + "unlimitedStorage" + ], + "host_permissions": [ "https://drive.google.com/*", "https://www.googleapis.com/*", "https://fonts.googleapis.com/*" ], "web_accessible_resources": [ - "editor/index.css", - "readability/index.css", - "monaco-editor/*" + { + "resources": [ + "monaco-editor/*", + "editor/index.css", + "readability/index.css" + ], + "matches": [""] + } ] } From 1269d5487357c00fe8e7b4bfa3e58811d063327f Mon Sep 17 00:00:00 2001 From: Ankit Ahuja <61857+ankit@users.noreply.github.com> Date: Thu, 14 Jul 2022 15:35:07 +0100 Subject: [PATCH 2/8] fix up background page build error; use chrome.action; update @types/chrome; update chrome.contextMenus --- package.json | 2 +- src/background/contextmenu.ts | 101 +++++++++++++++++----------------- src/background/index.ts | 4 +- src/background/styles.ts | 34 +++++------- webpack.config.js | 48 ++++++++++------ yarn.lock | 8 +-- 6 files changed, 103 insertions(+), 94 deletions(-) diff --git a/package.json b/package.json index 244572fa..881f17ea 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@babel/core": "^7.10.1", "@babel/plugin-proposal-optional-chaining": "^7.10.1", "@babel/preset-env": "^7.10.1", - "@types/chrome": "^0.0.114", + "@types/chrome": "^0.0.193", "@types/dedent": "^0.7.0", "@types/jest": "^26.0.4", "@types/lodash": "^4.14.157", diff --git a/src/background/contextmenu.ts b/src/background/contextmenu.ts index 414367eb..8ab0b318 100644 --- a/src/background/contextmenu.ts +++ b/src/background/contextmenu.ts @@ -4,54 +4,32 @@ import { OpenStylebotFromContextMenu } from '@stylebot/types'; import BackgroundPageUtils from './utils'; const CONTEXT_MENU_ID = 'stylebot-contextmenu'; - -const StyleElementContextMenu = () => { - chrome.contextMenus.create({ - contexts: ['all'], - title: t('style_element'), - parentId: CONTEXT_MENU_ID, - - onclick: (_info: chrome.contextMenus.OnClickData, tab: chrome.tabs.Tab) => { - if (tab.id) { - const message: OpenStylebotFromContextMenu = { - name: 'OpenStylebotFromContextMenu', - }; - - chrome.tabs.sendMessage(tab.id, message); - } - }, - }); -}; - -const ParentContextMenu = () => { - chrome.contextMenus.create({ - id: CONTEXT_MENU_ID, - title: 'Stylebot', - contexts: ['all'], - }); -}; - -const ViewOptionsContextMenu = () => { - chrome.contextMenus.create({ - contexts: ['all'], - title: t('view_options'), - parentId: CONTEXT_MENU_ID, - onclick: () => { - chrome.tabs.create({ - active: true, - url: 'options/index.html', - }); - }, - }); -}; +const VIEW_OPTIONS_MENU_ITEM_ID = 'view-options'; +const STYLE_ELEMENT_MENU_ITEM_ID = 'style-element'; const ContextMenu = { init(): void { this.remove(); - ParentContextMenu(); - StyleElementContextMenu(); - ViewOptionsContextMenu(); + chrome.contextMenus.create({ + id: CONTEXT_MENU_ID, + title: 'Stylebot', + contexts: ['all'], + }); + + chrome.contextMenus.create({ + contexts: ['all'], + title: t('style_element'), + parentId: CONTEXT_MENU_ID, + id: STYLE_ELEMENT_MENU_ITEM_ID, + }); + + chrome.contextMenus.create({ + contexts: ['all'], + title: t('view_options'), + parentId: CONTEXT_MENU_ID, + id: VIEW_OPTIONS_MENU_ITEM_ID, + }); }, update(tab: chrome.tabs.Tab): void { @@ -64,13 +42,15 @@ const ContextMenu = { chrome.contextMenus.update(CONTEXT_MENU_ID, { documentUrlPatterns: [''], }); - } else { - // If it isn't a valid url, hide the contextMenu - // Set the document pattern to foo/*random* - chrome.contextMenus.update(CONTEXT_MENU_ID, { - documentUrlPatterns: ['http://foo/' + Math.random()], - }); + + return; } + + // If it isn't a valid url, hide the contextMenu + // Set the document pattern to foo/*random* + chrome.contextMenus.update(CONTEXT_MENU_ID, { + documentUrlPatterns: ['http://foo/' + Math.random()], + }); }, remove(): void { @@ -78,4 +58,27 @@ const ContextMenu = { }, }; +chrome.contextMenus.onClicked.addListener((info, tab) => { + switch (info.menuItemId) { + case STYLE_ELEMENT_MENU_ITEM_ID: + if (tab?.id) { + const message: OpenStylebotFromContextMenu = { + name: 'OpenStylebotFromContextMenu', + }; + + chrome.tabs.sendMessage(tab.id, message); + } + + break; + + case VIEW_OPTIONS_MENU_ITEM_ID: + chrome.tabs.create({ + active: true, + url: 'options/index.html', + }); + + break; + } +}); + export default ContextMenu; diff --git a/src/background/index.ts b/src/background/index.ts index 742f156d..80dc1bc3 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -22,7 +22,7 @@ import { setNotification } from '@stylebot/utils'; Listeners.init(styles, options); - chrome.browserAction.setBadgeBackgroundColor({ + chrome.action.setBadgeBackgroundColor({ color: '#555', }); })(); @@ -30,7 +30,7 @@ import { setNotification } from '@stylebot/utils'; chrome.runtime.onInstalled.addListener(async ({ reason }) => { if (reason === 'install') { chrome.tabs.create({ - url: 'https://stylebot.dev/help' + url: 'https://stylebot.dev/help', }); setNotification('release/3.1', true); diff --git a/src/background/styles.ts b/src/background/styles.ts index c515fb53..a80a5236 100644 --- a/src/background/styles.ts +++ b/src/background/styles.ts @@ -152,24 +152,16 @@ class BackgroundPageStyles { getImportCss(url: string): Promise { return new Promise(resolve => { - const xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - - xhr.onreadystatechange = () => { - if (xhr.readyState == 4) { - try { - const css = xhr.responseText; - // validate css by parsing - postcss.parse(css); - resolve(css); - } catch (e) { - // if css is invalid, return back empty css - resolve(''); - } - } - }; - - xhr.send(); + fetch(url) + .then(response => response.text()) + .then(css => { + postcss.parse(css); + resolve(css); + }) + .catch(() => { + // if css is invalid, return back empty css + resolve(''); + }); }); } @@ -181,17 +173,17 @@ class BackgroundPageStyles { const enabledStyles = styles.filter(style => style.enabled); if (defaultStyle && defaultStyle.readability) { - chrome.browserAction.setBadgeText({ + chrome.action.setBadgeText({ text: `R`, tabId: tab.id, }); } else if (enabledStyles.length > 0) { - chrome.browserAction.setBadgeText({ + chrome.action.setBadgeText({ text: `${enabledStyles.length}`, tabId: tab.id, }); } else { - chrome.browserAction.setBadgeText({ text: '', tabId: tab.id }); + chrome.action.setBadgeText({ text: '', tabId: tab.id }); } } diff --git a/webpack.config.js b/webpack.config.js index 707882a9..94cfa8c0 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -21,6 +21,7 @@ const config = { stats: 'errors-only', mode: process.env.NODE_ENV, context: `${__dirname}/src`, + devtool: 'inline-source-map', optimization: { minimize: process.env.NODE_ENV === 'production', @@ -37,17 +38,6 @@ const config = { ], }, - entry: { - 'sync/index': './sync/index.ts', - 'popup/index': './popup/index.ts', - 'editor/index': './editor/index.ts', - 'options/index': './options/index.ts', - 'background/index': './background/index.ts', - 'inject-css/index': './inject-css/index.ts', - 'monaco-editor/iframe/index': './monaco-editor/iframe/index.ts', - 'readability/index': './readability/index.ts', - }, - output: { publicPath: '/', filename: '[name].js', @@ -126,9 +116,7 @@ const config = { plugins: [ new ProgressBarPlugin(), - new webpack.DefinePlugin({ - global: 'window', - }), + new VueLoaderPlugin(), new ForkTsCheckerWebpackPlugin({ typescript: { @@ -223,8 +211,9 @@ const config = { let jsonContent = JSON.parse(content); if (config.mode === 'development') { - jsonContent['content_security_policy'] = - "script-src 'self' 'unsafe-eval'; object-src 'self'"; + jsonContent['content_security_policy'] = { + extension_page: "script-src 'self'; object-src 'self'", + }; } if (process.env.BROWSER === 'firefox') { @@ -268,4 +257,29 @@ function transformHtml(content) { }); } -module.exports = config; +const backgroundPageConfig = { + ...config, + entry: { + 'background/index': './background/index.ts', + }, + plugins: [ + new webpack.DefinePlugin({ + global: 'this', + }), + ], +}; + +const clientConfig = { + ...config, + entry: { + 'sync/index': './sync/index.ts', + 'popup/index': './popup/index.ts', + 'editor/index': './editor/index.ts', + 'options/index': './options/index.ts', + 'inject-css/index': './inject-css/index.ts', + 'monaco-editor/iframe/index': './monaco-editor/iframe/index.ts', + 'readability/index': './readability/index.ts', + }, +}; + +module.exports = [backgroundPageConfig, clientConfig]; diff --git a/yarn.lock b/yarn.lock index 1d720331..2176f44f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1203,10 +1203,10 @@ dependencies: "@babel/types" "^7.3.0" -"@types/chrome@^0.0.114": - version "0.0.114" - resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.114.tgz#8ceb33fa261f4b9e307fa7344ba8182d8d410d4e" - integrity sha512-i7qRr74IrxHtbnrZSKUuP5Uvd5EOKwlwJq/yp7+yTPihOXnPhNQO4Z5bqb1XTnrjdbUKEJicaVVbhcgtRijmLA== +"@types/chrome@^0.0.193": + version "0.0.193" + resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.193.tgz#cd0dc5033f27a243d228aebe566c3ec19ef17e36" + integrity sha512-R8C84oqvk8A8C8G1viBd8qLpDr86Y/jwD+KLgzUekbIT9RGds6a9GnlQyg8P7ltnGogTMHkiEQK0ZlcrvTeo3Q== dependencies: "@types/filesystem" "*" "@types/har-format" "*" From b32077545c17f0b55e1b14ae496390e8d29edbfa Mon Sep 17 00:00:00 2001 From: Ankit Ahuja <61857+ankit@users.noreply.github.com> Date: Thu, 14 Jul 2022 15:38:14 +0100 Subject: [PATCH 3/8] replace chrome.extension.getURL with chrome.runtime.getURL --- src/editor/utils/init-editor.ts | 2 +- src/monaco-editor/iframe/MonacoEditorIframe.ts | 2 +- src/readability/reader.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/editor/utils/init-editor.ts b/src/editor/utils/init-editor.ts index 5a49f38f..89ee1d0b 100644 --- a/src/editor/utils/init-editor.ts +++ b/src/editor/utils/init-editor.ts @@ -48,7 +48,7 @@ Vue.mixin({ }); const injectCss = (shadowRoot: ShadowRoot): void => { - const url = chrome.extension.getURL('editor/index.css'); + const url = chrome.runtime.getURL('editor/index.css'); fetch(url, { method: 'GET' }) .then(response => response.text()) diff --git a/src/monaco-editor/iframe/MonacoEditorIframe.ts b/src/monaco-editor/iframe/MonacoEditorIframe.ts index 0421274e..4dea1cf2 100644 --- a/src/monaco-editor/iframe/MonacoEditorIframe.ts +++ b/src/monaco-editor/iframe/MonacoEditorIframe.ts @@ -25,7 +25,7 @@ class MonacEditorIframe { loadEditor(callback: () => void): void { window.require.config({ paths: { - vs: chrome.extension.getURL( + vs: chrome.runtime.getURL( 'monaco-editor/iframe/node_modules/monaco-editor/min/vs' ), }, diff --git a/src/readability/reader.ts b/src/readability/reader.ts index 7f86e891..59acf976 100644 --- a/src/readability/reader.ts +++ b/src/readability/reader.ts @@ -10,7 +10,7 @@ import { ReadabilityArticle } from '@stylebot/types'; import { cacheDocument } from './cache'; const initCss = async (root: ShadowRoot): Promise => { - const cssUrl = chrome.extension.getURL('readability/index.css'); + const cssUrl = chrome.runtime.getURL('readability/index.css'); return new Promise(resolve => { fetch(cssUrl, { method: 'GET' }) From ea228ed0b6f0096ebbc343688557895d039205dc Mon Sep 17 00:00:00 2001 From: Ankit Ahuja <61857+ankit@users.noreply.github.com> Date: Thu, 14 Jul 2022 17:37:22 +0100 Subject: [PATCH 4/8] refactor listeners, styles and options to move away from persistent state in background service worker --- src/background/cache.ts | 33 -- src/background/index.ts | 31 +- src/background/listeners.ts | 231 ++++++------ src/background/messages.ts | 123 +++---- src/background/options.ts | 67 ++-- src/background/styles.ts | 342 +++++++++--------- .../notifications/ReleaseNotification.vue | 2 +- src/sync/google-drive/sync.ts | 36 +- 8 files changed, 405 insertions(+), 460 deletions(-) delete mode 100644 src/background/cache.ts diff --git a/src/background/cache.ts b/src/background/cache.ts deleted file mode 100644 index 6848e9c8..00000000 --- a/src/background/cache.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { defaultOptions } from '@stylebot/settings'; - -import BackgroundPageStyles from './styles'; -import BackgroundPageOptions from './options'; - -const init = async (): Promise<{ - styles: BackgroundPageStyles; - options: BackgroundPageOptions; -}> => { - return new Promise(resolve => { - chrome.storage.local.get(['options', 'styles'], items => { - let styles: BackgroundPageStyles; - - if (items['styles']) { - styles = new BackgroundPageStyles(items['styles']); - } else { - styles = new BackgroundPageStyles({}); - } - - let options: BackgroundPageOptions; - - if (items['options']) { - options = new BackgroundPageOptions(items['options']); - } else { - options = new BackgroundPageOptions(defaultOptions); - } - - resolve({ styles, options }); - }); - }); -}; - -export default { init }; diff --git a/src/background/index.ts b/src/background/index.ts index 80dc1bc3..4e609531 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,40 +1,21 @@ import 'crx-hotreload'; -import Cache from './cache'; -import Listeners from './listeners'; +import './listeners'; + import ContextMenu from './contextmenu'; import DefaultShortcutUpdate from './default-shortcut-update'; import StylesMetadataUpdate from './styles-metadata-update'; import StylesModifiedTimeUpdate from './styles-modified-time-update'; -import { setNotification } from '@stylebot/utils'; - (async () => { await DefaultShortcutUpdate(); await StylesMetadataUpdate(); await StylesModifiedTimeUpdate(); - - const { styles, options } = await Cache.init(); - - if (options.get('contextMenu')) { - ContextMenu.init(); - } - - Listeners.init(styles, options); - - chrome.action.setBadgeBackgroundColor({ - color: '#555', - }); })(); -chrome.runtime.onInstalled.addListener(async ({ reason }) => { - if (reason === 'install') { - chrome.tabs.create({ - url: 'https://stylebot.dev/help', - }); - - setNotification('release/3.1', true); - } +chrome.runtime.setUninstallURL('https://stylebot.dev/goodbye'); +chrome.action.setBadgeBackgroundColor({ + color: '#555', }); -chrome.runtime.setUninstallURL('https://stylebot.dev/goodbye'); +ContextMenu.init(); diff --git a/src/background/listeners.ts b/src/background/listeners.ts index 7f7028a3..95640e2f 100644 --- a/src/background/listeners.ts +++ b/src/background/listeners.ts @@ -1,5 +1,4 @@ import ContextMenu from './contextmenu'; -import BackgroundPageStyles from './styles'; import { GetCommands, @@ -24,126 +23,134 @@ import { RunGoogleDriveSync, } from './messages'; +import { get as getOption } from './options'; + import { TabUpdated, BackgroundPageMessage, BackgroundPageMessageResponse, } from '@stylebot/types'; -import BackgroundPageOptions from './options'; +import { setNotification } from '@stylebot/utils'; /** - * Initialize listeners for the background page + * Open Help page on installation */ -const init = ( - styles: BackgroundPageStyles, - options: BackgroundPageOptions -): void => { - chrome.runtime.onMessage.addListener( - ( - message: BackgroundPageMessage, - sender: chrome.runtime.MessageSender, - sendResponse: (response: BackgroundPageMessageResponse) => void - ) => { - switch (message.name) { - case 'GetCommands': - GetCommands(sendResponse); - break; - case 'SetCommands': - SetCommands(message); - break; - - case 'GetOption': - GetOption(message, options, sendResponse); - break; - case 'SetOption': - SetOption(message, options); - break; - case 'GetAllOptions': - GetAllOptions(options, sendResponse); - break; - case 'OpenOptionsPage': - OpenOptionsPage(); - break; - case 'OpenDonatePage': - OpenDonatePage(); - break; - - case 'SetStyle': - SetStyle(message, styles); - break; - case 'MoveStyle': - MoveStyle(message, styles); - break; - case 'GetAllStyles': - GetAllStyles(styles, sendResponse); - break; - case 'SetAllStyles': - SetAllStyles(message, styles); - break; - case 'GetStylesForPage': - GetStylesForPage(message, styles, sender, sendResponse); - break; - case 'GetStylesForIframe': - GetStylesForIframe(message, styles, sendResponse); - break; - case 'EnableStyle': - EnableStyle(message, styles); - break; - case 'DisableStyle': - DisableStyle(message, styles); - break; - - case 'SetReadability': - SetReadability(message, styles); - break; - case 'GetReadabilitySettings': - GetReadabilitySettings(sendResponse); - break; - case 'SetReadabilitySettings': - SetReadabilitySettings(message); - break; - - case 'GetImportCss': - GetImportCss(message, styles, sendResponse); - break; - case 'RunGoogleDriveSync': - RunGoogleDriveSync(message, styles, sendResponse); - break; - } - - return true; - } - ); - - /** - * Listen when an existing tab is updated - * and update the context-menu and browser-action - */ - chrome.tabs.onUpdated.addListener((tabId, _, tab) => { - if (tab.status === 'complete') { - if (options.get('contextMenu')) { - ContextMenu.update(tab); - } - } +chrome.runtime.onInstalled.addListener(async ({ reason }) => { + if (reason === 'install') { + chrome.tabs.create({ + url: 'https://stylebot.dev/help', + }); + + setNotification('release/3.1', true); + } +}); + +/** + * When an existing tab is updated, refresh the context-menu and action. + */ +chrome.tabs.onUpdated.addListener(async (tabId, _, tab) => { + const option = await getOption('contextMenu'); + + if (option && tab.status === 'complete') { + ContextMenu.update(tab); + } + + const message: TabUpdated = { + name: 'TabUpdated', + }; + + chrome.tabs.sendMessage(tabId, message); +}); + +/** + * Listen when a tab is activated to refresh the context-menu. + */ +chrome.tabs.onActivated.addListener(async activeInfo => { + const option = await getOption('contextMenu'); + + if (option) { + chrome.tabs.get(activeInfo.tabId, tab => { + ContextMenu.update(tab); + }); + } +}); + +chrome.runtime.onMessage.addListener( + ( + message: BackgroundPageMessage, + sender: chrome.runtime.MessageSender, + sendResponse: (response: BackgroundPageMessageResponse) => void + ) => { + switch (message.name) { + case 'GetCommands': + GetCommands(sendResponse); + break; + case 'SetCommands': + SetCommands(message); + break; + + case 'GetOption': + GetOption(message, sendResponse); + break; + case 'SetOption': + SetOption(message); + break; + case 'GetAllOptions': + GetAllOptions(sendResponse); + break; + + case 'OpenOptionsPage': + OpenOptionsPage(); + break; + case 'OpenDonatePage': + OpenDonatePage(); + break; + + case 'SetStyle': + SetStyle(message); + break; + case 'MoveStyle': + MoveStyle(message); + break; + case 'GetAllStyles': + GetAllStyles(sendResponse); + break; + case 'SetAllStyles': + SetAllStyles(message); + break; + case 'GetStylesForPage': + GetStylesForPage(message, sender, sendResponse); + break; + case 'GetStylesForIframe': + GetStylesForIframe(message, sendResponse); + break; + case 'EnableStyle': + EnableStyle(message); + break; + case 'DisableStyle': + DisableStyle(message); + break; + + case 'SetReadability': + SetReadability(message); + break; + case 'GetReadabilitySettings': + GetReadabilitySettings(sendResponse); + break; + case 'SetReadabilitySettings': + SetReadabilitySettings(message); + break; + + case 'GetImportCss': + GetImportCss(message, sendResponse); + break; - const message: TabUpdated = { - name: 'TabUpdated', - }; - - chrome.tabs.sendMessage(tabId, message); - }); - - /** - * Listen when a tab is activated to update the context-menu - */ - chrome.tabs.onActivated.addListener(activeInfo => { - if (options.get('contextMenu')) { - chrome.tabs.get(activeInfo.tabId, tab => { - ContextMenu.update(tab); - }); + case 'RunGoogleDriveSync': + RunGoogleDriveSync(message, sendResponse); + break; } - }); -}; -export default { init }; + return true; + } +); diff --git a/src/background/messages.ts b/src/background/messages.ts index 75036d44..cb67fa37 100644 --- a/src/background/messages.ts +++ b/src/background/messages.ts @@ -1,5 +1,21 @@ -import BackgroundPageStyles from './styles'; -import BackgroundPageOptions from './options'; +import { + set, + disable, + enable, + getAll, + setAll, + move, + getStylesForPage, + updateIcon, + setReadability, + getImportCss, +} from './styles'; + +import { + get as getOption, + getAll as getAllOptions, + set as setOption, +} from './options'; import { GetOption as GetOptionType, @@ -34,87 +50,71 @@ import { import { get as getCommands, set as setCommands } from './commands'; -export const DisableStyle = ( - message: DisableStyleType, - styles: BackgroundPageStyles -): void => { - styles.disable(message.url); -}; +export const DisableStyle = (message: DisableStyleType): Promise => + disable(message.url); -export const EnableStyle = ( - message: EnableStyleType, - styles: BackgroundPageStyles -): void => { - styles.enable(message.url); -}; +export const EnableStyle = (message: EnableStyleType): Promise => + enable(message.url); -export const SetStyle = ( - message: SetStyleType, - styles: BackgroundPageStyles -): void => { - styles.set(message.url, message.css, message.readability); -}; +export const SetStyle = (message: SetStyleType): Promise => + set(message.url, message.css, message.readability); -export const GetAllStyles = ( - styles: BackgroundPageStyles, +export const GetAllStyles = async ( sendResponse: (response: GetAllStylesResponse) => void -): void => { - sendResponse(styles.getAll()); +): Promise => { + const styles = await getAll(); + sendResponse(styles); }; -export const SetAllStyles = ( - message: SetAllStylesType, - styles: BackgroundPageStyles -): void => { - styles.setAll(message.styles, message.shouldPersist); +export const SetAllStyles = (message: SetAllStylesType): void => { + setAll(message.styles); }; -export const GetStylesForIframe = ( +export const GetStylesForIframe = async ( message: GetStylesForIframeType, - styles: BackgroundPageStyles, sendResponse: (response: GetStylesForPageResponse) => void -): void => { - sendResponse(styles.getStylesForPage(message.url, message.important)); +): Promise => { + const styles = await getAll(); + const pageStyles = getStylesForPage(message.url, styles, message.important); + + sendResponse(pageStyles); }; -export const GetStylesForPage = ( +export const GetStylesForPage = async ( message: GetStylesForPageType, - styles: BackgroundPageStyles, sender: chrome.runtime.MessageSender, sendResponse: (response: GetStylesForPageResponse) => void -): void => { +): Promise => { const tab = sender.tab || message.tab; if (!tab || !tab.url) { return; } - const response = styles.getStylesForPage(tab.url, message.important); - styles.updateIcon(tab, response.styles, response.defaultStyle); + const styles = await getAll(); + const response = getStylesForPage(tab.url, styles, message.important); + updateIcon(tab, response.styles, response.defaultStyle); sendResponse(response); }; -export const MoveStyle = ( - message: MoveStyleType, - styles: BackgroundPageStyles -): void => { - styles.move(message.sourceUrl, message.destinationUrl); +export const MoveStyle = (message: MoveStyleType): void => { + move(message.sourceUrl, message.destinationUrl); }; -export const GetOption = ( +export const GetOption = async ( message: GetOptionType, - options: BackgroundPageOptions, sendResponse: (response: GetOptionResponse) => void -): void => { - sendResponse(options.get(message.optionName)); +): Promise => { + const option = await getOption(message.optionName); + sendResponse(option); }; -export const GetAllOptions = ( - options: BackgroundPageOptions, +export const GetAllOptions = async ( sendResponse: (response: GetAllOptionsResponse) => void -): void => { - sendResponse(options.getAll()); +): Promise => { + const options = await getAllOptions(); + sendResponse(options); }; export const OpenOptionsPage = (): void => { @@ -125,11 +125,8 @@ export const OpenDonatePage = (): void => { chrome.tabs.create({ url: 'https://ko-fi.com/stylebot' }); }; -export const SetOption = ( - message: SetOptionType, - options: BackgroundPageOptions -): void => { - options.set(message.option.name, message.option.value); +export const SetOption = (message: SetOptionType): void => { + setOption(message.option.name, message.option.value); }; export const GetCommands = async ( @@ -143,11 +140,8 @@ export const SetCommands = (message: SetCommandsType): void => { setCommands(message.value); }; -export const SetReadability = ( - message: SetReadabilityType, - styles: BackgroundPageStyles -): void => { - styles.setReadability(message.url, message.value); +export const SetReadability = (message: SetReadabilityType): void => { + setReadability(message.url, message.value); }; export const GetReadabilitySettings = async ( @@ -165,18 +159,17 @@ export const SetReadabilitySettings = ( export const GetImportCss = async ( message: GetImportCssType, - styles: BackgroundPageStyles, + sendResponse: (response: GetImportCssResponse) => void ): Promise => { - const css = await styles.getImportCss(message.url); + const css = await getImportCss(message.url); sendResponse(css); }; export const RunGoogleDriveSync = async ( _message: RunGoogleDriveSyncType, - styles: BackgroundPageStyles, sendResponse: (response: RunGoogleDriveSyncResponse) => void ): Promise => { - await runGoogleDriveSync(styles); + await runGoogleDriveSync(); sendResponse(); }; diff --git a/src/background/options.ts b/src/background/options.ts index 5ba603f8..46e086ff 100644 --- a/src/background/options.ts +++ b/src/background/options.ts @@ -1,41 +1,34 @@ -import ContextMenu from './contextmenu'; import { StylebotOptions } from '@stylebot/types'; +import { defaultOptions } from '@stylebot/settings'; -class BackgroundPageOptions { - options: StylebotOptions; - - constructor(options: StylebotOptions) { - this.options = options; - } - - get(name: keyof StylebotOptions): StylebotOptions[keyof StylebotOptions] { - return this.options[name]; - } - - getAll(): StylebotOptions { - return this.options; - } - - set( - name: keyof StylebotOptions, - value: StylebotOptions[keyof StylebotOptions] - ): void { - this.options = { - ...this.options, - [name]: value, - }; - - chrome.storage.local.set({ options: this.options }); - - // If the option was contextMenu, update it - if (name === 'contextMenu') { - if (value === false) { - ContextMenu.remove(); +export const getAll = (): Promise => + new Promise(resolve => { + chrome.storage.local.get('options', items => { + if (items['options']) { + resolve(items['options']); } else { - ContextMenu.init(); + resolve(defaultOptions); } - } - } -} - -export default BackgroundPageOptions; + }); + }); + +export const get = async ( + name: keyof StylebotOptions +): Promise => { + const options = await getAll(); + return options[name]; +}; + +export const set = async ( + name: keyof StylebotOptions, + value: StylebotOptions[keyof StylebotOptions] +): Promise => { + let options = await getAll(); + + options = { + ...options, + [name]: value, + }; + + chrome.storage.local.set({ options }); +}; diff --git a/src/background/styles.ts b/src/background/styles.ts index a80a5236..1a0dfc42 100644 --- a/src/background/styles.ts +++ b/src/background/styles.ts @@ -2,6 +2,7 @@ import * as postcss from 'postcss'; import { getCurrentTimestamp } from '@stylebot/utils'; import { appendImportantToDeclarations } from '@stylebot/css'; + import { Style, StyleMap, @@ -11,203 +12,210 @@ import { import BackgroundPageUtils from './utils'; -class BackgroundPageStyles { - styles: StyleMap; - - constructor(styles: StyleMap) { - this.styles = styles; - } - - persistStorage(): void { - chrome.storage.local.set({ - styles: this.styles, - - 'styles-metadata': { - modifiedTime: getCurrentTimestamp(), - }, +export const updateIcon = ( + tab: chrome.tabs.Tab, + styles: Array \ No newline at end of file + diff --git a/src/sync/google-drive/sync.ts b/src/sync/google-drive/sync.ts index f6e53280..9c0f68cf 100644 --- a/src/sync/google-drive/sync.ts +++ b/src/sync/google-drive/sync.ts @@ -15,7 +15,10 @@ import { downloadSyncFile, writeSyncFile, } from './sync-file'; -import BackgroundPageStyles from 'background/styles'; +import { + setAll as setAllStyles, + getAll as getAllStyles, +} from '../../background/styles'; const getStylesBlob = (styles: StyleMap) => new Blob([JSON.stringify(styles)], { type: 'application/json' }); @@ -43,10 +46,9 @@ const writeToRemote = async ( */ const writeToLocal = async ( syncMetadata: GoogleDriveSyncMetadata, - styles: StyleMap, - backgroundPageStyles: BackgroundPageStyles + styles: StyleMap ) => { - backgroundPageStyles.setAll(styles, false); + await setAllStyles(styles); return setGoogleDriveSyncMetadata({ ...syncMetadata, @@ -59,14 +61,13 @@ const writeToLocal = async ( */ const merge = async ( accessToken: string, - syncMetadata: GoogleDriveSyncMetadata, - backgroundPageStyles: BackgroundPageStyles + syncMetadata: GoogleDriveSyncMetadata ) => { - const localStyles = backgroundPageStyles.getAll(); + const localStyles = await getAllStyles(); const remoteStyles = await downloadSyncFile(accessToken, syncMetadata.id); const mergedStyles = mergeStyles(localStyles, remoteStyles); - await writeToLocal(syncMetadata, mergedStyles, backgroundPageStyles); + await writeToLocal(syncMetadata, mergedStyles); await writeToRemote(accessToken, syncMetadata, mergedStyles); }; @@ -79,9 +80,8 @@ const merge = async ( * - Else, write remote styles to local * 4) If local styles' modified timestamp > remote sync timestamp, write local styles to remote. */ -export const runGoogleDriveSync = async ( - backgroundPageStyles: BackgroundPageStyles -): Promise => { +export const runGoogleDriveSync = async (): Promise => { + const styles = await getAllStyles(); const accessToken = await getAccessToken(); const remoteSyncMetadata = await getSyncFileMetadata(accessToken); @@ -90,7 +90,7 @@ export const runGoogleDriveSync = async ( if (!remoteSyncMetadata) { console.debug('did not find remote sync file, updating remote...'); - const blob = getStylesBlob(backgroundPageStyles.getAll()); + const blob = getStylesBlob(styles); const remoteSyncMetadata = await writeSyncFile(accessToken, blob); return setGoogleDriveSyncMetadata(remoteSyncMetadata); } @@ -99,7 +99,7 @@ export const runGoogleDriveSync = async ( if (!localSyncMetadata) { console.debug('no local sync metadata found. merging local and remote...'); - return merge(accessToken, remoteSyncMetadata, backgroundPageStyles); + return merge(accessToken, remoteSyncMetadata); } const localStylesMetadata = await getLocalStylesMetadata(); @@ -122,7 +122,7 @@ export const runGoogleDriveSync = async ( 'both local and remote were updated since last sync, merging local and remote...' ); - return merge(accessToken, remoteSyncMetadata, backgroundPageStyles); + return merge(accessToken, remoteSyncMetadata); } console.debug('remote was updated since last sync, updating local...'); @@ -131,17 +131,13 @@ export const runGoogleDriveSync = async ( remoteSyncMetadata.id ); - return writeToLocal(remoteSyncMetadata, remoteStyles, backgroundPageStyles); + return writeToLocal(remoteSyncMetadata, remoteStyles); } // check if local styles were modified v/s remote if (compareAsc(localStylesModifiedTime, remoteSyncTime) > 0) { console.debug('local was updated since last sync, updating remote...'); - return writeToRemote( - accessToken, - remoteSyncMetadata, - backgroundPageStyles.getAll() - ); + return writeToRemote(accessToken, remoteSyncMetadata, styles); } return setGoogleDriveSyncMetadata({ From afade7557096a00aeed15cc6d1248544d3620cc4 Mon Sep 17 00:00:00 2001 From: Ankit Ahuja <61857+ankit@users.noreply.github.com> Date: Tue, 19 Jul 2022 15:28:51 +0100 Subject: [PATCH 5/8] remove implicit call to update all tabs on setAll; call it explicitly from messages --- src/background/messages.ts | 22 ++++++++++++++++------ src/background/styles.ts | 4 +--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/background/messages.ts b/src/background/messages.ts index cb67fa37..c118efc9 100644 --- a/src/background/messages.ts +++ b/src/background/messages.ts @@ -9,6 +9,7 @@ import { updateIcon, setReadability, getImportCss, + applyStylesToAllTabs, } from './styles'; import { @@ -50,11 +51,17 @@ import { import { get as getCommands, set as setCommands } from './commands'; -export const DisableStyle = (message: DisableStyleType): Promise => - disable(message.url); +export const DisableStyle = async ( + message: DisableStyleType +): Promise => { + await disable(message.url); + return applyStylesToAllTabs(); +}; -export const EnableStyle = (message: EnableStyleType): Promise => - enable(message.url); +export const EnableStyle = async (message: EnableStyleType): Promise => { + await enable(message.url); + return applyStylesToAllTabs(); +}; export const SetStyle = (message: SetStyleType): Promise => set(message.url, message.css, message.readability); @@ -66,8 +73,11 @@ export const GetAllStyles = async ( sendResponse(styles); }; -export const SetAllStyles = (message: SetAllStylesType): void => { - setAll(message.styles); +export const SetAllStyles = async ( + message: SetAllStylesType +): Promise => { + await setAll(message.styles); + return applyStylesToAllTabs(); }; export const GetStylesForIframe = async ( diff --git a/src/background/styles.ts b/src/background/styles.ts index 1a0dfc42..734eaf32 100644 --- a/src/background/styles.ts +++ b/src/background/styles.ts @@ -34,7 +34,7 @@ export const updateIcon = ( } }; -export const updateAllTabs = async (): Promise => { +export const applyStylesToAllTabs = async (): Promise => { const allStyles = await getAll(); chrome.tabs.query({}, tabs => { @@ -127,8 +127,6 @@ export const setAll = async (styles: StyleMap): Promise => { modifiedTime: getCurrentTimestamp(), }, }); - - return updateAllTabs(); }; export const set = async ( From 01a82b606112502224baab34e28f413722821cea Mon Sep 17 00:00:00 2001 From: Ankit Ahuja <61857+ankit@users.noreply.github.com> Date: Tue, 19 Jul 2022 15:49:27 +0100 Subject: [PATCH 6/8] send TabUpdated message when tab loading is complete to ensure content script can recieve the message --- src/background/listeners.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/background/listeners.ts b/src/background/listeners.ts index 95640e2f..bee25303 100644 --- a/src/background/listeners.ts +++ b/src/background/listeners.ts @@ -54,13 +54,13 @@ chrome.tabs.onUpdated.addListener(async (tabId, _, tab) => { if (option && tab.status === 'complete') { ContextMenu.update(tab); - } - const message: TabUpdated = { - name: 'TabUpdated', - }; + const message: TabUpdated = { + name: 'TabUpdated', + }; - chrome.tabs.sendMessage(tabId, message); + chrome.tabs.sendMessage(tabId, message); + } }); /** From e62b54f9c08f307ce241278780efca0cf12e140b Mon Sep 17 00:00:00 2001 From: Ankit Ahuja <61857+ankit@users.noreply.github.com> Date: Tue, 19 Jul 2022 15:58:41 +0100 Subject: [PATCH 7/8] fix up ts-ignore in test --- src/css/__tests__/import.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/__tests__/import.test.ts b/src/css/__tests__/import.test.ts index ecf862c3..d69c23f7 100644 --- a/src/css/__tests__/import.test.ts +++ b/src/css/__tests__/import.test.ts @@ -29,8 +29,8 @@ const mockExampleCss = dedent` `; global.chrome = { - /* @ts-ignore */ runtime: { + /* @ts-ignore */ sendMessage: (message: any, callback: any) => { if (message.url === 'https://fonts.googleapis.com/css?family=Lato') { callback(mockFontCss); From cb33e4ae0d0e526dc937753a9d51a5dbfc822875 Mon Sep 17 00:00:00 2001 From: Ankit Ahuja <61857+ankit@users.noreply.github.com> Date: Tue, 19 Jul 2022 16:15:41 +0100 Subject: [PATCH 8/8] use @ts-expect-error --- src/css/__tests__/import.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/css/__tests__/import.test.ts b/src/css/__tests__/import.test.ts index d69c23f7..d0d428d9 100644 --- a/src/css/__tests__/import.test.ts +++ b/src/css/__tests__/import.test.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-explicit-any */ + const dedent = require('dedent'); import { getCssWithExpandedImports } from '../import'; @@ -30,8 +31,9 @@ const mockExampleCss = dedent` global.chrome = { runtime: { - /* @ts-ignore */ - sendMessage: (message: any, callback: any) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error: not able to figure out how to override sendMessage here correctly. + sendMessage: (message: any, callback: (response: any) => void) => { if (message.url === 'https://fonts.googleapis.com/css?family=Lato') { callback(mockFontCss); } else if (message.url === 'https://example2.css') {