Merge pull request '8.0.2' (#155) from v8.0.2 into main
Reviewed-on: #155
This commit is contained in:
commit
a38d77d46d
@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Cookie Dialog Monster",
|
||||
"version": "8.0.1",
|
||||
"version": "8.0.2",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_appDesc__",
|
||||
"icons": {
|
||||
@ -29,28 +29,6 @@
|
||||
"content_scripts": [
|
||||
{
|
||||
"all_frames": true,
|
||||
"exclude_matches": [
|
||||
"*://*.bauhaus.cz/*",
|
||||
"*://*.codesandbox.io/*",
|
||||
"*://*.facebook.com/*",
|
||||
"*://*.googleapis.com/embed/*",
|
||||
"*://*.olympics.com/*",
|
||||
"*://*.youtube-nocookie.com/embed/*",
|
||||
"*://*.youtube.com/embed/*",
|
||||
"*://www.youtube.com/*",
|
||||
"*://translate.google.ca/*",
|
||||
"*://translate.google.co.in/*",
|
||||
"*://translate.google.co.jp/*",
|
||||
"*://translate.google.co.uk/*",
|
||||
"*://translate.google.com.au/*",
|
||||
"*://translate.google.com.br/*",
|
||||
"*://translate.google.com/*",
|
||||
"*://translate.google.de/*",
|
||||
"*://translate.google.es/*",
|
||||
"*://translate.google.fr/*",
|
||||
"*://translate.google.it/*",
|
||||
"*://www.cookie-dialog-monster.com/*"
|
||||
],
|
||||
"js": ["scripts/content.js"],
|
||||
"matches": ["http://*/*", "https://*/*"],
|
||||
"run_at": "document_start"
|
||||
|
@ -49,7 +49,7 @@ class RequestManager {
|
||||
* @description API URL
|
||||
* @type {string}
|
||||
*/
|
||||
const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v5';
|
||||
const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v6';
|
||||
|
||||
/**
|
||||
* @description Context menu identifier
|
||||
@ -171,34 +171,6 @@ async function getState(hostname) {
|
||||
return { ...stateByDefault, ...state, updateAvailable };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Format number to avoid errors
|
||||
* @param {number} [value]
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function formatNumber(value) {
|
||||
if (value) {
|
||||
if (value >= 1e6) {
|
||||
return `${Math.floor(value / 1e6)}M`;
|
||||
} else if (value >= 1e3) {
|
||||
return `${Math.floor(value / 1e3)}K`;
|
||||
} else {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Convert match string to pattern string
|
||||
* @param {string} match
|
||||
* @returns {string}
|
||||
*/
|
||||
function matchToPattern(match) {
|
||||
return `^${match.replaceAll('*.', '*(.)?').replaceAll('*', '.*')}$`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @description Refresh data
|
||||
@ -370,7 +342,7 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
|
||||
case 'UPDATE_BADGE':
|
||||
if (isPage && tabId !== undefined) {
|
||||
browser.action.setBadgeBackgroundColor({ color: '#6b7280' });
|
||||
browser.action.setBadgeText({ tabId, text: formatNumber(message.value) });
|
||||
browser.action.setBadgeText({ tabId, text: message.value ? `${message.value}` : null });
|
||||
}
|
||||
break;
|
||||
case 'UPDATE_STORE':
|
||||
@ -419,6 +391,7 @@ browser.runtime.onInstalled.addListener((details) => {
|
||||
);
|
||||
|
||||
if (details.reason === 'update') {
|
||||
refreshData();
|
||||
storage.remove('updateAvailable');
|
||||
}
|
||||
});
|
||||
@ -453,27 +426,24 @@ browser.webRequest.onBeforeRequest.addListener(
|
||||
const { tabId, type, url } = details;
|
||||
|
||||
if (tabId > -1 && type === 'main_frame') {
|
||||
const manifest = browser.runtime.getManifest();
|
||||
const excludeMatches = manifest.content_scripts[0].exclude_matches;
|
||||
const excludePatterns = excludeMatches.map(matchToPattern);
|
||||
const { exclusions, rules } = await getData();
|
||||
|
||||
if (excludePatterns.some((pattern) => new RegExp(pattern).test(url))) {
|
||||
if (exclusions.domains.some((x) => location.hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await getData();
|
||||
const hostname = getHostname(url);
|
||||
const state = await getState(hostname);
|
||||
|
||||
if (data?.rules?.length) {
|
||||
const rules = data.rules.map((rule) => ({
|
||||
if (rules?.length) {
|
||||
const rulesWithTabId = rules.map((rule) => ({
|
||||
...rule,
|
||||
condition: { ...rule.condition, tabIds: [tabId] },
|
||||
}));
|
||||
|
||||
await browser.declarativeNetRequest.updateSessionRules({
|
||||
addRules: state.on ? rules : undefined,
|
||||
removeRuleIds: data.rules.map((rule) => rule.id),
|
||||
addRules: state.on ? rulesWithTabId : undefined,
|
||||
removeRuleIds: rules.map((rule) => rule.id),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -486,15 +456,10 @@ browser.webRequest.onBeforeRequest.addListener(
|
||||
*/
|
||||
browser.webRequest.onErrorOccurred.addListener(
|
||||
async (details) => {
|
||||
const { error, tabId, url } = details;
|
||||
const { error, tabId } = details;
|
||||
|
||||
if (error === 'net::ERR_BLOCKED_BY_CLIENT' && tabId > -1) {
|
||||
const hostname = getHostname(url);
|
||||
const state = await getState(hostname);
|
||||
|
||||
if (state.on) {
|
||||
await browser.tabs.sendMessage(tabId, { type: 'INCREASE_ACTIONS_COUNT' });
|
||||
}
|
||||
await browser.tabs.sendMessage(tabId, { type: 'INCREASE_ACTIONS_COUNT', value: error });
|
||||
}
|
||||
},
|
||||
{ urls: ['<all_urls>'] }
|
||||
|
@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @typedef {Object} ExtensionData
|
||||
* @property {string[]} commonWords
|
||||
* @property {Fix[]} fixes
|
||||
* @property {{ domains: string[], tags: string[] }} skips
|
||||
* @property {{ backdrops: string[], classes: string[], containers: string[], selectors: string[] }} tokens
|
||||
* @typedef {Object} Action
|
||||
* @property {string} domain
|
||||
* @property {string} name
|
||||
* @property {string} [property]
|
||||
* @property {string} selector
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -12,11 +12,24 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Fix
|
||||
* @property {string} action
|
||||
* @property {string} domain
|
||||
* @property {string} [property]
|
||||
* @property {string} selector
|
||||
* @typedef {Object} ExclusionMap
|
||||
* @property {string[]} domains
|
||||
* @property {string[]} overflows
|
||||
* @property {string[]} tags
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ExtensionData
|
||||
* @property {Action[]} actions
|
||||
* @property {ExclusionMap} exclusions
|
||||
* @property {string[]} keywords
|
||||
* @property {TokenMap} tokens
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GetElementsParams
|
||||
* @property {boolean} [filterEarly]
|
||||
* @property {HTMLElement} [from]
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -27,9 +40,11 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GetElementsParams
|
||||
* @property {boolean} [filterEarly]
|
||||
* @property {HTMLElement} [from]
|
||||
* @typedef {Object} TokenMap
|
||||
* @property {string[]} backdrops
|
||||
* @property {string[]} classes
|
||||
* @property {string[]} containers
|
||||
* @property {string[]} selectors
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -42,22 +57,31 @@ if (typeof browser === 'undefined') {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Actions done by the extension
|
||||
* @type {Set<string>}
|
||||
* @description Class for request batching
|
||||
*/
|
||||
const actions = new Set();
|
||||
class NotifiableSet extends Set {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
}
|
||||
|
||||
add(value) {
|
||||
super.add(value);
|
||||
browser.runtime.sendMessage({ type: 'UPDATE_BADGE', value: super.size });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Data object with all the necessary information
|
||||
* @type {ExtensionData}
|
||||
*/
|
||||
let { commonWords, fixes, skips, tokens } = {
|
||||
commonWords: [],
|
||||
fixes: [],
|
||||
skips: {
|
||||
let { actions, exclusions, keywords, tokens } = {
|
||||
actions: [],
|
||||
exclusions: {
|
||||
domains: [],
|
||||
overflows: [],
|
||||
tags: [],
|
||||
},
|
||||
keywords: [],
|
||||
tokens: {
|
||||
backdrops: [],
|
||||
classes: [],
|
||||
@ -80,7 +104,13 @@ const hostname = getHostname();
|
||||
* @description Initial visibility state
|
||||
* @type {boolean}
|
||||
*/
|
||||
let initiallyVisible = document.visibilityState === 'visible';
|
||||
let initiallyVisible = false;
|
||||
|
||||
/**
|
||||
* @description Log of those steps done by the extension
|
||||
* @type {NotifiableSet<string>}
|
||||
*/
|
||||
const log = new NotifiableSet();
|
||||
|
||||
/**
|
||||
* @description Options provided to observer
|
||||
@ -96,9 +126,9 @@ const seen = new Set();
|
||||
|
||||
/**
|
||||
* @description Extension state
|
||||
* @type {ContentState}
|
||||
* @type {ContentState | undefined}
|
||||
*/
|
||||
let state = { on: true };
|
||||
let state = undefined;
|
||||
|
||||
/**
|
||||
* @description Clean DOM
|
||||
@ -120,8 +150,7 @@ function clean(elements, skipMatch) {
|
||||
if (element instanceof HTMLDialogElement) element.close();
|
||||
hide(element);
|
||||
|
||||
actions.add(`${Date.now()}`);
|
||||
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
|
||||
log.add(`${Date.now()}`);
|
||||
}
|
||||
|
||||
seen.add(element);
|
||||
@ -136,11 +165,11 @@ function clean(elements, skipMatch) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Check if element contains a common word
|
||||
* @description Check if element contains a keyword
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
function containsCommonWord(element) {
|
||||
return !!commonWords.length && !!element.outerHTML.match(new RegExp(commonWords.join('|')));
|
||||
function hasKeyword(element) {
|
||||
return !!keywords?.length && !!element.outerHTML.match(new RegExp(keywords.join('|')));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,6 +232,21 @@ function getHostname() {
|
||||
return hostname.split('.').slice(-3).join('.').replace('www.', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @description Run if the page wasn't visited yet
|
||||
* @param {Object} message
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
function handleRuntimeMessage(message) {
|
||||
switch (message.type) {
|
||||
case 'INCREASE_ACTIONS_COUNT': {
|
||||
log.add(message.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Check if an element is visible in the viewport
|
||||
* @param {HTMLElement} element
|
||||
@ -229,7 +273,7 @@ function isInViewport(element) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function match(element, skipMatch) {
|
||||
if (!tokens.selectors.length || !skips.tags.length) {
|
||||
if (!exclusions.tags.length || !tokens.selectors.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -243,7 +287,7 @@ function match(element, skipMatch) {
|
||||
|
||||
const tagName = element.tagName.toUpperCase();
|
||||
|
||||
if (skips.tags.includes(tagName)) {
|
||||
if (exclusions.tags.includes(tagName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -283,7 +327,7 @@ function filterNodeEarly(node, stopRecursion) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (commonWords && containsCommonWord(node) && !stopRecursion) {
|
||||
if (hasKeyword(node) && !stopRecursion) {
|
||||
return [node, ...[...node.children].flatMap((node) => filterNodeEarly(node, true))];
|
||||
}
|
||||
|
||||
@ -291,46 +335,27 @@ function filterNodeEarly(node, stopRecursion) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Fix data, middle consent page and scroll issues
|
||||
* @description Fix specific cases
|
||||
* @returns {void}
|
||||
*/
|
||||
function fix() {
|
||||
const backdrops = getElements(tokens.backdrops);
|
||||
const domains = skips.domains.map((x) => (x.split('.').length < 3 ? `*${x}` : x));
|
||||
for (const action of actions) {
|
||||
const { domain, name, property, selector } = action;
|
||||
|
||||
for (const backdrop of backdrops) {
|
||||
if (backdrop.children.length === 0 && !seen.has(backdrop)) {
|
||||
actions.add(`${Date.now()}`);
|
||||
seen.add(backdrop);
|
||||
hide(backdrop);
|
||||
}
|
||||
}
|
||||
|
||||
if (domains.every((x) => !hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
|
||||
for (const element of [document.body, document.documentElement]) {
|
||||
element?.classList.remove(...(tokens.classes ?? []));
|
||||
element?.style.setProperty('position', 'initial', 'important');
|
||||
element?.style.setProperty('overflow-y', 'initial', 'important');
|
||||
}
|
||||
}
|
||||
|
||||
for (const fix of fixes) {
|
||||
const { action, domain, property, selector } = fix;
|
||||
|
||||
if (hostname.includes(domain)) {
|
||||
switch (action) {
|
||||
if (hostname.match(domain.replaceAll(/\*/g, '[^ ]*'))) {
|
||||
switch (name) {
|
||||
case 'click': {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
actions.add('click');
|
||||
element?.click();
|
||||
log.add(name);
|
||||
break;
|
||||
}
|
||||
case 'remove': {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
actions.add('remove');
|
||||
element?.style?.removeProperty(property);
|
||||
log.add(name);
|
||||
break;
|
||||
}
|
||||
case 'reload': {
|
||||
@ -340,38 +365,56 @@ function fix() {
|
||||
case 'reset': {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
actions.add('reset');
|
||||
element?.style?.setProperty(property, 'initial', 'important');
|
||||
log.add(name);
|
||||
break;
|
||||
}
|
||||
case 'resetAll': {
|
||||
const elements = getElements(selector);
|
||||
|
||||
actions.add('resetAll');
|
||||
elements.forEach((e) => e?.style?.setProperty(property, 'initial', 'important'));
|
||||
log.add(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const backdrops = getElements(tokens.backdrops);
|
||||
|
||||
for (const backdrop of backdrops) {
|
||||
if (backdrop.children.length === 0 && !seen.has(backdrop)) {
|
||||
log.add(`${Date.now()}`);
|
||||
seen.add(backdrop);
|
||||
hide(backdrop);
|
||||
}
|
||||
}
|
||||
|
||||
const skips = exclusions.overflows.map((x) => (x.split('.').length < 3 ? `*${x}` : x));
|
||||
|
||||
if (!skips.some((x) => hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
|
||||
for (const element of [document.body, document.documentElement]) {
|
||||
element?.classList.remove(...(tokens.classes ?? []));
|
||||
element?.style.setProperty('position', 'initial', 'important');
|
||||
element?.style.setProperty('overflow-y', 'initial', 'important');
|
||||
}
|
||||
}
|
||||
|
||||
const ionRouterOutlet = document.getElementsByTagName('ion-router-outlet')[0];
|
||||
|
||||
if (ionRouterOutlet) {
|
||||
actions.add('ion-router-outlet');
|
||||
// 2024-08-02: fix #644 temporarily
|
||||
ionRouterOutlet.removeAttribute('inert');
|
||||
log.add('ion-router-outlet');
|
||||
}
|
||||
|
||||
const t4Wrapper = document.getElementsByClassName('t4-wrapper')[0];
|
||||
|
||||
if (t4Wrapper) {
|
||||
actions.add('t4-wrapper');
|
||||
log.add('t4-wrapper');
|
||||
// 2024-09-12: fix #945 temporarily
|
||||
t4Wrapper.removeAttribute('inert');
|
||||
}
|
||||
|
||||
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -412,41 +455,48 @@ function run(params = {}) {
|
||||
* @async
|
||||
* @description Set up the extension
|
||||
* @param {SetUpParams} [params]
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function setUp(params = {}) {
|
||||
state = await dispatch({ hostname, type: 'GET_STATE' });
|
||||
dispatch({ type: 'ENABLE_POPUP' });
|
||||
|
||||
if (state.on) {
|
||||
const data = await dispatch({ hostname, type: 'GET_DATA' });
|
||||
|
||||
commonWords = data?.commonWords ?? commonWords;
|
||||
fixes = data?.fixes ?? fixes;
|
||||
skips = data?.skips ?? skips;
|
||||
exclusions = data?.exclusions ?? exclusions;
|
||||
|
||||
if (exclusions.domains.some((x) => location.hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
|
||||
dispatch({ type: 'DISABLE_ICON' });
|
||||
observer.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
state = await dispatch({ hostname, type: 'GET_STATE' });
|
||||
dispatch({ type: 'ENABLE_POPUP' });
|
||||
dispatch({ type: 'ENABLE_REPORT' });
|
||||
|
||||
if (state.on) {
|
||||
browser.runtime.onMessage.addListener(handleRuntimeMessage);
|
||||
dispatch({ hostname, type: 'ENABLE_ICON' });
|
||||
|
||||
actions = data?.actions ?? actions;
|
||||
keywords = data?.keywords ?? keywords;
|
||||
tokens = data?.tokens ?? tokens;
|
||||
|
||||
dispatch({ type: 'ENABLE_REPORT' });
|
||||
dispatch({ hostname, type: 'ENABLE_ICON' });
|
||||
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
|
||||
observer.observe(document.body ?? document.documentElement, options);
|
||||
if (!params.skipRunFn) run({ containers: tokens.containers });
|
||||
} else {
|
||||
dispatch({ type: 'DISABLE_REPORT' });
|
||||
dispatch({ type: 'DISABLE_ICON' });
|
||||
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
|
||||
observer.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Wait for the body to exist
|
||||
* @param {void} callback
|
||||
* @returns {void}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function setUpAfterWaitForBody() {
|
||||
if (document.visibilityState === 'visible' && !initiallyVisible) {
|
||||
if (document.body) {
|
||||
initiallyVisible = true;
|
||||
await setUp();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(setUpAfterWaitForBody, 50);
|
||||
}
|
||||
}
|
||||
@ -466,50 +516,6 @@ const observer = new MutationObserver((mutations) => {
|
||||
run({ elements });
|
||||
});
|
||||
|
||||
/**
|
||||
* @description Listen to messages from any other scripts
|
||||
* @listens browser.runtime#onMessage
|
||||
*/
|
||||
browser.runtime.onMessage.addListener(async (message) => {
|
||||
switch (message.type) {
|
||||
case 'INCREASE_ACTIONS_COUNT': {
|
||||
actions.add(`${Date.now()}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @description Fix bfcache issues
|
||||
* @listens window#pageshow
|
||||
* @returns {void}
|
||||
*/
|
||||
window.addEventListener('pageshow', async (event) => {
|
||||
if (document.visibilityState === 'visible' && event.persisted) {
|
||||
await setUp();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @description Run if the page wasn't visited yet
|
||||
* @listens window#visibilitychange
|
||||
* @returns {void}
|
||||
*/
|
||||
window.addEventListener('visibilitychange', async () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
if (!initiallyVisible) {
|
||||
initiallyVisible = true;
|
||||
await setUp();
|
||||
}
|
||||
|
||||
dispatch({ type: state.on ? 'ENABLE_REPORT' : 'DISABLE_REPORT' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @description Run as soon as possible, if the user is in front of the page
|
||||
*/
|
||||
if (document.visibilityState === 'visible') {
|
||||
setUpAfterWaitForBody();
|
||||
}
|
||||
document.addEventListener('visibilitychange', setUpAfterWaitForBody);
|
||||
window.addEventListener('pageshow', setUpAfterWaitForBody);
|
||||
setUpAfterWaitForBody();
|
||||
|
Loading…
Reference in New Issue
Block a user