From a2c93c2663d4f61b3c88d39f27fa492aca999455 Mon Sep 17 00:00:00 2001 From: hackademix Date: Thu, 13 Sep 2018 00:23:24 +0200 Subject: Support for batch async list operations. --- bg/ListManager.js | 35 ++++++++++++++++--------------- bg/Storage.js | 62 +++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git a/bg/ListManager.js b/bg/ListManager.js index 34d9531..7284aca 100644 --- a/bg/ListManager.js +++ b/bg/ListManager.js @@ -30,20 +30,21 @@ class ListManager { this.lists = {whitelist, blacklist}; this.builtInHashes = new Set(builtInHashes); } - async whitelist(key) { - await this.lists.blacklist.remove(key); - await this.lists.whitelist.store(key); + + static async move(fromList, toList, ...keys) { + await Promise.all([fromList.remove(...keys), toList.store(...keys)]); } - async blacklist(key) { - await this.lists.whitelist.remove(key); - await this.lists.blacklist.store(key); + + async whitelist(...keys) { + ListManager.move(this.lists.blacklist, this.lists.whitelist, ...keys); } - async forget(key) { - for (let list of Object.values(this.lists)) { - await list.remove(key); - } + async blacklist(...keys) { + ListManager.move(this.lists.whitelist, this.lists.blacklist, ...keys); } - /* key is a string representing either a URL or an optional path + async forget(...keys) { + await Promise.all(Object.values(this.lists).map(l => l.remove(...keys))); + } + /* key is a string representing either a URL or an optional path with a trailing (hash). Returns "blacklisted", "whitelisted" or defValue */ @@ -53,16 +54,16 @@ class ListManager { if (!match) { let url = ListStore.urlItem(key); let site = ListStore.siteItem(key); - return (blacklist.contains(url) || blacklist.contains(site)) + return (blacklist.contains(url) || blacklist.contains(site)) ? "blacklisted" - : whitelist.contains(url) || whitelist.contains(site) - ? "whitelisted" : defValue; + : whitelist.contains(url) || whitelist.contains(site) + ? "whitelisted" : defValue; } - + let [hashItem, srcHash] = match; // (hash), hash - + return blacklist.contains(hashItem) ? "blacklisted" - : this.builtInHashes.has(srcHash) || whitelist.contains(hashItem) + : this.builtInHashes.has(srcHash) || whitelist.contains(hashItem) ? "whitelisted" : defValue; } diff --git a/bg/Storage.js b/bg/Storage.js index ecdc9e4..a83ce8f 100644 --- a/bg/Storage.js +++ b/bg/Storage.js @@ -23,11 +23,14 @@ A tiny wrapper around extensions storage API, supporting CSV serialization for retro-compatibility */ +"use strict"; var Storage = { ARRAY: { - async load(key) { - let array = (await browser.storage.local.get(key))[key]; + async load(key, array = undefined) { + if (array === undefined) { + array = (await browser.storage.local.get(key))[key]; + } return array ? new Set(array) : new Set(); }, async save(key, list) { @@ -40,7 +43,7 @@ var Storage = { let csv = (await browser.storage.local.get(key))[key]; return csv ? new Set(csv.split(/\s*,\s*/)) : new Set(); }, - + async save(key, list) { return await browser.storage.local.set({[key]: [...list].join(",")}); } @@ -56,8 +59,13 @@ class ListStore { this.key = key; this.storage = storage; this.items = new Set(); + browser.storage.onChanged.addListener(changes => { + if (!this.saving && this.key in changes) { + this.load(changes[this.key].newValue); + } + }); } - + static hashItem(hash) { return hash.startsWith("(") ? hash : `(${hash})`; } @@ -73,32 +81,50 @@ class ListStore { return `${url}/*`; } } - + async save() { - return await this.storage.save(this.key, this.items); + this._saving = true; + try { + return await this.storage.save(this.key, this.items); + } finally { + this._saving = false; + } } - - async load() { + + async load(values = undefined) { try { - this.items = await this.storage.load(this.key); + this.items = await this.storage.load(this.key, values); } catch (e) { console.error(e); } return this.items; } - - async store(item) { + + async store(...items) { let size = this.items.size; - return (size !== this.items.add(item).size) && await this.save(); + let changed = false; + for (let item of items) { + if (size !== this.items.add(item).size) { + changed = true; + } + } + return changed && await this.save(); } - - async remove(item) { - return this.items.delete(item) && await this.save(); + + async remove(...items) { + let changed = false; + for (let item of items) { + if (this.items.delete(item)) { + changed = true; + } + } + return changed && await this.save(); } - + contains(item) { return this.items.has(item); } } - -module.exports = { ListStore, Storage }; +if (typeof module === "object") { + module.exports = { ListStore, Storage }; +} -- cgit v1.2.3