diff --git a/packages/browser-extension/src/_locales/de/messages.json b/packages/browser-extension/src/_locales/de/messages.json index 1179af8..4f55111 100644 --- a/packages/browser-extension/src/_locales/de/messages.json +++ b/packages/browser-extension/src/_locales/de/messages.json @@ -7,9 +7,9 @@ "description": "Webseite melden...", "message": "Webseite melden..." }, - "footerText": { - "description": "Mit ❤️ gemacht von", - "message": "Mit ❤️ gemacht von" + "contributeText": { + "description": "Tragen Sie zu diesem Projekt bei", + "message": "Tragen Sie zu diesem Projekt bei" }, "helpText": { "description": "Hilfe oder Probleme?", @@ -23,6 +23,10 @@ "description": "Dankeschön! Bitte bewerten Sie unsere Erweiterung hier 😍", "message": "Dankeschön! Bitte bewerten Sie unsere Erweiterung hier 😍" }, + "reportText": { + "description": "Bericht gesendet!", + "message": "Bericht gesendet!" + }, "reviewText": { "description": "Gefällt dir diese Erweiterung?", "message": "Gefällt dir diese Erweiterung?" diff --git a/packages/browser-extension/src/_locales/en/messages.json b/packages/browser-extension/src/_locales/en/messages.json index 8ea8268..f8da84a 100644 --- a/packages/browser-extension/src/_locales/en/messages.json +++ b/packages/browser-extension/src/_locales/en/messages.json @@ -7,9 +7,9 @@ "description": "Report site...", "message": "Report site..." }, - "footerText": { - "description": "Made with ❤️ by", - "message": "Made with ❤️ by" + "contributeText": { + "description": "Contribute to this project", + "message": "Contribute to this project" }, "helpText": { "description": "Help or issues?", @@ -23,6 +23,10 @@ "description": "Thank you! Please rate our extension here 😍", "message": "Thank you! Please rate our extension here 😍" }, + "reportText": { + "description": "Report sent!", + "message": "Report sent!" + }, "reviewText": { "description": "Do you like this extension?", "message": "Do you like this extension?" diff --git a/packages/browser-extension/src/_locales/es/messages.json b/packages/browser-extension/src/_locales/es/messages.json index 2fe7cee..b9d421d 100644 --- a/packages/browser-extension/src/_locales/es/messages.json +++ b/packages/browser-extension/src/_locales/es/messages.json @@ -7,9 +7,9 @@ "description": "Reportar sitio...", "message": "Reportar sitio..." }, - "footerText": { - "description": "Hecho con ❤️ por", - "message": "Hecho con ❤️ por" + "contributeText": { + "description": "Contribuye a este proyecto", + "message": "Contribuye a este proyecto" }, "helpText": { "description": "¿Ayuda o problemas?", @@ -23,6 +23,10 @@ "description": "¡Gracias! Por favor valora la extensión aquí 😍", "message": "¡Gracias! Por favor valora la extensión aquí 😍" }, + "reportText": { + "description": "¡Reporte enviado!", + "message": "¡Reporte enviado!" + }, "reviewText": { "description": "¿Te gusta esta extensión?", "message": "¿Te gusta esta extensión?" diff --git a/packages/browser-extension/src/_locales/fr/messages.json b/packages/browser-extension/src/_locales/fr/messages.json index f63caa9..679ebf6 100644 --- a/packages/browser-extension/src/_locales/fr/messages.json +++ b/packages/browser-extension/src/_locales/fr/messages.json @@ -7,9 +7,9 @@ "description": "Signaler le site...", "message": "Signaler le site..." }, - "footerText": { - "description": "Fabriqué avec ❤️ par", - "message": "Fabriqué avec ❤️ par" + "contributeText": { + "description": "Contribuez à ce projet", + "message": "Contribuez à ce projet" }, "helpText": { "description": "Aide ou problèmes?", @@ -23,6 +23,10 @@ "description": "Merci! Veuillez évaluer notre extension ici 😍", "message": "Merci! Veuillez évaluer notre extension ici 😍" }, + "reportText": { + "description": "Rapport envoyé!", + "message": "Rapport envoyé!" + }, "reviewText": { "description": "Aimez-vous cette extension?", "message": "Aimez-vous cette extension?" diff --git a/packages/browser-extension/src/_locales/it/messages.json b/packages/browser-extension/src/_locales/it/messages.json index fe3fb02..34beb2e 100644 --- a/packages/browser-extension/src/_locales/it/messages.json +++ b/packages/browser-extension/src/_locales/it/messages.json @@ -7,9 +7,9 @@ "description": "Segnala sito...", "message": "Segnala sito..." }, - "footerText": { - "description": "Realizzato con ❤️ da", - "message": "Realizzato con ❤️ da" + "contributeText": { + "description": "Contribuisci a questo progetto", + "message": "Contribuisci a questo progetto" }, "helpText": { "description": "Aiuto o problemi?", @@ -23,6 +23,10 @@ "description": "Grazie! Valuta la nostra estensione qui 😍", "message": "Grazie! Valuta la nostra estensione qui 😍" }, + "reportText": { + "description": "Rapporto inviato!", + "message": "Rapporto inviato!" + }, "reviewText": { "description": "Ti piace questa estensione?", "message": "Ti piace questa estensione?" diff --git a/packages/browser-extension/src/_locales/pt_BR/messages.json b/packages/browser-extension/src/_locales/pt_BR/messages.json index ae40d16..ffc5032 100644 --- a/packages/browser-extension/src/_locales/pt_BR/messages.json +++ b/packages/browser-extension/src/_locales/pt_BR/messages.json @@ -7,9 +7,9 @@ "description": "Reportar site...", "message": "Reportar site..." }, - "footerText": { - "description": "Feito com ❤️ por", - "message": "Feito com ❤️ por" + "contributeText": { + "description": "Contribua para este projeto", + "message": "Contribua para este projeto" }, "helpText": { "description": "Ajuda ou problemas?", @@ -23,6 +23,10 @@ "description": "Obrigado! Avalie nossa extensão aqui 😍", "message": "Obrigado! Avalie nossa extensão aqui 😍" }, + "reportText": { + "description": "Relatório enviado!", + "message": "Relatório enviado!" + }, "reviewText": { "description": "Você gosta desta extensão?", "message": "Você gosta desta extensão?" diff --git a/packages/browser-extension/src/_locales/pt_PT/messages.json b/packages/browser-extension/src/_locales/pt_PT/messages.json index ae40d16..ffc5032 100644 --- a/packages/browser-extension/src/_locales/pt_PT/messages.json +++ b/packages/browser-extension/src/_locales/pt_PT/messages.json @@ -7,9 +7,9 @@ "description": "Reportar site...", "message": "Reportar site..." }, - "footerText": { - "description": "Feito com ❤️ por", - "message": "Feito com ❤️ por" + "contributeText": { + "description": "Contribua para este projeto", + "message": "Contribua para este projeto" }, "helpText": { "description": "Ajuda ou problemas?", @@ -23,6 +23,10 @@ "description": "Obrigado! Avalie nossa extensão aqui 😍", "message": "Obrigado! Avalie nossa extensão aqui 😍" }, + "reportText": { + "description": "Relatório enviado!", + "message": "Relatório enviado!" + }, "reviewText": { "description": "Você gosta desta extensão?", "message": "Você gosta desta extensão?" diff --git a/packages/browser-extension/src/_locales/ro/messages.json b/packages/browser-extension/src/_locales/ro/messages.json index d12e529..874828c 100644 --- a/packages/browser-extension/src/_locales/ro/messages.json +++ b/packages/browser-extension/src/_locales/ro/messages.json @@ -7,9 +7,9 @@ "description": "Raportați site-ul...", "message": "Raportați site-ul..." }, - "footerText": { - "description": "Realizat cu ❤️ de", - "message": "Realizat cu ❤️ de" + "contributeText": { + "description": "Contribuie la acest proiect", + "message": "Contribuie la acest proiect" }, "helpText": { "description": "Ajutor sau probleme?", @@ -23,6 +23,10 @@ "description": "Mulțumesc! Vă rugăm să evaluați extensia noastră aici 😍", "message": "Mulțumesc! Vă rugăm să evaluați extensia noastră aici 😍" }, + "reportText": { + "description": "Raport trimis!", + "message": "Raport trimis!" + }, "reviewText": { "description": "Îți place această extensie?", "message": "Îți place această extensie?" diff --git a/packages/browser-extension/src/_locales/ru/messages.json b/packages/browser-extension/src/_locales/ru/messages.json index fffc0ac..6dd079f 100644 --- a/packages/browser-extension/src/_locales/ru/messages.json +++ b/packages/browser-extension/src/_locales/ru/messages.json @@ -7,9 +7,9 @@ "description": "Сообщить о сайте...", "message": "Сообщить о сайте..." }, - "footerText": { - "description": "Сделано с ❤️", - "message": "Сделано с ❤️" + "contributeText": { + "description": "Внести свой вклад в этот проект", + "message": "Внести свой вклад в этот проект" }, "helpText": { "description": "Помощь или проблемы?", @@ -23,6 +23,10 @@ "description": "Спасибо! Пожалуйста, оцените наше расширение здесь 😍", "message": "Спасибо! Пожалуйста, оцените наше расширение здесь 😍" }, + "reportText": { + "description": "Отчет отправлен!", + "message": "Отчет отправлен!" + }, "reviewText": { "description": "Вам нравится это расширение?", "message": "Вам нравится это расширение?" diff --git a/packages/browser-extension/src/manifest.json b/packages/browser-extension/src/manifest.json index c7405f7..f31f8f3 100644 --- a/packages/browser-extension/src/manifest.json +++ b/packages/browser-extension/src/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Cookie Dialog Monster", - "version": "5.5.5", + "version": "5.5.6", "default_locale": "en", "description": "__MSG_appDesc__", "icons": { @@ -19,6 +19,7 @@ }, "content_scripts": [ { + "css": ["styles/snackbar.css"], "exclude_matches": [ "*://*.gfycat.com/*", "*://*.gmx.com/*", @@ -26,7 +27,7 @@ "*://*.rundschau-online.de/*", "*://*.youtube.com/embed/*" ], - "js": ["scripts/content.js"], + "js": ["scripts/content.js", "scripts/snackbar.js"], "matches": ["http://*/*", "https://*/*"], "run_at": "document_start" } diff --git a/packages/browser-extension/src/popup.html b/packages/browser-extension/src/popup.html index 9e2db9d..b605ed0 100644 --- a/packages/browser-extension/src/popup.html +++ b/packages/browser-extension/src/popup.html @@ -2,7 +2,7 @@ - + @@ -84,6 +84,27 @@ +
+ + + + + + + + + +
@@ -104,10 +125,6 @@
- + diff --git a/packages/browser-extension/src/scripts/background.js b/packages/browser-extension/src/scripts/background.js index 110c5fb..e1f5df2 100644 --- a/packages/browser-extension/src/scripts/background.js +++ b/packages/browser-extension/src/scripts/background.js @@ -3,230 +3,120 @@ * @type {string} */ -const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v1'; +const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v2'; /** - * @description Base data URL - * @type {string} - */ - -const baseDataUrl = 'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/main/data'; - -/** - * @description Cache data - * @type {{ attributes: string[], classes: string[], fixes: string[], selectors: string[], skips: string[] }} - */ - -let cache = undefined; - -/** - * @description Context menu identifier - * @type {string} - */ - -const contextMenuId = 'CDM_MENU'; - -/** - * @description Cache initial state + * @description Initial state * @type {{ enabled: boolean }} */ const initial = { enabled: true }; /** - * @description Disables icon - * @param {string} tabId + * @description Context menu identifier + * @type {string} */ -const disableIcon = (tabId) => - chrome.browserAction.setIcon({ path: 'assets/icons/disabled.png', tabId }); +const reportMenuItemId = 'REPORT'; /** - * @description Enables icon - * @param {string} tabId + * @description Refreshes data + * @param {void?} callback */ -const enableIcon = (tabId) => - chrome.browserAction.setIcon({ path: 'assets/icons/enabled.png', tabId }); - -/** - * @description Enables popup - * @param {string} tabId - */ - -const enablePopup = (tabId) => chrome.browserAction.setPopup({ popup: 'popup.html', tabId }); - -/** - * @description Retrieves store - * @param {string} hostname - * @param {void} callback - * @returns {{ enabled: boolean }} - */ - -const getStore = (hostname, callback) => { - chrome.storage.local.get(null, (store) => { - callback(store[hostname] ?? initial); - }); -}; - -/** - * @async - * @description Get all data from GitHub - * @param {void} callback - * @returns {Promise<{ attributes: string[], classes: string[], fixes: string[], selectors: string[], skips: string[] }>} - */ - -const getData = async (callback) => { - if (cache) { - callback(cache); - return; - } - - const data = await Promise.all([ - query('classes'), - query('elements'), - query('fixes'), - query('skips'), - ]); - - const result = { - attributes: [ - ...new Set( - data[1].elements.flatMap((element) => { - const attributes = element.match(/(?<=\[)[^(){}[\]]+(?=\])/g); - - return attributes?.length - ? [ - ...attributes.flatMap((attribute) => { - return attribute ? [attribute.replace(/\".*\"|(=|\^|\*|\$)/g, '')] : []; - }), - ] - : []; - }) - ), - ], - classes: data[0].classes, - fixes: data[2].fixes, - selectors: data[1].elements, - skips: data[3].skips, - }; - - if (Object.keys(result).every((key) => result[key].length > 0)) cache = result; - callback(result); -}; - -/** - * @description Retrieves current tab information - * @param {void} [callback] - * @returns {Promise<{ id: string, location: string }>} - */ - -const getTab = (callback) => { - chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { - const tab = tabs[0]; - - callback({ - id: tab?.id, - hostname: tab ? new URL(tab.url).hostname.split('.').slice(-2).join('.') : undefined, +const refreshData = (callback) => { + fetch(`${apiUrl}/data/`).then((result) => { + result.json().then(({ data }) => { + chrome.storage.local.set({ data }); + callback(data); }); }); }; /** * @async - * @description Retrieves data from GitHub - * @param {string} key - * @returns {Promise<{ [key]: string[] }>} - */ - -const query = async (key) => { - try { - const url = `${baseDataUrl}/${key}.txt`; - const response = await fetch(url); - const data = await response.text(); - - if (response.status !== 200) throw new Error(); - - return { [key]: [...new Set(data.split('\n'))] }; - } catch { - return { [key]: [] }; - } -}; - -/** * @description Reports active tab URL + * @param {chrome.tabs.Tab} tab */ -const report = () => { - chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { - const tab = tabs[0]; - const userAgent = window.navigator.userAgent; - const version = chrome.runtime.getManifest().version; +const report = async (tab) => { + const version = chrome.runtime.getManifest().version; + const body = JSON.stringify({ url: tab?.url, version }); + const headers = { 'Content-type': 'application/json' }; + const url = `${apiUrl}/report/`; - if (tab) { - fetch(`${apiUrl}/report/`, { - body: JSON.stringify({ - html: `Browser: ${userAgent}
Site: ${tab.url}
Version: ${version}`, - to: 'hello@wanhose.dev', - subject: 'Cookie Dialog Monster Report', - }), - headers: { - 'Content-type': 'application/json', - }, - method: 'POST', - }); - } - }); + await fetch(url, { body, headers, method: 'POST' }); + chrome.tabs.sendMessage(tab.id, { type: 'SHOW_REPORT_CONFIRMATION' }); }; /** - * @description Update store - * @param {string} [hostname] - * @param {object} [state] + * @description Listens to context menus */ -const updateStore = (hostname, state) => { - chrome.storage.local.get(null, (cache) => { - const current = cache[hostname]; +chrome.contextMenus.onClicked.addListener((info, tab) => { + switch (info.menuItemId) { + case reportMenuItemId: + if (tab) report(tab); + break; + default: + break; + } +}); - chrome.storage.local.set({ - [hostname]: { - enabled: typeof state.enabled === 'undefined' ? current.enabled : state.enabled, - }, - }); +/** + * @description Listens to extension installed/updated + */ + +chrome.runtime.onInstalled.addListener(() => { + chrome.contextMenus.create({ + contexts: ['all'], + documentUrlPatterns: chrome.runtime.getManifest().content_scripts[0].matches, + id: reportMenuItemId, + title: chrome.i18n.getMessage('contextMenuText'), }); -}; +}); + +/** + * @description Listens to first start + */ + +chrome.runtime.onStartup.addListener(() => { + refreshData(); +}); /** * @description Listens to messages */ -chrome.runtime.onMessage.addListener((request, sender, callback) => { - const hostname = request.hostname; - const state = request.state; +chrome.runtime.onMessage.addListener((message, sender, callback) => { + const hostname = message.hostname; const tabId = sender.tab?.id; - switch (request.type) { + switch (message.type) { case 'DISABLE_ICON': - if (tabId) disableIcon(tabId); + if (tabId) chrome.browserAction.setIcon({ path: 'assets/icons/disabled.png', tabId }); break; case 'ENABLE_ICON': - if (tabId) enableIcon(tabId); + if (tabId) chrome.browserAction.setIcon({ path: 'assets/icons/enabled.png', tabId }); break; case 'ENABLE_POPUP': - if (tabId) enablePopup(tabId); + if (tabId) chrome.browserAction.setPopup({ popup: 'popup.html', tabId }); break; case 'GET_DATA': - getData(callback); + chrome.storage.local.get('data', ({ data }) => { + if (data) callback(data); + else refreshData(callback); + }); break; - case 'GET_STORE': - getStore(hostname, callback); + case 'GET_STATE': + // prettier-ignore + if (hostname) chrome.storage.local.get(hostname, (state) => callback(state[hostname] ?? initial)); break; case 'GET_TAB': - getTab(callback); + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => callback(tabs[0])); break; - case 'UPDATE_STORE': - updateStore(hostname, state); + case 'UPDATE_STATE': + if (hostname) chrome.storage.local.set({ [hostname]: message.state }); break; default: break; @@ -234,23 +124,3 @@ chrome.runtime.onMessage.addListener((request, sender, callback) => { return true; }); - -/** - * @description Creates context menu - */ - -chrome.contextMenus.create({ - contexts: ['all'], - documentUrlPatterns: chrome.runtime.getManifest().content_scripts[0].matches, - id: contextMenuId, - title: chrome.i18n.getMessage('contextMenuText'), -}); - -/** - * @description Listens to context menus - */ - -chrome.contextMenus.onClicked.addListener((info) => { - if (info.menuItemId !== contextMenuId) return; - report(); -}); diff --git a/packages/browser-extension/src/scripts/content.js b/packages/browser-extension/src/scripts/content.js index da2e93f..76ee91e 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -1,36 +1,28 @@ /** - * @description Array of selectors - * @type {string[]} + * @description Data properties + * @type {{ classes: string[], fixes: string[], elements: string[], skips: string[] }?} */ -const classes = []; +let data = null; /** * @description Shortcut to send messages to background script - * @type {void} */ const dispatch = chrome.runtime.sendMessage; /** - * @description Array of skips to skip - * @type {string[]} + * @description Forbidden tags to ignore in the DOM */ -const skips = []; +const forbiddenTags = ['BASE', 'BODY', 'HEAD', 'HTML', 'LINK', 'META', 'SCRIPT', 'STYLE', 'TITLE']; /** - * @description Array of instructions - * @type {string[]} + * @description Current hostname + * @type {string} */ -const fixes = []; - -/** - * @description Hostname - */ - -const hostname = document.location.hostname.split('.').slice(-2).join('.'); +const hostname = document.location.hostname.split('.').slice(-3).join('.').replace('www.', ''); /** * @description Options provided to observer @@ -46,56 +38,43 @@ const options = { childList: true, subtree: true }; const preview = hostname.startsWith('consent.') || hostname.startsWith('myprivacy.'); /** - * @description Selectors list - * @type {string[]} - */ - -const selectors = []; - -/** - * @description Target provided to observer - */ - -const target = document.body || document.documentElement; - -/** - * @description Checks if node element is removable - * @param {any} node - * @param {boolean} skipMatch + * @description Matches if node element is removable + * @param {Element} node * @returns {boolean} */ -const check = (node, skipMatch) => +const match = (node) => node instanceof HTMLElement && node.parentElement && - !['BODY', 'HTML'].includes(node.tagName) && - !(node.id && ['APP', 'ROOT'].includes(node.id.toUpperCase?.())) && - (skipMatch || node.matches(selectors)); + !forbiddenTags.includes(node.tagName?.toUpperCase?.()) && + node.matches(data?.elements ?? []); /** * @description Cleans DOM * @param {HTMLElement[]} nodes - * @param {boolean} skipMatch + * @param {boolean?} skipMatch * @returns {void} */ const clean = (nodes, skipMatch) => - nodes.filter((node) => check(node, skipMatch)).forEach((node) => (node.outerHTML = '')); + nodes.filter((node) => skipMatch || match(node)).forEach((node) => node.remove()); /** * @description Fixes scroll issues */ const fix = () => { - if (skips.length && !skips.includes(hostname)) { + document.getElementsByClassName('_31e')[0]?.classList.remove('_31e'); + + if (data?.skips.length && !data.skips.includes(hostname)) { for (const item of [document.body, document.documentElement]) { - item?.classList.remove(...classes); + item?.classList.remove(...(data?.classes ?? [])); item?.style.setProperty('position', 'initial', 'important'); item?.style.setProperty('overflow-y', 'initial', 'important'); } } - for (const fix of fixes) { + for (const fix of data?.fixes ?? []) { const [match, selector, action, property] = fix.split('##'); if (hostname.includes(match)) { @@ -132,54 +111,40 @@ const fix = () => { * @type {MutationObserver} */ -const observer = new MutationObserver((mutations, instance) => { +const observer = new MutationObserver((mutations) => { const nodes = mutations.map((mutation) => Array.from(mutation.addedNodes)).flat(); - instance.disconnect(); fix(); - if (!preview && selectors.length) clean(nodes); - instance.observe(target, options); + if (data?.elements.length && !preview) clean(nodes); }); /** - * @description Cleans DOM again after all - * @listens document#readystatechange + * @description Fixes bfcache issues + * @listens window#pageshow */ -document.addEventListener('readystatechange', () => { - dispatch({ hostname, type: 'GET_STORE' }, null, async ({ enabled }) => { - if (document.readyState === 'complete' && enabled && !preview) { - const nodes = selectors.length ? Array.from(document.querySelectorAll(selectors)) : []; - - fix(); - clean(nodes, true); - setTimeout(() => clean(nodes, true), 2000); - } - }); +window.addEventListener('pageshow', (event) => { + if (event.persisted) { + dispatch({ hostname, type: 'GET_STATE' }, null, (state) => { + if (data?.elements.length && state?.enabled && !preview) { + fix(); + clean(Array.from(document.querySelectorAll(data.elements)), true); + } + }); + } }); /** - * @description Fix bfcache issues - * @listens window#unload + * @description Sets up everything */ -window.addEventListener('unload', () => {}); - -/** - * @description Setups everything and starts to observe if enabled - */ - -dispatch({ hostname, type: 'GET_STORE' }, null, ({ enabled }) => { +dispatch({ hostname, type: 'GET_STATE' }, null, (state) => { dispatch({ type: 'ENABLE_POPUP' }); - if (enabled) { - dispatch({ type: 'GET_DATA' }, null, (data) => { - classes.push(...data.classes); - fixes.push(...data.fixes); - options.attributeFilter = data.attributes; - selectors.push(...data.selectors); - skips.push(...data.skips); - observer.observe(target, options); + if (state?.enabled) { + dispatch({ hostname, type: 'GET_DATA' }, null, (result) => { + data = result; + observer.observe(document.body ?? document.documentElement, options); dispatch({ type: 'ENABLE_ICON' }); }); } diff --git a/packages/browser-extension/src/scripts/popup.js b/packages/browser-extension/src/scripts/popup.js index df0379c..32355a9 100644 --- a/packages/browser-extension/src/scripts/popup.js +++ b/packages/browser-extension/src/scripts/popup.js @@ -1,5 +1,4 @@ /** - * @constant chromeUrl * @description Chrome Web Store link * @type {string} */ @@ -7,15 +6,12 @@ const chromeUrl = 'https://chrome.google.com/webstore/detail/djcbfpkdhdkaflcigibkbpboflaplabg'; /** - * @constant dispatch * @description Shortcut to send messages to background script - * @type {void} */ const dispatch = chrome.runtime.sendMessage; /** - * @constant edgeUrl * @description Edge Add-ons link * @type {string} */ @@ -24,7 +20,6 @@ const edgeUrl = 'https://microsoftedge.microsoft.com/addons/detail/hbogodfciblakeneadpcolhmfckmjcii'; /** - * @constant firefoxUrl * @description Firefox Add-ons link * @type {string} */ @@ -32,7 +27,13 @@ const edgeUrl = const firefoxUrl = 'https://addons.mozilla.org/es/firefox/addon/cookie-dialog-monster/'; /** - * @constant isChromium + * @description Current hostname + * @type {string} + */ + +let hostname = '?'; + +/** * @description Is current browser an instance of Chromium? * @type {boolean} */ @@ -40,7 +41,6 @@ const firefoxUrl = 'https://addons.mozilla.org/es/firefox/addon/cookie-dialog-mo const isChromium = navigator.userAgent.indexOf('Chrome') !== -1; /** - * @constant isEdge * @description Is current browser an instance of Edge? * @type {boolean} */ @@ -48,7 +48,6 @@ const isChromium = navigator.userAgent.indexOf('Chrome') !== -1; const isEdge = navigator.userAgent.indexOf('Edg') !== -1; /** - * @constant isFirefox * @description Is current browser an instance of Firefox? * @type {boolean} */ @@ -59,22 +58,10 @@ const isFirefox = navigator.userAgent.indexOf('Firefox') !== -1; * @description Disables or enables extension on current page */ -const handlePowerChange = () => { - dispatch({ type: 'GET_TAB' }, null, ({ hostname, id }) => { - dispatch({ hostname, type: 'GET_STORE' }, null, ({ enabled }) => { - dispatch({ hostname, state: { enabled: !enabled }, type: 'UPDATE_STORE' }); - chrome.tabs.reload(id, { bypassCache: true }); - }); - }); -}; - -/** - * @description Reload current page - */ - -const handleReload = () => { - dispatch({ type: 'GET_TAB' }, null, ({ id }) => { - chrome.tabs.reload(id, { bypassCache: true }); +const handlePowerChange = async () => { + dispatch({ hostname, type: 'GET_STATE' }, null, (state) => { + dispatch({ hostname, state: { enabled: !state?.enabled }, type: 'UPDATE_STATE' }); + chrome.tabs.reload({ bypassCache: true }); }); }; @@ -106,8 +93,12 @@ const handleRate = (event) => { */ const handleContentLoaded = () => { - dispatch({ type: 'GET_TAB' }, null, ({ hostname }) => { - dispatch({ hostname, type: 'GET_STORE' }, null, ({ enabled }) => { + dispatch({ type: 'GET_TAB' }, null, (tab) => { + hostname = tab?.url + ? new URL(tab.url).hostname.split('.').slice(-3).join('.').replace('www.', '') + : undefined; + + dispatch({ hostname, type: 'GET_STATE' }, null, (state) => { translate(); const host = document.getElementById('host'); @@ -119,13 +110,14 @@ const handleContentLoaded = () => { like.addEventListener('click', handleRate); power.addEventListener('change', handlePowerChange); - reload.addEventListener('click', handleReload); - if (isEdge) store.setAttribute('href', edgeUrl); - else if (isChromium) store.setAttribute('href', chromeUrl); - else if (isFirefox) store.setAttribute('href', firefoxUrl); + reload.addEventListener('click', () => chrome.tabs.reload({ bypassCache: true })); unlike.addEventListener('click', handleRate); - if (location) host.innerText = hostname.replace('www.', ''); - if (!enabled) power.removeAttribute('checked'); + + host.innerText = hostname ?? 'unknown'; + if (isEdge) store?.setAttribute('href', edgeUrl); + else if (isChromium) store?.setAttribute('href', chromeUrl); + else if (isFirefox) store?.setAttribute('href', firefoxUrl); + if (!state.enabled) power.removeAttribute('checked'); }); }); }; diff --git a/packages/browser-extension/src/scripts/snackbar.js b/packages/browser-extension/src/scripts/snackbar.js new file mode 100644 index 0000000..fcfc3cd --- /dev/null +++ b/packages/browser-extension/src/scripts/snackbar.js @@ -0,0 +1,97 @@ +/** + * @description Listens to messages + */ + +chrome.runtime.onMessage.addListener((message) => { + switch (message.type) { + case 'HIDE_REPORT_CONFIRMATION': + hideReportConfirmation(); + break; + case 'SHOW_REPORT_CONFIRMATION': + showReportConfirmation(); + break; + default: + break; + } +}); + +/** + * @description Report confirmation ID + */ + +const REPORT_CONFIRMATION_ID = 'report-confirmation'; + +/** + * @description Report confirmation outer HTML + */ + +const REPORT_CONFIRMATION_HTML = ` +
+
+
+ + ${chrome.i18n.getMessage('reportText')} +
+
+ `; + +/** + * @description Hides report confirmation + */ + +const hideReportConfirmation = () => { + document.getElementById(REPORT_CONFIRMATION_ID)?.setAttribute('hidden', 'true'); +}; + +/** + * @description Shows report confirmation + */ + +const showReportConfirmation = () => { + const element = document.getElementById(REPORT_CONFIRMATION_ID); + + if (element) { + element.removeAttribute('hidden'); + } else { + const parser = new DOMParser(); + const result = parser.parseFromString(REPORT_CONFIRMATION_HTML, 'text/html'); + const snackbar = result.body.firstElementChild; + + document.body.appendChild(snackbar); + } + + setTimeout(() => hideReportConfirmation(), 3750); +}; diff --git a/packages/browser-extension/src/styles/globals.css b/packages/browser-extension/src/styles/popup.css similarity index 95% rename from packages/browser-extension/src/styles/globals.css rename to packages/browser-extension/src/styles/popup.css index bd187e8..e395a36 100644 --- a/packages/browser-extension/src/styles/globals.css +++ b/packages/browser-extension/src/styles/popup.css @@ -25,7 +25,7 @@ body { display: flex; flex-direction: column; font-family: 'Lato', Arial, Helvetica, sans-serif; - height: 25rem; + height: 24rem; width: 20rem; } @@ -34,9 +34,10 @@ button { } footer { + background-color: var(--color-secondary); font-size: 0.75rem; + height: 0.25rem; margin-top: auto; - padding: 1rem; text-align: center; } @@ -109,18 +110,23 @@ svg { font-size: 1rem; } +.contribute, .help { align-items: center; display: flex; + font-size: 0.875rem; justify-content: space-between; } +.contribute > a, .help > a { color: var(--color-secondary); padding: 0.25rem; transition: 0.4s; } +.contribute > a:focus, +.contribute > a:hover, .help > a:focus, .help > a:hover { background-color: var(--color-secondary); @@ -129,18 +135,11 @@ svg { outline: none; } -.help > span { - font-size: 0.875rem; -} - .rating { align-items: center; display: flex; - justify-content: space-between; -} - -.rating > span { font-size: 0.875rem; + justify-content: space-between; } .rating-actions { diff --git a/packages/browser-extension/src/styles/snackbar.css b/packages/browser-extension/src/styles/snackbar.css new file mode 100644 index 0000000..12f3e46 --- /dev/null +++ b/packages/browser-extension/src/styles/snackbar.css @@ -0,0 +1,65 @@ +#report-confirmation { + bottom: 30px; + font-family: 'Lato', Arial, Helvetica, sans-serif !important; + min-width: 250px; + position: fixed; + right: 10px; + text-align: left; + visibility: hidden; + z-index: 99999; +} + +#report-confirmation:not([hidden]) { + animation: fadeIn 0.5s, fadeOut 0.5s 3.5s; + visibility: visible !important; +} + +#report-confirmation:not([hidden]) #report-confirmation-bar { + animation: roundTime 3.5s linear forwards; +} + +#report-confirmation-content { + align-items: center; + background-color: #34495e !important; + border-radius: 2px; + color: #fff !important; + display: flex; + font-size: 14px !important; + gap: 16px; + overflow: hidden; + padding: 16px; +} + +#report-confirmation-bar { + background-color: #3dd9eb !important; + height: 4px; + transform-origin: left center; +} + +@keyframes fadeIn { + from { + bottom: 0; + opacity: 0; + } + to { + bottom: 30px; + opacity: 1; + } +} + +@keyframes fadeOut { + from { + bottom: 30px; + opacity: 1; + } + to { + bottom: 0; + opacity: 0; + } +} + +@keyframes roundTime { + to { + transform: scaleX(0); + } +} diff --git a/packages/web/src/images/popup.png b/packages/web/src/images/popup.png index 0ed537e..209d767 100644 Binary files a/packages/web/src/images/popup.png and b/packages/web/src/images/popup.png differ