From 02eeb58353acdd7e217a29fdd3add83db47bd50a Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 16:53:57 +0200 Subject: [PATCH 01/11] fix(browser-extension): dialog styles in some pages --- packages/browser-extension/src/styles/dialog.css | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/browser-extension/src/styles/dialog.css b/packages/browser-extension/src/styles/dialog.css index 4edb653..4d179f8 100644 --- a/packages/browser-extension/src/styles/dialog.css +++ b/packages/browser-extension/src/styles/dialog.css @@ -25,6 +25,7 @@ #report-dialog * { box-sizing: border-box; + visibility: visible !important; } report-dialog-body { From afe466f114cae7edc5605f63d8c7c24122545ff1 Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 16:56:24 +0200 Subject: [PATCH 02/11] feat(browser-extension): improve performance --- .../browser-extension/src/scripts/content.js | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/browser-extension/src/scripts/content.js b/packages/browser-extension/src/scripts/content.js index f0082fe..c04218b 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -1,6 +1,6 @@ /** * @description Data properties - * @type {{ classes: string[], fixes: string[], elements: string[], skips: string[], tags: string[] }?} + * @type {{ classes: string[], commonWords?: string[], fixes: string[], elements: string[], skips: string[], tags: string[] }?} */ let data = null; @@ -64,13 +64,14 @@ const clean = (nodes, skipMatch) => { }; /** - * @description Forces a DOM clean + * @description Forces a DOM clean in the specific node + * @param {HTMLElement} node * @returns {void} */ -const forceClean = () => { +const forceClean = (node) => { if (data?.elements.length && state.enabled && !preview) { - const nodes = [...document.querySelectorAll(data.elements)]; + const nodes = [...node.querySelectorAll(data.elements)]; if (nodes.length) { fix(); @@ -103,12 +104,28 @@ const isInViewport = (node) => { * @returns {boolean} */ -const match = (node, skipMatch) => - node instanceof HTMLElement && - !node.getAttribute('data-cookie-dialog-monster') && - !data?.tags.includes(node.tagName?.toUpperCase?.()) && - isInViewport(node) && - (skipMatch || node.matches(data?.elements ?? [])); +const match = (node, skipMatch) => { + if (node instanceof HTMLElement) { + if (node.hasAttributes()) { + return ( + // 2023-06-10: twitch.tv temporary fix + node.className !== 'chat-line__message' && + // ... + !node.getAttribute('data-cookie-dialog-monster') && + !data?.tags.includes(node.tagName?.toUpperCase?.()) && + isInViewport(node) && + (skipMatch || node.matches(data?.elements ?? [])) + ); + } else { + // 2023-06-10: fix edge case force cleaning on children if no attributes + if (data?.commonWords && node.outerHTML.match(new RegExp(commonWords?.join('|')))) { + forceClean(node); + } + } + } + + return false; +}; /** * @description Fixes scroll issues @@ -184,7 +201,7 @@ const observer = new MutationObserver((mutations) => { */ window.addEventListener('DOMContentLoaded', () => { - forceClean(); + forceClean(document.documentElement); }); /** @@ -194,7 +211,7 @@ window.addEventListener('DOMContentLoaded', () => { window.addEventListener('pageshow', (event) => { if (event.persisted) { - forceClean(); + forceClean(document.documentElement); } }); @@ -210,6 +227,6 @@ window.addEventListener('pageshow', (event) => { if (state.enabled) { data = await dispatch({ hostname, type: 'GET_DATA' }); dispatch({ type: 'ENABLE_ICON' }); - observer.observe(document.body ?? document.documentElement, options); + observer.observe(document.documentElement, options); } })(); From e793c5b4d9b17f82d1de84c6cd789170f591f92e Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 16:56:37 +0200 Subject: [PATCH 03/11] 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 1e7ef83..7d9f622 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": "6.3.2", + "version": "6.3.3", "default_locale": "en", "description": "__MSG_appDesc__", "icons": { From e3b88285a6da3e256abd157a3a7e5264dec7a35b Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 17:20:11 +0200 Subject: [PATCH 04/11] fix(data): issue #243 --- data/tags.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/data/tags.txt b/data/tags.txt index bf19730..6459785 100644 --- a/data/tags.txt +++ b/data/tags.txt @@ -78,6 +78,7 @@ SEARCH SELECT SLOT SMALL +SPAN SOURCE STRONG STYLE From 31e06256fac6a955c42a0f11f9e44e6f800e6ce9 Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 17:28:33 +0200 Subject: [PATCH 05/11] fix(browser-extension): property didn't exist --- 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 c04218b..4328bdd 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -118,7 +118,7 @@ const match = (node, skipMatch) => { ); } else { // 2023-06-10: fix edge case force cleaning on children if no attributes - if (data?.commonWords && node.outerHTML.match(new RegExp(commonWords?.join('|')))) { + if (data?.commonWords && node.outerHTML.match(new RegExp(data.commonWords.join('|')))) { forceClean(node); } } From 21a6106aec041f243449bccc077129f1ccfba4ca Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 17:44:53 +0200 Subject: [PATCH 06/11] fix(data): issue #243 --- data/tags.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/data/tags.txt b/data/tags.txt index bf19730..701f852 100644 --- a/data/tags.txt +++ b/data/tags.txt @@ -1,3 +1,4 @@ +A ABBR ADDRESS AREA @@ -9,6 +10,7 @@ BDO BLOCKQUOTE BODY BR +BUTTON CANVAS CAPTION CITE @@ -20,6 +22,7 @@ DATALIST DD DEL DETAILS +DETAILS-MENU DFN DL DT @@ -29,6 +32,7 @@ FIELDSET FIGCAPTION FIGURE FOOTER +G-EMOJI H1 H2 H3 @@ -43,6 +47,7 @@ HTML I IFRAME IMG +INCLUDE-FRAGMENT INPUT INS KBD @@ -68,6 +73,7 @@ PICTURE PRE PROGRESS Q +RELATIVE-TIME RP RT RUBY @@ -78,6 +84,7 @@ SEARCH SELECT SLOT SMALL +SPAN SOURCE STRONG STYLE @@ -85,11 +92,13 @@ SUB SUMMARY SUP SVG +TASK-LISTS TBODY TD TEMPLATE TEXTAREA TFOOT +TOOL-TIP TH THEAD TIME From 421359b0e06256f8a3fdc17911d2b5967345df3f Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 19:11:35 +0200 Subject: [PATCH 07/11] refactor(browser-extension): drop only text children, improve legibility and remove deprecated stuff --- .../browser-extension/src/scripts/content.js | 80 ++++++++++++------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/packages/browser-extension/src/scripts/content.js b/packages/browser-extension/src/scripts/content.js index 4328bdd..7c6429d 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -42,10 +42,9 @@ let state = { enabled: true }; * @description Cleans DOM * @param {Element[]} nodes * @param {boolean?} skipMatch - * @returns {void} */ -const clean = (nodes, skipMatch) => { +function clean(nodes, skipMatch) { for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; @@ -61,15 +60,29 @@ const clean = (nodes, skipMatch) => { } } } -}; +} + +/** + * @description Flat child nodes + * @param {HTMLElement} node + * @param {HTMLElement[] | undefined} children + * @returns {number[]} + */ + +function flatNode(node) { + return [...node.childNodes].flatMap((childNode) => + childNode.nodeType === Node.TEXT_NODE + ? [childNode.nodeType] + : [...[...childNode.childNodes].map((x) => x.nodeType)] + ); +} /** * @description Forces a DOM clean in the specific node * @param {HTMLElement} node - * @returns {void} */ -const forceClean = (node) => { +function forceClean(node) { if (data?.elements.length && state.enabled && !preview) { const nodes = [...node.querySelectorAll(data.elements)]; @@ -78,7 +91,7 @@ const forceClean = (node) => { clean(nodes, true); } } -}; +} /** * @description Checks if an element is visible in the viewport @@ -86,16 +99,16 @@ const forceClean = (node) => { * @returns {boolean} */ -const isInViewport = (node) => { +function isInViewport(node) { const height = window.innerHeight || document.documentElement.clientHeight; const position = node.getBoundingClientRect(); - const scroll = window.scrollY || window.pageYOffset; + const scroll = window.scrollY; return ( position.bottom === position.top || (scroll + position.top <= scroll + height && scroll + position.bottom >= scroll) ); -}; +} /** * @description Checks if node element is removable @@ -104,34 +117,43 @@ const isInViewport = (node) => { * @returns {boolean} */ -const match = (node, skipMatch) => { - if (node instanceof HTMLElement) { - if (node.hasAttributes()) { - return ( - // 2023-06-10: twitch.tv temporary fix - node.className !== 'chat-line__message' && - // ... - !node.getAttribute('data-cookie-dialog-monster') && - !data?.tags.includes(node.tagName?.toUpperCase?.()) && - isInViewport(node) && - (skipMatch || node.matches(data?.elements ?? [])) - ); - } else { - // 2023-06-10: fix edge case force cleaning on children if no attributes - if (data?.commonWords && node.outerHTML.match(new RegExp(data.commonWords.join('|')))) { - forceClean(node); - } +function match(node, skipMatch) { + if (!node instanceof HTMLElement) { + return false; + } + + if (data?.tags.includes(node.tagName?.toUpperCase?.())) { + return false; + } + + if (flatNode(node).every((x) => x === Node.TEXT_NODE)) { + return false; + } + + if (node.hasAttributes()) { + return ( + // 2023-06-10: twitch.tv temporary fix + node.className !== 'chat-line__message' && + // ... + !node.getAttribute('data-cookie-dialog-monster') && + isInViewport(node) && + (skipMatch || node.matches(data?.elements ?? [])) + ); + } else { + // 2023-06-10: fix edge case force cleaning on children if no attributes + if (data?.commonWords && node.outerHTML.match(new RegExp(data.commonWords.join('|')))) { + forceClean(node); } } return false; -}; +} /** * @description Fixes scroll issues */ -const fix = () => { +function fix() { const backdrop = document.getElementsByClassName('modal-backdrop')[0]; const facebook = document.getElementsByClassName('_31e')[0]; const fixes = data?.fixes ?? []; @@ -181,7 +203,7 @@ const fix = () => { item?.style.setProperty('overflow-y', 'initial', 'important'); } } -}; +} /** * @description Mutation Observer instance From a2ede05c9b9983e4cb2c382ffa34bcac72de7e2b Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 19:57:55 +0200 Subject: [PATCH 08/11] fix(browser-extension): lag in some pages due a large query selector --- packages/browser-extension/src/scripts/content.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/browser-extension/src/scripts/content.js b/packages/browser-extension/src/scripts/content.js index 7c6429d..df5431e 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -217,15 +217,6 @@ const observer = new MutationObserver((mutations) => { if (data?.elements.length && !preview) clean(nodes); }); -/** - * @description Fixes already existing element when page load issues - * @listens window#DOMContentLoaded - */ - -window.addEventListener('DOMContentLoaded', () => { - forceClean(document.documentElement); -}); - /** * @description Fixes bfcache issues * @listens window#pageshow From dcc9dfef217bcd8ed322e30bd35638237964238a Mon Sep 17 00:00:00 2001 From: wanhose Date: Sat, 10 Jun 2023 20:07:33 +0200 Subject: [PATCH 09/11] feat(browser-extension): minor code improvement about use class list instead class name --- 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 df5431e..58f141a 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -133,7 +133,7 @@ function match(node, skipMatch) { if (node.hasAttributes()) { return ( // 2023-06-10: twitch.tv temporary fix - node.className !== 'chat-line__message' && + !node.classList.contains('chat-line__message') && // ... !node.getAttribute('data-cookie-dialog-monster') && isInViewport(node) && From 2ef1b0238339ae8edecffb1acad5aa452819bd56 Mon Sep 17 00:00:00 2001 From: wanhose Date: Sun, 11 Jun 2023 12:19:36 +0200 Subject: [PATCH 10/11] fix(browser-extension): child nodes issue --- packages/browser-extension/src/scripts/content.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/browser-extension/src/scripts/content.js b/packages/browser-extension/src/scripts/content.js index 58f141a..1f5e1b7 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -118,7 +118,7 @@ function isInViewport(node) { */ function match(node, skipMatch) { - if (!node instanceof HTMLElement) { + if (!node instanceof HTMLElement || !node.tagName) { return false; } @@ -126,7 +126,7 @@ function match(node, skipMatch) { return false; } - if (flatNode(node).every((x) => x === Node.TEXT_NODE)) { + if (node.childNodes.length && flatNode(node).every((x) => x === Node.TEXT_NODE)) { return false; } From 8bcc5f92a592879569ca599f82c4e116eec18a65 Mon Sep 17 00:00:00 2001 From: wanhose Date: Sun, 11 Jun 2023 12:45:47 +0200 Subject: [PATCH 11/11] feat(browser-extension): improve documentation and naming --- .../browser-extension/src/scripts/content.js | 158 ++++++++++-------- 1 file changed, 92 insertions(+), 66 deletions(-) diff --git a/packages/browser-extension/src/scripts/content.js b/packages/browser-extension/src/scripts/content.js index 1f5e1b7..ccc4f23 100644 --- a/packages/browser-extension/src/scripts/content.js +++ b/packages/browser-extension/src/scripts/content.js @@ -40,37 +40,30 @@ let state = { enabled: true }; /** * @description Cleans DOM - * @param {Element[]} nodes + * @param {Element[]} elements * @param {boolean?} skipMatch */ -function clean(nodes, skipMatch) { - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; +function clean(elements, skipMatch) { + for (const element of elements) { + if (match(element, skipMatch)) { + const observer = new MutationObserver(() => forceElementStyles(element)); - if (match(node, skipMatch)) { - const observer = new MutationObserver(() => { - node.style.setProperty('display', 'none', 'important'); - }); - - if (!node.hasAttribute('data-cookie-dialog-monster')) { - node.setAttribute('data-cookie-dialog-monster', 'true'); - node.style.setProperty('display', 'none', 'important'); - observer.observe(node, { attributes: true, attributeFilter: ['style'] }); - } + element.setAttribute('data-cookie-dialog-monster', 'true'); + element.style.setProperty('display', 'none', 'important'); + observer.observe(element, { attributes: true, attributeFilter: ['class', 'style'] }); } } } /** - * @description Flat child nodes - * @param {HTMLElement} node - * @param {HTMLElement[] | undefined} children + * @description Flat child nodes for a given element + * @param {HTMLElement} element * @returns {number[]} */ -function flatNode(node) { - return [...node.childNodes].flatMap((childNode) => +function flatElement(element) { + return [...element.childNodes].flatMap((childNode) => childNode.nodeType === Node.TEXT_NODE ? [childNode.nodeType] : [...[...childNode.childNodes].map((x) => x.nodeType)] @@ -78,30 +71,39 @@ function flatNode(node) { } /** - * @description Forces a DOM clean in the specific node - * @param {HTMLElement} node + * @description Forces a DOM clean in the specific element + * @param {HTMLElement} element */ -function forceClean(node) { +function forceClean(element) { if (data?.elements.length && state.enabled && !preview) { - const nodes = [...node.querySelectorAll(data.elements)]; + const elements = [...element.querySelectorAll(data.elements)]; - if (nodes.length) { + if (elements.length) { fix(); - clean(nodes, true); + clean(elements, true); } } } +/** + * @description Forces element to have these styles + * @param {HTMLElement} element + */ + +function forceElementStyles(element) { + element.style.setProperty('display', 'none', 'important'); +} + /** * @description Checks if an element is visible in the viewport - * @param {HTMLElement} node + * @param {HTMLElement} element * @returns {boolean} */ -function isInViewport(node) { +function isInViewport(element) { const height = window.innerHeight || document.documentElement.clientHeight; - const position = node.getBoundingClientRect(); + const position = element.getBoundingClientRect(); const scroll = window.scrollY; return ( @@ -111,38 +113,41 @@ function isInViewport(node) { } /** - * @description Checks if node element is removable - * @param {Element} node + * @description Checks if element element is removable + * @param {Element} element * @param {boolean?} skipMatch * @returns {boolean} */ -function match(node, skipMatch) { - if (!node instanceof HTMLElement || !node.tagName) { +function match(element, skipMatch) { + if (!element instanceof HTMLElement || !element.tagName) { return false; } - if (data?.tags.includes(node.tagName?.toUpperCase?.())) { + if (element.getAttribute('data-cookie-dialog-monster')) { return false; } - if (node.childNodes.length && flatNode(node).every((x) => x === Node.TEXT_NODE)) { + if (data?.tags.includes(element.tagName?.toUpperCase?.())) { return false; } - if (node.hasAttributes()) { + if (element.childNodes.length && flatElement(element).every((x) => x === Node.TEXT_NODE)) { + return false; + } + + if (element.hasAttributes()) { return ( // 2023-06-10: twitch.tv temporary fix - !node.classList.contains('chat-line__message') && + !element.classList.contains('chat-line__message') && // ... - !node.getAttribute('data-cookie-dialog-monster') && - isInViewport(node) && - (skipMatch || node.matches(data?.elements ?? [])) + isInViewport(element) && + (skipMatch || element.matches(data?.elements ?? [])) ); } else { // 2023-06-10: fix edge case force cleaning on children if no attributes - if (data?.commonWords && node.outerHTML.match(new RegExp(data.commonWords.join('|')))) { - forceClean(node); + if (data?.commonWords && element.outerHTML.match(new RegExp(data.commonWords.join('|')))) { + forceClean(element); } } @@ -170,26 +175,20 @@ function fix() { if (hostname.includes(match)) { switch (action) { - case 'click': { - const node = document.querySelector(selector); - node?.click(); + case 'click': + document.querySelector(selector)?.click(); break; - } - case 'remove': { - const node = document.querySelector(selector); - node?.style?.removeProperty(property); + case 'remove': + document.querySelector(selector)?.style?.removeProperty(property); break; - } - case 'reset': { - const node = document.querySelector(selector); - node?.style?.setProperty(property, 'initial', 'important'); + case 'reset': + document.querySelector(selector)?.style?.setProperty(property, 'initial', 'important'); break; - } - case 'resetAll': { - const nodes = document.querySelectorAll(selector); - nodes.forEach((node) => node?.style?.setProperty(property, 'initial', 'important')); + case 'resetAll': + document.querySelectorAll(selector).forEach((element) => { + element?.style?.setProperty(property, 'initial', 'important'); + }); break; - } default: break; } @@ -197,24 +196,51 @@ function fix() { } if (skips.indexOf(hostname) === -1) { - for (const item of [document.body, document.documentElement]) { - item?.classList.remove(...(data?.classes ?? [])); - item?.style.setProperty('position', 'initial', 'important'); - item?.style.setProperty('overflow-y', 'initial', 'important'); + for (const element of [document.body, document.documentElement]) { + element?.classList.remove(...(data?.classes ?? [])); + element?.style.setProperty('position', 'initial', 'important'); + element?.style.setProperty('overflow-y', 'initial', 'important'); } } } +/** + * @description Calculates reading time for the current page to avoid lags in large pages + * @returns {number} + */ + +function readingTime() { + const text = document.body.innerText; + const wpm = 225; + const words = text.trim().split(/\s+/).length; + const time = Math.ceil(words / wpm); + + return time; +} + /** * @description Mutation Observer instance * @type {MutationObserver} */ const observer = new MutationObserver((mutations) => { - const nodes = mutations.map((mutation) => Array.from(mutation.addedNodes)).flat(); + const elements = mutations.map((mutation) => Array.from(mutation.addedNodes)).flat(); - fix(); - if (data?.elements.length && !preview) clean(nodes); + if (data?.elements.length && !preview) { + fix(); + clean(elements); + } +}); + +/** + * @description Fixes already existing element when page load issues + * @listens window#DOMContentLoaded + */ + +window.addEventListener('DOMContentLoaded', () => { + if (readingTime() < 4) { + forceClean(document.body); + } }); /** @@ -224,7 +250,7 @@ const observer = new MutationObserver((mutations) => { window.addEventListener('pageshow', (event) => { if (event.persisted) { - forceClean(document.documentElement); + forceClean(document.body); } }); @@ -240,6 +266,6 @@ window.addEventListener('pageshow', (event) => { if (state.enabled) { data = await dispatch({ hostname, type: 'GET_DATA' }); dispatch({ type: 'ENABLE_ICON' }); - observer.observe(document.documentElement, options); + observer.observe(document.body ?? document.documentElement, options); } })();