aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/observable.js28
-rw-r--r--common/storage_light.js129
-rw-r--r--common/storage_raw.js11
3 files changed, 148 insertions, 20 deletions
diff --git a/common/observable.js b/common/observable.js
index 1fb0b0a..02f1c1b 100644
--- a/common/observable.js
+++ b/common/observable.js
@@ -6,28 +6,22 @@
* Redistribution terms are gathered in the `copyright' file.
*/
-function make()
-{
- return new Set();
-}
+const make = (value=undefined) => ({value, listeners: new Set()});
+const subscribe = (observable, cb) => observable.listeners.add(cb);
+const unsubscribe = (observable, cb) => observable.listeners.delete(cb);
-function subscribe(observable, cb)
-{
- observable.add(cb);
-}
-
-function unsubscribe(observable, cb)
-{
- observable.delete(cb);
-}
+const silent_set = (observable, value) => observable.value = value;
+const broadcast = (observable, ...values) =>
+ observable.listeners.forEach(cb => cb(...values));
-function broadcast(observable, event)
+function set(observable, value)
{
- for (const callback of observable)
- callback(event);
+ const old_value = observable.value;
+ silent_set(observable, value);
+ broadcast(observable, value, old_value);
}
-const observables = {make, subscribe, unsubscribe, broadcast};
+const observables = {make, subscribe, unsubscribe, broadcast, silent_set, set};
/*
* EXPORTS_START
diff --git a/common/storage_light.js b/common/storage_light.js
new file mode 100644
index 0000000..067bf0c
--- /dev/null
+++ b/common/storage_light.js
@@ -0,0 +1,129 @@
+/**
+ * part of Hachette
+ * Storage manager, lighter than the previous one.
+ *
+ * Copyright (C) 2021 Wojtek Kosior
+ * Redistribution terms are gathered in the `copyright' file.
+ */
+
+/*
+ * IMPORTS_START
+ * IMPORT TYPE_PREFIX
+ * IMPORT raw_storage
+ * IMPORT is_mozilla
+ * IMPORT observables
+ */
+
+const reg_spec = new Set(["\\", "[", "]", "(", ")", "{", "}", ".", "*", "+"]);
+const escape_reg_special = c => reg_spec.has(c) ? "\\" + c : c;
+
+function make_regex(name)
+{
+ return new RegExp(`^${name.split("").map(escape_reg_special).join("")}\$`);
+}
+
+const listeners_by_callback = new Map();
+
+function listen(callback, prefix, name)
+{
+ let by_prefix = listeners_by_callback.get(callback);
+ if (!by_prefix) {
+ by_prefix = new Map();
+ listeners_by_callback.set(callback, by_prefix);
+ }
+
+ let by_name = by_prefix.get(prefix);
+ if (!by_name) {
+ by_name = new Map();
+ by_prefix.set(prefix, by_name);
+ }
+
+ let name_reg = by_name.get(name);
+ if (!name_reg) {
+ name_reg = name.test ? name : make_regex(name);
+ by_name.set(name, name_reg);
+ }
+}
+
+function no_listen(callback, prefix, name)
+{
+ const by_prefix = listeners_by_callback.get(callback);
+ if (!by_prefix)
+ return;
+
+ const by_name = by_prefix.get(prefix);
+ if (!by_name)
+ return;
+
+ const name_reg = by_name.get(name);
+ if (!name_reg)
+ return;
+
+ by_name.delete(name);
+
+ if (by_name.size === 0)
+ by_prefix.delete(prefix);
+
+ if (by_prefix.size === 0)
+ listeners_by_callback.delete(callback);
+}
+
+function storage_change_callback(changes, area)
+{
+ if (is_mozilla && area !== "local")
+ {console.log("area", area);return;}
+
+ for (const item of Object.keys(changes)) {
+ for (const [callback, by_prefix] of listeners_by_callback.entries()) {
+ const by_name = by_prefix.get(item[0]);
+ if (!by_name)
+ continue;
+
+ for (const reg of by_name.values()) {
+ if (!reg.test(item.substring(1)))
+ continue;
+
+ try {
+ callback(item, changes[item]);
+ } catch(e) {
+ console.error(e);
+ }
+ }
+ }
+ }
+}
+
+raw_storage.listen(storage_change_callback);
+
+
+const created_observables = new Map();
+
+async function observe(prefix, name)
+{
+ const observable = observables.make();
+ const callback = (it, ch) => observables.set(observable, ch.newValue);
+ listen(callback, prefix, name);
+ created_observables.set(observable, [callback, prefix, name]);
+ observables.silent_set(observable, await raw_storage.get(prefix + name));
+
+ return observable;
+}
+
+const observe_var = name => observe(TYPE_PREFIX.VAR, name);
+
+function no_observe(observable)
+{
+ no_listen(...created_observables.get(observable) || []);
+ created_observables.delete(observable);
+}
+
+const light_storage = {};
+Object.assign(light_storage, raw_storage);
+Object.assign(light_storage,
+ {listen, no_listen, observe, observe_var, no_observe});
+
+/*
+ * EXPORTS_START
+ * EXPORT light_storage
+ * EXPORTS_END
+ */
diff --git a/common/storage_raw.js b/common/storage_raw.js
index 9ce3980..4c02ee4 100644
--- a/common/storage_raw.js
+++ b/common/storage_raw.js
@@ -26,8 +26,9 @@ async function get(key)
async function set(key_or_object, value)
{
- return browser.storage.local.set(typeof key_or_object === "object" ?
- key_or_object : {[key]: value});
+ const arg = typeof key_or_object === "object" ?
+ key_or_object : {[key_or_object]: value};
+ return browser.storage.local.set(arg);
}
async function set_var(name, value)
@@ -40,7 +41,11 @@ async function get_var(name)
return get(TYPE_PREFIX.VAR + name);
}
-const raw_storage = {get, set, get_var, set_var};
+const on_changed = browser.storage.onChanged || browser.storage.local.onChanged;
+const listen = cb => on_changed.addListener(cb);
+const no_listen = cb => on_changed.removeListener(cb);
+
+const raw_storage = {get, set, get_var, set_var, listen, no_listen};
/*
* EXPORTS_START