mirror of https://github.com/gorhill/uBlock.git
Centralize access to browser.storage.local('localStorage')
Related commit:
- 2ac288397c
Instead of having the `localStorage` data being accessed
from different locations, all accesses are now funnelled
to the main process.
Doing so simplifies the code in auxiliary processes and
also remove the need for browser.storage.local.onChanged()
listeners.
No longer using an onChanged() listener also happens to
remove spurious warnings from the Firefox console.
This commit is contained in:
parent
572750584c
commit
0bcf04d3dd
|
@ -943,6 +943,7 @@ vAPI.messaging = {
|
|||
onFrameworkMessage: function(request, port, callback) {
|
||||
const sender = port && port.sender;
|
||||
if ( !sender ) { return; }
|
||||
const fromDetails = this.ports.get(port.name) || {};
|
||||
const tabId = sender.tab && sender.tab.id || undefined;
|
||||
const msg = request.msg;
|
||||
switch ( msg.what ) {
|
||||
|
@ -981,12 +982,21 @@ vAPI.messaging = {
|
|||
break;
|
||||
}
|
||||
case 'extendClient':
|
||||
if ( fromDetails.privileged !== true ) { break; }
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
file: '/js/vapi-client-extra.js',
|
||||
}).then(( ) => {
|
||||
callback();
|
||||
});
|
||||
break;
|
||||
case 'localStorage': {
|
||||
if ( fromDetails.privileged !== true ) { break; }
|
||||
const args = msg.args || [];
|
||||
vAPI.localStorage[msg.fn](...args).then(result => {
|
||||
callback(result);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'userCSS':
|
||||
if ( tabId === undefined ) { break; }
|
||||
const details = {
|
||||
|
@ -1401,6 +1411,78 @@ vAPI.adminStorage = (( ) => {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// A localStorage-like object which should be accessible from the
|
||||
// background page or auxiliary pages.
|
||||
//
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/899
|
||||
// Convert into asynchronous access API.
|
||||
//
|
||||
// Note: vAPI.localStorage should already be defined with the client-side
|
||||
// implementation at this point, but we override with the
|
||||
// background-side implementation.
|
||||
vAPI.localStorage = {
|
||||
start: async function() {
|
||||
if ( this.cache instanceof Promise ) { return this.cache; }
|
||||
if ( this.cache instanceof Object ) { return this.cache; }
|
||||
this.cache = webext.storage.local.get('localStorage').then(bin => {
|
||||
this.cache = undefined;
|
||||
try {
|
||||
if (
|
||||
bin instanceof Object === false ||
|
||||
bin.localStorage instanceof Object === false
|
||||
) {
|
||||
this.cache = {};
|
||||
const ls = self.localStorage;
|
||||
for ( let i = 0; i < ls.length; i++ ) {
|
||||
const key = ls.key(i);
|
||||
this.cache[key] = ls.getItem(key);
|
||||
}
|
||||
webext.storage.local.set({ localStorage: this.cache });
|
||||
} else {
|
||||
this.cache = bin.localStorage;
|
||||
}
|
||||
} catch(ex) {
|
||||
}
|
||||
if ( this.cache instanceof Object === false ) {
|
||||
this.cache = {};
|
||||
}
|
||||
});
|
||||
return this.cache;
|
||||
},
|
||||
clear: function() {
|
||||
this.cache = {};
|
||||
return webext.storage.local.set({ localStorage: this.cache });
|
||||
},
|
||||
getItem: function(key) {
|
||||
if ( this.cache instanceof Object === false ) {
|
||||
console.info(`localStorage.getItem('${key}') not ready`);
|
||||
return null;
|
||||
}
|
||||
const value = this.cache[key];
|
||||
return value !== undefined ? value : null;
|
||||
},
|
||||
getItemAsync: async function(key) {
|
||||
await this.start();
|
||||
const value = this.cache[key];
|
||||
return value !== undefined ? value : null;
|
||||
},
|
||||
removeItem: async function(key) {
|
||||
this.setItem(key);
|
||||
},
|
||||
setItem: async function(key, value = undefined) {
|
||||
await this.start();
|
||||
if ( value === this.cache[key] ) { return; }
|
||||
this.cache[key] = value;
|
||||
return webext.storage.local.set({ localStorage: this.cache });
|
||||
},
|
||||
cache: undefined,
|
||||
};
|
||||
|
||||
vAPI.localStorage.start();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/sync
|
||||
|
||||
vAPI.cloud = (( ) => {
|
||||
|
|
|
@ -216,98 +216,41 @@ vAPI.closePopup = function() {
|
|||
|
||||
// A localStorage-like object which should be accessible from the
|
||||
// background page or auxiliary pages.
|
||||
// This storage is optional, but it is nice to have, for a more polished user
|
||||
// experience.
|
||||
//
|
||||
// https://github.com/gorhill/uBlock/issues/2824
|
||||
// Use a dummy localStorage if for some reasons it's not available.
|
||||
//
|
||||
// https://github.com/gorhill/uMatrix/issues/840
|
||||
// Always use a wrapper to seamlessly handle exceptions
|
||||
//
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/899
|
||||
// Convert into asynchronous access API.
|
||||
|
||||
vAPI.localStorage = {
|
||||
start: function() {
|
||||
if ( this.cache instanceof Promise ) { return this.cache; }
|
||||
if ( this.cache instanceof Object ) { return Promise.resolve(); }
|
||||
const onChanged = (changes, area) => {
|
||||
if (
|
||||
area !== 'local' ||
|
||||
changes instanceof Object === false ||
|
||||
changes.localStorage instanceof Object === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const newValue = changes.localStorage.newValue;
|
||||
this.cache = newValue instanceof Object ? newValue : {};
|
||||
};
|
||||
this.cache = new Promise(resolve => {
|
||||
browser.storage.local.get('localStorage', bin => {
|
||||
this.cache = undefined;
|
||||
try {
|
||||
if (
|
||||
bin instanceof Object === false ||
|
||||
bin.localStorage instanceof Object === false
|
||||
) {
|
||||
this.cache = {};
|
||||
const ls = self.localStorage;
|
||||
for ( let i = 0; i < ls.length; i++ ) {
|
||||
const key = ls.key(i);
|
||||
this.cache[key] = ls.getItem(key);
|
||||
}
|
||||
browser.storage.local.set({ localStorage: this.cache });
|
||||
} else {
|
||||
this.cache = bin.localStorage;
|
||||
}
|
||||
} catch(ex) {
|
||||
}
|
||||
if ( this.cache instanceof Object === false ) {
|
||||
this.cache = {};
|
||||
}
|
||||
resolve();
|
||||
browser.storage.onChanged.addListener(onChanged);
|
||||
self.addEventListener('beforeunload', ( ) => {
|
||||
this.cache = undefined;
|
||||
browser.storage.onChanged.removeListener(onChanged);
|
||||
});
|
||||
});
|
||||
});
|
||||
return this.cache;
|
||||
},
|
||||
clear: function() {
|
||||
this.cache = {};
|
||||
return browser.storage.local.set({ localStorage: this.cache });
|
||||
},
|
||||
getItem: function(key) {
|
||||
if ( this.cache instanceof Object === false ) {
|
||||
console.info(`localStorage.getItem('${key}') not ready`);
|
||||
return null;
|
||||
}
|
||||
const value = this.cache[key];
|
||||
return value !== undefined ? value : null;
|
||||
vAPI.messaging.send('vapi', {
|
||||
what: 'localStorage',
|
||||
fn: 'clear',
|
||||
});
|
||||
},
|
||||
getItemAsync: function(key) {
|
||||
return this.start().then(( ) => {
|
||||
const value = this.cache[key];
|
||||
return value !== undefined ? value : null;
|
||||
return vAPI.messaging.send('vapi', {
|
||||
what: 'localStorage',
|
||||
fn: 'getItemAsync',
|
||||
args: [ key ],
|
||||
});
|
||||
},
|
||||
removeItem: function(key) {
|
||||
this.setItem(key);
|
||||
},
|
||||
setItem: function(key, value = undefined) {
|
||||
return this.start().then(( ) => {
|
||||
if ( value === this.cache[key] ) { return; }
|
||||
this.cache[key] = value;
|
||||
return browser.storage.local.set({ localStorage: this.cache });
|
||||
return vAPI.messaging.send('vapi', {
|
||||
what: 'localStorage',
|
||||
fn: 'removeItem',
|
||||
args: [ key ],
|
||||
});
|
||||
},
|
||||
setItem: function(key, value = undefined) {
|
||||
return vAPI.messaging.send('vapi', {
|
||||
what: 'localStorage',
|
||||
fn: 'setItem',
|
||||
args: [ key, value ]
|
||||
});
|
||||
},
|
||||
cache: undefined,
|
||||
};
|
||||
|
||||
vAPI.localStorage.start();
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -202,21 +202,29 @@ uDom('#userFiltersRevert').on('click', revertChanges);
|
|||
// https://github.com/gorhill/uBlock/issues/3706
|
||||
// Save/restore cursor position
|
||||
//
|
||||
// CoreMirror reference: https://codemirror.net/doc/manual.html#api_selection
|
||||
renderUserFilters().then(( ) => {
|
||||
// CodeMirror reference: https://codemirror.net/doc/manual.html#api_selection
|
||||
{
|
||||
let curline = 0;
|
||||
let timer;
|
||||
|
||||
renderUserFilters().then(( ) => {
|
||||
cmEditor.clearHistory();
|
||||
return vAPI.localStorage.getItemAsync('myFiltersCursorPosition');
|
||||
}).then(line => {
|
||||
}).then(line => {
|
||||
if ( typeof line === 'number' ) {
|
||||
cmEditor.setCursor(line, 0);
|
||||
}
|
||||
cmEditor.on('cursorActivity', ( ) => {
|
||||
const line = cmEditor.getCursor().line;
|
||||
if ( vAPI.localStorage.getItem('myFiltersCursorPosition') !== line ) {
|
||||
vAPI.localStorage.setItem('myFiltersCursorPosition', line);
|
||||
}
|
||||
if ( timer !== undefined ) { return; }
|
||||
if ( cmEditor.getCursor().line === curline ) { return; }
|
||||
timer = vAPI.setTimeout(( ) => {
|
||||
timer = undefined;
|
||||
curline = cmEditor.getCursor().line;
|
||||
vAPI.localStorage.setItem('myFiltersCursorPosition', curline);
|
||||
}, 701);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
cmEditor.on('changes', userFiltersChanged);
|
||||
CodeMirror.commands.save = applyChanges;
|
||||
|
|
Loading…
Reference in New Issue