[mv3] Add spinner as visual feedback rulesets are being registered

Additionally, fixed a race condition where changes to rulesets would
not be ultimately registered when the changes were made during an
ongoing registration operation. This race condition would be
especially likely to occur on platforms where rulesets registration
take long.
This commit is contained in:
Raymond Hill 2025-08-07 08:56:17 -04:00
parent 31795fb6e6
commit b6829698cc
No known key found for this signature in database
GPG key ID: 25E1490B761470C2
4 changed files with 48 additions and 35 deletions

View file

@ -1,5 +1,10 @@
nav {
header {
background-color: var(--surface-1);
position: sticky;
top: 0;
z-index: 100;
}
nav {
border: 0;
border-bottom: 1px solid var(--border-1);
display: flex;
@ -7,9 +12,6 @@ nav {
flex-wrap: wrap;
overflow-x: hidden;
padding: 0;
position: sticky;
top: 0;
z-index: 100;
}
nav > .tabButton {
background-color: transparent;
@ -44,6 +46,9 @@ body[data-pane="about"] #dashboard-nav .tabButton[data-pane="about"] {
body:not([data-develop="true"]) #dashboard-nav .tabButton[data-pane="develop"] {
display: none;
}
body:not([data-pane="rulesets"]) header [data-pane-related="rulesets"] {
display: none;
}
body > section {
display: none;

View file

@ -1,3 +1,8 @@
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
:root {
--filtering-mode-button-size: 32px;
}
@ -80,20 +85,12 @@ label:has(input[type="checkbox"][disabled]) + legend {
h3[data-i18n="filteringMode0Name"]::first-letter {
text-transform: capitalize;
}
#trustedSites {
background-color: var(--surface-0);
border: 1px solid var(--surface-3);
font-size: var(--monospace-size);
min-height: 8rem;
}
section[data-pane="rulesets"] > div:first-of-type {
background-color: var(--surface-1);
flex-shrink: 0;
padding: 1em 0;
position: sticky;
top: 0;
z-index: 10;
body:not(.committing) #commit-spinner {
display: none;
}
body.committing #commit-spinner {
animation: spin 1s steps(8) infinite;
}
section[data-pane="rulesets"] > div:first-of-type > p:first-of-type {
margin-top: 0;

View file

@ -20,13 +20,20 @@
<body data-pane="settings" class="loading">
<!-- -------- -->
<nav id="dashboard-nav">
<span class="logo"><img data-i18n-title="extName" src="img/ublock.svg" alt="uBO Lite"></span><!--
--><button class="tabButton" type="button" data-pane="settings" data-i18n="settingsPageName" tabindex="0"></button><!--
--><button class="tabButton" type="button" data-pane="rulesets" data-i18n="aboutFilterLists" tabindex="0"></button><!--
--><button class="tabButton" type="button" data-pane="develop" data-i18n="developPageName"tabindex="0"></button><!--
--><button class="tabButton" type="button" data-pane="about" data-i18n="aboutPageName" tabindex="0"></button>
</nav>
<header>
<nav id="dashboard-nav">
<span class="logo"><img data-i18n-title="extName" src="img/ublock.svg" alt="uBO Lite"></span><!--
--><button class="tabButton" type="button" data-pane="settings" data-i18n="settingsPageName" tabindex="0"></button><!--
--><button class="tabButton" type="button" data-pane="rulesets" data-i18n="aboutFilterLists" tabindex="0"></button><!--
--><button class="tabButton" type="button" data-pane="develop" data-i18n="developPageName"tabindex="0"></button><!--
--><button class="tabButton" type="button" data-pane="about" data-i18n="aboutPageName" tabindex="0"></button>
</nav>
<!-- -------- -->
<div data-pane-related="rulesets">
<p><span id="listsOfBlockedHostsPrompt"></span> <span id="commit-spinner" class="fa-icon">spinner</span></p>
<p><input id="findInLists" type="search" spellcheck="false" placeholder="findListsPlaceholder" /></p>
</div>
</header>
<!-- -------- -->
<section data-pane="settings">
<div>
@ -92,10 +99,6 @@
</section>
<!-- -------- -->
<section data-pane="rulesets">
<div>
<p id="listsOfBlockedHostsPrompt"></p>
<p><input id="findInLists" type="search" spellcheck="false" placeholder="findListsPlaceholder" /></p>
</div>
<div id="lists"></div>
</section>
<!-- -------- -->

View file

@ -397,6 +397,8 @@ dom.on('#findInLists', 'input', searchFilterLists);
const applyEnabledRulesets = (( ) => {
const apply = async ( ) => {
dom.cl.add(dom.body, 'committing');
const enabledRulesets = [];
for ( const liEntry of qsa$('#lists .listEntry[data-role="leaf"][data-rulesetid]') ) {
const checked = qs$(liEntry, 'input[type="checkbox"]:checked') !== null;
@ -408,14 +410,16 @@ const applyEnabledRulesets = (( ) => {
dom.cl.remove('#lists .listEntry.toggled', 'toggled');
const unmodified = hashFromIterable(enabledRulesets) ===
const modified = hashFromIterable(enabledRulesets) !==
hashFromIterable(cachedRulesetData.enabledRulesets);
if ( unmodified ) { return; }
if ( modified ) {
await sendMessage({
what: 'applyRulesets',
enabledRulesets,
});
}
await sendMessage({
what: 'applyRulesets',
enabledRulesets,
});
dom.cl.remove(dom.body, 'committing');
};
let timer;
@ -433,7 +437,11 @@ const applyEnabledRulesets = (( ) => {
}
timer = self.setTimeout(( ) => {
timer = undefined;
apply();
if ( dom.cl.has(dom.body, 'committing') ) {
applyEnabledRulesets();
} else {
apply();
}
}, 997);
}
})();