diff --git a/platform/mv3/extension/js/filter-manager.js b/platform/mv3/extension/js/filter-manager.js index 52839cc64..94a41b7b2 100644 --- a/platform/mv3/extension/js/filter-manager.js +++ b/platform/mv3/extension/js/filter-manager.js @@ -38,6 +38,10 @@ import { ubolErr } from './debug.js'; /******************************************************************************/ +const perSitePendingIO = new Map(); + +/******************************************************************************/ + export async function selectorsFromCustomFilters(hostname) { const promises = []; let hn = hostname; @@ -132,6 +136,9 @@ export async function injectCustomFilters(tabId, frameId, hostname) { /******************************************************************************/ export async function registerCustomFilters(context) { + if ( perSitePendingIO.size !== 0 ) { + await Promise.all(Array.from(perSitePendingIO.values())); + } const siteKeys = await getAllCustomFilterKeys(); if ( siteKeys.length === 0 ) { return; } @@ -168,6 +175,20 @@ export async function registerCustomFilters(context) { /******************************************************************************/ export async function addCustomFilter(hostname, selector) { + const pending = perSitePendingIO.get(hostname); + const promise = pending + ? pending.then(( ) => addCustomFilterByHostname(hostname, selector)) + : addCustomFilterByHostname(hostname, selector); + perSitePendingIO.set(hostname, promise); + promise.then(( ) => { + if ( promise !== perSitePendingIO.get(hostname) ) { return; } + perSitePendingIO.delete(hostname); + }); + return promise; +} + +async function addCustomFilterByHostname(hostname, selector) { + if ( hostname === '' ) { return false; } const key = `site.${hostname}`; const selectors = await localRead(key) || []; if ( selectors.includes(selector) ) { return false; } @@ -183,9 +204,7 @@ export async function removeCustomFilter(hostname, selector) { const promises = []; let hn = hostname; while ( hn !== '' ) { - promises.push( - removeCustomFilterByKey(`site.${hn}`, selector).catch(( ) => false) - ); + promises.push(removeCustomFilterByHostname(hn, selector)); const pos = hn.indexOf('.'); if ( pos === -1 ) { break; } hn = hn.slice(pos + 1); @@ -194,11 +213,28 @@ export async function removeCustomFilter(hostname, selector) { return results.some(a => a); } +async function removeCustomFilterByHostname(hostname, selector) { + const pending = perSitePendingIO.get(hostname); + const key = `site.${hostname}`; + const promise = pending + ? pending.then(( ) => removeCustomFilterByKey(key, selector)) + : removeCustomFilterByKey(key, selector); + perSitePendingIO.set(hostname, promise); + promise.then(( ) => { + if ( promise !== perSitePendingIO.get(hostname) ) { return; } + perSitePendingIO.delete(hostname); + }); + return promise; +} + async function removeCustomFilterByKey(key, selector) { const selectors = await localRead(key); if ( selectors === undefined ) { return false; } - const i = selectors.indexOf(selector); - if ( i === -1 ) { return false; } + let i = selectors.indexOf(selector); + if ( i === -1 ) { + i = selectors.indexOf(`0${selector}`); + if ( i === -1 ) { return false; } + } selectors.splice(i, 1); if ( selectors.length !== 0 ) { await localWrite(key, selectors);