cookie-dialog-monster/packages/browser-extension/src/scripts/options.js

270 lines
8.5 KiB
JavaScript
Raw Normal View History

if (typeof browser === 'undefined') {
browser = chrome;
}
/**
* @description Shortcut to send messages to background script
*/
const dispatch = browser.runtime.sendMessage;
/**
* @description Domain RegExp
*/
const domainRx = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/g;
/**
* @description Exclusion list, URLs where the user prefers to disable the extension
* @type {string[]}
*/
let exclusionList = [];
/**
2024-02-24 18:13:40 +00:00
* @description Render exclusion items into exclusion list
* @returns {void}
*/
2023-09-25 18:15:47 +00:00
function createList() {
const emptyItemElement = document.getElementById('exclusion-list-item-empty');
const exclusionListElement = document.getElementById('exclusion-list');
const exclusionListItemTemplateElement = document.getElementById('exclusion-list-item-template');
Array.from(exclusionListElement.querySelectorAll('[data-value]')).forEach((exclusionItem) => {
exclusionItem.remove();
});
if (exclusionList.length) {
for (const exclusionValue of exclusionList) {
const ariaLabelOrTitle = `Delete ${exclusionValue}`;
const itemElement = exclusionListItemTemplateElement.cloneNode(true);
const deleteButtonElement = itemElement.getElementsByTagName('button')[0];
deleteButtonElement.addEventListener('click', handleDeleteClick);
deleteButtonElement.setAttribute('aria-label', ariaLabelOrTitle);
deleteButtonElement.setAttribute('title', ariaLabelOrTitle);
itemElement.removeAttribute('id');
itemElement.getElementsByTagName('span')[0].innerText = exclusionValue;
itemElement.setAttribute('data-value', exclusionValue);
itemElement.style.removeProperty('display');
exclusionListElement.appendChild(itemElement);
}
} else {
emptyItemElement.innerText = "You don't have any exclusions yet";
emptyItemElement.style.removeProperty('display');
}
2023-09-25 18:15:47 +00:00
}
/**
* @async
* @description Add a new item to the exclusion list
* @returns {Promise<void>}
*/
async function handleAddClick() {
const exclusionValue = window.prompt(browser.i18n.getMessage('options_addPrompt'));
if (exclusionValue?.trim() && (domainRx.test(exclusionValue) || exclusionValue === 'localhost')) {
const filterInputElement = document.getElementById('filter-input');
const state = { enabled: false };
await dispatch({ hostname: exclusionValue, state, type: 'SET_HOSTNAME_STATE' });
exclusionList = [...new Set([...exclusionList, exclusionValue])].sort();
createList();
updateList(filterInputElement.value.trim());
}
}
/**
* @async
* @description Clear all items from the exclusion list
* @returns {Promise<void>}
*/
2023-09-25 18:15:47 +00:00
async function handleClearClick() {
const filterInputElement = document.getElementById('filter-input');
for (const exclusionValue of exclusionList) {
const state = { enabled: true };
await dispatch({ hostname: exclusionValue, state, type: 'SET_HOSTNAME_STATE' });
}
exclusionList = [];
createList();
updateList(filterInputElement.value.trim());
2023-09-25 18:15:47 +00:00
}
/**
* @async
* @description Setup handlers and items
*/
2023-09-25 18:15:47 +00:00
async function handleContentLoaded() {
exclusionList = await dispatch({ type: 'GET_EXCLUSION_LIST' });
createList();
const addButtonElement = document.getElementById('add-button');
addButtonElement.addEventListener('click', handleAddClick);
const clearButtonElement = document.getElementById('clear-button');
clearButtonElement.addEventListener('click', handleClearClick);
const exportButtonElement = document.getElementById('export-button');
exportButtonElement.addEventListener('click', handleExportClick);
const fileInputElement = document.getElementById('file-input');
fileInputElement.addEventListener('change', handleFileChange);
const filterInputElement = document.getElementById('filter-input');
filterInputElement.addEventListener('keydown', handleFilterKeyDown);
const importButtonElement = document.getElementById('import-button');
importButtonElement.addEventListener('click', handleImportClick);
translate();
2023-09-25 18:15:47 +00:00
}
/**
* @async
2024-02-24 18:13:40 +00:00
* @description Delete the clicked element from the exclusion list
* @param {MouseEvent} event
* @returns {Promise<void>}
*/
2023-09-25 18:15:47 +00:00
async function handleDeleteClick(event) {
const filterInputElement = document.getElementById('filter-input');
const { value } = event.currentTarget.parentElement.dataset;
const itemElement = document.querySelector(`[data-value="${value}"]`);
const state = { enabled: true };
await dispatch({ hostname: value, state, type: 'SET_HOSTNAME_STATE' });
exclusionList = exclusionList.filter((exclusionValue) => exclusionValue !== value);
itemElement?.remove();
updateList(filterInputElement.value.trim());
2023-09-25 18:15:47 +00:00
}
/**
2024-02-24 18:13:40 +00:00
* @description Export a file with the current exclusion list
* @returns {void}
*/
2023-09-25 18:15:47 +00:00
function handleExportClick() {
const anchor = document.createElement('a');
const now = new Date();
const day = now.getDate().toString().padStart(2, '0');
const month = now.getMonth().toString().padStart(2, '0');
const year = now.getUTCFullYear();
const text = exclusionList.join('\n');
const defaultTitle = `${year}${month}${day}`;
const customTitle = window.prompt('Enter a file name', defaultTitle);
const blob = new Blob([text], { type: 'octet/stream' });
const url = window.URL.createObjectURL(blob);
anchor.href = url;
anchor.download = `${customTitle || defaultTitle}.cdm`;
anchor.click();
window.URL.revokeObjectURL(url);
2023-09-25 18:15:47 +00:00
}
/**
2024-02-24 18:13:40 +00:00
* @description Process a file and send the updates
* @param {InputEvent} event
* @returns {void}
*/
2023-09-25 18:15:47 +00:00
function handleFileChange(event) {
const file = event.currentTarget.files[0];
const filterInputElement = document.getElementById('filter-input');
const reader = new FileReader();
reader.addEventListener('load', async (event) => {
const newExclusionList = event.currentTarget.result.split('\n').filter((x) => x.trim());
for (const exclusionValue of newExclusionList) {
const state = { enabled: false };
await dispatch({ hostname: exclusionValue, state, type: 'SET_HOSTNAME_STATE' });
}
if (newExclusionList.length) {
exclusionList = [...new Set([...exclusionList, ...newExclusionList])].sort();
createList();
updateList(filterInputElement.value.trim());
}
});
event.currentTarget.value = '';
reader.readAsText(file);
2023-09-25 18:15:47 +00:00
}
/**
2024-02-24 18:13:40 +00:00
* @description Apply filter to the exclusion list when the user presses ENTER key
* @param {KeyboardEvent} event
* @returns {void}
*/
2023-09-25 18:15:47 +00:00
function handleFilterKeyDown(event) {
if (event.key === 'Enter') {
const filterValue = event.currentTarget.value.trim();
updateList(filterValue);
}
2023-09-25 18:15:47 +00:00
}
/**
2024-02-24 18:13:40 +00:00
* @description Shallow click an hidden input to open the file explorer
* @returns {void}
*/
2023-09-25 18:15:47 +00:00
function handleImportClick() {
const fileInputElement = document.getElementById('file-input');
fileInputElement.click();
2023-09-25 18:15:47 +00:00
}
/**
2024-02-24 18:13:40 +00:00
* @description Apply translations to tags with i18n data attribute
* @returns {void}
*/
2023-09-25 18:15:47 +00:00
function translate() {
const nodes = document.querySelectorAll('[data-i18n], [data-i18n-placeholder]');
for (let i = nodes.length; i--; ) {
const node = nodes[i];
2023-09-25 18:15:47 +00:00
const { i18n, i18nPlaceholder } = node.dataset;
if (i18n) {
node.innerHTML = browser.i18n.getMessage(i18n);
}
if (i18nPlaceholder) {
node.setAttribute('placeholder', browser.i18n.getMessage(i18nPlaceholder));
}
}
2023-09-25 18:15:47 +00:00
}
/**
2024-02-24 18:13:40 +00:00
* @description Update exclusion items in DOM
* @param {string | undefined} filterValue
* @returns {void}
*/
2023-09-25 18:15:47 +00:00
function updateList(filterValue) {
const emptyItemElement = document.getElementById('exclusion-list-item-empty');
const exclusionListElement = document.getElementById('exclusion-list');
const exclusionListElements = exclusionListElement.querySelectorAll(`[data-value]`);
if (exclusionListElements.length) {
let isEmpty = true;
emptyItemElement.style.setProperty('display', 'none');
for (const exclusionItemElement of Array.from(exclusionListElements)) {
if (exclusionItemElement.matches(`[data-value*="${filterValue}"]`) || !filterValue) {
exclusionItemElement.style.removeProperty('display');
isEmpty = false;
} else {
exclusionItemElement.style.setProperty('display', 'none');
}
}
if (isEmpty) {
emptyItemElement.innerText = 'No exclusions found';
emptyItemElement.style.removeProperty('display');
}
} else {
emptyItemElement.innerText = "You don't have any exclusions yet";
emptyItemElement.style.removeProperty('display');
}
2023-09-25 18:15:47 +00:00
}
/**
* @description Listen to document ready
* @listens document#DOMContentLoaded
*/
document.addEventListener('DOMContentLoaded', handleContentLoaded);