From 21ee8a1e99575a62d762ad08002fbbe7debfeac9 Mon Sep 17 00:00:00 2001 From: wanhose Date: Mon, 15 Apr 2024 18:04:23 +0200 Subject: [PATCH 1/4] feat(browser-extension): polyfill chrome APIs for other browsers --- packages/browser-extension/package.json | 2 +- .../src/scripts/background.js | 66 ++++++++++--------- .../browser-extension/src/scripts/content.js | 10 ++- .../browser-extension/src/scripts/dialog.js | 28 ++++---- .../browser-extension/src/scripts/options.js | 12 ++-- .../browser-extension/src/scripts/popup.js | 20 +++--- 6 files changed, 79 insertions(+), 59 deletions(-) diff --git a/packages/browser-extension/package.json b/packages/browser-extension/package.json index fded2ba..f5b33b3 100644 --- a/packages/browser-extension/package.json +++ b/packages/browser-extension/package.json @@ -6,7 +6,7 @@ "lint": "eslint src/**/*.js --fix" }, "devDependencies": { - "@types/chrome": "^0.0.260", + "@types/firefox-webext-browser": "^0.0.260", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", diff --git a/packages/browser-extension/src/scripts/background.js b/packages/browser-extension/src/scripts/background.js index 838aee0..712876e 100644 --- a/packages/browser-extension/src/scripts/background.js +++ b/packages/browser-extension/src/scripts/background.js @@ -1,3 +1,7 @@ +if (typeof browser === 'undefined') { + browser = chrome; +} + /** * @description API URL * @type {string} @@ -23,16 +27,16 @@ const reportMenuItemId = 'CDM-REPORT'; const settingsMenuItemId = 'CDM-SETTINGS'; /** - * @description A shortcut for chrome.scripting - * @type {chrome.scripting} + * @description A shortcut for browser.scripting + * @type {browser.scripting} */ -const script = chrome.scripting; +const script = browser.scripting; /** * @description The storage to use - * @type {chrome.storage.LocalStorageArea} + * @type {browser.storage.LocalStorageArea} */ -const storage = chrome.storage.local; +const storage = browser.storage.local; /** * @description Refresh data @@ -42,7 +46,7 @@ const refreshData = (callback) => { try { fetch(`${apiUrl}/data/`).then((result) => { result.json().then(({ data }) => { - chrome.storage.local.set({ data }, suppressLastError); + storage.set({ data }, suppressLastError); callback?.(data); }); }); @@ -55,14 +59,14 @@ const refreshData = (callback) => { * @async * @description Report active tab URL * @param {any} message - * @param {chrome.tabs.Tab} tab + * @param {browser.tabs.Tab} tab * @param {void?} callback */ const report = async (message, tab, callback) => { try { const reason = message.reason; const userAgent = message.userAgent; - const version = chrome.runtime.getManifest().version; + const version = browser.runtime.getManifest().version; const body = JSON.stringify({ reason, url: tab.url, userAgent, version }); const headers = { 'Content-type': 'application/json' }; const url = `${apiUrl}/report/`; @@ -75,22 +79,22 @@ const report = async (message, tab, callback) => { }; /** - * @description Supress `chrome.runtime.lastError` + * @description Supress `browser.runtime.lastError` */ -const suppressLastError = () => void chrome.runtime.lastError; +const suppressLastError = () => void browser.runtime.lastError; /** * @description Listen to context menus clicked */ -chrome.contextMenus.onClicked.addListener((info, tab) => { +browser.contextMenus.onClicked.addListener((info, tab) => { const tabId = tab?.id; switch (info.menuItemId) { case reportMenuItemId: - if (tabId) chrome.tabs.sendMessage(tabId, { type: 'SHOW_REPORT_DIALOG' }, suppressLastError); + if (tabId) browser.tabs.sendMessage(tabId, { type: 'SHOW_REPORT_DIALOG' }, suppressLastError); break; case settingsMenuItemId: - chrome.runtime.openOptionsPage(); + browser.runtime.openOptionsPage(); break; default: break; @@ -100,7 +104,7 @@ chrome.contextMenus.onClicked.addListener((info, tab) => { /** * @description Listens to messages */ -chrome.runtime.onMessage.addListener((message, sender, callback) => { +browser.runtime.onMessage.addListener((message, sender, callback) => { const hostname = message.hostname; const isPage = sender.frameId === 0; const tabId = sender.tab?.id; @@ -108,18 +112,18 @@ chrome.runtime.onMessage.addListener((message, sender, callback) => { switch (message.type) { case 'DISABLE_ICON': if (isPage && tabId) { - chrome.action.setIcon({ path: '/assets/icons/disabled.png', tabId }, suppressLastError); - chrome.action.setBadgeText({ tabId, text: '' }); + browser.action.setIcon({ path: '/assets/icons/disabled.png', tabId }, suppressLastError); + browser.action.setBadgeText({ tabId, text: '' }); } break; case 'ENABLE_ICON': if (isPage && tabId) { - chrome.action.setIcon({ path: '/assets/icons/enabled.png', tabId }, suppressLastError); + browser.action.setIcon({ path: '/assets/icons/enabled.png', tabId }, suppressLastError); } break; case 'ENABLE_POPUP': if (isPage && tabId) { - chrome.action.setPopup({ popup: '/popup.html', tabId }, suppressLastError); + browser.action.setPopup({ popup: '/popup.html', tabId }, suppressLastError); } break; case 'GET_DATA': @@ -148,7 +152,7 @@ chrome.runtime.onMessage.addListener((message, sender, callback) => { } break; case 'GET_TAB': - chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + browser.tabs.query({ active: true, currentWindow: true }, (tabs) => { callback(tabs[0]); }); return true; @@ -165,8 +169,8 @@ chrome.runtime.onMessage.addListener((message, sender, callback) => { break; case 'SET_BADGE': if (tabId) { - chrome.action.setBadgeBackgroundColor({ color: '#6b7280' }); - chrome.action.setBadgeText({ tabId, text: message.value }); + browser.action.setBadgeBackgroundColor({ color: '#6b7280' }); + browser.action.setBadgeText({ tabId, text: message.value }); } break; case 'SET_HOSTNAME_STATE': @@ -184,33 +188,33 @@ chrome.runtime.onMessage.addListener((message, sender, callback) => { /** * @description Listens to extension installed */ -chrome.runtime.onInstalled.addListener(() => { - chrome.contextMenus.create( +browser.runtime.onInstalled.addListener(() => { + browser.contextMenus.create( { contexts: ['all'], - documentUrlPatterns: chrome.runtime.getManifest().content_scripts[0].matches, + documentUrlPatterns: browser.runtime.getManifest().content_scripts[0].matches, id: extensionMenuItemId, title: 'Cookie Dialog Monster', }, suppressLastError ); - chrome.contextMenus.create( + browser.contextMenus.create( { contexts: ['all'], - documentUrlPatterns: chrome.runtime.getManifest().content_scripts[0].matches, + documentUrlPatterns: browser.runtime.getManifest().content_scripts[0].matches, id: settingsMenuItemId, parentId: extensionMenuItemId, - title: chrome.i18n.getMessage('contextMenu_settingsOption'), + title: browser.i18n.getMessage('contextMenu_settingsOption'), }, suppressLastError ); - chrome.contextMenus.create( + browser.contextMenus.create( { contexts: ['all'], - documentUrlPatterns: chrome.runtime.getManifest().content_scripts[0].matches, + documentUrlPatterns: browser.runtime.getManifest().content_scripts[0].matches, id: reportMenuItemId, parentId: extensionMenuItemId, - title: chrome.i18n.getMessage('contextMenu_reportOption'), + title: browser.i18n.getMessage('contextMenu_reportOption'), }, suppressLastError ); @@ -219,6 +223,6 @@ chrome.runtime.onInstalled.addListener(() => { /** * @description Listen to first start */ -chrome.runtime.onStartup.addListener(() => { +browser.runtime.onStartup.addListener(() => { refreshData(); }); diff --git a/packages/browser-extension/src/scripts/content.js b/packages/browser-extension/src/scripts/content.js index 510af88..4d38064 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -1,3 +1,7 @@ +if (typeof browser === 'undefined') { + browser = chrome; +} + /** * @typedef {Object} ExtensionData * @property {string[]} commonWords @@ -26,7 +30,7 @@ let { commonWords, fixes = [], skips, tokens } = {}; /** * @description Shortcut to send messages to background script */ -const dispatch = chrome.runtime.sendMessage; +const dispatch = browser.runtime.sendMessage; /** * @description Event name @@ -350,9 +354,9 @@ const observer = new MutationObserver((mutations) => { /** * @description Listen to messages from any other scripts - * @listens chrome.tabs#onMessage + * @listens browser.tabs#onMessage */ -chrome.runtime.onMessage.addListener((message) => { +browser.runtime.onMessage.addListener((message) => { switch (message.type) { case 'RESTORE': { restoreDOM(); diff --git a/packages/browser-extension/src/scripts/dialog.js b/packages/browser-extension/src/scripts/dialog.js index 65c8fb1..7b1696f 100644 --- a/packages/browser-extension/src/scripts/dialog.js +++ b/packages/browser-extension/src/scripts/dialog.js @@ -1,3 +1,7 @@ +if (typeof browser === 'undefined') { + browser = chrome; +} + /** * @description Report reasons * @type {string[]} @@ -41,7 +45,7 @@ const reportDialogHtml = ` - ${chrome.i18n.getMessage('reportDialog_bodyText')} + ${browser.i18n.getMessage('reportDialog_bodyText')} @@ -49,46 +53,46 @@ const reportDialogHtml = ` aria-checked="false" data-value="0" role="radio" tabindex="0"> - ${chrome.i18n.getMessage('reportDialog_cannotClickOption')} + ${browser.i18n.getMessage('reportDialog_cannotClickOption')} - ${chrome.i18n.getMessage('reportDialog_pageVisualGlitchOption')} + ${browser.i18n.getMessage('reportDialog_pageVisualGlitchOption')} - ${chrome.i18n.getMessage('reportDialog_blankPageOption')} + ${browser.i18n.getMessage('reportDialog_blankPageOption')} - ${chrome.i18n.getMessage('reportDialog_laggyPageOption')} + ${browser.i18n.getMessage('reportDialog_laggyPageOption')} - ${chrome.i18n.getMessage('reportDialog_pageNotRespondingOption')} + ${browser.i18n.getMessage('reportDialog_pageNotRespondingOption')} - ${chrome.i18n.getMessage('reportDialog_popupShowUpOption')} + ${browser.i18n.getMessage('reportDialog_popupShowUpOption')} - ${chrome.i18n.getMessage('contextMenu_reportOption')?.replace('...', '')} + ${browser.i18n.getMessage('contextMenu_reportOption')?.replace('...', '')} @@ -107,13 +111,13 @@ const reportDialogHtml = ` - ${chrome.i18n.getMessage('reportDialog_submitText')} + ${browser.i18n.getMessage('reportDialog_submitText')} - ${chrome.i18n.getMessage('reportDialog_submitExtraText')} + ${browser.i18n.getMessage('reportDialog_submitExtraText')} - ${chrome.i18n.getMessage('contextMenu_issueOption')} + ${browser.i18n.getMessage('contextMenu_issueOption')} @@ -212,7 +216,7 @@ async function submitButtonClickHandler(event) { /** * @description Listen to messages */ -chrome.runtime.onMessage.addListener((message) => { +browser.runtime.onMessage.addListener((message) => { const isPage = window === window.top; switch (message.type) { diff --git a/packages/browser-extension/src/scripts/options.js b/packages/browser-extension/src/scripts/options.js index 58facac..619772f 100644 --- a/packages/browser-extension/src/scripts/options.js +++ b/packages/browser-extension/src/scripts/options.js @@ -1,7 +1,11 @@ +if (typeof browser === 'undefined') { + browser = chrome; +} + /** * @description Shortcut to send messages to background script */ -const dispatch = chrome.runtime.sendMessage; +const dispatch = browser.runtime.sendMessage; /** * @description Domain RegExp @@ -54,7 +58,7 @@ function createList() { * @returns {Promise} */ async function handleAddClick() { - const exclusionValue = window.prompt(chrome.i18n.getMessage('options_addPrompt')); + const exclusionValue = window.prompt(browser.i18n.getMessage('options_addPrompt')); if (exclusionValue?.trim() && (domainRx.test(exclusionValue) || exclusionValue === 'localhost')) { const filterInputElement = document.getElementById('filter-input'); @@ -216,11 +220,11 @@ function translate() { const { i18n, i18nPlaceholder } = node.dataset; if (i18n) { - node.innerHTML = chrome.i18n.getMessage(i18n); + node.innerHTML = browser.i18n.getMessage(i18n); } if (i18nPlaceholder) { - node.setAttribute('placeholder', chrome.i18n.getMessage(i18nPlaceholder)); + node.setAttribute('placeholder', browser.i18n.getMessage(i18nPlaceholder)); } } } diff --git a/packages/browser-extension/src/scripts/popup.js b/packages/browser-extension/src/scripts/popup.js index 902d9b4..13a4691 100644 --- a/packages/browser-extension/src/scripts/popup.js +++ b/packages/browser-extension/src/scripts/popup.js @@ -1,3 +1,7 @@ +if (typeof browser === 'undefined') { + browser = chrome; +} + /** * @description Chrome Web Store link * @type {string} @@ -53,13 +57,13 @@ let state = { enabled: true, tabId: undefined }; * @returns {Promise} */ async function handleContentLoaded() { - const tab = await chrome.runtime.sendMessage({ type: 'GET_TAB' }); + const tab = await browser.runtime.sendMessage({ type: 'GET_TAB' }); hostname = tab?.url ? new URL(tab.url).hostname.split('.').slice(-3).join('.').replace('www.', '') : undefined; - const next = await chrome.runtime.sendMessage({ hostname, type: 'GET_HOSTNAME_STATE' }); + const next = await browser.runtime.sendMessage({ hostname, type: 'GET_HOSTNAME_STATE' }); state = { ...(next ?? state), tabId: tab?.id }; const hostTextElement = document.getElementById('host'); @@ -98,7 +102,7 @@ async function handleLinkRedirect(event) { const { href } = event.currentTarget.dataset; if (href) { - await chrome.tabs.create({ url: href }); + await browser.tabs.create({ url: href }); } } @@ -112,8 +116,8 @@ async function handlePowerToggle(event) { const element = event.currentTarget; const next = { enabled: !state.enabled }; - chrome.runtime.sendMessage({ hostname, state: next, type: 'SET_HOSTNAME_STATE' }); - chrome.tabs.sendMessage(state.tabId, { type: next.enabled ? 'RUN' : 'RESTORE' }); + browser.runtime.sendMessage({ hostname, state: next, type: 'SET_HOSTNAME_STATE' }); + browser.tabs.sendMessage(state.tabId, { type: next.enabled ? 'RUN' : 'RESTORE' }); element.setAttribute('disabled', 'true'); element.setAttribute('data-value', next.enabled ? 'on' : 'off'); window.close(); @@ -124,7 +128,7 @@ async function handlePowerToggle(event) { * @returns {void} */ function handleSettingsClick() { - chrome.runtime.openOptionsPage(); + browser.runtime.openOptionsPage(); } /** @@ -139,11 +143,11 @@ function translate() { const { i18n, i18nPlaceholder } = node.dataset; if (i18n) { - node.innerHTML = chrome.i18n.getMessage(i18n); + node.innerHTML = browser.i18n.getMessage(i18n); } if (i18nPlaceholder) { - node.setAttribute('placeholder', chrome.i18n.getMessage(i18nPlaceholder)); + node.setAttribute('placeholder', browser.i18n.getMessage(i18nPlaceholder)); } } } From 3f1de4f536d51f03a96f3e0d5c6df6507dab34e2 Mon Sep 17 00:00:00 2001 From: wanhose Date: Mon, 15 Apr 2024 18:04:45 +0200 Subject: [PATCH 2/4] chore(browser-extension): upgrade version --- packages/browser-extension/src/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser-extension/src/manifest.json b/packages/browser-extension/src/manifest.json index 81e9604..60929dd 100644 --- a/packages/browser-extension/src/manifest.json +++ b/packages/browser-extension/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Cookie Dialog Monster", - "version": "7.0.2", + "version": "7.0.3", "default_locale": "en", "description": "__MSG_appDesc__", "icons": { From bd8b9a1ac775fce38279f7b140c5c1f7b7d114d7 Mon Sep 17 00:00:00 2001 From: wanhose Date: Mon, 15 Apr 2024 18:08:26 +0200 Subject: [PATCH 3/4] fix(browser-extension): minor change in onMessage comment --- packages/browser-extension/src/scripts/content.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser-extension/src/scripts/content.js b/packages/browser-extension/src/scripts/content.js index 4d38064..5e00f15 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -354,7 +354,7 @@ const observer = new MutationObserver((mutations) => { /** * @description Listen to messages from any other scripts - * @listens browser.tabs#onMessage + * @listens browser.runtime#onMessage */ browser.runtime.onMessage.addListener((message) => { switch (message.type) { From 5848baeda775b3c80ca4126cb6e3b31a87bc4799 Mon Sep 17 00:00:00 2001 From: wanhose Date: Mon, 15 Apr 2024 18:35:12 +0200 Subject: [PATCH 4/4] fix(browser-extension): error when importing as temporary --- packages/browser-extension/src/manifest.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/browser-extension/src/manifest.json b/packages/browser-extension/src/manifest.json index 60929dd..59c049b 100644 --- a/packages/browser-extension/src/manifest.json +++ b/packages/browser-extension/src/manifest.json @@ -16,6 +16,7 @@ "options_page": "options.html", "author": "wanhose", "background": { + "scripts": ["scripts/background.js"], "service_worker": "scripts/background.js" }, "content_scripts": [