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: -eec53c0154
-915687fddb
-55cc0c6997
-e27328f931
This commit is contained in:
parent
c74df9b172
commit
0051f3b5c7
|
@ -58,10 +58,6 @@ window.addEventListener('webextFlavor', function() {
|
|||
vAPI.webextFlavor.soup.has('user_stylesheet');
|
||||
}, { once: true });
|
||||
|
||||
vAPI.insertCSS = function(tabId, details) {
|
||||
return chrome.tabs.insertCSS(tabId, details, vAPI.resetLastError);
|
||||
};
|
||||
|
||||
const noopFunc = function(){};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -364,6 +360,16 @@ vAPI.Tabs = class {
|
|||
});
|
||||
}
|
||||
|
||||
async executeScript() {
|
||||
let result;
|
||||
try {
|
||||
result = await webext.tabs.executeScript(...arguments);
|
||||
}
|
||||
catch(reason) {
|
||||
}
|
||||
return Array.isArray(result) ? result : [];
|
||||
}
|
||||
|
||||
async get(tabId) {
|
||||
if ( tabId === null ) {
|
||||
return this.getCurrent();
|
||||
|
@ -383,6 +389,14 @@ vAPI.Tabs = class {
|
|||
return tabs.length !== 0 ? tabs[0] : null;
|
||||
}
|
||||
|
||||
async insertCSS() {
|
||||
try {
|
||||
await webext.tabs.insertCSS(...arguments);
|
||||
}
|
||||
catch(reason) {
|
||||
}
|
||||
}
|
||||
|
||||
async query(queryInfo) {
|
||||
let tabs;
|
||||
try {
|
||||
|
@ -393,6 +407,14 @@ vAPI.Tabs = class {
|
|||
return Array.isArray(tabs) ? tabs : [];
|
||||
}
|
||||
|
||||
async removeCSS() {
|
||||
try {
|
||||
await webext.tabs.removeCSS(...arguments);
|
||||
}
|
||||
catch(reason) {
|
||||
}
|
||||
}
|
||||
|
||||
// Properties of the details object:
|
||||
// - url: 'URL', => the address that will be opened
|
||||
// - index: -1, => undefined: end of the list, -1: following tab,
|
||||
|
@ -600,28 +622,6 @@ vAPI.Tabs = class {
|
|||
vAPI.windows.update(tab.windowId, { focused: true });
|
||||
}
|
||||
|
||||
injectScript(tabId, details, callback) {
|
||||
const onScriptExecuted = function() {
|
||||
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
|
||||
void browser.runtime.lastError;
|
||||
if ( typeof callback === 'function' ) {
|
||||
callback.apply(null, arguments);
|
||||
}
|
||||
};
|
||||
if ( tabId ) {
|
||||
browser.tabs.executeScript(
|
||||
toTabId(tabId),
|
||||
details,
|
||||
onScriptExecuted
|
||||
);
|
||||
} else {
|
||||
browser.tabs.executeScript(
|
||||
details,
|
||||
onScriptExecuted
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// https://forums.lanik.us/viewtopic.php?f=62&t=32826
|
||||
// Chromium-based browsers: sanitize target URL. I've seen data: URI with
|
||||
// newline characters in standard fields, possibly as a way of evading
|
||||
|
@ -984,29 +984,20 @@ vAPI.messaging = {
|
|||
if ( msg.add ) {
|
||||
details.runAt = 'document_start';
|
||||
}
|
||||
let countdown = 0;
|
||||
const countdownHandler = function() {
|
||||
void chrome.runtime.lastError;
|
||||
countdown -= 1;
|
||||
if ( countdown === 0 && typeof callback === 'function' ) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
const promises = [];
|
||||
for ( const cssText of msg.add ) {
|
||||
countdown += 1;
|
||||
details.code = cssText;
|
||||
browser.tabs.insertCSS(tabId, details, countdownHandler);
|
||||
promises.push(vAPI.tabs.insertCSS(tabId, details));
|
||||
}
|
||||
if ( typeof chrome.tabs.removeCSS === 'function' ) {
|
||||
if ( typeof webext.tabs.removeCSS === 'function' ) {
|
||||
for ( const cssText of msg.remove ) {
|
||||
countdown += 1;
|
||||
details.code = cssText;
|
||||
browser.tabs.removeCSS(tabId, details, countdownHandler);
|
||||
promises.push(vAPI.tabs.removeCSS(tabId, details));
|
||||
}
|
||||
}
|
||||
if ( countdown === 0 && typeof callback === 'function' ) {
|
||||
Promise.all(promises).then(( ) => {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -94,6 +94,22 @@ const webext = { // jshint ignore:line
|
|||
});
|
||||
});
|
||||
},
|
||||
executeScript: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.tabs.executeScript(...arguments, result => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
},
|
||||
insertCSS: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.tabs.insertCSS(...arguments, ( ) => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
query: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.tabs.query(...arguments, tabs => {
|
||||
|
@ -113,7 +129,7 @@ const webext = { // jshint ignore:line
|
|||
},
|
||||
|
||||
windows: {
|
||||
get: async function() {
|
||||
get: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.windows.get(...arguments, win => {
|
||||
void chrome.runtime.lastError;
|
||||
|
@ -121,7 +137,7 @@ const webext = { // jshint ignore:line
|
|||
});
|
||||
});
|
||||
},
|
||||
create: async function() {
|
||||
create: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.windows.create(...arguments, win => {
|
||||
void chrome.runtime.lastError;
|
||||
|
@ -129,7 +145,7 @@ const webext = { // jshint ignore:line
|
|||
});
|
||||
});
|
||||
},
|
||||
update: async function() {
|
||||
update: function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.windows.update(...arguments, win => {
|
||||
void chrome.runtime.lastError;
|
||||
|
@ -140,6 +156,18 @@ const webext = { // jshint ignore:line
|
|||
},
|
||||
};
|
||||
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=608854
|
||||
if ( chrome.tabs.removeCSS instanceof Function ) {
|
||||
webext.tabs.removeCSS = function() {
|
||||
return new Promise(resolve => {
|
||||
chrome.tabs.removeCSS(...arguments, ( ) => {
|
||||
void chrome.runtime.lastError;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if ( chrome.storage.managed instanceof Object ) {
|
||||
webext.storage.managed = {
|
||||
get: function() {
|
||||
|
|
|
@ -65,8 +65,6 @@ const µBlock = (function() { // jshint ignore:line
|
|||
};
|
||||
|
||||
return {
|
||||
firstInstall: false,
|
||||
|
||||
userSettings: {
|
||||
advancedUserEnabled: false,
|
||||
alwaysDetachLogger: true,
|
||||
|
|
|
@ -922,7 +922,7 @@ FilterContainer.prototype.retrieveGenericSelectors = function(request) {
|
|||
out.complex = [];
|
||||
}
|
||||
out.injected = injected.join(',\n');
|
||||
vAPI.insertCSS(request.tabId, {
|
||||
vAPI.tabs.insertCSS(request.tabId, {
|
||||
code: out.injected + '\n{display:none!important;}',
|
||||
cssOrigin: 'user',
|
||||
frameId: request.frameId,
|
||||
|
@ -1105,11 +1105,11 @@ FilterContainer.prototype.retrieveSpecificSelectors = function(
|
|||
};
|
||||
if ( out.injectedHideFilters.length !== 0 ) {
|
||||
details.code = out.injectedHideFilters + '\n{display:none!important;}';
|
||||
vAPI.insertCSS(request.tabId, details);
|
||||
vAPI.tabs.insertCSS(request.tabId, details);
|
||||
}
|
||||
if ( out.networkFilters.length !== 0 ) {
|
||||
details.code = out.networkFilters + '\n{display:none!important;}';
|
||||
vAPI.insertCSS(request.tabId, details);
|
||||
vAPI.tabs.insertCSS(request.tabId, details);
|
||||
out.networkFilters = '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -386,7 +386,7 @@ const onMessage = function(request, sender, callback) {
|
|||
if ( pageStore !== null ) {
|
||||
pageStore.hiddenElementCount = 0;
|
||||
pageStore.scriptCount = 0;
|
||||
vAPI.tabs.injectScript(request.tabId, {
|
||||
vAPI.tabs.executeScript(request.tabId, {
|
||||
allFrames: true,
|
||||
file: '/js/scriptlets/dom-survey.js',
|
||||
runAt: 'document_end'
|
||||
|
@ -539,14 +539,11 @@ const onMessage = function(request, sender, callback) {
|
|||
if ( pageStore === null ) { break; }
|
||||
const fctxt = µb.filteringContext.fromTabId(tabId);
|
||||
if ( pageStore.filterScripting(fctxt, undefined) ) {
|
||||
vAPI.tabs.injectScript(
|
||||
tabId,
|
||||
{
|
||||
file: '/js/scriptlets/noscript-spoof.js',
|
||||
frameId: frameId,
|
||||
runAt: 'document_end'
|
||||
}
|
||||
);
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
file: '/js/scriptlets/noscript-spoof.js',
|
||||
frameId: frameId,
|
||||
runAt: 'document_end'
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -394,7 +394,7 @@ const PageStore = class {
|
|||
}
|
||||
|
||||
injectLargeMediaElementScriptlet() {
|
||||
vAPI.tabs.injectScript(this.tabId, {
|
||||
vAPI.tabs.executeScript(this.tabId, {
|
||||
file: '/js/scriptlets/load-large-media-interactive.js',
|
||||
allFrames: true,
|
||||
runAt: 'document_idle',
|
||||
|
|
|
@ -449,15 +449,12 @@
|
|||
if ( µb.hiddenSettings.debugScriptletInjector ) {
|
||||
code = 'debugger;\n' + code;
|
||||
}
|
||||
vAPI.tabs.injectScript(
|
||||
details.tabId,
|
||||
{
|
||||
code: code,
|
||||
frameId: details.frameId,
|
||||
matchAboutBlank: false,
|
||||
runAt: 'document_start'
|
||||
}
|
||||
);
|
||||
vAPI.tabs.executeScript(details.tabId, {
|
||||
code: code,
|
||||
frameId: details.frameId,
|
||||
matchAboutBlank: false,
|
||||
runAt: 'document_start'
|
||||
});
|
||||
};
|
||||
|
||||
api.toSelfie = function() {
|
||||
|
|
157
src/js/start.js
157
src/js/start.js
|
@ -48,87 +48,20 @@ vAPI.app.onShutdown = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Final initialization steps after all needed assets are in memory.
|
||||
// - Initialize internal state with maybe already existing tabs.
|
||||
// - Schedule next update operation.
|
||||
|
||||
const onAllReady = function() {
|
||||
µb.webRequest.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
|
||||
// garbage collection of these resources kicks in. Relinquishing as soon
|
||||
// as possible ensure minimal memory usage baseline.
|
||||
µb.lz4Codec.relinquish();
|
||||
|
||||
initializeTabs();
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/184
|
||||
// Check for updates not too far in the future.
|
||||
µb.assets.addObserver(µb.assetObserver.bind(µb));
|
||||
µb.scheduleAssetUpdater(
|
||||
µb.userSettings.autoUpdate
|
||||
? µb.hiddenSettings.autoUpdateDelayAfterLaunch * 1000
|
||||
: 0
|
||||
);
|
||||
|
||||
// vAPI.cloud is optional.
|
||||
if ( µb.cloudStorageSupported ) {
|
||||
vAPI.cloud.start([
|
||||
'tpFiltersPane',
|
||||
'myFiltersPane',
|
||||
'myRulesPane',
|
||||
'whitelistPane'
|
||||
]);
|
||||
}
|
||||
|
||||
µb.contextMenu.update(null);
|
||||
µb.firstInstall = false;
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/717
|
||||
// Prevent the extensions from being restarted mid-session.
|
||||
browser.runtime.onUpdateAvailable.addListener(details => {
|
||||
const toInt = vAPI.app.intFromVersion;
|
||||
if (
|
||||
µBlock.hiddenSettings.extensionUpdateForceReload === true ||
|
||||
toInt(details.version) <= toInt(vAPI.app.version)
|
||||
) {
|
||||
vAPI.app.restart();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// This is called only once, when everything has been loaded in memory after
|
||||
// the extension was launched. It can be used to inject content scripts
|
||||
// in already opened web pages, to remove whatever nuisance could make it to
|
||||
// the web pages before uBlock was ready.
|
||||
|
||||
const initializeTabs = async function() {
|
||||
const handleScriptResponse = function(tabId, results) {
|
||||
if (
|
||||
Array.isArray(results) === false ||
|
||||
results.length === 0 ||
|
||||
results[0] !== true
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Inject dclarative content scripts programmatically.
|
||||
const manifest = chrome.runtime.getManifest();
|
||||
if ( manifest instanceof Object === false ) { return; }
|
||||
for ( const contentScript of manifest.content_scripts ) {
|
||||
for ( const file of contentScript.js ) {
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
file: file,
|
||||
allFrames: contentScript.all_frames,
|
||||
runAt: contentScript.run_at
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const manifest = browser.runtime.getManifest();
|
||||
if ( manifest instanceof Object === false ) { return; }
|
||||
|
||||
const tabs = await vAPI.tabs.query({ url: '<all_urls>' });
|
||||
const toCheck = [];
|
||||
const checker = {
|
||||
file: 'js/scriptlets/should-inject-contentscript.js'
|
||||
};
|
||||
for ( const tab of tabs ) {
|
||||
µb.tabContextManager.commit(tab.id, tab.url);
|
||||
µb.bindTabToPageStats(tab.id);
|
||||
|
@ -136,13 +69,28 @@ const initializeTabs = async function() {
|
|||
// Find out whether content scripts need to be injected
|
||||
// programmatically. This may be necessary for web pages which
|
||||
// were loaded before uBO launched.
|
||||
if ( /^https?:\/\//.test(tab.url) === false ) { continue; }
|
||||
vAPI.tabs.injectScript(
|
||||
tab.id,
|
||||
{ file: 'js/scriptlets/should-inject-contentscript.js' },
|
||||
handleScriptResponse.bind(null, tab.id)
|
||||
toCheck.push(
|
||||
/^https?:\/\//.test(tab.url)
|
||||
? vAPI.tabs.executeScript(tab.id, checker)
|
||||
: false
|
||||
);
|
||||
}
|
||||
const results = await Promise.all(toCheck);
|
||||
for ( let i = 0; i < results.length; i++ ) {
|
||||
const result = results[i];
|
||||
if ( result.length === 0 || result[0] !== true ) { continue; }
|
||||
// Inject dclarative content scripts programmatically.
|
||||
const tabId = tabs[i].id;
|
||||
for ( const contentScript of manifest.content_scripts ) {
|
||||
for ( const file of contentScript.js ) {
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
file: file,
|
||||
allFrames: contentScript.all_frames,
|
||||
runAt: contentScript.run_at
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -250,9 +198,6 @@ const onFirstFetchReady = function(fetched) {
|
|||
fetched = createDefaultProps();
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/747
|
||||
µb.firstInstall = fetched.version === '0.0.0.0';
|
||||
|
||||
// Order is important -- do not change:
|
||||
onSystemSettingsReady(fetched);
|
||||
fromFetch(µb.localSettings, fetched);
|
||||
|
@ -350,7 +295,53 @@ try {
|
|||
console.trace(ex);
|
||||
}
|
||||
|
||||
onAllReady();
|
||||
// Final initialization steps after all needed assets are in memory.
|
||||
|
||||
µb.webRequest.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
|
||||
// garbage collection of these resources kicks in. Relinquishing as soon
|
||||
// as possible ensure minimal memory usage baseline.
|
||||
µb.lz4Codec.relinquish();
|
||||
|
||||
// Initialize internal state with maybe already existing tabs.
|
||||
initializeTabs();
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/184
|
||||
// Check for updates not too far in the future.
|
||||
µb.assets.addObserver(µb.assetObserver.bind(µb));
|
||||
µb.scheduleAssetUpdater(
|
||||
µb.userSettings.autoUpdate
|
||||
? µb.hiddenSettings.autoUpdateDelayAfterLaunch * 1000
|
||||
: 0
|
||||
);
|
||||
|
||||
// vAPI.cloud is optional.
|
||||
if ( µb.cloudStorageSupported ) {
|
||||
vAPI.cloud.start([
|
||||
'tpFiltersPane',
|
||||
'myFiltersPane',
|
||||
'myRulesPane',
|
||||
'whitelistPane'
|
||||
]);
|
||||
}
|
||||
|
||||
µb.contextMenu.update(null);
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/717
|
||||
// Prevent the extensions from being restarted mid-session.
|
||||
browser.runtime.onUpdateAvailable.addListener(details => {
|
||||
const toInt = vAPI.app.intFromVersion;
|
||||
if (
|
||||
µBlock.hiddenSettings.extensionUpdateForceReload === true ||
|
||||
toInt(details.version) <= toInt(vAPI.app.version)
|
||||
) {
|
||||
vAPI.app.restart();
|
||||
}
|
||||
});
|
||||
|
||||
log.info(`All ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
|
||||
// <<<<< end of private scope
|
||||
|
|
|
@ -255,7 +255,8 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Select default filter lists if first-time launch.
|
||||
// https://github.com/gorhill/uBlock/issues/747
|
||||
// Select default filter lists if first-time launch.
|
||||
const lists = await this.assets.metadata();
|
||||
this.saveSelectedFilterLists(this.autoSelectRegionalFilterLists(lists));
|
||||
};
|
||||
|
|
|
@ -414,7 +414,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.elementPickerExec = function(tabId, targetElement, zap) {
|
||||
µBlock.elementPickerExec = async function(tabId, targetElement, zap) {
|
||||
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
|
||||
|
||||
this.epickerTarget = targetElement || '';
|
||||
|
@ -422,27 +422,20 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/40
|
||||
// The element picker needs this library
|
||||
vAPI.tabs.injectScript(
|
||||
tabId,
|
||||
{
|
||||
file: '/lib/diff/swatinem_diff.js',
|
||||
runAt: 'document_end'
|
||||
}
|
||||
);
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
file: '/lib/diff/swatinem_diff.js',
|
||||
runAt: 'document_end'
|
||||
});
|
||||
|
||||
await vAPI.tabs.executeScript(tabId, {
|
||||
file: '/js/scriptlets/element-picker.js',
|
||||
runAt: 'document_end'
|
||||
});
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/168
|
||||
// Force activate the target tab once the element picker has been
|
||||
// injected.
|
||||
vAPI.tabs.injectScript(
|
||||
tabId,
|
||||
{
|
||||
file: '/js/scriptlets/element-picker.js',
|
||||
runAt: 'document_end'
|
||||
},
|
||||
( ) => {
|
||||
vAPI.tabs.select(tabId);
|
||||
}
|
||||
);
|
||||
vAPI.tabs.select(tabId);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -638,7 +631,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
// cosmetic filters.
|
||||
|
||||
µBlock.logCosmeticFilters = function(tabId, frameId) {
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
file: '/js/scriptlets/cosmetic-logger.js',
|
||||
frameId: frameId,
|
||||
runAt: 'document_start'
|
||||
|
@ -694,15 +687,15 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
}
|
||||
pendingEntries.set(key, new Entry(tabId, scriptlet, callback));
|
||||
}
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
file: '/js/scriptlets/' + scriptlet + '.js'
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
file: `/js/scriptlets/${scriptlet}.js`
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: think about a callback mechanism.
|
||||
const injectDeep = function(tabId, scriptlet) {
|
||||
vAPI.tabs.injectScript(tabId, {
|
||||
file: '/js/scriptlets/' + scriptlet + '.js',
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
file: `/js/scriptlets/${scriptlet}.js`,
|
||||
allFrames: true
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue