diff --git a/platform/mv3/extension/about.html b/platform/mv3/extension/about.html index b4ea3cee0..a0bb164ea 100644 --- a/platform/mv3/extension/about.html +++ b/platform/mv3/extension/about.html @@ -34,6 +34,7 @@ + diff --git a/platform/mv3/extension/dashboard.html b/platform/mv3/extension/dashboard.html index 4f446dee3..deb6efb15 100644 --- a/platform/mv3/extension/dashboard.html +++ b/platform/mv3/extension/dashboard.html @@ -30,6 +30,7 @@ + diff --git a/platform/mv3/extension/js/about.js b/platform/mv3/extension/js/about.js index 5596b777e..2717501a5 100644 --- a/platform/mv3/extension/js/about.js +++ b/platform/mv3/extension/js/about.js @@ -21,15 +21,13 @@ 'use strict'; -/******************************************************************************/ - import { runtime } from './ext.js'; -import { qs$ } from './dom.js'; +import { dom } from './dom.js'; /******************************************************************************/ (async ( ) => { const manifest = runtime.getManifest(); - qs$('#aboutNameVer').textContent = `${manifest.name} ${manifest.version}`; + dom.text('#aboutNameVer', `${manifest.name} ${manifest.version}`); })(); diff --git a/platform/mv3/extension/js/dashboard-common.js b/platform/mv3/extension/js/dashboard-common.js index 7aa3b3261..80a520653 100644 --- a/platform/mv3/extension/js/dashboard-common.js +++ b/platform/mv3/extension/js/dashboard-common.js @@ -21,12 +21,10 @@ 'use strict'; -/******************************************************************************/ - -import { dom, qsa$ } from './dom.js'; +import { dom } from './dom.js'; /******************************************************************************/ // Open links in the proper window -dom.attr(qsa$('a'), 'target', '_blank'); -dom.attr(qsa$('a[href*="dashboard.html"]'), 'target', '_parent'); +dom.attr('a', 'target', '_blank'); +dom.attr('a[href*="dashboard.html"]', 'target', '_parent'); diff --git a/platform/mv3/extension/js/dashboard.js b/platform/mv3/extension/js/dashboard.js index f21fc9961..b3301160b 100644 --- a/platform/mv3/extension/js/dashboard.js +++ b/platform/mv3/extension/js/dashboard.js @@ -21,15 +21,13 @@ 'use strict'; -/******************************************************************************/ - import { simpleStorage } from './storage.js'; import { dom, qs$ } from './dom.js'; /******************************************************************************/ const discardUnsavedData = function(synchronous = false) { - const paneFrame = document.getElementById('iframe'); + const paneFrame = qs$('#iframe'); const paneWindow = paneFrame.contentWindow; if ( typeof paneWindow.hasUnsavedData !== 'function' || @@ -44,11 +42,11 @@ const discardUnsavedData = function(synchronous = false) { return new Promise(resolve => { const modal = document.querySelector('#unsavedWarning'); - modal.classList.add('on'); + dom.cl.add(modal, 'on'); modal.focus(); const onDone = status => { - modal.classList.remove('on'); + dom.cl.remove(modal, 'on'); document.removeEventListener('click', onClick, true); resolve(status); }; @@ -73,15 +71,15 @@ const discardUnsavedData = function(synchronous = false) { const loadDashboardPanel = function(pane, first) { const tabButton = document.querySelector(`[data-pane="${pane}"]`); - if ( tabButton === null || tabButton.classList.contains('selected') ) { + if ( tabButton === null || dom.cl.has(tabButton, 'selected') ) { return; } const loadPane = ( ) => { self.location.replace(`#${pane}`); for ( const node of document.querySelectorAll('.tabButton.selected') ) { - node.classList.remove('selected'); + dom.cl.remove(node, 'selected'); } - tabButton.classList.add('selected'); + dom.cl.add(tabButton, 'selected'); tabButton.scrollIntoView(); document.querySelector('#iframe').contentWindow.location.replace(pane); if ( pane !== 'no-dashboard.html' ) { @@ -103,11 +101,11 @@ const loadDashboardPanel = function(pane, first) { }; const onTabClickHandler = function(ev) { - loadDashboardPanel(ev.target.getAttribute('data-pane')); + loadDashboardPanel(dom.attr(ev.target, 'data-pane')); }; if ( self.location.hash.slice(1) === 'no-dashboard.html' ) { - document.body.classList.add('noDashboard'); + dom.cl.add(dom.body, 'noDashboard'); } (async ( ) => { @@ -117,12 +115,7 @@ if ( self.location.hash.slice(1) === 'no-dashboard.html' ) { } loadDashboardPanel(pane !== null ? pane : 'settings.html', true); - dom.on( - qs$('#dashboard-nav'), - 'click', - '.tabButton', - onTabClickHandler - ); + dom.on('#dashboard-nav', 'click', '.tabButton', onTabClickHandler); // https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event window.addEventListener('beforeunload', ( ) => { diff --git a/platform/mv3/extension/js/popup.js b/platform/mv3/extension/js/popup.js index ca95b4637..9cf55fed1 100644 --- a/platform/mv3/extension/js/popup.js +++ b/platform/mv3/extension/js/popup.js @@ -51,7 +51,7 @@ function setFilteringMode(level, commit = false) { modeSlider.dataset.level = level; if ( qs$('.filteringModeSlider.moving') === null ) { dom.text( - qs$('#filteringModeText > span:nth-of-type(1)'), + '#filteringModeText > span:nth-of-type(1)', i18n$(`filteringMode${level}Name`) ); } @@ -79,7 +79,7 @@ async function commitFilteringMode() { } } dom.text( - qs$('#filteringModeText > span:nth-of-type(1)'), + '#filteringModeText > span:nth-of-type(1)', i18n$(`filteringMode${afterLevel}Name`) ); const actualLevel = await sendMessage({ @@ -112,7 +112,7 @@ async function commitFilteringMode() { const modeSlider = qs$('.filteringModeSlider'); if ( `${level}` === modeSlider.dataset.level ) { return; } dom.text( - qs$('#filteringModeText > span:nth-of-type(2)'), + '#filteringModeText > span:nth-of-type(2)', i18n$(`filteringMode${level}Name`) ); setFilteringMode(level); @@ -131,7 +131,7 @@ async function commitFilteringMode() { dom.cl.remove(modeSlider, 'moving'); self.removeEventListener('mousemove', moveAsync, { capture: true }); self.removeEventListener('mouseup', stop, { capture: true }); - dom.text(qs$('#filteringModeText > span:nth-of-type(2)'), ''); + dom.text('#filteringModeText > span:nth-of-type(2)', ''); commitFilteringMode(); ev.stopPropagation(); ev.preventDefault(); @@ -160,11 +160,11 @@ async function commitFilteringMode() { ev.preventDefault(); }; - dom.on(qs$('.filteringModeButton'), 'mousedown', startSliding); + dom.on('.filteringModeButton', 'mousedown', startSliding); } dom.on( - qs$('.filteringModeSlider'), + '.filteringModeSlider', 'click', '.filteringModeSlider span[data-level]', ev => { @@ -177,25 +177,25 @@ dom.on( ); dom.on( - qs$('.filteringModeSlider'), + '.filteringModeSlider', 'mouseenter', '.filteringModeSlider span[data-level]', ev => { const span = ev.target; const level = parseInt(span.dataset.level, 10); dom.text( - qs$('#filteringModeText > span:nth-of-type(2)'), + '#filteringModeText > span:nth-of-type(2)', i18n$(`filteringMode${level}Name`) ); } ); dom.on( - qs$('.filteringModeSlider'), + '.filteringModeSlider', 'mouseleave', '.filteringModeSlider span[data-level]', ( ) => { - dom.text(qs$('#filteringModeText > span:nth-of-type(2)'), ''); + dom.text('#filteringModeText > span:nth-of-type(2)', ''); } ); @@ -249,11 +249,11 @@ simpleStorage.getItem('popupPanelSections').then(s => { sectionBitsToAttribute(parseInt(s, 10) || 0); }); -dom.on(qs$('#moreButton'), 'click', ( ) => { +dom.on('#moreButton', 'click', ( ) => { toggleSections(true); }); -dom.on(qs$('#lessButton'), 'click', ( ) => { +dom.on('#lessButton', 'click', ( ) => { toggleSections(false); }); @@ -284,12 +284,12 @@ async function init() { setFilteringMode(popupPanelData.level); - dom.text(qs$('#hostname'), tabHostname); + dom.text('#hostname', tabHostname); const parent = qs$('#rulesetStats'); for ( const details of popupPanelData.rulesetDetails || [] ) { - const div = qs$('#templates .rulesetDetails').cloneNode(true); - dom.text(qs$('h1', div), details.name); + const div = dom.clone('#templates .rulesetDetails'); + dom.text(qs$(div, 'h1'), details.name); const { rules, filters, css } = details; let ruleCount = rules.plain + rules.regex; if ( popupPanelData.hasOmnipotence ) { @@ -301,7 +301,7 @@ async function init() { specificCount += css.specific.entityBased; } dom.text( - qs$('p', div), + qs$(div, 'p'), i18n$('perRulesetStats') .replace('{{ruleCount}}', ruleCount.toLocaleString()) .replace('{{filterCount}}', filters.accepted.toLocaleString()) diff --git a/platform/mv3/extension/js/settings.js b/platform/mv3/extension/js/settings.js index 08acaede3..7772bf972 100644 --- a/platform/mv3/extension/js/settings.js +++ b/platform/mv3/extension/js/settings.js @@ -21,8 +21,6 @@ 'use strict'; -/******************************************************************************/ - import { browser, sendMessage } from './ext.js'; import { i18n$ } from './i18n.js'; import { dom, qs$, qsa$ } from './dom.js'; @@ -66,25 +64,24 @@ function renderFilterLists(soft = false) { const liFromListEntry = function(ruleset, li, hideUnused) { if ( !li ) { - li = listEntryTemplate.cloneNode(true); + li = dom.clone(listEntryTemplate); } const on = enabledRulesets.includes(ruleset.id); - li.classList.toggle('checked', on); + dom.cl.toggle(li, 'checked', on); if ( dom.attr(li, 'data-listkey') !== ruleset.id ) { dom.attr(li, 'data-listkey', ruleset.id); - qs$('input[type="checkbox"]', li).checked = on; - qs$('.listname', li).textContent = ruleset.name || ruleset.id; + qs$(li, 'input[type="checkbox"]').checked = on; + dom.text(qs$(li, '.listname'), ruleset.name || ruleset.id); dom.cl.remove(li, 'toRemove'); if ( ruleset.homeURL ) { dom.cl.add(li, 'support'); - const elem = qs$('a.support', li); - dom.attr(elem, 'href', ruleset.homeURL); + dom.attr(qs$(li, 'a.support'), 'href', ruleset.homeURL); } else { dom.cl.remove(li, 'support'); } if ( ruleset.instructionURL ) { dom.cl.add(li, 'mustread'); - dom.attr(qs$('a.mustread', li), 'href', ruleset.instructionURL); + dom.attr(qs$(li, 'a.mustread'), 'href', ruleset.instructionURL); } else { dom.cl.remove(li, 'mustread'); } @@ -93,14 +90,14 @@ function renderFilterLists(soft = false) { } // https://github.com/gorhill/uBlock/issues/1429 if ( soft !== true ) { - qs$('input[type="checkbox"]', li).checked = on; + qs$(li, 'input[type="checkbox"]').checked = on; } const stats = rulesetStats(ruleset.id); li.title = listStatsTemplate .replace('{{ruleCount}}', renderNumber(stats.ruleCount)) .replace('{{filterCount}}', renderNumber(stats.filterCount)); dom.attr( - qs$('.input.checkbox', li), + qs$(li, '.input.checkbox'), 'disabled', stats.ruleCount === 0 ? '' : null ); @@ -126,22 +123,25 @@ function renderFilterLists(soft = false) { const liFromListGroup = function(groupKey, groupRulesets) { let liGroup = qs$(`#lists > .groupEntry[data-groupkey="${groupKey}"]`); if ( liGroup === null ) { - liGroup = listGroupTemplate.cloneNode(true); + liGroup = dom.clone(listGroupTemplate); let groupName = groupNames.get(groupKey); if ( groupName === undefined ) { groupName = i18n$('3pGroup' + groupKey.charAt(0).toUpperCase() + groupKey.slice(1)); groupNames.set(groupKey, groupName); } if ( groupName !== '' ) { - qs$('.geName', liGroup).textContent = groupName; + dom.text(qs$(liGroup, '.geName'), groupName); } } - if ( qs$('.geName:empty', liGroup) === null ) { - qs$('.geCount', liGroup).textContent = listEntryCountFromGroup(groupRulesets); + if ( qs$(liGroup, '.geName:empty') === null ) { + dom.text( + qs$(liGroup, '.geCount'), + listEntryCountFromGroup(groupRulesets) + ); } const hideUnused = mustHideUnusedLists(groupKey); - liGroup.classList.toggle('hideUnused', hideUnused); - const ulGroup = qs$('.listEntries', liGroup); + dom.cl.toggle(liGroup, 'hideUnused', hideUnused); + const ulGroup = qs$(liGroup, '.listEntries'); if ( !groupRulesets ) { return liGroup; } groupRulesets.sort(function(a, b) { return (a.name || '').localeCompare(b.name || ''); @@ -161,10 +161,7 @@ function renderFilterLists(soft = false) { // Incremental rendering: this will allow us to easily discard unused // DOM list entries. - dom.cl.add( - qsa$('#lists .listEntries .listEntry[data-listkey]'), - 'discard' - ); + dom.cl.add('#lists .listEntries .listEntry[data-listkey]', 'discard'); // Visually split the filter lists in three groups const ulLists = qs$('#lists'); @@ -192,14 +189,14 @@ function renderFilterLists(soft = false) { dom.cl.toggle(dom.body, 'hideUnused', mustHideUnusedLists('*')); for ( const [ groupKey, groupRulesets ] of groups ) { - let liGroup = liFromListGroup(groupKey, groupRulesets); - liGroup.setAttribute('data-groupkey', groupKey); + const liGroup = liFromListGroup(groupKey, groupRulesets); + dom.attr(liGroup, 'data-groupkey', groupKey); if ( liGroup.parentElement === null ) { ulLists.appendChild(liGroup); } } - dom.remove(qsa$('#lists .listEntries .listEntry.discard')); + dom.remove('#lists .listEntries .listEntry.discard'); renderWidgets(); } @@ -220,15 +217,16 @@ const renderWidgets = function() { let filterCount = 0; let ruleCount = 0; for ( const liEntry of qsa$('#lists .listEntry[data-listkey]') ) { - if ( qs$('input[type="checkbox"]:checked', liEntry) === null ) { continue; } + if ( qs$(liEntry, 'input[type="checkbox"]:checked') === null ) { continue; } const stats = rulesetStats(liEntry.dataset.listkey); if ( stats === undefined ) { continue; } ruleCount += stats.ruleCount; filterCount += stats.filterCount; } - qs$('#listsOfBlockedHostsPrompt').textContent = i18n$('perRulesetStats') + dom.text('#listsOfBlockedHostsPrompt', i18n$('perRulesetStats') .replace('{{ruleCount}}', ruleCount.toLocaleString()) - .replace('{{filterCount}}', filterCount.toLocaleString()); + .replace('{{filterCount}}', filterCount.toLocaleString()) + ); }; /******************************************************************************/ @@ -267,7 +265,7 @@ async function onFilteringModeChange(ev) { } dom.on( - qs$('#defaultFilteringMode'), + '#defaultFilteringMode', 'change', '.filteringModeCard input[type="radio"]', ev => { onFilteringModeChange(ev); } @@ -275,7 +273,7 @@ dom.on( /******************************************************************************/ -dom.on(qs$('#autoReload input[type="checkbox"'), 'change', ev => { +dom.on('#autoReload input[type="checkbox"', 'change', ev => { sendMessage({ what: 'setAutoReload', state: ev.target.checked, @@ -287,7 +285,7 @@ dom.on(qs$('#autoReload input[type="checkbox"'), 'change', ev => { async function applyEnabledRulesets() { const enabledRulesets = []; for ( const liEntry of qsa$('#lists .listEntry[data-listkey]') ) { - if ( qs$('input[type="checkbox"]:checked', liEntry) === null ) { continue; } + if ( qs$(liEntry, 'input[type="checkbox"]:checked') === null ) { continue; } enabledRulesets.push(liEntry.dataset.listkey); } @@ -299,7 +297,7 @@ async function applyEnabledRulesets() { renderWidgets(); } -dom.on(qs$('#lists'), 'change', '.listEntry input[type="checkbox"]', ( ) => { +dom.on('#lists', 'change', '.listEntry input[type="checkbox"]', ( ) => { applyEnabledRulesets(); }); @@ -324,8 +322,8 @@ function toggleHideUnusedLists(which) { if ( mustHide ) { hideUnusedSet.add(which); } - document.body.classList.toggle('hideUnused', mustHide); - dom.cl.toggle(qsa$('.groupEntry[data-groupkey]'), 'hideUnused', mustHide); + dom.cl.toggle(dom.body, 'hideUnused', mustHide); + dom.cl.toggle('.groupEntry[data-groupkey]', 'hideUnused', mustHide); } else { const doesHide = hideUnusedSet.has(which); if ( doesHide ) { @@ -335,7 +333,7 @@ function toggleHideUnusedLists(which) { } mustHide = doesHide === doesHideAll; groupSelector = `.groupEntry[data-groupkey="${which}"]`; - dom.cl.toggle(qsa$(groupSelector), 'hideUnused', mustHide); + dom.cl.toggle(groupSelector, 'hideUnused', mustHide); } for ( const elem of qsa$(`#lists ${groupSelector} .listEntry[data-listkey] input[type="checkbox"]:not(:checked)`) ) { @@ -352,16 +350,11 @@ function toggleHideUnusedLists(which) { ); } -dom.on( - qs$('#lists'), - 'click', - '.groupEntry[data-groupkey] > .geDetails', - ev => { - toggleHideUnusedLists( - dom.attr(ev.target.closest('[data-groupkey]'), 'data-groupkey') - ); - } -); +dom.on('#lists', 'click', '.groupEntry[data-groupkey] > .geDetails', ev => { + toggleHideUnusedLists( + dom.attr(ev.target.closest('[data-groupkey]'), 'data-groupkey') + ); +}); // Initialize from saved state. simpleStorage.getItem('hideUnusedFilterLists').then(value => { diff --git a/src/css/shortcuts.css b/platform/mv3/extension/js/theme.js similarity index 50% rename from src/css/shortcuts.css rename to platform/mv3/extension/js/theme.js index 735d87411..48755382e 100644 --- a/src/css/shortcuts.css +++ b/platform/mv3/extension/js/theme.js @@ -1,6 +1,7 @@ -/** +/******************************************************************************* + uBlock Origin - a browser extension to block requests. - Copyright (C) 2018-present Raymond Hill + Copyright (C) 2014-present Raymond Hill This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,38 +19,17 @@ Home: https://github.com/gorhill/uBlock */ -.commandEntries { - margin: 2em; - } +/* jshint esversion:11 */ -.commandEntries td { - padding: 0.5em 0.25em; - } +'use strict'; -.commandEntries td.commandDesc { - text-align: end; - } +import { dom } from './dom.js'; -.commandEntries td.commandShortcut { - white-space: nowrap; - } +/******************************************************************************/ -.commandEntries td.commandShortcut input { - padding: 0.4em; - } - -.commandEntries td.commandShortcut input:focus { - outline: 2px solid blue; - } - -.commandEntries td.commandShortcut input ~ .commandReset { - cursor: pointer; - font-size: 150%; - padding: 0 0.2em; - vertical-align: middle; - } - -.commandEntries td.commandShortcut input:placeholder-shown ~ .commandReset, -.commandEntries td.commandShortcut input:focus ~ .commandReset { - display: none; - } +const mql = self.matchMedia('(prefers-color-scheme: dark)'); +const theme = mql instanceof Object && mql.matches === true + ? 'dark' + : 'light'; +dom.cl.toggle(dom.html, 'dark', theme === 'dark'); +dom.cl.toggle(dom.html, 'light', theme !== 'dark'); diff --git a/platform/mv3/extension/popup.html b/platform/mv3/extension/popup.html index 6af293570..77937a74d 100644 --- a/platform/mv3/extension/popup.html +++ b/platform/mv3/extension/popup.html @@ -51,6 +51,7 @@