Merge pull request #734 from wanhose/v7.1.0

7.1.0
This commit is contained in:
wanhose 2024-08-03 15:25:54 +02:00 committed by GitHub
commit a4fd76ce95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 14132 additions and 13353 deletions

View File

@ -17,7 +17,7 @@
[ [
"api", "api",
"browser-extension", "browser-extension",
"data", "database",
"docs", "docs",
"packages", "packages",
"web" "web"

View File

@ -1,15 +0,0 @@
[
"banner",
"cc",
"cmp",
"compliance",
"consent",
"cookie",
"dialog",
"disclaimer",
"gdpr",
"law",
"policy",
"popup",
"privacy"
]

View File

@ -1,59 +0,0 @@
action.com###CybotCookiebotDialogBodyLevelButtonLevelOptinDeclineAll##click
amazon.de###sp-cc-rejectall-link##click
automobielmanagement.nl##body > *##resetAll##filter
bilbaomuseoa.eus##.alert_message .btn-confirm##click
breitbart.com##.twitter-tweet##resetAll##display
breitbart.com##.twitter-tweet##resetAll##visibility
buscotelefonosgratis.es###cookie_action_close_header_reject##click
chollometro.com##[data-t="continueWithoutAccepting"]##click
classicube.net###acceptcookies##click
compact-online.de##[id*="bnnr-body-rightSide-"] div + div > span##click
consent.google##[aria-label="Reject all"]##click
consent.yahoo##.reject-all##click
consent.youtube##[aria-label="Reject all"]##click
dailymotion.com##[class*="TCF2Popup__containerButtons"] > button:nth-child(2)##click
dealabs.com##[data-t="continueWithoutAccepting"]##click
fiberplane.dev##button[aria-label="Close Banner"]##click
foto-erhardt.de##[class="modal show"]##click
gamestar.de###content##reset##filter
gettr.com##button.bold##click
gmx.com###onetrust-accept-btn-handler##click
gmx.net##[data-section="accept"]##click
golem.de##[title="Zustimmen und weiter"]##click
google##[aria-label*="Google"][role="dialog"] button:not([aria-label]):not([tabindex]):first-child##click
google##[aria-label="Alle ablehnen"]##click
google##[aria-label="Odrzuć wszystko"]##click
google##[aria-label="Rechazar todo"]##click
google##[aria-label="Recusar tudo"]##click
google##[aria-label="Reject all"]##click
google##[aria-label="Rejeitar tudo"]##click
google##[aria-label="Respinge tot"]##click
google##[aria-label="Rifiuta tutto"]##click
google##[aria-label="Tout refuser"]##click
google##[aria-label="Отклонить все"]##click
hagglezon.com##[data-test="cookie-submit"]##click
instagram.com##[role="dialog"] > [style="display: flex; flex-direction: column; height: 100%; max-width: 100%;"] > button##click
motorolasound.com###cookie-btn-denied##click
mydealz.de##[data-t="continueWithoutAccepting"]##click
myprivacy.dpgmedia##.pg-accept-button##click
play.google##body > div##reset##z-index
popeyes.es##.cookie-buttons > .cookie-buttons-column > div:last-child##click
producthunt.com##[data-test="dismiss-CookiePopup"] button##click
resonanz-labor.de###wrapwrap##reset##overflow
staylibere.com##[class*="LayoutCookieBanner_buttons"] > button:last-child##click
twitch.tv##[data-a-target="consent-banner-accept"]##click
usnews.com###gdpr-modal-agree##click
web.de###reminder##click
web.dev##a[href*="cookies"] + button##click
youtube##[aria-label="Alle ablehnen"]##click
youtube##[aria-label="Odrzuć wszystko"]##click
youtube##[aria-label="Rechazar todo"]##click
youtube##[aria-label="Recusar tudo"]##click
youtube##[aria-label="Reject all"]##click
youtube##[aria-label="Rejeitar tudo"]##click
youtube##[aria-label="Respinge tot"]##click
youtube##[aria-label="Rifiuta tutto"]##click
youtube##[aria-label="Tout refuser"]##click
youtube##[aria-label="Отклонить все"]##click
zdf.de###aria-dialog-cmp-error-dialog > .dialog-close##click
zeit.de##[title="ACCEPT AND CONTINUE"]##click

View File

@ -1,255 +0,0 @@
{
"domains": [
"app.diagrams.net",
"blog.sapegin.me",
"buyagift.co.uk",
"canvasjs.com",
"chessmadra.com",
"correos.es",
"diariodeunlondinense.com",
"flickr.com",
"godotforums.org",
"godotvr.github.io",
"google.*",
"gudog.com",
"iea.org",
"jobs.lever.co",
"key-shortcut.com",
"login.microsoftonline.com",
"mantisbt.org",
"mossgreen.github.io",
"musicmeter.nl",
"personio.com",
"restaurantguru.com",
"retroachievements.org",
"seeklogo.com",
"shuttledirect.com",
"stackage.org",
"steamcommunity.com",
"substack.com",
"sucuri.net",
"tesla.com",
"visualstudio.com",
"xkcd.com",
"yandex.ru",
"youtube.com"
],
"tags": [
"A",
"ABBR",
"ADDRESS",
"AREA",
"AUDIO",
"B",
"BADGE-SHAPE",
"BASE",
"BDI",
"BDO",
"BLOCKQUOTE",
"BODY",
"BR",
"BUTTON",
"CANVAS",
"CAPTION",
"CIRCLE",
"CITE",
"CLIPPATH",
"CODE",
"COL",
"COLGROUP",
"DATA",
"DATALIST",
"DD",
"DEFS",
"DEL",
"DETAILS-MENU",
"DETAILS",
"DEVELOPMENT-MENU",
"DFN",
"DL",
"DOM-IF",
"DOM-REPEAT",
"DT",
"EM",
"EMBED",
"FIELDSET",
"FIGCAPTION",
"FIGURE",
"G-EMOJI",
"G",
"H1",
"H2",
"H3",
"H4",
"H5",
"H6",
"HEAD",
"HEADER",
"HGROUP",
"HR",
"HTML",
"I",
"ICON-SHAPE",
"IFRAME",
"IMG",
"INCLUDE-FRAGMENT",
"INPUT",
"INS",
"IRON-A11Y-ANNOUNCER",
"IRON-ICONSET-SVG",
"IRON-MEDIA-QUERY",
"KBD",
"LABEL",
"LEGEND",
"LINEARGRADIENT",
"LINK",
"MAIN",
"MAP",
"MARK",
"MASK",
"MENU",
"META",
"METER",
"NAV",
"NOSCRIPT",
"OBJECT",
"OL",
"OPTGROUP",
"OPTION",
"OUTPUT",
"P",
"PATH",
"PICTURE",
"POLYGON",
"PRE",
"PROGRESS",
"Q",
"RADIALGRADIENT",
"RECT",
"RELATIVE-TIME",
"RP",
"RT",
"RUBY",
"S",
"SAMP",
"SCRIPT",
"SEARCH",
"SELECT",
"SLOT",
"SMALL",
"SOURCE",
"SPAN",
"STOP",
"STRONG",
"STYLE",
"SUB",
"SUMMARY",
"SUP",
"SVG",
"TASK-LISTS",
"TBODY",
"TD",
"TEMPLATE",
"TEXT",
"TEXTAREA",
"TFOOT",
"TH",
"THEAD",
"TIME",
"TITLE",
"TOOL-TIP",
"TP-YT-APP-DRAWER",
"TP-YT-PAPER-BUTTON",
"TP-YT-PAPER-SPINNER-LITE",
"TP-YT-PAPER-SPINNER",
"TP-YT-PAPER-TOOLTIP",
"TR",
"TRACK",
"U",
"UL",
"USE",
"VAR",
"VIDEO",
"WBR",
"YT-ANIMATED-ROLLING-NUMBER",
"YT-ATTRIBUTED-STRING",
"YT-BUTTON-SHAPE",
"YT-COLLECTIONS-STACK",
"YT-FORMATTED-STRING",
"YT-GUIDE-MANAGER",
"YT-HOTKEY-MANAGER",
"YT-ICON-BADGE-SHAPE",
"YT-ICON-BUTTON",
"YT-ICON-SHAPE",
"YT-ICON",
"YT-IMAGE",
"YT-IMG-SHADOW",
"YT-INLINE-PLAYER-CONTROLS",
"YT-INTERACTION",
"YT-MDX-MANAGER",
"YT-PAGE-NAVIGATION-PROGRESS",
"YT-PLAYABILITY-ERROR-SUPPORTED-RENDERERS",
"YT-PLAYLIST-MANAGER",
"YT-TOUCH-FEEDBACK-SHAPE",
"YTD-APP",
"YTD-BADGE-SUPPORTED-RENDERER",
"YTD-BROWSE",
"YTD-BUTTON-RENDERER",
"YTD-CHANNEL-LEGAL-INFO-RENDERER",
"YTD-CHANNEL-NAME",
"YTD-COMMENTS",
"YTD-CONTINUATION-ITEM-RENDERER",
"YTD-GHOST-GRID-RENDERER",
"YTD-LOGO",
"YTD-LOTTIE-PLAYER",
"YTD-MASTHEAD",
"YTD-MENU-RENDERER",
"YTD-METADATA-ROW-CONTAINER-RENDERER",
"YTD-MINI-GUIDE-ENTRY-RENDERER",
"YTD-MINI-GUIDE-RENDERER",
"YTD-MINIPLAYER-TOAST",
"YTD-MINIPLAYER",
"YTD-NOTIFICATION-TOPBAR-BUTTON-RENDERER",
"YTD-PAGE-MANAGER",
"YTD-PERMISSION-ROLE-BOTTOM-BAR-RENDERER",
"YTD-PLAYER",
"YTD-PLAYLIST-HEADER-RENDERER",
"YTD-PLAYLIST-PANEL-RENDERER",
"YTD-PLAYLIST-SIDEBAR-RENDERER",
"YTD-PLAYLIST-THUMBNAIL",
"YTD-POPUP-CONTAINER",
"YTD-REFRESH",
"YTD-RICH-GRID-MEDIA",
"YTD-RICH-GRID-RENDERER",
"YTD-RICH-GRID-ROW",
"YTD-RICH-GRID-SLIM-MEDIA",
"YTD-RICH-ITEM-RENDERER",
"YTD-RICH-SECTION-RENDERER",
"YTD-RICH-SHELF-RENDERER",
"YTD-SEARCHBOX",
"YTD-SENTIMENT-BAR-RENDERER",
"YTD-SETTINGS-SIDEBAR-RENDERER",
"YTD-SHELF-RENDERER",
"YTD-STRUCTURED-DESCRIPTION-CONTENT-RENDERER",
"YTD-TEXT-INLINE-EXPANDER",
"YTD-THIRD-PARTY-MANAGER",
"YTD-THUMBNAIL-OVERLAY-EQUALIZER",
"YTD-THUMBNAIL-OVERLAY-NOW-PLAYING-RENDERER",
"YTD-THUMBNAIL-OVERLAY-TIME-STATUS-RENDERER",
"YTD-THUMBNAIL",
"YTD-TOPBAR-LOGO-RENDERER",
"YTD-TOPBAR-MENU-BUTTON-RENDERER",
"YTD-TWO-COLUMN-BROWSE-RESULTS-RENDERER",
"YTD-VIDEO-META-BLOCK",
"YTD-VIDEO-OWNER-RENDERER",
"YTD-VIDEO-PREVIEW",
"YTD-VIDEO-PRIMARY-INFO-RENDERER",
"YTD-VIDEO-QUALITY-PROMO-RENDERER",
"YTD-WATCH-ENGAGEMENT-PANELS",
"YTD-WATCH-FLEXY",
"YTD-WATCH-INFO-TEXT",
"YTD-WATCH-METADATA",
"YTD-WATCH-NEXT-SECONDARY-RESULTS-RENDERER",
"YTD-YOODLE-RENDERER"
]
}

File diff suppressed because it is too large Load Diff

13653
database.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,8 @@ import v2DataRoutes from 'routes/v2/data';
import v2ReportRoutes from 'routes/v2/report'; import v2ReportRoutes from 'routes/v2/report';
import v3DataRoutes from 'routes/v3/data'; import v3DataRoutes from 'routes/v3/data';
import v3ReportRoutes from 'routes/v3/report'; import v3ReportRoutes from 'routes/v3/report';
import v4DataRoutes from 'routes/v4/data';
import v4ReportRoutes from 'routes/v4/report';
import environment from 'services/environment'; import environment from 'services/environment';
const server = fastify({ logger: true }); const server = fastify({ logger: true });
@ -31,6 +33,8 @@ server.register(v2DataRoutes, { prefix: '/rest/v2' });
server.register(v2ReportRoutes, { prefix: '/rest/v2' }); server.register(v2ReportRoutes, { prefix: '/rest/v2' });
server.register(v3DataRoutes, { prefix: '/rest/v3' }); server.register(v3DataRoutes, { prefix: '/rest/v3' });
server.register(v3ReportRoutes, { prefix: '/rest/v3' }); server.register(v3ReportRoutes, { prefix: '/rest/v3' });
server.register(v4DataRoutes, { prefix: '/rest/v4' });
server.register(v4ReportRoutes, { prefix: '/rest/v4' });
server.listen({ host: '0.0.0.0', port: environment.port }, (error, address) => { server.listen({ host: '0.0.0.0', port: environment.port }, (error, address) => {
if (error) { if (error) {

View File

@ -1,17 +1,14 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch';
/**
* @deprecated This API route is no longer supported. Please use a newer version
*/
export default (server: FastifyInstance, options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, options: RouteShorthandOptions, done: () => void) => {
server.get('/entries/', async (request, reply) => { server.get('/entries/', async (request, reply) => {
try { reply.send({
const repositoryUrl = 'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/main'; success: false,
const dataUrl = `${repositoryUrl}/data/elements.txt`; errors: ['This API route is no longer supported. Please use a newer version'],
const entriesLength = (await (await fetch(dataUrl)).text()).split('\n').length; });
reply.send({ entries: entriesLength, success: true });
} catch {
reply.send({ success: false });
}
}); });
done(); done();

View File

@ -1,31 +1,15 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
type PostReportBody = { /**
html?: string; * @deprecated This API route is no longer supported. Please use a newer version
subject: string; */
text?: string;
to: string;
};
export default (server: FastifyInstance, options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, options: RouteShorthandOptions, done: () => void) => {
server.post<{ Body: PostReportBody }>( server.post('/report/', {}, async (_request, reply) => {
'/report/', reply.send({
{
schema: {
body: {
properties: {},
required: [],
type: 'object',
},
},
},
async (_request, reply) => {
reply.status(500).send({
success: false, success: false,
errors: ['This API route is no longer supported. Please upgrade to the latest version'], errors: ['This API route is no longer supported. Please use a newer version'],
});
}); });
}
);
done(); done();
}; };

View File

@ -1,32 +1,22 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import { parseNewFix } from 'services/compatibility';
export default (server: FastifyInstance, options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, options: RouteShorthandOptions, done: () => void) => {
server.get('/data/', async (request, reply) => { server.get('/data/', async (request, reply) => {
try { try {
const dataUrl = 'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/main/data'; const databaseUrl =
const commonWordsUrl = `${dataUrl}/common-words.json`; 'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/main/database.json';
const fixesUrl = `${dataUrl}/fixes.txt`; const result = await (await fetch(databaseUrl)).json();
const skipsUrl = `${dataUrl}/skips.json`;
const tokensUrl = `${dataUrl}/tokens.json`;
const results = await Promise.all([
fetch(commonWordsUrl),
fetch(fixesUrl),
fetch(skipsUrl),
fetch(tokensUrl),
]);
const skips = await results[2].json();
const tokens = await results[3].json();
reply.send({ reply.send({
data: { data: {
classes: tokens.classes, classes: result.tokens.classes,
commonWords: await results[0].json(), commonWords: result.commonWords,
elements: tokens.selectors, elements: result.tokens.selectors,
fixes: (await results[1].text()).split('\n').filter((x) => !!x), fixes: result.fixes.map(parseNewFix),
skips: skips.domains, skips: result.skips.domains,
tags: skips.tags, tags: result.skips.tags,
}, },
success: true, success: true,
}); });

View File

@ -1,33 +1,26 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import { parseNewFix } from 'services/compatibility';
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.get('/data/', async (_request, reply) => { server.get('/data/', async (_request, reply) => {
try { try {
const dataUrl = 'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/main/data'; const databaseUrl =
const commonWordsUrl = `${dataUrl}/common-words.json`; 'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/main/database.json';
const fixesUrl = `${dataUrl}/fixes.txt`; const result = await (await fetch(databaseUrl)).json();
const skipsUrl = `${dataUrl}/skips.json`;
const tokensUrl = `${dataUrl}/tokens.json`;
const results = await Promise.all([
fetch(commonWordsUrl),
fetch(fixesUrl),
fetch(skipsUrl),
fetch(tokensUrl),
]);
reply.send({ reply.send({
data: { data: {
commonWords: await results[0].json(), ...result,
fixes: (await results[1].text()).split('\n').filter((x) => !!x), fixes: result.fixes.map(parseNewFix),
skips: await results[2].json(),
tokens: await results[3].json(),
}, },
success: true, success: true,
}); });
} catch (error) { } catch (error) {
reply.send({ success: false }); reply.send({
errors: [error.message],
success: false,
});
} }
}); });

View File

@ -39,6 +39,7 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
const issues = await octokit.request('GET /repos/{owner}/{repo}/issues', { const issues = await octokit.request('GET /repos/{owner}/{repo}/issues', {
owner: environment.github.owner, owner: environment.github.owner,
repo: environment.github.repo, repo: environment.github.repo,
state: 'all',
}); });
const ua = new UAParser(request.body.userAgent ?? '').getResult(); const ua = new UAParser(request.body.userAgent ?? '').getResult();
const url = new URL(request.body.url).hostname const url = new URL(request.body.url).hostname
@ -49,8 +50,19 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
const existingIssue = issues.data.find((issue) => issue.title.includes(url)); const existingIssue = issues.data.find((issue) => issue.title.includes(url));
try { try {
if (existingIssue) { if (existingIssue?.state === 'closed') {
throw new Error('Issue already exists'); await octokit.request('PATCH /repos/{owner}/{repo}/issues/{issue_number}', {
owner: environment.github.owner,
repo: environment.github.repo,
issue_number: existingIssue.number,
state: 'open',
});
reply.send({
data: existingIssue.html_url,
success: true,
});
return;
} }
const response = await octokit.request('POST /repos/{owner}/{repo}/issues', { const response = await octokit.request('POST /repos/{owner}/{repo}/issues', {
@ -84,7 +96,6 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
reply.send({ reply.send({
errors: [error.message], errors: [error.message],
success: false, success: false,
data: existingIssue?.html_url,
}); });
} }
} }

View File

@ -0,0 +1,24 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch';
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.get('/data/', async (_request, reply) => {
try {
const databaseUrl =
'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/main/database.json';
const fetchOptions = {
headers: { 'Cache-Control': 'no-cache' },
};
const result = await (await fetch(databaseUrl, fetchOptions)).json();
reply.send({ data: result, success: true });
} catch (error) {
reply.send({
errors: [error.message],
success: false,
});
}
});
done();
};

View File

@ -0,0 +1 @@
export { default as default } from '../v3/report';

View File

@ -0,0 +1,13 @@
/**
* Parse the new fix object into the old string format used by older versions of the extension
*/
export function parseNewFix(fix: Fix): string {
return `${fix.domain}##${fix.selector}##${fix.action}${fix.property ? `##${fix.property}` : ''}`;
}
export interface Fix {
readonly action: string;
readonly domain: string;
readonly property?: string;
readonly selector: string;
}

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Tragen Sie zu diesem Projekt bei" "message": "Tragen Sie zu diesem Projekt bei"
}, },
"popup_databaseVersion": {
"message": "Datenbankversion"
},
"popup_extensionVersion": {
"message": "Erweiterungsversion"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Hilfe oder Probleme?" "message": "Hilfe oder Probleme?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribute to this project" "message": "Contribute to this project"
}, },
"popup_databaseVersion": {
"message": "Database version"
},
"popup_extensionVersion": {
"message": "Extension version"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Help or issues?" "message": "Help or issues?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuye a este proyecto" "message": "Contribuye a este proyecto"
}, },
"popup_databaseVersion": {
"message": "Versión de la base de datos"
},
"popup_extensionVersion": {
"message": "Versión de la extensión"
},
"popup_helpOption": { "popup_helpOption": {
"message": "¿Ayuda o problemas?" "message": "¿Ayuda o problemas?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuez à ce projet" "message": "Contribuez à ce projet"
}, },
"popup_databaseVersion": {
"message": "Version de la base de données"
},
"popup_extensionVersion": {
"message": "Version de l'extension"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Aide ou problèmes?" "message": "Aide ou problèmes?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuisci a questo progetto" "message": "Contribuisci a questo progetto"
}, },
"popup_databaseVersion": {
"message": "Versione del database"
},
"popup_extensionVersion": {
"message": "Versione dell'estensione"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Aiuto o problemi?" "message": "Aiuto o problemi?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Weź udział w rozwoju projektu" "message": "Weź udział w rozwoju projektu"
}, },
"popup_databaseVersion": {
"message": "Wersja bazy danych"
},
"popup_extensionVersion": {
"message": "Wersja rozszerzenia"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Potrzebujesz pomocy lub masz problem?" "message": "Potrzebujesz pomocy lub masz problem?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribua para este projeto" "message": "Contribua para este projeto"
}, },
"popup_databaseVersion": {
"message": "Versão do banco de dados"
},
"popup_extensionVersion": {
"message": "Versão da extensão"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Ajuda ou problemas?" "message": "Ajuda ou problemas?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribua para este projeto" "message": "Contribua para este projeto"
}, },
"popup_databaseVersion": {
"message": "Versão do banco de dados"
},
"popup_extensionVersion": {
"message": "Versão da extensão"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Ajuda ou problemas?" "message": "Ajuda ou problemas?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuie la acest proiect" "message": "Contribuie la acest proiect"
}, },
"popup_databaseVersion": {
"message": "Versiunea bazei de date"
},
"popup_extensionVersion": {
"message": "Versiunea extensiei"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Ajutor sau probleme?" "message": "Ajutor sau probleme?"
}, },

View File

@ -35,6 +35,12 @@
"popup_contributeOption": { "popup_contributeOption": {
"message": "Внести свой вклад в этот проект" "message": "Внести свой вклад в этот проект"
}, },
"popup_databaseVersion": {
"message": "Версия базы данных"
},
"popup_extensionVersion": {
"message": "Версия расширения"
},
"popup_helpOption": { "popup_helpOption": {
"message": "Помощь или проблемы?" "message": "Помощь или проблемы?"
}, },

View File

@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "Cookie Dialog Monster", "name": "Cookie Dialog Monster",
"version": "7.0.4", "version": "7.1.0",
"default_locale": "en", "default_locale": "en",
"description": "__MSG_appDesc__", "description": "__MSG_appDesc__",
"icons": { "icons": {

View File

@ -105,6 +105,53 @@
</svg> </svg>
<span data-i18n="popup_rateOption"></span> <span data-i18n="popup_rateOption"></span>
</popup-button> </popup-button>
<popup-data-container>
<popup-data>
<strong data-i18n="popup_databaseVersion"></strong>
<span id="database-version"></span>
<popup-data-button
data-animation="flip"
id="refresh-database-button"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="none"
height="12"
id="refresh-database-spinner"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
stroke="currentColor"
viewBox="0 0 24 24"
width="12"
>
<polyline points="1 4 1 10 7 10"></polyline>
<polyline points="23 20 23 14 17 14"></polyline>
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>
</svg>
<svg
aria-hidden="true"
fill="none"
height="12"
id="refresh-database-check"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
stroke="var(--color-success)"
viewBox="0 0 24 24"
width="12"
>
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</popup-data-button>
</popup-data>
<popup-data>
<strong data-i18n="popup_extensionVersion"></strong>
<span id="extension-version"></span>
</popup-data>
</popup-data-container>
</main> </main>
<footer></footer> <footer></footer>
</body> </body>

View File

@ -6,7 +6,7 @@ if (typeof browser === 'undefined') {
* @description API URL * @description API URL
* @type {string} * @type {string}
*/ */
const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v3'; const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v4';
/** /**
* @description Context menu identifier * @description Context menu identifier
@ -68,7 +68,7 @@ const report = async (message, tab, callback) => {
const userAgent = message.userAgent; const userAgent = message.userAgent;
const version = browser.runtime.getManifest().version; const version = browser.runtime.getManifest().version;
const body = JSON.stringify({ reason, url: tab.url, userAgent, version }); const body = JSON.stringify({ reason, url: tab.url, userAgent, version });
const headers = { 'Content-type': 'application/json' }; const headers = { 'Cache-Control': 'no-cache', 'Content-type': 'application/json' };
const url = `${apiUrl}/report/`; const url = `${apiUrl}/report/`;
const response = await fetch(url, { body, headers, method: 'POST' }); const response = await fetch(url, { body, headers, method: 'POST' });
@ -91,7 +91,9 @@ browser.contextMenus.onClicked.addListener((info, tab) => {
switch (info.menuItemId) { switch (info.menuItemId) {
case reportMenuItemId: case reportMenuItemId:
if (tabId) browser.tabs.sendMessage(tabId, { type: 'SHOW_REPORT_DIALOG' }, suppressLastError); if (tabId !== undefined) {
browser.tabs.sendMessage(tabId, { type: 'SHOW_REPORT_DIALOG' }, suppressLastError);
}
break; break;
case settingsMenuItemId: case settingsMenuItemId:
browser.runtime.openOptionsPage(); browser.runtime.openOptionsPage();
@ -111,18 +113,18 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
switch (message.type) { switch (message.type) {
case 'DISABLE_ICON': case 'DISABLE_ICON':
if (isPage && tabId) { if (isPage && tabId !== undefined) {
browser.action.setIcon({ path: '/assets/icons/disabled.png', tabId }, suppressLastError); browser.action.setIcon({ path: '/assets/icons/disabled.png', tabId }, suppressLastError);
browser.action.setBadgeText({ tabId, text: '' }); browser.action.setBadgeText({ tabId, text: '' });
} }
break; break;
case 'ENABLE_ICON': case 'ENABLE_ICON':
if (isPage && tabId) { if (isPage && tabId !== undefined) {
browser.action.setIcon({ path: '/assets/icons/enabled.png', tabId }, suppressLastError); browser.action.setIcon({ path: '/assets/icons/enabled.png', tabId }, suppressLastError);
} }
break; break;
case 'ENABLE_POPUP': case 'ENABLE_POPUP':
if (isPage && tabId) { if (isPage && tabId !== undefined) {
browser.action.setPopup({ popup: '/popup.html', tabId }, suppressLastError); browser.action.setPopup({ popup: '/popup.html', tabId }, suppressLastError);
} }
break; break;
@ -137,8 +139,8 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
return true; return true;
case 'GET_EXCLUSION_LIST': case 'GET_EXCLUSION_LIST':
storage.get(null, (exclusions) => { storage.get(null, (exclusions) => {
const exclusionList = Object.entries(exclusions || {}).flatMap((x) => const exclusionList = Object.entries(exclusions || {}).flatMap((exclusion) =>
x[0] !== 'data' && !x[1]?.enabled ? [x[0]] : [] exclusion[0] !== 'data' && !exclusion[1]?.enabled ? [exclusion[0]] : []
); );
callback(exclusionList); callback(exclusionList);
}); });
@ -157,28 +159,33 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
}); });
return true; return true;
case 'INSERT_DIALOG_CSS': case 'INSERT_DIALOG_CSS':
if (isPage && tabId) { if (isPage && tabId !== undefined) {
script.insertCSS({ files: ['styles/dialog.css'], target: { tabId } }); script.insertCSS({ files: ['styles/dialog.css'], target: { tabId } });
} }
break; break;
case 'REFRESH_DATA':
refreshData(callback);
return true;
case 'REPORT': case 'REPORT':
if (tabId) { if (tabId !== undefined) {
report(message, sender.tab, callback); report(message, sender.tab, callback);
return true; return true;
} }
break; break;
case 'SET_BADGE': case 'SET_BADGE':
if (tabId) { if (tabId !== undefined) {
browser.action.setBadgeBackgroundColor({ color: '#6b7280' }); browser.action.setBadgeBackgroundColor({ color: '#6b7280' });
browser.action.setBadgeText({ tabId, text: message.value }); browser.action.setBadgeText({ tabId, text: message.value });
} }
break; break;
case 'SET_HOSTNAME_STATE': case 'SET_HOSTNAME_STATE':
if (hostname && message.state.enabled === false) { if (hostname) {
if (message.state.enabled === false) {
storage.set({ [hostname]: message.state }); storage.set({ [hostname]: message.state });
} else if (hostname) { } else {
storage.remove(hostname); storage.remove(hostname);
} }
}
break; break;
default: default:
break; break;

View File

@ -1,20 +1,28 @@
/**
* @typedef {Object} ExtensionData
* @property {string[] | undefined} commonWords
* @property {Fix[] | undefined} fixes
* @property {{ domains: string[] | undefined, tags: string[] | undefined } | undefined} skips
* @property {{ classes: string[] | undefined, selectors: string[] | undefined } | undefined} tokens
*/
/**
* @typedef {Object} Fix
* @property {string} action
* @property {string} domain
* @property {string | undefined} property
* @property {string} selector
*/
/**
* @typedef {Object} RunParams
* @property {boolean | undefined} skipTriggerEvent
*/
if (typeof browser === 'undefined') { if (typeof browser === 'undefined') {
browser = chrome; browser = chrome;
} }
/**
* @typedef {Object} ExtensionData
* @property {string[]} commonWords
* @property {string[]} fixes
* @property {{ domains: string[], tags: string[] }} skips
* @property {{ classes: string[], selectors: string[] }} tokens
*/
/**
* @description Attribute name
*/
const dataAttributeName = 'data-cookie-dialog-monster';
/** /**
* @description Matched elements count * @description Matched elements count
* @type {number} * @type {number}
@ -27,16 +35,16 @@ let count = 0;
*/ */
let { commonWords, fixes = [], skips, tokens } = {}; let { commonWords, fixes = [], skips, tokens } = {};
/**
* @description Attribute name
*/
const dataAttributeName = 'data-cookie-dialog-monster';
/** /**
* @description Shortcut to send messages to background script * @description Shortcut to send messages to background script
*/ */
const dispatch = browser.runtime.sendMessage; const dispatch = browser.runtime.sendMessage;
/**
* @description Event name
*/
const setupEventName = 'cookie-dialog-monster';
/** /**
* @description Current hostname * @description Current hostname
* @type {string} * @type {string}
@ -44,10 +52,10 @@ const setupEventName = 'cookie-dialog-monster';
const hostname = getHostname(); const hostname = getHostname();
/** /**
* @description Elements that were already matched and are removable * @description Initial visibility state
* @type {HTMLElement[]} * @type {boolean}
*/ */
const removables = []; let initiallyVisible = document.visibilityState === 'visible';
/** /**
* @description Options provided to observer * @description Options provided to observer
@ -60,6 +68,12 @@ const options = { childList: true, subtree: true };
*/ */
const preview = hostname.startsWith('consent.') || hostname.startsWith('myprivacy.'); const preview = hostname.startsWith('consent.') || hostname.startsWith('myprivacy.');
/**
* @description Elements that were already matched and are removable
* @type {HTMLElement[]}
*/
const removables = [];
/** /**
* @description Elements that were already seen * @description Elements that were already seen
* @type {HTMLElement[]} * @type {HTMLElement[]}
@ -72,6 +86,11 @@ const seen = [];
*/ */
let state = { enabled: true }; let state = { enabled: true };
/**
* @description Event name to trigger the cleaning process
*/
const triggerEventName = 'cookie-dialog-monster';
/** /**
* @description Clean DOM * @description Clean DOM
* @param {Element[]} elements * @param {Element[]} elements
@ -79,14 +98,25 @@ let state = { enabled: true };
* @returns {void} * @returns {void}
*/ */
function clean(elements, skipMatch) { function clean(elements, skipMatch) {
for (const element of elements) { let index = 0;
const size = 50;
function chunk() {
const end = Math.min(index + size, elements.length);
for (; index < end; index++) {
const element = elements[index];
if (match(element, skipMatch)) { if (match(element, skipMatch)) {
const observer = new MutationObserver(forceElementStyles); const observer = new MutationObserver(forceElementStyles);
const options = { attributes: true, attributeFilter: [dataAttributeName, 'class', 'style'] };
element.setAttribute(dataAttributeName, 'true'); element.setAttribute(dataAttributeName, 'true');
element.style.setProperty('display', 'none', 'important'); element.style.setProperty('display', 'none', 'important');
observer.observe(element, options);
observer.observe(element, {
attributes: true,
attributeFilter: [dataAttributeName, 'class', 'style'],
});
count += 1; count += 1;
dispatch({ type: 'SET_BADGE', value: `${count}` }); dispatch({ type: 'SET_BADGE', value: `${count}` });
@ -98,6 +128,13 @@ function clean(elements, skipMatch) {
seen.push(element); seen.push(element);
} }
if (index < elements.length) {
requestAnimationFrame(chunk);
}
}
requestAnimationFrame(chunk);
} }
/** /**
@ -108,8 +145,10 @@ function clean(elements, skipMatch) {
function forceClean(element) { function forceClean(element) {
const elements = [...element.querySelectorAll(tokens.selectors)]; const elements = [...element.querySelectorAll(tokens.selectors)];
if (elements.length) {
fix(); fix();
if (elements.length && !preview) clean(elements, true); clean(elements, true);
}
} }
/** /**
@ -169,7 +208,12 @@ function isInViewport(element) {
* @returns {boolean} * @returns {boolean}
*/ */
function match(element, skipMatch) { function match(element, skipMatch) {
if (!tokens?.classes.length || !tokens?.selectors.length) { if (
!commonWords.length ||
!tokens?.classes?.length ||
!tokens?.selectors?.length ||
!skips?.tags?.length
) {
return false; return false;
} }
@ -192,11 +236,16 @@ function match(element, skipMatch) {
} }
if (element.hasAttributes()) { if (element.hasAttributes()) {
// 2023-06-10: twitch.tv temporary fix // 2023-06-10: fix #113 temporarily
if (element.classList.contains('chat-line__message')) { if (element.classList.contains('chat-line__message')) {
return false; return false;
} }
// 2024-08-03: fix #701 temporarily
if (element.classList.contains('sellos')) {
return false;
}
const isDialog = tagName === 'DIALOG' && element.getAttribute('open') === 'true'; const isDialog = tagName === 'DIALOG' && element.getAttribute('open') === 'true';
const isFakeDialog = tagName === 'DIV' && element.className.includes('cmp'); const isFakeDialog = tagName === 'DIV' && element.className.includes('cmp');
@ -215,7 +264,7 @@ function match(element, skipMatch) {
} }
/** /**
* @description Fix data, consent page and scroll issues * @description Fix data, middle consent page and scroll issues
* @returns {void} * @returns {void}
*/ */
function fix() { function fix() {
@ -230,10 +279,13 @@ function fix() {
} }
} }
for (const fix of fixes) { // 2024-08-02: fix #644 temporarily
const [match, selector, action, property] = fix.split('##'); document.getElementsByTagName('ion-router-outlet')[0]?.removeAttribute('inert');
if (hostname.includes(match)) { for (const fix of fixes) {
const { action, domain, property, selector } = fix;
if (hostname.includes(domain)) {
switch (action) { switch (action) {
case 'click': { case 'click': {
const element = document.querySelector(selector); const element = document.querySelector(selector);
@ -309,10 +361,10 @@ function restoreDOM() {
/** /**
* @async * @async
* @description Set up everything * @description Run the extension
* @param {boolean} skipReadyStateHack * @param {RunParams | undefined} params
*/ */
async function setup(skipReadyStateHack) { async function run(params) {
state = (await dispatch({ hostname, type: 'GET_HOSTNAME_STATE' })) ?? state; state = (await dispatch({ hostname, type: 'GET_HOSTNAME_STATE' })) ?? state;
dispatch({ type: 'ENABLE_POPUP' }); dispatch({ type: 'ENABLE_POPUP' });
@ -328,13 +380,12 @@ async function setup(skipReadyStateHack) {
dispatch({ type: 'SET_BADGE', value: `${count}` }); dispatch({ type: 'SET_BADGE', value: `${count}` });
} }
// 2023-06-13: hack to force clean when data request takes too long and there are no changes later
if (document.readyState === 'complete' && !skipReadyStateHack) {
window.dispatchEvent(new Event(setupEventName));
}
dispatch({ type: 'ENABLE_ICON' }); dispatch({ type: 'ENABLE_ICON' });
observer.observe(document.body ?? document.documentElement, options); observer.observe(document.body ?? document.documentElement, options);
if (!params?.skipTriggerEvent) {
window.dispatchEvent(new CustomEvent(triggerEventName));
}
} else { } else {
dispatch({ type: 'DISABLE_ICON' }); dispatch({ type: 'DISABLE_ICON' });
observer.disconnect(); observer.disconnect();
@ -352,50 +403,44 @@ const observer = new MutationObserver((mutations) => {
const elements = mutations.flatMap((mutation) => Array.from(mutation.addedNodes)); const elements = mutations.flatMap((mutation) => Array.from(mutation.addedNodes));
fix(); window.dispatchEvent(new CustomEvent(triggerEventName, { detail: { elements } }));
clean(elements);
}); });
/** /**
* @description Listen to messages from any other scripts * @description Listen to messages from any other scripts
* @listens browser.runtime#onMessage * @listens browser.runtime#onMessage
*/ */
browser.runtime.onMessage.addListener((message) => { browser.runtime.onMessage.addListener(async (message) => {
switch (message.type) { switch (message.type) {
case 'RESTORE': { case 'RESTORE': {
restoreDOM(); restoreDOM();
break; break;
} }
case 'RUN': { case 'RUN': {
if (removables.length) clean(removables, true); if (removables.length) {
window.dispatchEvent(new CustomEvent(triggerEventName), {
detail: {
elements: removables,
skipMatch: true,
},
});
}
break; break;
} }
} }
setup(); await run({ skipTriggerEvent: message.type === 'RESTORE' });
}); });
/** /**
* @async * @async
* @description Run setup if the page wasn't visible yet * @description Fix still existing elements when page loads
* @listens window#visibilitychange * @listens window#DOMContentLoaded
* @returns {void} * @returns {void}
*/ */
window.addEventListener('visibilitychange', async () => { window.addEventListener('DOMContentLoaded', async () => {
if (document.body?.children.length && !tokens) {
await setup(true);
clean([...document.body.children]);
}
});
/**
* @description Fix still existing elements when page fully load
* @listens window#load
* @returns {void}
*/
window.addEventListener('load', () => {
if (document.visibilityState === 'visible') { if (document.visibilityState === 'visible') {
window.dispatchEvent(new Event(setupEventName)); await run();
} }
}); });
@ -404,10 +449,10 @@ window.addEventListener('load', () => {
* @listens window#pageshow * @listens window#pageshow
* @returns {void} * @returns {void}
*/ */
window.addEventListener('pageshow', (event) => { window.addEventListener('pageshow', async (event) => {
if (document.visibilityState === 'visible' && event.persisted) { if (document.visibilityState === 'visible' && event.persisted) {
setup(true); await run();
window.dispatchEvent(new Event(setupEventName)); window.dispatchEvent(new CustomEvent(triggerEventName));
} }
}); });
@ -416,8 +461,13 @@ window.addEventListener('pageshow', (event) => {
* @listens window#cookie-dialog-monster * @listens window#cookie-dialog-monster
* @returns {void} * @returns {void}
*/ */
window.addEventListener(setupEventName, () => { window.addEventListener(triggerEventName, (event) => {
if (document.body?.children.length && state.enabled && tokens?.selectors.length && !preview) { if (document.body?.children.length && !preview && state.enabled && tokens?.selectors?.length) {
fix();
if (event.detail?.elements) {
clean(event.detail.elements, event.detail.skipMatch);
} else {
if (readingTime() < 4) { if (readingTime() < 4) {
forceClean(document.body); forceClean(document.body);
} else { } else {
@ -425,8 +475,19 @@ window.addEventListener(setupEventName, () => {
clean([...document.body.children]); clean([...document.body.children]);
} }
} }
}
}); });
if (document.visibilityState === 'visible') { /**
setup(); * @async
* @description Run run if the page wasn't visible yet
* @listens window#visibilitychange
* @returns {void}
*/
window.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'visible' && !initiallyVisible) {
initiallyVisible = true;
await run();
window.dispatchEvent(new CustomEvent(triggerEventName));
} }
});

View File

@ -195,7 +195,14 @@ function showReportDialog() {
* @param {MouseEvent} event * @param {MouseEvent} event
*/ */
async function submitButtonClickHandler(event) { async function submitButtonClickHandler(event) {
const target = event.currentTarget;
if (target.getAttribute('aria-disabled') === 'true') {
return;
}
event.preventDefault(); event.preventDefault();
target.setAttribute('aria-disabled', 'true');
const dialog = document.getElementById(reportDialogId); const dialog = document.getElementById(reportDialogId);
const formView = dialog?.getElementsByTagName('report-dialog-form-view')[0]; const formView = dialog?.getElementsByTagName('report-dialog-form-view')[0];

View File

@ -72,6 +72,12 @@ async function handleContentLoaded() {
const contributeButtonElement = document.getElementById('contribute-option'); const contributeButtonElement = document.getElementById('contribute-option');
contributeButtonElement?.addEventListener('click', handleLinkRedirect); contributeButtonElement?.addEventListener('click', handleLinkRedirect);
const databaseRefreshButtonElement = document.getElementById('refresh-database-button');
databaseRefreshButtonElement?.addEventListener('click', handleDatabaseRefresh);
const extensionVersionElement = document.getElementById('extension-version');
extensionVersionElement.innerText = browser.runtime.getManifest().version;
const helpButtonElement = document.getElementById('help-option'); const helpButtonElement = document.getElementById('help-option');
helpButtonElement?.addEventListener('click', handleLinkRedirect); helpButtonElement?.addEventListener('click', handleLinkRedirect);
@ -90,6 +96,39 @@ async function handleContentLoaded() {
settingsButtonElement.addEventListener('click', handleSettingsClick); settingsButtonElement.addEventListener('click', handleSettingsClick);
translate(); translate();
updateDatabaseVersion();
}
/**
* @async
* @description Refresh the database
* @param {MouseEvent} event
*/
async function handleDatabaseRefresh(event) {
const target = event.currentTarget;
if (target.getAttribute('aria-disabled') === 'true') {
return;
}
const checkIcon = target.querySelector('#refresh-database-check');
const spinnerIcon = target.querySelector('#refresh-database-spinner');
target.setAttribute('data-refreshing', 'true');
target.setAttribute('aria-disabled', 'true');
await browser.runtime.sendMessage({ type: 'REFRESH_DATA' });
checkIcon.style.setProperty('display', 'block');
spinnerIcon.style.setProperty('display', 'none');
target.removeAttribute('data-animation');
target.removeAttribute('data-refreshing');
updateDatabaseVersion();
window.setTimeout(() => {
checkIcon.style.setProperty('display', 'none');
spinnerIcon.style.setProperty('display', 'block');
target.removeAttribute('aria-disabled');
target.setAttribute('data-animation', 'flip');
}, 5000);
} }
/** /**
@ -113,13 +152,13 @@ async function handleLinkRedirect(event) {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async function handlePowerToggle(event) { async function handlePowerToggle(event) {
const element = event.currentTarget; const target = event.currentTarget;
const next = { enabled: !state.enabled }; const next = { enabled: !state.enabled };
browser.runtime.sendMessage({ hostname, state: next, type: 'SET_HOSTNAME_STATE' }); browser.runtime.sendMessage({ hostname, state: next, type: 'SET_HOSTNAME_STATE' });
browser.tabs.sendMessage(state.tabId, { type: next.enabled ? 'RUN' : 'RESTORE' }); browser.tabs.sendMessage(state.tabId, { type: next.enabled ? 'RUN' : 'RESTORE' });
element.setAttribute('disabled', 'true'); target.setAttribute('aria-disabled', 'true');
element.setAttribute('data-value', next.enabled ? 'on' : 'off'); target.setAttribute('data-value', next.enabled ? 'on' : 'off');
window.close(); window.close();
} }
@ -152,6 +191,19 @@ function translate() {
} }
} }
/**
* @async
* @description Update the database version element
* @returns {Promise<void>}
*/
async function updateDatabaseVersion() {
const data = await browser.runtime.sendMessage({ hostname, type: 'GET_DATA' });
const databaseVersionElement = document.getElementById('database-version');
if (data.version) databaseVersionElement.innerText = data.version;
else databaseVersionElement.style.setProperty('display', 'none');
}
/** /**
* @description Listen to document ready * @description Listen to document ready
* @listens document#DOMContentLoaded * @listens document#DOMContentLoaded

View File

@ -85,7 +85,9 @@ popup-button {
popup-button:focus, popup-button:focus,
popup-button:hover { popup-button:hover {
box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px; box-shadow:
rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
} }
popup-button > span { popup-button > span {
@ -96,10 +98,58 @@ popup-button > svg {
align-self: flex-end; align-self: flex-end;
} }
popup-data {
align-items: center;
display: flex;
gap: 4px;
justify-content: center;
outline: none;
}
popup-data:not(:first-child) {
margin-top: 4px;
}
popup-data-button {
cursor: pointer;
outline: none;
transition: 0.4s;
}
popup-data-button[aria-disabled='true'] {
cursor: not-allowed;
}
popup-data-button[data-animation='flip']:focus,
popup-data-button[data-animation='flip']:hover {
transform: rotate(-180deg);
}
popup-data-button[data-refreshing='true'] {
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(-360deg);
}
}
popup-data-container {
font-size: 12px;
grid-column: 1 / -1;
justify-self: center;
text-align: center;
}
strong { strong {
font-weight: bold; font-weight: bold;
} }
#refresh-database-check {
display: none;
}
#power-option { #power-option {
color: var(--color-white); color: var(--color-white);
word-break: break-all; word-break: break-all;