1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-10-04 16:47:15 +02:00

Remove usage of synchronous localStorage API

Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/899

browser.storage.local is now used to store non-critical
local settings.

These settings are all collated under the key
`localStorage`, and vAPI.localStorage is an API to
handle access to these values stored under this key.

vAPI.localStorage.getItem() is still synchronous but
its purpose is to return internally cached values --
this minimizes code changes throughout uBO.
This commit is contained in:
Raymond Hill 2020-02-21 15:34:54 -05:00
parent 5da3aaaabf
commit 2ac288397c
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
9 changed files with 144 additions and 123 deletions

View File

@ -218,48 +218,92 @@ vAPI.closePopup = function() {
// 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 = {
started: false,
start: function() {
this.started = true;
if ( this.cache instanceof Object ) { return Promise.resolve(); }
if ( this.promise !== undefined ) { return this.promise; }
this.promise = new Promise(resolve => {
browser.storage.local.get('localStorage', bin => {
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);
}
//ls.clear();
browser.storage.local.set({ localStorage: this.cache });
} else {
try {
this.cache = bin.localStorage;
} catch(ex) {
}
}
if ( this.cache instanceof Object === false ) {
this.cache = {};
}
this.promise = undefined;
browser.storage.onChanged.addListener((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 : {};
});
resolve();
});
});
return this.promise;
},
clear: function() {
try {
window.localStorage.clear();
} catch(ex) {
}
this.cache = {};
return browser.storage.local.set({ localStorage: this.cache });
},
getItem: function(key) {
if ( this.started === false ) { return null; }
try {
return window.localStorage.getItem(key);
} catch(ex) {
if ( this.cache instanceof Object === false ) {
console.info(`localStorage.getItem('${key}') not ready`);
return null;
}
return null;
const value = this.cache[key];
return value !== undefined ? value : null;
},
getItemAsync: function(key) {
return this.start().then(( ) => {
const value = this.cache[key];
return value !== undefined ? value : null;
});
},
removeItem: function(key) {
try {
window.localStorage.removeItem(key);
} catch(ex) {
}
this.setItem(key);
},
setItem: function(key, value) {
if ( this.started === false ) { return; }
try {
window.localStorage.setItem(key, value);
} catch(ex) {
}
}
setItem: function(key, value = undefined) {
return this.start().then(( ) => {
this.cache[key] = value;
return browser.storage.local.set({ localStorage: this.cache });
});
},
promise: undefined,
cache: undefined,
};
vAPI.localStorage.start();

View File

@ -45,20 +45,6 @@ let cachedUserFilters = '';
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/3706
// Save/restore cursor position
//
// CoreMirror reference: https://codemirror.net/doc/manual.html#api_selection
window.addEventListener('beforeunload', ( ) => {
vAPI.localStorage.setItem(
'myFiltersCursorPosition',
JSON.stringify(cmEditor.getCursor().line)
);
});
/******************************************************************************/
// This is to give a visual hint that the content of user blacklist has changed.
const userFiltersChanged = function(changed) {
@ -71,7 +57,7 @@ const userFiltersChanged = function(changed) {
/******************************************************************************/
const renderUserFilters = async function(first) {
const renderUserFilters = async function() {
const details = await vAPI.messaging.send('dashboard', {
what: 'readUserFilters',
});
@ -83,18 +69,7 @@ const renderUserFilters = async function(first) {
content += '\n';
}
cmEditor.setValue(content);
if ( first ) {
cmEditor.clearHistory();
try {
const line = JSON.parse(
vAPI.localStorage.getItem('myFiltersCursorPosition')
);
if ( typeof line === 'number' ) {
cmEditor.setCursor(line, 0);
}
} catch(ex) {
}
}
userFiltersChanged(false);
};
@ -224,7 +199,24 @@ uDom('#exportUserFiltersToFile').on('click', exportUserFiltersToFile);
uDom('#userFiltersApply').on('click', ( ) => { applyChanges(); });
uDom('#userFiltersRevert').on('click', revertChanges);
renderUserFilters(true);
// https://github.com/gorhill/uBlock/issues/3706
// Save/restore cursor position
//
// CoreMirror reference: https://codemirror.net/doc/manual.html#api_selection
renderUserFilters().then(( ) => {
cmEditor.clearHistory();
return vAPI.localStorage.getItemAsync('myFiltersCursorPosition');
}).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);
}
});
});
cmEditor.on('changes', userFiltersChanged);
CodeMirror.commands.save = applyChanges;

View File

@ -34,7 +34,7 @@ const reValidExternalList = /[a-z-]+:\/\/\S*\/\S+/;
let listDetails = {};
let filteringSettingsHash = '';
let hideUnusedSet = new Set();
let hideUnusedSet = new Set([ '*' ]);
/******************************************************************************/
@ -258,10 +258,6 @@ const renderFilterLists = function(soft) {
let groupKey = groupKeys[i];
let liGroup = liFromListGroup(groupKey, groups.get(groupKey));
liGroup.setAttribute('data-groupkey', groupKey);
liGroup.classList.toggle(
'collapsed',
vAPI.localStorage.getItem('collapseGroup' + (i + 1)) === 'y'
);
if ( liGroup.parentElement === null ) {
ulLists.appendChild(liGroup);
}
@ -548,7 +544,7 @@ const toggleHideUnusedLists = function(which) {
.toggleClass('unused', mustHide);
vAPI.localStorage.setItem(
'hideUnusedFilterLists',
JSON.stringify(Array.from(hideUnusedSet))
Array.from(hideUnusedSet)
);
};
@ -571,20 +567,11 @@ uDom('#lists').on('click', '.groupEntry[data-groupkey] > .geDetails', function(e
});
// Initialize from saved state.
{
let aa;
try {
const json = vAPI.localStorage.getItem('hideUnusedFilterLists');
if ( json !== null ) {
aa = JSON.parse(json);
}
} catch (ex) {
vAPI.localStorage.getItemAsync('hideUnusedFilterLists').then(value => {
if ( Array.isArray(value) ) {
hideUnusedSet = new Set(value);
}
if ( Array.isArray(aa) === false ) {
aa = [ '*' ];
}
hideUnusedSet = new Set(aa);
}
});
/******************************************************************************/

View File

@ -84,10 +84,10 @@ const discardUnsavedData = function(synchronous = false) {
const loadDashboardPanel = function(pane = '') {
if ( pane === '' ) {
pane = vAPI.localStorage.getItem('dashboardLastVisitedPane');
if ( pane === null ) {
pane = 'settings.html';
}
vAPI.localStorage.getItemAsync('dashboardLastVisitedPane').then(value => {
loadDashboardPanel(value !== null ? value : 'settings.html');
});
return;
}
const tabButton = uDom(`[href="#${pane}"]`);
if ( !tabButton || tabButton.hasClass('selected') ) { return; }

View File

@ -194,10 +194,12 @@ uDom.nodeFromId('why').textContent = details.fs;
);
});
uDom.nodeFromId('theURL').classList.toggle(
'collapsed',
vAPI.localStorage.getItem('document-blocked-expand-url') !== 'true'
);
vAPI.localStorage.getItemAsync('document-blocked-expand-url').then(value => {
uDom.nodeFromId('theURL').classList.toggle(
'collapsed',
value !== 'true' && value !== true
);
});
})();
/******************************************************************************/

View File

@ -2675,9 +2675,9 @@ const loggerSettings = (( ) => {
linesPerEntry: 4,
};
{
vAPI.localStorage.getItemAsync('loggerSettings').then(value => {
try {
const stored = JSON.parse(vAPI.localStorage.getItem('loggerSettings'));
const stored = JSON.parse(value);
if ( typeof stored.discard.maxAge === 'number' ) {
settings.discard.maxAge = stored.discard.maxAge;
}
@ -2695,7 +2695,7 @@ const loggerSettings = (( ) => {
}
} catch(ex) {
}
}
});
const valueFromInput = function(input, def) {
let value = parseInt(input.value, 10);

View File

@ -30,19 +30,23 @@
/******************************************************************************/
let popupFontSize = vAPI.localStorage.getItem('popupFontSize');
if ( typeof popupFontSize === 'string' && popupFontSize !== 'unset' ) {
document.body.style.setProperty('font-size', popupFontSize);
}
let popupFontSize;
vAPI.localStorage.getItemAsync('popupFontSize').then(value => {
if ( typeof value !== 'string' || value === 'unset' ) { return; }
document.body.style.setProperty('font-size', value);
popupFontSize = value;
});
// https://github.com/chrisaljoudi/uBlock/issues/996
// Experimental: mitigate glitchy popup UI: immediately set the firewall
// pane visibility to its last known state. By default the pane is hidden.
let dfPaneVisibleStored =
vAPI.localStorage.getItem('popupFirewallPane') === 'true';
if ( dfPaneVisibleStored ) {
document.getElementById('main').classList.add('dfEnabled');
}
// Experimental: mitigate glitchy popup UI: immediately set the firewall
// pane visibility to its last known state. By default the pane is hidden.
let dfPaneVisibleStored;
vAPI.localStorage.getItemAsync('popupFirewallPane').then(value => {
dfPaneVisibleStored = value === true || value === 'true';
if ( dfPaneVisibleStored ) {
document.getElementById('panes').classList.add('dfEnabled');
}
});
/******************************************************************************/
@ -838,11 +842,8 @@ document.addEventListener(
const expandExceptions = new Set();
(( ) => {
vAPI.localStorage.getItemAsync('popupExpandExceptions').then(exceptions => {
try {
const exceptions = JSON.parse(
vAPI.localStorage.getItem('popupExpandExceptions')
);
if ( Array.isArray(exceptions) === false ) { return; }
for ( const exception of exceptions ) {
expandExceptions.add(exception);
@ -850,13 +851,12 @@ const expandExceptions = new Set();
}
catch(ex) {
}
})();
});
const saveExpandExceptions = function() {
vAPI.localStorage.setItem(
'popupExpandExceptions',
JSON.stringify(Array.from(expandExceptions))
Array.from(expandExceptions)
);
};

View File

@ -29,10 +29,12 @@
/******************************************************************************/
let popupFontSize = vAPI.localStorage.getItem('popupFontSize');
if ( typeof popupFontSize === 'string' && popupFontSize !== 'unset' ) {
document.body.style.setProperty('font-size', popupFontSize);
}
let popupFontSize;
vAPI.localStorage.getItemAsync('popupFontSize').then(value => {
if ( typeof value !== 'string' || value === 'unset' ) { return; }
document.body.style.setProperty('font-size', value);
popupFontSize = value;
});
// https://github.com/gorhill/uBlock/issues/3032
// Popup panel can be in one of two modes:
@ -48,13 +50,15 @@ if (
}
// https://github.com/chrisaljoudi/uBlock/issues/996
// Experimental: mitigate glitchy popup UI: immediately set the firewall
// pane visibility to its last known state. By default the pane is hidden.
let dfPaneVisibleStored =
vAPI.localStorage.getItem('popupFirewallPane') === 'true';
if ( dfPaneVisibleStored ) {
document.getElementById('panes').classList.add('dfEnabled');
}
// Experimental: mitigate glitchy popup UI: immediately set the firewall
// pane visibility to its last known state. By default the pane is hidden.
let dfPaneVisibleStored;
vAPI.localStorage.getItemAsync('popupFirewallPane').then(value => {
dfPaneVisibleStored = value === true || value === 'true';
if ( dfPaneVisibleStored ) {
document.getElementById('panes').classList.add('dfEnabled');
}
});
/******************************************************************************/
@ -931,11 +935,8 @@ document.addEventListener(
const expandExceptions = new Set();
(( ) => {
vAPI.localStorage.getItemAsync('popupExpandExceptions').then(exceptions => {
try {
const exceptions = JSON.parse(
vAPI.localStorage.getItem('popupExpandExceptions')
);
if ( Array.isArray(exceptions) === false ) { return; }
for ( const exception of exceptions ) {
expandExceptions.add(exception);
@ -943,13 +944,12 @@ const expandExceptions = new Set();
}
catch(ex) {
}
})();
});
const saveExpandExceptions = function() {
vAPI.localStorage.setItem(
'popupExpandExceptions',
JSON.stringify(Array.from(expandExceptions))
Array.from(expandExceptions)
);
};

View File

@ -316,10 +316,6 @@ if ( selfieIsValid !== true ) {
// Start network observers.
µb.webRequest.start();
// https://github.com/uBlockOrigin/uBlock-issues/issues/899
// Signal that localStorage can be used now that uBO is ready.
vAPI.localStorage.start();
// Ensure that the resources allocated for decompression purpose (likely
// large buffers) are garbage-collectable immediately after launch.
// Otherwise I have observed that it may take quite a while before the