summaryrefslogtreecommitdiff
path: root/src/lib/LastListener.js
diff options
context:
space:
mode:
authorhackademix2018-08-06 15:59:47 +0200
committerhackademix2018-08-07 09:53:01 +0200
commit8caa2536bda8ad8c19d79327331145a254fb08de (patch)
tree345a0b2c4c9dcf657690dd0f0d11e67ff9ac370d /src/lib/LastListener.js
parent2250d51aa44353409864511382e44e39b7468df9 (diff)
downloadnoscript-8caa2536bda8ad8c19d79327331145a254fb08de.tar.gz
noscript-8caa2536bda8ad8c19d79327331145a254fb08de.tar.xz
noscript-8caa2536bda8ad8c19d79327331145a254fb08de.zip
Best effort to run webRequest.onHeaderReceived listener last (issue #6)
Diffstat (limited to 'src/lib/LastListener.js')
-rw-r--r--src/lib/LastListener.js50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/lib/LastListener.js b/src/lib/LastListener.js
new file mode 100644
index 0000000..51600eb
--- /dev/null
+++ b/src/lib/LastListener.js
@@ -0,0 +1,50 @@
+/**
+* Wrapper around listeners on various WebExtensions
+* APIs (e.g. webRequest.on*), as a best effort to
+* let them run last by removing and re-adding them
+* on each call (swapping 2 copies because
+* addListener() calls are asynchronous).
+* Note: we rely on implementation details Like
+* listeners being called in addition order; also,
+* clients should ensure they're not called twice for
+* the same event, if that's important.
+}
+*/
+
+class LastListener {
+ constructor(observed, listener, ...extras) {
+ this.observed = observed;
+ this.listener = listener;
+ this.extras = extras;
+ let ww = this._wrapped = [listener, listener].map(l => {
+ let w = (...args) => {
+ if (this.observed.hasListener(w._other)) {
+ this.observed.removeListener(w._other);
+ if (this.last === w) return this.defaultResult;
+ } else if (this.installed) {
+ this.observed.addListener(w._other, ...this.extras);
+ this.last = w._other;
+ }
+ return this.installed ? this.listener(...args)
+ : this.defaultResult;
+ }
+ return w;
+ });
+
+ ww[0]._other = ww[1];
+ ww[1]._other = ww[0];
+ this.installed = false;
+ this.defaultResult = null;
+ }
+
+ install() {
+ if (this.installed) return;
+ this.observed.addListener(this._wrapped[0], ...this.extras);
+ this.installed = true;
+ }
+
+ uninstall() {
+ this.installed = false;
+ for (let l of this._wrapped) this.observed.removeListener(l);
+ }
+}