This script can be used to maintain a addon-local copy of the browser tabs' state primarily to avoid performing browser.tabs.query
, browser.tabs.get
, and browser.sessions.getTabValue
function calls.
The script hasn't been tested on chrome.
Depends on js-syncqueue
(see Queue).
Required manifest permissions: tabs
, sessions
.
The tabs.Tab
objects that are returned from the cache methods, or passed to the cache event handlers must not be mutated.
Creating the cache: let cache = newCache(myConfig);
Initializing the cache: await cache.init(myInitFunction);
async function myOnCreatedHandler(tab) { /* */ }
async function myInitFunction(cache) { /* initialize addon state by querying the cache */ }
async function init() {
let myListeners = { onCreated: myOnCreatedHandler };
let myConfig = {
listeners: myListeners,
auto: true,
tabValueKeys: ['foo', 'bar'],
};
let cache = newCache(myConfig);
await cache.init(myInitFunction);
}
init();
The listeners
object may contain function callbacks for any combination of the following keys: onActivated
, onAttached
, onCreated
, onMoved
, onRemoved
, and onUpdated
, corresponding to browser.tabs
events. The values are registered as cache event handlers (see Cache Event Handlers). Instead of passing the callbacks in this object the listeners could be added later, e.g. in myInitFunction
.
auto
is a boolean which can be used to avoid manually adding the required browser event listeners. If true
, it will also create the required queue
object (see Queue). This may be set as false
if some browser events are not desired to be listened to, but hooking the cache listeners must be done manually.
queue
is required only when configuration doesn't have auto: true
. The value is the js-syncqueue
object used for processing asynchronous browser events in a synchronous manner.
tabValueKeys
is an array of keys (strings) used for the sessions
api tabValue functions. Values for keys defined in the array are fetched and stored by the cache. This prefetching occurs when initializing the cache itself and in the cache onCreated handler. The fetched values are guaranteed to be available in the cache for myInitFunction
and onCreated
cache event handler functions.
The cache object has onActivated
, onAttached
, onCreated
, onMoved
, onRemoved
, and onUpdated
keys which provide a similar interface as the corresponding browser.tabs
events. Each key supports the following:
addListener(myListenerFunction)
: the function passed as a parameter will be invoked by the cache as described in the Cache Event Handlers section.removeListener(myListenerFunction)
: removes the specified function from the list of functions invoked when the event is fired.hasListener(myListenerFunction)
: returnstrue
if the parameter is currently registered as a listener of the event,false
otherwise.
The cache event handlers are the functions passed to the cache in the listeners
object, and any function that was added as a listener for one of the cache events. They will be invoked after the cache state has been updated following a browser event. They may be asynchronous and will be awaited on before the cache continues processing further browser events.
onActivated
will be invoked with argumentstabs.Tab
,activeInfo
.onAttached
will be invoked with argumentstabs.Tab
,attachInfo
. There will not be a correspondingonDetached
event. Instead, theattachInfo
contains the values of thedetachInfo
and the cache will immediately reflect the browser state after theonDetached
event. In addition, the cache will re-submit any cached tabValues before invoking the cache event handlers.onCreated
will be invoked with the argumenttabs.Tab
. Any values (if defined) for keys intabValueKeys
will be available in the cache before the cache event handlers are invoked. If prefetching one of the values fails the cache will not invoke any events related to the tab, as the tab will have been closed.onMoved
will be invoked with the argumentstabs.Tab
,moveInfo
.onRemoved
will be invoked with argumentstabs.Tab
,removeInfo
,values
.values
is an object consisting of the key-value pairs which were present in the cache when the tab was removed. The values may not correspond to the actual values stored by the browser, for example, when the cache values were updated after a tab was removed.onUpdated
will be invoked with argumentstabs.Tab
,updateProperties
.
cache.setValue(tabId, key, value)
will store a tabValue in the cache. If the argument value doesn't match the currently cached value thenbrowser.sessions
tabValue will be updated.cache.getValue(tabId, key)
returns the cached tabValue. If the cache was configured withtabValueKeys
any keys for which there is a defined value will be available in the cache, otherwise the value must be stored manually with thesetValue
function.cache.removeValue(tabId, key)
removes a value from the cache andbrowser.sessions
.
cache.get(tabId)
returns the correspondingtabs.Tab
object in the cache.cache.getIndexed(windowId, index)
returns the correspondingtabs.Tab
object in the cache.cache.getActive(windowId)
returns thetabs.Tab
of the active tab in the window.
cache.forEach(callback, windowId, filter)
(asynchronous) will invokecallback
for every cached tab, passing thetabs.Tab
object as the only argument. IfwindowId
is defined, only tabs in the specified window are iterated. If defined,filter
will be invoked for every iterated tab with thetabs.Tab
as the only argument. Iffilter
returns a value that coerces tofalse
thecallback
will not be invoked for that tab.callback
may be asynchronous, and will be awaited on as a group.cache.forEachWindow(callback)
(asynchronous) will invokecallback
for every cached window, passing thewindowId
value as the only argument.callback
may be asynchronous, and will be awaited on as a group.
cache.init(myInitFunction)
(asynchronous) causes the cache to initialize, querying for the current tab data from the browser, updating its internal state, invokingmyInitFunction
function with the cache itself as the parameter, and finally beginning to process browser events.myInitFunction
is optional, may be asynchronous, and will be awaited on.cache.debug()
returns an object containing the internal variables in the cache.
- The cache event handlers for
tabs.onUpdated
will not be invoked before thetabs.onCreated
event for a given tab. - The
index
andwindowId
oftabs.Tab
passed toonUpdated
cache event handler may differ from the values passed by the browser to the cache'stabs.onUpdated
event callback, particularly when tabs are moved from one window to another. These values will always be coherent to the cache itself.
Internally the script maintains a js-syncqueue
object to queue pending browser events while its internal state is updating and the cache event handlers are being awaited on. This also guarantees all browser events are handled, even the ones occurring during cache initialization.
src.js
of js-syncqueue
must be in scope when using auto:true
.
Accessing the queue when using auto: true
can be done via let cacheQueue = cache.debug().queue
as soon as the cache has been created (not necessarily initialized).
Some event listeners must be hooked for the cache to function correctly, as below
let myQueue = newSyncQueue({ enabled: false });
let cache = newCache({ queue: myQueue });
/* mandatory listeners */
browser.tabs.onActivated.addListener(info => myQueue.do(cache.cacheOnActivated, info));
browser.tabs.onAttached.addListener((id, info) => myQueue.do(cache.cacheOnAttached, id, info));
browser.tabs.onCreated.addListener(tab => myQueue.do(cache.cacheOnCreated, tab));
browser.tabs.onMoved.addListener((id, info) => myQueue.do(cache.cacheOnMoved, id, info));
browser.tabs.onRemoved.addListener((id, info) => myQueue.do(cache.cacheOnRemoved, id, info));
/* optional listeners */
browser.tabs.onUpdated.addListener((id, info, tab) => myQueue.do(cache.cacheOnUpdated, id, info, tab));
/* initialize cache and start processing events */
await cache.init(myInitFunction);
myQueue.enable()