mirror of https://github.com/gorhill/uBlock.git
Work toward modernizing code base: promisification
Swathes of code have been converted to use Promises/async/await. More left to do. Related commits: -915687fddb
-55cc0c6997
-e27328f931
This commit is contained in:
parent
c4ee846cd4
commit
eec53c0154
|
@ -11,6 +11,7 @@
|
|||
"safari": false,
|
||||
"self": false,
|
||||
"vAPI": false,
|
||||
"webext": false,
|
||||
"µBlock": false
|
||||
},
|
||||
"laxbreak": true,
|
||||
|
|
|
@ -43,15 +43,6 @@ vAPI.lastError = function() {
|
|||
return chrome.runtime.lastError;
|
||||
};
|
||||
|
||||
vAPI.apiIsPromisified = (( ) => {
|
||||
try {
|
||||
return browser.storage.local.get('_') instanceof Promise;
|
||||
}
|
||||
catch(ex) {
|
||||
}
|
||||
return false;
|
||||
})();
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/875
|
||||
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
|
||||
// Must not leave `lastError` unchecked.
|
||||
|
@ -116,83 +107,7 @@ vAPI.app = {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.storage = (( ) => {
|
||||
if ( vAPI.apiIsPromisified ) {
|
||||
return browser.storage.local;
|
||||
}
|
||||
return {
|
||||
clear: function(callback) {
|
||||
if ( callback !== undefined ) {
|
||||
return browser.storage.local.clear(...arguments);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.local.clear(( ) => {
|
||||
const lastError = browser.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
get: function(keys, callback) {
|
||||
if ( callback !== undefined ) {
|
||||
return browser.storage.local.get(...arguments);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.local.get(keys, result => {
|
||||
const lastError = browser.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
},
|
||||
getBytesInUse: function(keys, callback) {
|
||||
if ( callback !== undefined ) {
|
||||
return browser.storage.local.getBytesInUse(...arguments);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.local.getBytesInUse(keys, result => {
|
||||
const lastError = browser.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
},
|
||||
remove: function(keys, callback) {
|
||||
if ( callback !== undefined ) {
|
||||
return browser.storage.local.remove(...arguments);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.local.remove(keys, ( ) => {
|
||||
const lastError = browser.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
set: function(items, callback) {
|
||||
if ( callback !== undefined ) {
|
||||
return browser.storage.local.set(...arguments);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.local.set(items, ( ) => {
|
||||
const lastError = browser.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
})();
|
||||
vAPI.storage = webext.storage.local;
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
@ -211,7 +126,7 @@ vAPI.storage = (( ) => {
|
|||
// Do not mess up with existing settings if not assigning them stricter
|
||||
// values.
|
||||
|
||||
vAPI.browserSettings = (function() {
|
||||
vAPI.browserSettings = (( ) => {
|
||||
// Not all platforms support `chrome.privacy`.
|
||||
if ( chrome.privacy instanceof Object === false ) { return; }
|
||||
|
||||
|
@ -384,9 +299,8 @@ vAPI.isBehindTheSceneTabId = function(tabId) {
|
|||
vAPI.unsetTabId = 0;
|
||||
vAPI.noTabId = -1; // definitely not any existing tab
|
||||
|
||||
// To remove when tabId-as-integer has been tested enough.
|
||||
|
||||
const toChromiumTabId = function(tabId) {
|
||||
// To ensure we always use a good tab id
|
||||
const toTabId = function(tabId) {
|
||||
return typeof tabId === 'number' && isNaN(tabId) === false
|
||||
? tabId
|
||||
: 0;
|
||||
|
@ -436,17 +350,12 @@ vAPI.Tabs = class {
|
|||
// https://github.com/uBlockOrigin/uBlock-issues/issues/151
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/680#issuecomment-515215220
|
||||
if ( browser.windows instanceof Object ) {
|
||||
browser.windows.onFocusChanged.addListener(windowId => {
|
||||
browser.windows.onFocusChanged.addListener(async windowId => {
|
||||
if ( windowId === browser.windows.WINDOW_ID_NONE ) { return; }
|
||||
browser.tabs.query({ active: true, windowId }, tabs => {
|
||||
if ( Array.isArray(tabs) === false ) { return; }
|
||||
const tabs = await vAPI.tabs.query({ active: true, windowId });
|
||||
if ( tabs.length === 0 ) { return; }
|
||||
const tab = tabs[0];
|
||||
this.onActivated({
|
||||
tabId: tab.id,
|
||||
windowId: tab.windowId,
|
||||
});
|
||||
});
|
||||
this.onActivated({ tabId: tab.id, windowId: tab.windowId });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -455,32 +364,33 @@ vAPI.Tabs = class {
|
|||
});
|
||||
}
|
||||
|
||||
get(tabId, callback) {
|
||||
async get(tabId) {
|
||||
if ( tabId === null ) {
|
||||
browser.tabs.query(
|
||||
{ active: true, currentWindow: true },
|
||||
tabs => {
|
||||
void browser.runtime.lastError;
|
||||
callback(
|
||||
Array.isArray(tabs) && tabs.length !== 0
|
||||
? tabs[0]
|
||||
: null
|
||||
);
|
||||
return this.getCurrent();
|
||||
}
|
||||
);
|
||||
return;
|
||||
if ( tabId <= 0 ) { return null; }
|
||||
let tab;
|
||||
try {
|
||||
tab = await webext.tabs.get(tabId);
|
||||
}
|
||||
catch(reason) {
|
||||
}
|
||||
return tab instanceof Object ? tab : null;
|
||||
}
|
||||
|
||||
tabId = toChromiumTabId(tabId);
|
||||
if ( tabId === 0 ) {
|
||||
callback(null);
|
||||
return;
|
||||
async getCurrent() {
|
||||
const tabs = await this.query({ active: true, currentWindow: true });
|
||||
return tabs.length !== 0 ? tabs[0] : null;
|
||||
}
|
||||
|
||||
browser.tabs.get(tabId, function(tab) {
|
||||
void browser.runtime.lastError;
|
||||
callback(tab);
|
||||
});
|
||||
async query(queryInfo) {
|
||||
let tabs;
|
||||
try {
|
||||
tabs = await webext.tabs.query(queryInfo);
|
||||
}
|
||||
catch(reason) {
|
||||
}
|
||||
return Array.isArray(tabs) ? tabs : [];
|
||||
}
|
||||
|
||||
// Properties of the details object:
|
||||
|
@ -491,12 +401,12 @@ vAPI.Tabs = class {
|
|||
// foreground: undefined
|
||||
// - popup: 'popup' => open in a new window
|
||||
|
||||
create(url, details) {
|
||||
async create(url, details) {
|
||||
if ( details.active === undefined ) {
|
||||
details.active = true;
|
||||
}
|
||||
|
||||
const subWrapper = ( ) => {
|
||||
const subWrapper = async ( ) => {
|
||||
const updateDetails = {
|
||||
url: url,
|
||||
active: !!details.active
|
||||
|
@ -505,8 +415,8 @@ vAPI.Tabs = class {
|
|||
// Opening a tab from incognito window won't focus the window
|
||||
// in which the tab was opened
|
||||
const focusWindow = tab => {
|
||||
if ( tab.active && browser.windows instanceof Object ) {
|
||||
browser.windows.update(tab.windowId, { focused: true });
|
||||
if ( tab.active && vAPI.windows instanceof Object ) {
|
||||
vAPI.windows.update(tab.windowId, { focused: true });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -519,29 +429,27 @@ vAPI.Tabs = class {
|
|||
}
|
||||
|
||||
// update doesn't accept index, must use move
|
||||
browser.tabs.update(
|
||||
toChromiumTabId(details.tabId),
|
||||
updateDetails,
|
||||
tab => {
|
||||
const tab = await vAPI.tabs.update(
|
||||
toTabId(details.tabId),
|
||||
updateDetails
|
||||
);
|
||||
// if the tab doesn't exist
|
||||
if ( vAPI.lastError() ) {
|
||||
if ( tab === null ) {
|
||||
browser.tabs.create(updateDetails, focusWindow);
|
||||
} else if ( details.index !== undefined ) {
|
||||
browser.tabs.move(tab.id, { index: details.index });
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// Open in a standalone window
|
||||
//
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/168#issuecomment-413038191
|
||||
// Not all platforms support browser.windows API.
|
||||
// Not all platforms support vAPI.windows.
|
||||
//
|
||||
// For some reasons, some platforms do not honor the left,top
|
||||
// position when specified. I found that further calling
|
||||
// windows.update again with the same position _may_ help.
|
||||
if ( details.popup !== undefined && browser.windows instanceof Object ) {
|
||||
if ( details.popup !== undefined && vAPI.windows instanceof Object ) {
|
||||
const createDetails = {
|
||||
url: details.url,
|
||||
type: details.popup,
|
||||
|
@ -549,8 +457,8 @@ vAPI.Tabs = class {
|
|||
if ( details.box instanceof Object ) {
|
||||
Object.assign(createDetails, details.box);
|
||||
}
|
||||
browser.windows.create(createDetails, win => {
|
||||
if ( win instanceof Object === false ) { return; }
|
||||
const win = await vAPI.windows.create(createDetails);
|
||||
if ( win === null ) { return; }
|
||||
if ( details.box instanceof Object === false ) { return; }
|
||||
if (
|
||||
win.left === details.box.left &&
|
||||
|
@ -558,11 +466,10 @@ vAPI.Tabs = class {
|
|||
) {
|
||||
return;
|
||||
}
|
||||
browser.windows.update(win.id, {
|
||||
vAPI.windows.update(win.id, {
|
||||
left: details.box.left,
|
||||
top: details.box.top
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -571,15 +478,13 @@ vAPI.Tabs = class {
|
|||
return;
|
||||
}
|
||||
|
||||
vAPI.tabs.get(null, tab => {
|
||||
if ( tab ) {
|
||||
const tab = await vAPI.tabs.getCurrent();
|
||||
if ( tab !== null ) {
|
||||
details.index = tab.index + 1;
|
||||
} else {
|
||||
delete details.index;
|
||||
details.index = undefined;
|
||||
}
|
||||
|
||||
subWrapper();
|
||||
});
|
||||
}
|
||||
|
||||
// Properties of the details object:
|
||||
|
@ -593,7 +498,7 @@ vAPI.Tabs = class {
|
|||
// it instead of opening a new one
|
||||
// - popup: true => open in a new window
|
||||
|
||||
open(details) {
|
||||
async open(details) {
|
||||
let targetURL = details.url;
|
||||
if ( typeof targetURL !== 'string' || targetURL === '' ) {
|
||||
return null;
|
||||
|
@ -628,29 +533,35 @@ vAPI.Tabs = class {
|
|||
? targetURL
|
||||
: targetURL.slice(0, pos);
|
||||
|
||||
browser.tabs.query({ url: targetURLWithoutHash }, tabs => {
|
||||
void browser.runtime.lastError;
|
||||
const tab = Array.isArray(tabs) && tabs[0];
|
||||
if ( !tab ) {
|
||||
const tabs = await vAPI.tabs.query({ url: targetURLWithoutHash });
|
||||
if ( tabs.length === 0 ) {
|
||||
this.create(targetURL, details);
|
||||
return;
|
||||
}
|
||||
let tab = tabs[0];
|
||||
const updateDetails = { active: true };
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/592
|
||||
if ( tab.url.startsWith(targetURL) === false ) {
|
||||
updateDetails.url = targetURL;
|
||||
}
|
||||
browser.tabs.update(tab.id, updateDetails, tab => {
|
||||
if ( browser.windows instanceof Object === false ) { return; }
|
||||
browser.windows.update(tab.windowId, { focused: true });
|
||||
});
|
||||
});
|
||||
tab = await vAPI.tabs.update(tab.id, updateDetails);
|
||||
if ( vAPI.windows instanceof Object === false ) { return; }
|
||||
vAPI.windows.update(tab.windowId, { focused: true });
|
||||
}
|
||||
|
||||
async update() {
|
||||
let tab;
|
||||
try {
|
||||
tab = await webext.tabs.update(...arguments);
|
||||
}
|
||||
catch (reason) {
|
||||
}
|
||||
return tab instanceof Object ? tab : null;
|
||||
}
|
||||
|
||||
// Replace the URL of a tab. Noop if the tab does not exist.
|
||||
|
||||
replace(tabId, url) {
|
||||
tabId = toChromiumTabId(tabId);
|
||||
tabId = toTabId(tabId);
|
||||
if ( tabId === 0 ) { return; }
|
||||
|
||||
let targetURL = url;
|
||||
|
@ -660,18 +571,17 @@ vAPI.Tabs = class {
|
|||
targetURL = vAPI.getURL(targetURL);
|
||||
}
|
||||
|
||||
browser.tabs.update(tabId, { url: targetURL }, vAPI.resetLastError);
|
||||
vAPI.tabs.update(tabId, { url: targetURL });
|
||||
}
|
||||
|
||||
remove(tabId) {
|
||||
tabId = toChromiumTabId(tabId);
|
||||
tabId = toTabId(tabId);
|
||||
if ( tabId === 0 ) { return; }
|
||||
|
||||
browser.tabs.remove(tabId, vAPI.resetLastError);
|
||||
}
|
||||
|
||||
reload(tabId, bypassCache = false) {
|
||||
tabId = toChromiumTabId(tabId);
|
||||
tabId = toTabId(tabId);
|
||||
if ( tabId === 0 ) { return; }
|
||||
|
||||
browser.tabs.reload(
|
||||
|
@ -681,16 +591,13 @@ vAPI.Tabs = class {
|
|||
);
|
||||
}
|
||||
|
||||
select(tabId) {
|
||||
tabId = toChromiumTabId(tabId);
|
||||
async select(tabId) {
|
||||
tabId = toTabId(tabId);
|
||||
if ( tabId === 0 ) { return; }
|
||||
|
||||
browser.tabs.update(tabId, { active: true }, function(tab) {
|
||||
void browser.runtime.lastError;
|
||||
if ( !tab ) { return; }
|
||||
if ( browser.windows instanceof Object === false ) { return; }
|
||||
browser.windows.update(tab.windowId, { focused: true });
|
||||
});
|
||||
const tab = await vAPI.tabs.update(tabId, { active: true });
|
||||
if ( tab === null ) { return; }
|
||||
if ( vAPI.windows instanceof Object === false ) { return; }
|
||||
vAPI.windows.update(tab.windowId, { focused: true });
|
||||
}
|
||||
|
||||
injectScript(tabId, details, callback) {
|
||||
|
@ -703,7 +610,7 @@ vAPI.Tabs = class {
|
|||
};
|
||||
if ( tabId ) {
|
||||
browser.tabs.executeScript(
|
||||
toChromiumTabId(tabId),
|
||||
toTabId(tabId),
|
||||
details,
|
||||
onScriptExecuted
|
||||
);
|
||||
|
@ -749,6 +656,41 @@ vAPI.Tabs = class {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
if ( browser.windows instanceof Object ) {
|
||||
vAPI.windows = {
|
||||
get: async function() {
|
||||
let win;
|
||||
try {
|
||||
win = await webext.windows.get(...arguments);
|
||||
}
|
||||
catch (reason) {
|
||||
}
|
||||
return win instanceof Object ? win : null;
|
||||
},
|
||||
create: async function() {
|
||||
let win;
|
||||
try {
|
||||
win = await webext.windows.create(...arguments);
|
||||
}
|
||||
catch (reason) {
|
||||
}
|
||||
return win instanceof Object ? win : null;
|
||||
},
|
||||
update: async function() {
|
||||
let win;
|
||||
try {
|
||||
win = await webext.windows.update(...arguments);
|
||||
}
|
||||
catch (reason) {
|
||||
}
|
||||
return win instanceof Object ? win : null;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// Must read: https://code.google.com/p/chromium/issues/detail?id=410868#c8
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/19
|
||||
|
@ -852,8 +794,17 @@ vAPI.setIcon = (( ) => {
|
|||
}
|
||||
})();
|
||||
|
||||
const onTabReady = function(tab, details) {
|
||||
if ( vAPI.lastError() || !tab ) { return; }
|
||||
// parts: bit 0 = icon
|
||||
// bit 1 = badge text
|
||||
// bit 2 = badge color
|
||||
// bit 3 = hide badge
|
||||
|
||||
return async function(tabId, details) {
|
||||
tabId = toTabId(tabId);
|
||||
if ( tabId === 0 ) { return; }
|
||||
|
||||
const tab = await vAPI.tabs.get(tabId);
|
||||
if ( tab === null ) { return; }
|
||||
|
||||
const { parts, state, badge, color } = details;
|
||||
|
||||
|
@ -883,18 +834,6 @@ vAPI.setIcon = (( ) => {
|
|||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// parts: bit 0 = icon
|
||||
// bit 1 = badge text
|
||||
// bit 2 = badge color
|
||||
// bit 3 = hide badge
|
||||
|
||||
return function(tabId, details) {
|
||||
tabId = toChromiumTabId(tabId);
|
||||
if ( tabId === 0 ) { return; }
|
||||
|
||||
browser.tabs.get(tabId, tab => onTabReady(tab, details));
|
||||
|
||||
if ( vAPI.contextMenu instanceof Object ) {
|
||||
vAPI.contextMenu.onMustUpdate(tabId);
|
||||
|
@ -1381,48 +1320,27 @@ vAPI.commands = chrome.commands;
|
|||
// Also, UC Browser: http://www.upsieutoc.com/image/WXuH
|
||||
|
||||
vAPI.adminStorage = (( ) => {
|
||||
if ( browser.storage.managed instanceof Object === false ) {
|
||||
if ( webext.storage.managed instanceof Object === false ) {
|
||||
return {
|
||||
getItem: function() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
}
|
||||
const managedStorage = vAPI.apiIsPromisified
|
||||
? browser.storage.managed
|
||||
: {
|
||||
get: function(keys) {
|
||||
return new Promise((resolve, reject) => {
|
||||
browser.storage.managed.get(keys, result => {
|
||||
const lastError = browser.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
return {
|
||||
getItem: async function(key) {
|
||||
let bin;
|
||||
try {
|
||||
bin = await managedStorage.get(key);
|
||||
bin = await webext.storage.managed.get(key);
|
||||
} catch(ex) {
|
||||
}
|
||||
let data;
|
||||
if (
|
||||
chrome.runtime.lastError instanceof Object === false &&
|
||||
bin instanceof Object
|
||||
) {
|
||||
data = bin[key];
|
||||
if ( bin instanceof Object ) {
|
||||
return bin[key];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2019-present Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// `webext` is a promisified api of `chrome`. Entries are added as
|
||||
// the promisification of uBO progress.
|
||||
|
||||
const webext = { // jshint ignore:line
|
||||
storage: {
|
||||
local: {
|
||||
clear: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.storage.local.clear(( ) => {
|
||||
const lastError = chrome.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
get: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.storage.local.get(...arguments, result => {
|
||||
const lastError = chrome.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
},
|
||||
getBytesInUse: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.storage.local.getBytesInUse(...arguments, result => {
|
||||
const lastError = chrome.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
},
|
||||
remove: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.storage.local.remove(...arguments, ( ) => {
|
||||
const lastError = chrome.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
set: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.storage.local.set(...arguments, ( ) => {
|
||||
const lastError = chrome.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
tabs: {
|
||||
get: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.tabs.get(...arguments, tab => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve(tab instanceof Object ? tab : null);
|
||||
});
|
||||
});
|
||||
},
|
||||
query: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.tabs.query(...arguments, tabs => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve(Array.isArray(tabs) ? tabs : []);
|
||||
});
|
||||
});
|
||||
},
|
||||
update: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.tabs.update(...arguments, tab => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve(tab instanceof Object ? tab : null);
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
windows: {
|
||||
get: async function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.windows.get(...arguments, win => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve(win instanceof Object ? win : null);
|
||||
});
|
||||
});
|
||||
},
|
||||
create: async function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.windows.create(...arguments, win => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve(win instanceof Object ? win : null);
|
||||
});
|
||||
});
|
||||
},
|
||||
update: async function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.windows.update(...arguments, win => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve(win instanceof Object ? win : null);
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if ( chrome.storage.managed instanceof Object ) {
|
||||
webext.storage.managed = {
|
||||
get: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.storage.local.get(...arguments, result => {
|
||||
const lastError = chrome.runtime.lastError;
|
||||
if ( lastError instanceof Object ) {
|
||||
return reject(lastError);
|
||||
}
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2019-present Raymond Hill
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const webext = browser; // jshint ignore:line
|
|
@ -9,6 +9,7 @@
|
|||
<script src="lib/lz4/lz4-block-codec-any.js"></script>
|
||||
<script src="lib/punycode.js"></script>
|
||||
<script src="lib/publicsuffixlist/publicsuffixlist.js"></script>
|
||||
<script src="js/webext.js"></script>
|
||||
<script src="js/vapi.js"></script>
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-background.js"></script>
|
||||
|
|
|
@ -54,64 +54,15 @@
|
|||
|
||||
const STORAGE_NAME = 'uBlock0CacheStorage';
|
||||
|
||||
// Default to webext storage. Wrapped into promises if the API does not
|
||||
// support returning promises.
|
||||
const promisified = (( ) => {
|
||||
try {
|
||||
return browser.storage.local.get('_') instanceof Promise;
|
||||
}
|
||||
catch(ex) {
|
||||
}
|
||||
return false;
|
||||
})();
|
||||
|
||||
// Default to webext storage.
|
||||
const localStorage = webext.storage.local;
|
||||
const api = {
|
||||
name: 'browser.storage.local',
|
||||
get: promisified ?
|
||||
browser.storage.local.get :
|
||||
function(keys) {
|
||||
return new Promise(resolve => {
|
||||
browser.storage.local.get(keys, bin => {
|
||||
resolve(bin);
|
||||
});
|
||||
});
|
||||
},
|
||||
set: promisified ?
|
||||
browser.storage.local.set :
|
||||
function(keys) {
|
||||
return new Promise(resolve => {
|
||||
browser.storage.local.set(keys, ( ) => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
remove: promisified ?
|
||||
browser.storage.local.remove :
|
||||
function(keys) {
|
||||
return new Promise(resolve => {
|
||||
browser.storage.local.remove(keys, ( ) => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
clear: promisified ?
|
||||
browser.storage.local.clear :
|
||||
function() {
|
||||
return new Promise(resolve => {
|
||||
browser.storage.local.clear(( ) => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
getBytesInUse: promisified ?
|
||||
browser.storage.local.getBytesInUse :
|
||||
function(keys) {
|
||||
return new Promise(resolve => {
|
||||
browser.storage.local.getBytesInUse(keys, count => {
|
||||
resolve(count);
|
||||
});
|
||||
});
|
||||
},
|
||||
get: localStorage.get,
|
||||
set: localStorage.set,
|
||||
remove: localStorage.remove,
|
||||
clear: localStorage.clear,
|
||||
getBytesInUse: localStorage.getBytesInUse,
|
||||
select: function(selectedBackend) {
|
||||
let actualBackend = selectedBackend;
|
||||
if ( actualBackend === undefined || actualBackend === 'unset' ) {
|
||||
|
@ -139,7 +90,7 @@
|
|||
};
|
||||
|
||||
// Reassign API entries to that of indexedDB-based ones
|
||||
const selectIDB = function() {
|
||||
const selectIDB = async function() {
|
||||
let db;
|
||||
let dbPromise;
|
||||
let dbTimer;
|
||||
|
@ -244,7 +195,7 @@
|
|||
return dbPromise;
|
||||
};
|
||||
|
||||
const getFromDb = function(keys, keyvalStore, callback) {
|
||||
const getFromDb = async function(keys, keyvalStore, callback) {
|
||||
if ( typeof callback !== 'function' ) { return; }
|
||||
if ( keys.length === 0 ) { return callback(keyvalStore); }
|
||||
const promises = [];
|
||||
|
@ -261,7 +212,8 @@
|
|||
})
|
||||
);
|
||||
};
|
||||
getDb().then(db => {
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||
transaction.oncomplete =
|
||||
|
@ -277,14 +229,15 @@
|
|||
req.onsuccess = gotOne;
|
||||
req.onerror = noopfn;
|
||||
}
|
||||
}).catch(reason => {
|
||||
}
|
||||
catch(reason) {
|
||||
console.info(`cacheStorage.getFromDb() failed: ${reason}`);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const visitAllFromDb = function(visitFn) {
|
||||
getDb().then(db => {
|
||||
const visitAllFromDb = async function(visitFn) {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return visitFn(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||
transaction.oncomplete =
|
||||
|
@ -299,7 +252,6 @@
|
|||
visitFn(entry);
|
||||
cursor.continue();
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const getAllFromDb = function(callback) {
|
||||
|
@ -335,7 +287,7 @@
|
|||
// https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/transaction
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/put
|
||||
|
||||
const putToDb = function(keyvalStore, callback) {
|
||||
const putToDb = async function(keyvalStore, callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
|
@ -359,9 +311,6 @@
|
|||
µBlock.lz4Codec.encode(key, data).then(handleEncodingResult)
|
||||
);
|
||||
}
|
||||
Promise.all(promises).then(results => {
|
||||
const db = results[0];
|
||||
if ( !db ) { return callback(); }
|
||||
const finish = ( ) => {
|
||||
if ( callback === undefined ) { return; }
|
||||
let cb = callback;
|
||||
|
@ -369,6 +318,9 @@
|
|||
cb();
|
||||
};
|
||||
try {
|
||||
const results = await Promise.all(promises);
|
||||
const db = results[0];
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(
|
||||
STORAGE_NAME,
|
||||
'readwrite'
|
||||
|
@ -383,17 +335,14 @@
|
|||
} catch (ex) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const deleteFromDb = function(input, callback) {
|
||||
const deleteFromDb = async function(input, callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
const keys = Array.isArray(input) ? input.slice() : [ input ];
|
||||
if ( keys.length === 0 ) { return callback(); }
|
||||
getDb().then(db => {
|
||||
if ( !db ) { return callback(); }
|
||||
const finish = ( ) => {
|
||||
if ( callback === undefined ) { return; }
|
||||
let cb = callback;
|
||||
|
@ -401,6 +350,8 @@
|
|||
cb();
|
||||
};
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
|
@ -412,14 +363,15 @@
|
|||
} catch (ex) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const clearDb = function(callback) {
|
||||
const clearDb = async function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
getDb().then(db => {
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
|
@ -427,14 +379,16 @@
|
|||
callback();
|
||||
};
|
||||
transaction.objectStore(STORAGE_NAME).clear();
|
||||
}).catch(reason => {
|
||||
}
|
||||
catch(reason) {
|
||||
console.info(`cacheStorage.clearDb() failed: ${reason}`);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return getDb().then(db => {
|
||||
await getDb();
|
||||
if ( !db ) { return false; }
|
||||
|
||||
api.name = 'indexedDB';
|
||||
api.get = function get(keys) {
|
||||
return new Promise(resolve => {
|
||||
|
@ -472,13 +426,12 @@
|
|||
return Promise.resolve(0);
|
||||
};
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/328
|
||||
// Delete cache-related entries from webext storage.
|
||||
const clearWebext = function() {
|
||||
browser.storage.local.get('assetCacheRegistry', bin => {
|
||||
const clearWebext = async function() {
|
||||
const bin = await webext.storage.local.get('assetCacheRegistry');
|
||||
if (
|
||||
bin instanceof Object === false ||
|
||||
bin.assetCacheRegistry instanceof Object === false
|
||||
|
@ -496,8 +449,7 @@
|
|||
toRemove.push('cache/' + key);
|
||||
}
|
||||
}
|
||||
browser.storage.local.remove(toRemove);
|
||||
});
|
||||
webext.storage.local.remove(toRemove);
|
||||
};
|
||||
|
||||
const clearIDB = function() {
|
||||
|
|
|
@ -128,13 +128,13 @@ const relaxBlockingMode = (( ) => {
|
|||
};
|
||||
})();
|
||||
|
||||
vAPI.commands.onCommand.addListener(command => {
|
||||
vAPI.commands.onCommand.addListener(async command => {
|
||||
const µb = µBlock;
|
||||
|
||||
switch ( command ) {
|
||||
case 'launch-element-picker':
|
||||
case 'launch-element-zapper':
|
||||
vAPI.tabs.get(null, tab => {
|
||||
case 'launch-element-zapper': {
|
||||
const tab = await vAPI.tabs.getCurrent();
|
||||
if ( tab instanceof Object === false ) { return; }
|
||||
µb.mouseEventRegister.x = µb.mouseEventRegister.y = -1;
|
||||
µb.elementPickerExec(
|
||||
|
@ -142,10 +142,11 @@ vAPI.commands.onCommand.addListener(command => {
|
|||
undefined,
|
||||
command === 'launch-element-zapper'
|
||||
);
|
||||
});
|
||||
break;
|
||||
case 'launch-logger':
|
||||
vAPI.tabs.get(null, tab => {
|
||||
}
|
||||
case 'launch-logger': {
|
||||
const tab = await vAPI.tabs.getCurrent();
|
||||
if ( tab instanceof Object === false ) { return; }
|
||||
const hash = tab.url.startsWith(vAPI.getURL(''))
|
||||
? ''
|
||||
: `#_+${tab.id}`;
|
||||
|
@ -154,10 +155,10 @@ vAPI.commands.onCommand.addListener(command => {
|
|||
select: true,
|
||||
index: -1
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'relax-blocking-mode':
|
||||
vAPI.tabs.get(null, relaxBlockingMode);
|
||||
relaxBlockingMode(await vAPI.tabs.getCurrent());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -128,17 +128,16 @@ const update = function(tabId = undefined) {
|
|||
// For unknown reasons, the currently active tab will not be successfully
|
||||
// looked up after closing a window.
|
||||
|
||||
vAPI.contextMenu.onMustUpdate = function(tabId = undefined) {
|
||||
vAPI.contextMenu.onMustUpdate = async function(tabId = undefined) {
|
||||
if ( µBlock.userSettings.contextMenuEnabled === false ) {
|
||||
return update();
|
||||
}
|
||||
if ( tabId !== undefined ) {
|
||||
return update(tabId);
|
||||
}
|
||||
vAPI.tabs.get(null, tab => {
|
||||
const tab = await vAPI.tabs.getCurrent();
|
||||
if ( tab instanceof Object === false ) { return; }
|
||||
update(tab.id);
|
||||
});
|
||||
};
|
||||
|
||||
return { update: vAPI.contextMenu.onMustUpdate };
|
||||
|
|
|
@ -346,22 +346,20 @@ const popupDataFromTabId = function(tabId, tabTitle) {
|
|||
return r;
|
||||
};
|
||||
|
||||
const popupDataFromRequest = function(request, callback) {
|
||||
const popupDataFromRequest = async function(request) {
|
||||
if ( request.tabId ) {
|
||||
callback(popupDataFromTabId(request.tabId, ''));
|
||||
return;
|
||||
return popupDataFromTabId(request.tabId, '');
|
||||
}
|
||||
|
||||
// Still no target tab id? Use currently selected tab.
|
||||
vAPI.tabs.get(null, function(tab) {
|
||||
var tabId = '';
|
||||
var tabTitle = '';
|
||||
if ( tab ) {
|
||||
const tab = await vAPI.tabs.getCurrent();
|
||||
let tabId = '';
|
||||
let tabTitle = '';
|
||||
if ( tab instanceof Object ) {
|
||||
tabId = tab.id;
|
||||
tabTitle = tab.title || '';
|
||||
}
|
||||
callback(popupDataFromTabId(tabId, tabTitle));
|
||||
});
|
||||
return popupDataFromTabId(tabId, tabTitle);
|
||||
};
|
||||
|
||||
const onMessage = function(request, sender, callback) {
|
||||
|
@ -370,7 +368,9 @@ const onMessage = function(request, sender, callback) {
|
|||
// Async
|
||||
switch ( request.what ) {
|
||||
case 'getPopupData':
|
||||
popupDataFromRequest(request, callback);
|
||||
popupDataFromRequest(request).then(popupData => {
|
||||
callback(popupData);
|
||||
});
|
||||
return;
|
||||
|
||||
default:
|
||||
|
@ -1151,7 +1151,7 @@ vAPI.messaging.listen({
|
|||
const µb = µBlock;
|
||||
const extensionOriginURL = vAPI.getURL('');
|
||||
|
||||
const getLoggerData = function(details, activeTabId, callback) {
|
||||
const getLoggerData = async function(details, activeTabId, callback) {
|
||||
const response = {
|
||||
colorBlind: µb.userSettings.colorBlindFriendly,
|
||||
entries: µb.logger.readAll(details.ownerId),
|
||||
|
@ -1178,26 +1178,20 @@ const getLoggerData = function(details, activeTabId, callback) {
|
|||
response.activeTabId = undefined;
|
||||
}
|
||||
}
|
||||
if ( details.popupLoggerBoxChanged && browser.windows instanceof Object ) {
|
||||
browser.tabs.query(
|
||||
{ url: vAPI.getURL('/logger-ui.html?popup=1') },
|
||||
tabs => {
|
||||
if ( Array.isArray(tabs) === false ) { return; }
|
||||
if ( tabs.length === 0 ) { return; }
|
||||
browser.windows.get(tabs[0].windowId, win => {
|
||||
if ( win instanceof Object === false ) { return; }
|
||||
vAPI.localStorage.setItem(
|
||||
'popupLoggerBox',
|
||||
JSON.stringify({
|
||||
if ( details.popupLoggerBoxChanged && vAPI.windows instanceof Object ) {
|
||||
const tabs = await vAPI.tabs.query({
|
||||
url: vAPI.getURL('/logger-ui.html?popup=1')
|
||||
});
|
||||
if ( tabs.length !== 0 ) {
|
||||
const win = await vAPI.windows.get(tabs[0].windowId);
|
||||
if ( win === null ) { return; }
|
||||
vAPI.localStorage.setItem('popupLoggerBox', JSON.stringify({
|
||||
left: win.left,
|
||||
top: win.top,
|
||||
width: win.width,
|
||||
height: win.height,
|
||||
})
|
||||
);
|
||||
});
|
||||
}));
|
||||
}
|
||||
);
|
||||
}
|
||||
callback(response);
|
||||
};
|
||||
|
@ -1242,10 +1236,9 @@ const onMessage = function(request, sender, callback) {
|
|||
µb.logger.ownerId !== undefined &&
|
||||
µb.logger.ownerId !== request.ownerId
|
||||
) {
|
||||
callback({ unavailable: true });
|
||||
return;
|
||||
return callback({ unavailable: true });
|
||||
}
|
||||
vAPI.tabs.get(null, function(tab) {
|
||||
vAPI.tabs.getCurrent().then(tab => {
|
||||
getLoggerData(request, tab && tab.id, callback);
|
||||
});
|
||||
return;
|
||||
|
|
|
@ -106,7 +106,7 @@ const onAllReady = function() {
|
|||
// in already opened web pages, to remove whatever nuisance could make it to
|
||||
// the web pages before uBlock was ready.
|
||||
|
||||
const initializeTabs = function() {
|
||||
const initializeTabs = async function() {
|
||||
const handleScriptResponse = function(tabId, results) {
|
||||
if (
|
||||
Array.isArray(results) === false ||
|
||||
|
@ -128,7 +128,7 @@ const initializeTabs = function() {
|
|||
}
|
||||
}
|
||||
};
|
||||
const bindToTabs = function(tabs) {
|
||||
const tabs = await vAPI.tabs.query({ url: '<all_urls>' });
|
||||
for ( const tab of tabs ) {
|
||||
µb.tabContextManager.commit(tab.id, tab.url);
|
||||
µb.bindTabToPageStats(tab.id);
|
||||
|
@ -145,9 +145,6 @@ const initializeTabs = function() {
|
|||
}
|
||||
};
|
||||
|
||||
browser.tabs.query({ url: '<all_urls>' }, bindToTabs);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const onCommandShortcutsReady = function(commandShortcuts) {
|
||||
|
|
|
@ -542,19 +542,18 @@ housekeep itself.
|
|||
}
|
||||
};
|
||||
|
||||
TabContext.prototype.onGC = function() {
|
||||
TabContext.prototype.onGC = async function() {
|
||||
if ( vAPI.isBehindTheSceneTabId(this.tabId) ) { return; }
|
||||
// https://github.com/gorhill/uBlock/issues/1713
|
||||
// For unknown reasons, Firefox's setTimeout() will sometimes
|
||||
// causes the callback function to be called immediately, bypassing
|
||||
// the main event loop. For now this should prevent uBO from crashing
|
||||
// as a result of the bad setTimeout() behavior.
|
||||
if ( this.onGCBarrier ) {
|
||||
return;
|
||||
}
|
||||
if ( this.onGCBarrier ) { return; }
|
||||
this.onGCBarrier = true;
|
||||
this.gcTimer = null;
|
||||
vAPI.tabs.get(this.tabId, tab => { this.onTab(tab); });
|
||||
const tab = await vAPI.tabs.get(this.tabId);
|
||||
this.onTab(tab);
|
||||
this.onGCBarrier = false;
|
||||
};
|
||||
|
||||
|
@ -1065,9 +1064,10 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
}
|
||||
};
|
||||
|
||||
const updateTitle = function(entry) {
|
||||
const updateTitle = async function(entry) {
|
||||
tabIdToTimer.delete(entry.tabId);
|
||||
vAPI.tabs.get(entry.tabId, onTabReady.bind(null, entry));
|
||||
const tab = await vAPI.tabs.get(entry.tabId);
|
||||
onTabReady(entry, tab);
|
||||
};
|
||||
|
||||
return function(tabId) {
|
||||
|
@ -1098,11 +1098,10 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
|
||||
const pageStoreJanitor = function() {
|
||||
const tabIds = Array.from(µBlock.pageStores.keys()).sort();
|
||||
const checkTab = tabId => {
|
||||
vAPI.tabs.get(tabId, tab => {
|
||||
const checkTab = async tabId => {
|
||||
const tab = await vAPI.tabs.get(tabId);
|
||||
if ( tab ) { return; }
|
||||
µBlock.unbindTabFromPageStats(tabId);
|
||||
});
|
||||
};
|
||||
if ( pageStoreJanitorSampleAt >= tabIds.length ) {
|
||||
pageStoreJanitorSampleAt = 0;
|
||||
|
|
|
@ -15,6 +15,7 @@ bash ./tools/copy-common-files.sh $DES
|
|||
cp -R $DES/_locales/nb $DES/_locales/no
|
||||
|
||||
cp platform/firefox/manifest.json $DES/
|
||||
cp platform/firefox/webext.js $DES/js/
|
||||
cp platform/firefox/vapi-usercss.js $DES/js/
|
||||
cp platform/firefox/vapi-webrequest.js $DES/js/
|
||||
|
||||
|
|
Loading…
Reference in New Issue