feat(scripts): improve content and popup scripts
This commit is contained in:
parent
e4b1289d0f
commit
4108c4cb8a
245
scripts/content.js
Normal file
245
scripts/content.js
Normal file
@ -0,0 +1,245 @@
|
||||
/**
|
||||
* @var attempts
|
||||
* @description Number of attempts
|
||||
* @type {number}
|
||||
*/
|
||||
|
||||
let attempts = 1;
|
||||
|
||||
/**
|
||||
* @var enabled
|
||||
* @description Is extension enabled?
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
||||
let enabled = true;
|
||||
|
||||
/**
|
||||
* @var selectors
|
||||
* @description Array of selectors
|
||||
* @type {string[]}
|
||||
*/
|
||||
|
||||
let selectors = [];
|
||||
|
||||
/**
|
||||
* @constant url
|
||||
* @description Database link
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
const url = chrome.runtime.getURL("data/elements.txt");
|
||||
/*const url =
|
||||
"https://raw.githubusercontent.com/wanhose/do-not-consent/master/data/elements.txt";*/
|
||||
|
||||
/**
|
||||
* @function commit
|
||||
* @description Commits selector to cache
|
||||
* @param {string} selector
|
||||
*/
|
||||
|
||||
const commit = (selector) => {
|
||||
chrome.storage.local.get(null, (cache) => {
|
||||
const current = cache[document.location.hostname];
|
||||
|
||||
chrome.storage.local.set({
|
||||
[document.location.hostname]: {
|
||||
...current,
|
||||
matches: [...new Set([...cache.matches, selector])],
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function fix
|
||||
* @description Fix scroll issues
|
||||
*/
|
||||
|
||||
const fix = () => {
|
||||
const html = document.documentElement;
|
||||
const body = document.body;
|
||||
|
||||
html.style.setProperty("overflow-y", "unset", "important");
|
||||
body.style.setProperty("overflow-y", "unset", "important");
|
||||
};
|
||||
|
||||
/**
|
||||
* @function search
|
||||
* @description Retrieves HTML element if selector exists
|
||||
*
|
||||
* @param {string} selector
|
||||
* @returns {HTMLElement | null} An HTML element or null
|
||||
*/
|
||||
|
||||
const search = (selector) => {
|
||||
if (!selector.includes("[") && !selector.includes(">")) {
|
||||
if (selector.startsWith(".")) {
|
||||
return document.getElementsByClassName(selector.slice(1))[0];
|
||||
}
|
||||
|
||||
if (selector.startsWith("#")) {
|
||||
return document.getElementById(selector.slice(1));
|
||||
}
|
||||
} else {
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @function check
|
||||
* @description Checks if extension is enabled
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
|
||||
const check = () =>
|
||||
new Promise((resolve) => {
|
||||
chrome.storage.local.get(null, (store) => {
|
||||
try {
|
||||
const cache = store[document.location.hostname];
|
||||
|
||||
resolve(cache.enabled);
|
||||
} catch {
|
||||
chrome.storage.local.set(
|
||||
{
|
||||
[document.location.hostname]: {
|
||||
enabled: true,
|
||||
matches: [],
|
||||
},
|
||||
},
|
||||
() => resolve(true)
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @function removeFromCache
|
||||
* @description Removes matched elements from cache results
|
||||
*/
|
||||
|
||||
const removeFromCache = () => {
|
||||
chrome.storage.local.get(null, (store) => {
|
||||
const cache = store[document.location.hostname];
|
||||
const matches = cache.matches;
|
||||
|
||||
if (!!matches.length) {
|
||||
for (let i = matches.length; i--; ) {
|
||||
const selector = selectors[i];
|
||||
const element = search(selector);
|
||||
|
||||
if (element) {
|
||||
const tagName = element.tagName.toUpperCase();
|
||||
|
||||
if (!["BODY", "HTML"].includes(tagName)) {
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function removeFromNetwork
|
||||
* @description Removes matched elements from network results
|
||||
*/
|
||||
|
||||
const removeFromNetwork = () => {
|
||||
for (let i = selectors.length; i--; ) {
|
||||
const selector = selectors[i];
|
||||
const element = search(selector);
|
||||
|
||||
if (element) {
|
||||
const tagName = element.tagName.toUpperCase();
|
||||
|
||||
if (!["BODY", "HTML"].includes(tagName)) {
|
||||
element.remove();
|
||||
commit(selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @function query
|
||||
* @description Retrieves selectors list
|
||||
*
|
||||
* @returns {Promise<string[]>} A selectors list
|
||||
*/
|
||||
|
||||
const query = async () => {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const data = await response.text();
|
||||
|
||||
if (response.status !== 200) throw new Error();
|
||||
|
||||
return data.split("\n");
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @constant observer
|
||||
* @description Observer instance
|
||||
* @type {MutationObserver}
|
||||
*/
|
||||
|
||||
const observer = new MutationObserver((_, instance) => {
|
||||
instance.disconnect();
|
||||
fix();
|
||||
removeFromCache();
|
||||
if (attempts <= 5) removeFromNetwork();
|
||||
attempts += 1;
|
||||
observe();
|
||||
});
|
||||
|
||||
/**
|
||||
* @function observe
|
||||
* @description Starts observing document.body element
|
||||
*/
|
||||
|
||||
const observe = () => {
|
||||
observer.observe(document.body, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @function handleContentLoaded
|
||||
* @description Cleans, fixes scroll issues and observes document.body element
|
||||
*/
|
||||
|
||||
const handleContentLoaded = async () => {
|
||||
chrome.runtime.sendMessage({ type: "ENABLE_POPUP" });
|
||||
enabled = await check();
|
||||
|
||||
if (enabled) {
|
||||
chrome.runtime.sendMessage({ type: "ENABLE_ICON" });
|
||||
selectors = await query();
|
||||
|
||||
if (selectors.length > 0) {
|
||||
fix();
|
||||
removeFromCache();
|
||||
removeFromNetwork();
|
||||
observe();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Listen to document ready
|
||||
*
|
||||
* @type {Document}
|
||||
* @listens document#ready
|
||||
*/
|
||||
|
||||
document.addEventListener("DOMContentLoaded", handleContentLoaded);
|
151
scripts/popup.js
Normal file
151
scripts/popup.js
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @constant chromeUrl
|
||||
* @description Chrome Web Store link
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
const chromeUrl =
|
||||
"https://chrome.google.com/webstore/detail/do-not-consent/djcbfpkdhdkaflcigibkbpboflaplabg";
|
||||
|
||||
/**
|
||||
* @constant firefoxUrl
|
||||
* @description Firefox Add-ons link
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
const firefoxUrl =
|
||||
"https://addons.mozilla.org/es/firefox/addon/do-not-consent/";
|
||||
|
||||
/**
|
||||
* @constant isChromium
|
||||
* @description Is current browser an instance of Chromium?
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
||||
const isChromium = chrome.runtime.getURL("").startsWith("chrome-extension://");
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @function currentTab
|
||||
* @description Returns current tab state
|
||||
*
|
||||
* @returns {Promise<{ id: string, location: URL }>}
|
||||
*/
|
||||
|
||||
const currentTab = () =>
|
||||
new Promise((resolve) => {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
||||
resolve({
|
||||
id: tabs[0].id,
|
||||
location: new URL(tabs[0].url),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @function currentState
|
||||
* @description Returns current extension state
|
||||
*
|
||||
* @returns {Promise<Object<string, { enabled: boolean, matches: string[] }>>}>}
|
||||
*/
|
||||
|
||||
const currentState = async () => {
|
||||
const tab = await currentTab();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.get(null, (store) => {
|
||||
resolve(store[tab.location.hostname]);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function handleButtonClick
|
||||
* @description Disables or enables extension
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
|
||||
const handleStateButtonClick = async () => {
|
||||
const state = await currentState();
|
||||
const tab = await currentTab();
|
||||
|
||||
chrome.storage.local.set(
|
||||
{
|
||||
[tab.location.hostname]: {
|
||||
...state,
|
||||
enabled: !state.enabled,
|
||||
},
|
||||
},
|
||||
() => {
|
||||
const stateButton = document.getElementById("state-button");
|
||||
|
||||
stateButton.innerHTML = state.enabled
|
||||
? "Enable extension"
|
||||
: "Disable extension";
|
||||
chrome.runtime.sendMessage({
|
||||
type: state.enabled ? "DISABLE_ICON" : "ENABLE:ICON",
|
||||
});
|
||||
chrome.tabs.reload(tab.id, { bypassCache: true });
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @function handleStarClick
|
||||
* @description Hides stars and shows negative or positive messages
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
|
||||
const handleStarClick = (event) => {
|
||||
const negative = document.getElementById("negative");
|
||||
const positive = document.getElementById("positive");
|
||||
const { score } = event.currentTarget.dataset;
|
||||
const stars = document.getElementById("stars");
|
||||
|
||||
switch (score) {
|
||||
case "1":
|
||||
case "2":
|
||||
case "3":
|
||||
stars.setAttribute("hidden", "true");
|
||||
negative.removeAttribute("hidden");
|
||||
break;
|
||||
case "4":
|
||||
case "5":
|
||||
stars.setAttribute("hidden", "true");
|
||||
positive.removeAttribute("hidden");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @function handleContentLoaded
|
||||
* @description Setup stars handlers and result message links
|
||||
*/
|
||||
|
||||
const handleContentLoaded = async () => {
|
||||
const stars = Array.from(document.getElementsByClassName("star"));
|
||||
const state = await currentState();
|
||||
const stateButton = document.getElementById("state-button");
|
||||
const storeLink = document.getElementById("store-link");
|
||||
|
||||
stars.forEach((star) => star.addEventListener("click", handleStarClick));
|
||||
stateButton.innerHTML = state.enabled
|
||||
? "Disable extension"
|
||||
: "Enable extension";
|
||||
stateButton.addEventListener("click", handleStateButtonClick);
|
||||
storeLink.setAttribute("href", isChromium ? chromeUrl : firefoxUrl);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Listen to document ready
|
||||
*
|
||||
* @type {Document}
|
||||
* @listens document#ready
|
||||
*/
|
||||
|
||||
document.addEventListener("DOMContentLoaded", handleContentLoaded);
|
Loading…
Reference in New Issue
Block a user