Enhance: promisify chrome
into browser
, drop promisify
(#866)
* promisify `chrome` into `browser` * comment * comment * comment * Add: a naive browser polyfill * Fix: polyfill doesn't detect content script env correctly Co-authored-by: eight04 <eight04@gmail.com>
This commit is contained in:
parent
3d94c641b3
commit
54b1f218e0
|
@ -1,7 +1,7 @@
|
||||||
/* global download prefs openURL FIREFOX CHROME
|
/* global download prefs openURL FIREFOX CHROME
|
||||||
URLS ignoreChromeError usercssHelper
|
URLS ignoreChromeError usercssHelper
|
||||||
styleManager msg navigatorUtil workerUtil contentScripts sync
|
styleManager msg navigatorUtil workerUtil contentScripts sync
|
||||||
findExistingTab createTab activateTab isTabReplaceable getActiveTab
|
findExistingTab activateTab isTabReplaceable getActiveTab
|
||||||
tabManager */
|
tabManager */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -336,7 +336,7 @@ function openManage({options = false, search} = {}) {
|
||||||
if (isTabReplaceable(tab, url)) {
|
if (isTabReplaceable(tab, url)) {
|
||||||
return activateTab(tab, {url});
|
return activateTab(tab, {url});
|
||||||
}
|
}
|
||||||
return createTab({url});
|
return browser.tabs.create({url});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global msg queryTabs ignoreChromeError URLS */
|
/* global msg ignoreChromeError URLS */
|
||||||
/* exported contentScripts */
|
/* exported contentScripts */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ const contentScripts = (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function injectToAllTabs() {
|
function injectToAllTabs() {
|
||||||
return queryTabs({}).then(tabs => {
|
return browser.tabs.query({}).then(tabs => {
|
||||||
for (const tab of tabs) {
|
for (const tab of tabs) {
|
||||||
// skip unloaded/discarded/chrome tabs
|
// skip unloaded/discarded/chrome tabs
|
||||||
if (!tab.width || tab.discarded || !URLS.supported(tab.url)) continue;
|
if (!tab.width || tab.discarded || !URLS.supported(tab.url)) continue;
|
||||||
|
|
|
@ -1,46 +1,29 @@
|
||||||
/* global promisify */
|
/* global chromeLocal */
|
||||||
/* exported createChromeStorageDB */
|
/* exported createChromeStorageDB */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function createChromeStorageDB() {
|
function createChromeStorageDB() {
|
||||||
const get = promisify(chrome.storage.local.get.bind(chrome.storage.local));
|
|
||||||
const set = promisify(chrome.storage.local.set.bind(chrome.storage.local));
|
|
||||||
const remove = promisify(chrome.storage.local.remove.bind(chrome.storage.local));
|
|
||||||
|
|
||||||
let INC;
|
let INC;
|
||||||
|
|
||||||
const PREFIX = 'style-';
|
const PREFIX = 'style-';
|
||||||
const METHODS = {
|
const METHODS = {
|
||||||
// FIXME: we don't use this method at all. Should we remove this?
|
// FIXME: we don't use this method at all. Should we remove this?
|
||||||
get: id => get(PREFIX + id)
|
get: id => chromeLocal.getValue(PREFIX + id),
|
||||||
.then(result => result[PREFIX + id]),
|
put: obj =>
|
||||||
put: obj => Promise.resolve()
|
// FIXME: should we clone the object?
|
||||||
.then(() => {
|
Promise.resolve(!obj.id && prepareInc().then(() => Object.assign(obj, {id: INC++})))
|
||||||
if (!obj.id) {
|
.then(() => chromeLocal.setValue(PREFIX + obj.id, obj))
|
||||||
return prepareInc()
|
.then(() => obj.id),
|
||||||
.then(() => {
|
|
||||||
// FIXME: should we clone the object?
|
|
||||||
obj.id = INC++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(() => set({[PREFIX + obj.id]: obj}))
|
|
||||||
.then(() => obj.id),
|
|
||||||
putMany: items => prepareInc()
|
putMany: items => prepareInc()
|
||||||
.then(() => {
|
.then(() =>
|
||||||
for (const item of items) {
|
chromeLocal.set(items.reduce((data, item) => {
|
||||||
if (!item.id) {
|
if (!item.id) item.id = INC++;
|
||||||
item.id = INC++;
|
data[PREFIX + item.id] = item;
|
||||||
}
|
return data;
|
||||||
}
|
}, {})))
|
||||||
return set(items.reduce((obj, curr) => {
|
|
||||||
obj[PREFIX + curr.id] = curr;
|
|
||||||
return obj;
|
|
||||||
}, {}));
|
|
||||||
})
|
|
||||||
.then(() => items.map(i => i.id)),
|
.then(() => items.map(i => i.id)),
|
||||||
delete: id => remove(PREFIX + id),
|
delete: id => chromeLocal.remove(PREFIX + id),
|
||||||
getAll: () => get(null)
|
getAll: () => chromeLocal.get()
|
||||||
.then(result => {
|
.then(result => {
|
||||||
const output = [];
|
const output = [];
|
||||||
for (const key in result) {
|
for (const key in result) {
|
||||||
|
@ -69,7 +52,7 @@ function createChromeStorageDB() {
|
||||||
|
|
||||||
function prepareInc() {
|
function prepareInc() {
|
||||||
if (INC) return Promise.resolve();
|
if (INC) return Promise.resolve();
|
||||||
return get(null).then(result => {
|
return chromeLocal.get().then(result => {
|
||||||
INC = 1;
|
INC = 1;
|
||||||
for (const key in result) {
|
for (const key in result) {
|
||||||
if (key.startsWith(PREFIX)) {
|
if (key.startsWith(PREFIX)) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global promisify CHROME URLS */
|
/* global CHROME URLS */
|
||||||
/* exported navigatorUtil */
|
/* exported navigatorUtil */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ const navigatorUtil = (() => {
|
||||||
const handler = {
|
const handler = {
|
||||||
urlChange: null
|
urlChange: null
|
||||||
};
|
};
|
||||||
const tabGet = promisify(chrome.tabs.get.bind(chrome.tabs));
|
|
||||||
return extendNative({onUrlChange});
|
return extendNative({onUrlChange});
|
||||||
|
|
||||||
function onUrlChange(fn) {
|
function onUrlChange(fn) {
|
||||||
|
@ -48,7 +47,7 @@ const navigatorUtil = (() => {
|
||||||
) {
|
) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return tabGet(data.tabId)
|
return browser.tabs.get(data.tabId)
|
||||||
.then(tab => {
|
.then(tab => {
|
||||||
if (tab.url === 'chrome://newtab/') {
|
if (tab.url === 'chrome://newtab/') {
|
||||||
data.url = tab.url;
|
data.url = tab.url;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
/* global chromeLocal promisify FIREFOX */
|
/* global chromeLocal promisifyChrome FIREFOX */
|
||||||
/* exported tokenManager */
|
/* exported tokenManager */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const tokenManager = (() => {
|
const tokenManager = (() => {
|
||||||
const launchWebAuthFlow = promisify(chrome.identity.launchWebAuthFlow.bind(chrome.identity));
|
promisifyChrome({
|
||||||
|
identity: ['launchWebAuthFlow'],
|
||||||
|
});
|
||||||
const AUTH = {
|
const AUTH = {
|
||||||
dropbox: {
|
dropbox: {
|
||||||
flow: 'token',
|
flow: 'token',
|
||||||
|
@ -158,7 +160,7 @@ const tokenManager = (() => {
|
||||||
Object.assign(query, provider.authQuery);
|
Object.assign(query, provider.authQuery);
|
||||||
}
|
}
|
||||||
const url = `${provider.authURL}?${stringifyQuery(query)}`;
|
const url = `${provider.authURL}?${stringifyQuery(query)}`;
|
||||||
return launchWebAuthFlow({
|
return browser.identity.launchWebAuthFlow({
|
||||||
url,
|
url,
|
||||||
interactive
|
interactive
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
/* global API_METHODS usercss styleManager deepCopy openURL download URLS getTab */
|
/* global API_METHODS usercss styleManager deepCopy openURL download URLS */
|
||||||
/* exports usercssHelper */
|
/* exported usercssHelper */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
const usercssHelper = (() => {
|
const usercssHelper = (() => {
|
||||||
const installCodeCache = {};
|
const installCodeCache = {};
|
||||||
const clearInstallCode = url => delete installCodeCache[url];
|
const clearInstallCode = url => delete installCodeCache[url];
|
||||||
|
@ -46,7 +45,7 @@ const usercssHelper = (() => {
|
||||||
openInstallerPage(tabId, url, {code, inTab} = {}) {
|
openInstallerPage(tabId, url, {code, inTab} = {}) {
|
||||||
const newUrl = `${URLS.installUsercss}?updateUrl=${encodeURIComponent(url)}`;
|
const newUrl = `${URLS.installUsercss}?updateUrl=${encodeURIComponent(url)}`;
|
||||||
if (inTab) {
|
if (inTab) {
|
||||||
getTab(tabId).then(tab =>
|
browser.tabs.get(tabId).then(tab =>
|
||||||
openURL({
|
openURL({
|
||||||
url: `${newUrl}&tabId=${tabId}`,
|
url: `${newUrl}&tabId=${tabId}`,
|
||||||
active: tab.active,
|
active: tab.active,
|
||||||
|
|
|
@ -64,7 +64,6 @@
|
||||||
<script src="vendor-overwrites/codemirror-addon/match-highlighter.js"></script>
|
<script src="vendor-overwrites/codemirror-addon/match-highlighter.js"></script>
|
||||||
|
|
||||||
<script src="js/polyfill.js"></script>
|
<script src="js/polyfill.js"></script>
|
||||||
<script src="js/promisify.js"></script>
|
|
||||||
<script src="js/dom.js"></script>
|
<script src="js/dom.js"></script>
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
<script src="js/prefs.js"></script>
|
<script src="js/prefs.js"></script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* global CodeMirror onDOMready prefs setupLivePrefs $ $$ $create t tHTML
|
/* global CodeMirror onDOMready prefs setupLivePrefs $ $$ $create t tHTML
|
||||||
createSourceEditor queryTabs sessionStorageHash getOwnTab FIREFOX API tryCatch
|
createSourceEditor sessionStorageHash getOwnTab FIREFOX API tryCatch
|
||||||
closeCurrentTab messageBox debounce workerUtil
|
closeCurrentTab messageBox debounce workerUtil
|
||||||
initBeautifyButton ignoreChromeError
|
initBeautifyButton ignoreChromeError
|
||||||
moveFocus msg createSectionsEditor rerouteHotkeys CODEMIRROR_THEMES */
|
moveFocus msg createSectionsEditor rerouteHotkeys CODEMIRROR_THEMES */
|
||||||
|
@ -226,7 +226,7 @@ function preinit() {
|
||||||
}).observe(document, {subtree: true, childList: true});
|
}).observe(document, {subtree: true, childList: true});
|
||||||
|
|
||||||
if (chrome.windows) {
|
if (chrome.windows) {
|
||||||
queryTabs({currentWindow: true}).then(tabs => {
|
browser.tabs.query({currentWindow: true}).then(tabs => {
|
||||||
const windowId = tabs[0].windowId;
|
const windowId = tabs[0].windowId;
|
||||||
if (prefs.get('openEditInWindow')) {
|
if (prefs.get('openEditInWindow')) {
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global CodeMirror focusAccessibility colorMimicry editor
|
/* global CodeMirror focusAccessibility colorMimicry editor chromeLocal
|
||||||
onDOMready $ $$ $create t debounce tryRegExp stringAsRegExp template */
|
onDOMready $ $$ $create t debounce tryRegExp stringAsRegExp template */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -915,7 +915,7 @@ onDOMready().then(() => {
|
||||||
|
|
||||||
|
|
||||||
function readStorage() {
|
function readStorage() {
|
||||||
chrome.storage.local.get('editor', ({editor = {}}) => {
|
chromeLocal.getValue('editor').then((editor = {}) => {
|
||||||
state.find = editor.find || '';
|
state.find = editor.find || '';
|
||||||
state.replace = editor.replace || '';
|
state.replace = editor.replace || '';
|
||||||
state.icase = editor.icase || state.icase;
|
state.icase = editor.icase || state.icase;
|
||||||
|
@ -924,14 +924,12 @@ onDOMready().then(() => {
|
||||||
|
|
||||||
|
|
||||||
function writeStorage() {
|
function writeStorage() {
|
||||||
chrome.storage.local.get('editor', ({editor}) =>
|
chromeLocal.getValue('editor').then((editor = {}) =>
|
||||||
chrome.storage.local.set({
|
chromeLocal.setValue('editor', Object.assign(editor, {
|
||||||
editor: Object.assign(editor || {}, {
|
find: state.find,
|
||||||
find: state.find,
|
replace: state.replace,
|
||||||
replace: state.replace,
|
icase: state.icase,
|
||||||
icase: state.icase,
|
})));
|
||||||
})
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global showHelp $ $create tryRegExp queryTabs URLS t template openURL */
|
/* global showHelp $ $create tryRegExp URLS t template openURL */
|
||||||
/* exported regExpTester */
|
/* exported regExpTester */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ const regExpTester = (() => {
|
||||||
return rxData;
|
return rxData;
|
||||||
});
|
});
|
||||||
const getMatchInfo = m => m && {text: m[0], pos: m.index};
|
const getMatchInfo = m => m && {text: m[0], pos: m.index};
|
||||||
queryTabs({}).then(tabs => {
|
browser.tabs.query({}).then(tabs => {
|
||||||
const supported = tabs.map(tab => tab.url)
|
const supported = tabs.map(tab => tab.url)
|
||||||
.filter(url => URLS.supported(url));
|
.filter(url => URLS.supported(url));
|
||||||
const unique = [...new Set(supported).values()];
|
const unique = [...new Set(supported).values()];
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
<link href="install-usercss/install-usercss.css" rel="stylesheet">
|
<link href="install-usercss/install-usercss.css" rel="stylesheet">
|
||||||
|
|
||||||
<script src="js/polyfill.js"></script>
|
<script src="js/polyfill.js"></script>
|
||||||
<script src="js/promisify.js"></script>
|
|
||||||
<script src="js/msg.js"></script>
|
<script src="js/msg.js"></script>
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
<script src="js/prefs.js"></script>
|
<script src="js/prefs.js"></script>
|
||||||
|
|
|
@ -394,13 +394,9 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
port.onDisconnect.addListener(() => {
|
port.onDisconnect.addListener(() => {
|
||||||
chrome.tabs.get(tabId, tab => {
|
browser.tabs.get(tabId)
|
||||||
if (chrome.runtime.lastError) {
|
.then(tab => tab.url === initialUrl && location.reload())
|
||||||
closeCurrentTab();
|
.catch(closeCurrentTab);
|
||||||
} else if (tab.url === initialUrl) {
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
return ({timer = true} = {}) => new Promise((resolve, reject) => {
|
return ({timer = true} = {}) => new Promise((resolve, reject) => {
|
||||||
const id = performance.now();
|
const id = performance.now();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* exported getTab getActiveTab onTabReady stringAsRegExp openURL ignoreChromeError
|
/* exported getTab getActiveTab onTabReady stringAsRegExp openURL ignoreChromeError
|
||||||
getStyleWithNoCode tryRegExp sessionStorageHash download deepEqual
|
getStyleWithNoCode tryRegExp sessionStorageHash download deepEqual
|
||||||
closeCurrentTab capitalize CHROME_HAS_BORDER_BUG */
|
closeCurrentTab capitalize CHROME_HAS_BORDER_BUG */
|
||||||
/* global promisify */
|
/* global promisifyChrome */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const CHROME = Boolean(chrome.app) && parseInt(navigator.userAgent.match(/Chrom\w+\/(\d+)|$/)[1]);
|
const CHROME = Boolean(chrome.app) && parseInt(navigator.userAgent.match(/Chrom\w+\/(\d+)|$/)[1]);
|
||||||
|
@ -93,33 +93,20 @@ if (IS_BG) {
|
||||||
// Object.defineProperty(window, 'localStorage', {value: {}});
|
// Object.defineProperty(window, 'localStorage', {value: {}});
|
||||||
// Object.defineProperty(window, 'sessionStorage', {value: {}});
|
// Object.defineProperty(window, 'sessionStorage', {value: {}});
|
||||||
|
|
||||||
const createTab = promisify(chrome.tabs.create.bind(chrome.tabs));
|
promisifyChrome({
|
||||||
const queryTabs = promisify(chrome.tabs.query.bind(chrome.tabs));
|
tabs: ['create', 'get', 'getCurrent', 'move', 'query', 'update'],
|
||||||
const updateTab = promisify(chrome.tabs.update.bind(chrome.tabs));
|
windows: ['create', 'update'], // Android doesn't have chrome.windows
|
||||||
const moveTabs = promisify(chrome.tabs.move.bind(chrome.tabs));
|
});
|
||||||
|
|
||||||
// Android doesn't have chrome.windows
|
|
||||||
const updateWindow = chrome.windows && promisify(chrome.windows.update.bind(chrome.windows));
|
|
||||||
const createWindow = chrome.windows && promisify(chrome.windows.create.bind(chrome.windows));
|
|
||||||
// FF57+ supports openerTabId, but not in Android
|
// FF57+ supports openerTabId, but not in Android
|
||||||
// (detecting FF57 by the feature it added, not navigator.ua which may be spoofed in about:config)
|
// (detecting FF57 by the feature it added, not navigator.ua which may be spoofed in about:config)
|
||||||
const openerTabIdSupported = (!FIREFOX || window.AbortController) && chrome.windows != null;
|
const openerTabIdSupported = (!FIREFOX || window.AbortController) && chrome.windows != null;
|
||||||
|
|
||||||
function getTab(id) {
|
|
||||||
return new Promise(resolve =>
|
|
||||||
chrome.tabs.get(id, tab =>
|
|
||||||
!chrome.runtime.lastError && resolve(tab)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function getOwnTab() {
|
function getOwnTab() {
|
||||||
return new Promise(resolve =>
|
return browser.tabs.getCurrent();
|
||||||
chrome.tabs.getCurrent(tab => resolve(tab)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getActiveTab() {
|
function getActiveTab() {
|
||||||
return queryTabs({currentWindow: true, active: true})
|
return browser.tabs.query({currentWindow: true, active: true})
|
||||||
.then(tabs => tabs[0]);
|
.then(tabs => tabs[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +127,7 @@ function urlToMatchPattern(url, ignoreSearch) {
|
||||||
|
|
||||||
function findExistingTab({url, currentWindow, ignoreHash = true, ignoreSearch = false}) {
|
function findExistingTab({url, currentWindow, ignoreHash = true, ignoreSearch = false}) {
|
||||||
url = new URL(url);
|
url = new URL(url);
|
||||||
return queryTabs({url: urlToMatchPattern(url, ignoreSearch), currentWindow})
|
return browser.tabs.query({url: urlToMatchPattern(url, ignoreSearch), currentWindow})
|
||||||
// FIXME: is tab.url always normalized?
|
// FIXME: is tab.url always normalized?
|
||||||
.then(tabs => tabs.find(matchTab));
|
.then(tabs => tabs.find(matchTab));
|
||||||
|
|
||||||
|
@ -191,8 +178,8 @@ function openURL({
|
||||||
url: url !== tab.url && url.includes('#') ? url : undefined,
|
url: url !== tab.url && url.includes('#') ? url : undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (newWindow && createWindow) {
|
if (newWindow && browser.windows) {
|
||||||
return createWindow(Object.assign({url}, windowPosition))
|
return browser.windows.create(Object.assign({url}, windowPosition))
|
||||||
.then(wnd => wnd.tabs[0]);
|
.then(wnd => wnd.tabs[0]);
|
||||||
}
|
}
|
||||||
return getActiveTab().then((activeTab = {url: ''}) =>
|
return getActiveTab().then((activeTab = {url: ''}) =>
|
||||||
|
@ -205,7 +192,7 @@ function openURL({
|
||||||
if (id != null && !openerTab.incognito && openerTabIdSupported) {
|
if (id != null && !openerTab.incognito && openerTabIdSupported) {
|
||||||
options.openerTabId = id;
|
options.openerTabId = id;
|
||||||
}
|
}
|
||||||
return createTab(options);
|
return browser.tabs.create(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,9 +219,9 @@ function activateTab(tab, {url, index, openerTabId} = {}) {
|
||||||
options.openerTabId = openerTabId;
|
options.openerTabId = openerTabId;
|
||||||
}
|
}
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
updateTab(tab.id, options),
|
browser.tabs.update(tab.id, options),
|
||||||
updateWindow && updateWindow(tab.windowId, {focused: true}),
|
browser.windows && browser.windows.update(tab.windowId, {focused: true}),
|
||||||
index != null && moveTabs(tab.id, {index})
|
index != null && browser.tabs.move(tab.id, {index})
|
||||||
])
|
])
|
||||||
.then(() => tab);
|
.then(() => tab);
|
||||||
}
|
}
|
||||||
|
|
24
js/msg.js
24
js/msg.js
|
@ -1,12 +1,12 @@
|
||||||
/* global promisify deepCopy */
|
/* global promisifyChrome deepCopy */
|
||||||
// deepCopy is only used if the script is executed in extension pages.
|
// deepCopy is only used if the script is executed in extension pages.
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
||||||
const runtimeSend = promisify(chrome.runtime.sendMessage.bind(chrome.runtime));
|
promisifyChrome({
|
||||||
const tabSend = chrome.tabs && promisify(chrome.tabs.sendMessage.bind(chrome.tabs));
|
runtime: ['sendMessage'],
|
||||||
const tabQuery = chrome.tabs && promisify(chrome.tabs.query.bind(chrome.tabs));
|
tabs: ['sendMessage', 'query'],
|
||||||
|
});
|
||||||
const isBg = chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window;
|
const isBg = chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window;
|
||||||
if (isBg) {
|
if (isBg) {
|
||||||
window._msg = {
|
window._msg = {
|
||||||
|
@ -49,19 +49,21 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chrome.runtime.getBackgroundPage) {
|
if (chrome.runtime.getBackgroundPage) {
|
||||||
return promisify(chrome.runtime.getBackgroundPage.bind(chrome.runtime))()
|
promisifyChrome({
|
||||||
.catch(() => null);
|
runtime: ['getBackgroundPage'],
|
||||||
|
});
|
||||||
|
return browser.runtime.getBackgroundPage().catch(() => null);
|
||||||
}
|
}
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function send(data, target = 'extension') {
|
function send(data, target = 'extension') {
|
||||||
const message = {data, target};
|
const message = {data, target};
|
||||||
return runtimeSend(message).then(unwrapData);
|
return browser.runtime.sendMessage(message).then(unwrapData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendTab(tabId, data, options, target = 'tab') {
|
function sendTab(tabId, data, options, target = 'tab') {
|
||||||
return tabSend(tabId, {data, target}, options)
|
return browser.tabs.sendMessage(tabId, {data, target}, options)
|
||||||
.then(unwrapData);
|
.then(unwrapData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +101,7 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function broadcastTab(data, filter, options, ignoreExtension = false, target = 'tab') {
|
function broadcastTab(data, filter, options, ignoreExtension = false, target = 'tab') {
|
||||||
return tabQuery({})
|
return browser.tabs.query({})
|
||||||
// TODO: send to activated tabs first?
|
// TODO: send to activated tabs first?
|
||||||
.then(tabs => {
|
.then(tabs => {
|
||||||
const requests = [];
|
const requests = [];
|
||||||
|
@ -123,7 +125,7 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
||||||
const message = {data: dataObj, target};
|
const message = {data: dataObj, target};
|
||||||
if (tab && tab.id) {
|
if (tab && tab.id) {
|
||||||
requests.push(
|
requests.push(
|
||||||
tabSend(tab.id, message, options)
|
browser.tabs.sendMessage(tab.id, message, options)
|
||||||
.then(unwrapData)
|
.then(unwrapData)
|
||||||
.catch(ignoreError)
|
.catch(ignoreError)
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
// eslint-disable-next-line no-unused-expressions
|
// eslint-disable-next-line no-unused-expressions
|
||||||
self.INJECTED !== 1 && (() => {
|
self.INJECTED !== 1 && (() => {
|
||||||
|
|
||||||
|
// this part runs in workers, content scripts, our extension pages
|
||||||
|
|
||||||
if (!Object.entries) {
|
if (!Object.entries) {
|
||||||
Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]]);
|
Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]]);
|
||||||
}
|
}
|
||||||
|
@ -10,9 +12,38 @@ self.INJECTED !== 1 && (() => {
|
||||||
Object.values = obj => Object.keys(obj).map(k => obj[k]);
|
Object.values = obj => Object.keys(obj).map(k => obj[k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the above was shared by content scripts and workers,
|
// don't use self.chrome. It is undefined in Firefox
|
||||||
// the rest is only needed for our extension pages
|
if (typeof chrome !== 'object') return;
|
||||||
if (!self.chrome || !self.chrome.tabs) return;
|
// the rest is for content scripts and our extension pages
|
||||||
|
|
||||||
|
self.browser = polyfillBrowser();
|
||||||
|
|
||||||
|
/* Promisifies the specified `chrome` methods into `browser`.
|
||||||
|
The definitions is an object like this: {
|
||||||
|
'storage.sync': ['get', 'set'], // if deeper than one level, combine the path via `.`
|
||||||
|
windows: ['create', 'update'], // items and sub-objects will only be created if present in `chrome`
|
||||||
|
} */
|
||||||
|
self.promisifyChrome = definitions => {
|
||||||
|
for (const [scopeName, methods] of Object.entries(definitions)) {
|
||||||
|
const path = scopeName.split('.');
|
||||||
|
const src = path.reduce((obj, p) => obj && obj[p], chrome);
|
||||||
|
if (!src) continue;
|
||||||
|
const dst = path.reduce((obj, p) => obj[p] || (obj[p] = {}), browser);
|
||||||
|
for (const name of methods) {
|
||||||
|
const fn = src[name];
|
||||||
|
if (!fn || dst[name] && !dst[name].isTrap) continue;
|
||||||
|
dst[name] = (...args) => new Promise((resolve, reject) =>
|
||||||
|
fn.call(src, ...args, (...results) =>
|
||||||
|
chrome.runtime.lastError ?
|
||||||
|
reject(chrome.runtime.lastError) :
|
||||||
|
resolve(results.length <= 1 ? results[0] : results)));
|
||||||
|
// a couple of callbacks have 2 parameters (we don't use those methods, but just in case)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!chrome.tabs) return;
|
||||||
|
// the rest is for our extension pages
|
||||||
|
|
||||||
if (typeof document === 'object') {
|
if (typeof document === 'object') {
|
||||||
const ELEMENT_METH = {
|
const ELEMENT_METH = {
|
||||||
|
@ -75,4 +106,27 @@ self.INJECTED !== 1 && (() => {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Object.defineProperty(self, 'sessionStorage', {value: {}});
|
Object.defineProperty(self, 'sessionStorage', {value: {}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function polyfillBrowser() {
|
||||||
|
if (typeof browser === 'object' && browser.runtime) {
|
||||||
|
return browser;
|
||||||
|
}
|
||||||
|
return createTrap(chrome, null);
|
||||||
|
|
||||||
|
function createTrap(base, parent) {
|
||||||
|
const target = typeof base === 'function' ? () => {} : {};
|
||||||
|
target.isTrap = true;
|
||||||
|
return new Proxy(target, {
|
||||||
|
get: (target, prop) => {
|
||||||
|
if (target[prop]) return target[prop];
|
||||||
|
if (base[prop] && (typeof base[prop] === 'object' || typeof base[prop] === 'function')) {
|
||||||
|
target[prop] = createTrap(base[prop], base);
|
||||||
|
return target[prop];
|
||||||
|
}
|
||||||
|
return base[prop];
|
||||||
|
},
|
||||||
|
apply: (target, thisArg, args) => base.apply(parent, args)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|
11
js/prefs.js
11
js/prefs.js
|
@ -1,4 +1,4 @@
|
||||||
/* global promisify */
|
/* global promisifyChrome */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
||||||
|
@ -107,10 +107,11 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
||||||
specific: new Map(),
|
specific: new Map(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const syncSet = promisify(chrome.storage.sync.set.bind(chrome.storage.sync));
|
promisifyChrome({
|
||||||
const syncGet = promisify(chrome.storage.sync.get.bind(chrome.storage.sync));
|
'storage.sync': ['get', 'set'],
|
||||||
|
});
|
||||||
|
|
||||||
const initializing = syncGet('settings')
|
const initializing = browser.storage.sync.get('settings')
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (result.settings) {
|
if (result.settings) {
|
||||||
setAll(result.settings, true);
|
setAll(result.settings, true);
|
||||||
|
@ -237,7 +238,7 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
timer = null;
|
timer = null;
|
||||||
syncSet({settings: values})
|
browser.storage.sync.set({settings: values})
|
||||||
.then(resolve, reject);
|
.then(resolve, reject);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
'use strict';
|
|
||||||
/*
|
|
||||||
Convert chrome APIs into promises. Example:
|
|
||||||
|
|
||||||
const storageSyncGet = promisify(chrome.storage.sync.get.bind(chrome.storage.sync));
|
|
||||||
storageSyncGet(['key']).then(result => {...});
|
|
||||||
|
|
||||||
*/
|
|
||||||
self.promisify = self.INJECTED === 1 ? self.promisify : fn =>
|
|
||||||
(...args) =>
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
fn(...args, (...result) => {
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
reject(chrome.runtime.lastError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(
|
|
||||||
result.length === 0 ? undefined :
|
|
||||||
result.length === 1 ? result[0] : result
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,7 +1,12 @@
|
||||||
/* global loadScript tryJSONparse */
|
/* global loadScript tryJSONparse promisifyChrome */
|
||||||
/* exported chromeLocal chromeSync */
|
/* exported chromeLocal chromeSync */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
promisifyChrome({
|
||||||
|
'storage.local': ['get', 'remove', 'set'],
|
||||||
|
'storage.sync': ['get', 'remove', 'set'],
|
||||||
|
});
|
||||||
|
|
||||||
const [chromeLocal, chromeSync] = (() => {
|
const [chromeLocal, chromeSync] = (() => {
|
||||||
return [
|
return [
|
||||||
createWrapper('local'),
|
createWrapper('local'),
|
||||||
|
@ -9,11 +14,11 @@ const [chromeLocal, chromeSync] = (() => {
|
||||||
];
|
];
|
||||||
|
|
||||||
function createWrapper(name) {
|
function createWrapper(name) {
|
||||||
const storage = chrome.storage[name];
|
const storage = browser.storage[name];
|
||||||
const wrapper = {
|
const wrapper = {
|
||||||
get: data => new Promise(resolve => storage.get(data, resolve)),
|
get: storage.get.bind(storage),
|
||||||
set: data => new Promise(resolve => storage.set(data, () => resolve(data))),
|
set: data => storage.set(data).then(() => data),
|
||||||
remove: data => new Promise(resolve => storage.remove(data, resolve)),
|
remove: storage.remove.bind(storage),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} key
|
* @param {String} key
|
||||||
|
|
|
@ -147,7 +147,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="js/polyfill.js"></script>
|
<script src="js/polyfill.js"></script>
|
||||||
<script src="js/promisify.js"></script>
|
|
||||||
<script src="js/dom.js"></script>
|
<script src="js/dom.js"></script>
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
<script src="js/prefs.js"></script>
|
<script src="js/prefs.js"></script>
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"js/polyfill.js",
|
"js/polyfill.js",
|
||||||
"js/promisify.js",
|
|
||||||
"js/messaging.js",
|
"js/messaging.js",
|
||||||
"js/msg.js",
|
"js/msg.js",
|
||||||
"js/storage-util.js",
|
"js/storage-util.js",
|
||||||
|
@ -77,7 +76,6 @@
|
||||||
"match_about_blank": true,
|
"match_about_blank": true,
|
||||||
"js": [
|
"js": [
|
||||||
"js/polyfill.js",
|
"js/polyfill.js",
|
||||||
"js/promisify.js",
|
|
||||||
"js/msg.js",
|
"js/msg.js",
|
||||||
"js/prefs.js",
|
"js/prefs.js",
|
||||||
"content/style-injector.js",
|
"content/style-injector.js",
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
<script src="js/polyfill.js"></script>
|
<script src="js/polyfill.js"></script>
|
||||||
<script src="js/dom.js"></script>
|
<script src="js/dom.js"></script>
|
||||||
<script src="js/promisify.js"></script>
|
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
<script src="js/msg.js"></script>
|
<script src="js/msg.js"></script>
|
||||||
<script src="js/localization.js"></script>
|
<script src="js/localization.js"></script>
|
||||||
|
|
|
@ -179,7 +179,6 @@
|
||||||
<script src="manage/config-dialog.js"></script>
|
<script src="manage/config-dialog.js"></script>
|
||||||
|
|
||||||
<script src="js/polyfill.js"></script>
|
<script src="js/polyfill.js"></script>
|
||||||
<script src="js/promisify.js"></script>
|
|
||||||
<script src="js/dom.js"></script>
|
<script src="js/dom.js"></script>
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
<script src="js/localization.js"></script>
|
<script src="js/localization.js"></script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* global tabURL handleEvent $ $$ prefs template FIREFOX chromeLocal debounce
|
/* global tabURL handleEvent $ $$ prefs template FIREFOX chromeLocal debounce
|
||||||
$create t API tWordBreak formatDate tryCatch tryJSONparse LZString
|
$create t API tWordBreak formatDate tryCatch tryJSONparse LZString
|
||||||
ignoreChromeError download */
|
promisifyChrome download */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
window.addEventListener('showStyles:done', function _() {
|
window.addEventListener('showStyles:done', function _() {
|
||||||
|
@ -88,6 +88,9 @@ window.addEventListener('showStyles:done', function _() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
promisifyChrome({
|
||||||
|
'storage.local': ['getBytesInUse'], // FF doesn't implement it
|
||||||
|
});
|
||||||
setTimeout(() => document.body.classList.add(BODY_CLASS));
|
setTimeout(() => document.body.classList.add(BODY_CLASS));
|
||||||
|
|
||||||
$('#find-styles-inline-group').classList.add('hidden');
|
$('#find-styles-inline-group').classList.add('hidden');
|
||||||
|
@ -711,7 +714,7 @@ window.addEventListener('showStyles:done', function _() {
|
||||||
return chromeLocal.loadLZStringScript().then(() =>
|
return chromeLocal.loadLZStringScript().then(() =>
|
||||||
tryJSONparse(LZString.decompressFromUTF16(item.payload)));
|
tryJSONparse(LZString.decompressFromUTF16(item.payload)));
|
||||||
} else if (item) {
|
} else if (item) {
|
||||||
chrome.storage.local.remove(key);
|
chromeLocal.remove(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -742,16 +745,8 @@ window.addEventListener('showStyles:done', function _() {
|
||||||
|
|
||||||
function cleanupCache() {
|
function cleanupCache() {
|
||||||
chromeLocal.remove(CACHE_CLEANUP_NEEDED);
|
chromeLocal.remove(CACHE_CLEANUP_NEEDED);
|
||||||
if (chrome.storage.local.getBytesInUse) {
|
Promise.resolve(!browser.storage.local.getBytesInUse ? 1e99 : browser.storage.local.getBytesInUse())
|
||||||
chrome.storage.local.getBytesInUse(null, size => {
|
.then(size => size > CACHE_SIZE && chromeLocal.get().then(cleanupCacheInternal));
|
||||||
if (size > CACHE_SIZE) {
|
|
||||||
chrome.storage.local.get(null, cleanupCacheInternal);
|
|
||||||
}
|
|
||||||
ignoreChromeError();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
chrome.storage.local.get(null, cleanupCacheInternal);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanupCacheInternal(storage) {
|
function cleanupCacheInternal(storage) {
|
||||||
|
@ -764,9 +759,8 @@ window.addEventListener('showStyles:done', function _() {
|
||||||
sortedByTime.slice(0, sortedByTime.length / 2);
|
sortedByTime.slice(0, sortedByTime.length / 2);
|
||||||
const toRemove = expired.length ? expired : sortedByTime;
|
const toRemove = expired.length ? expired : sortedByTime;
|
||||||
if (toRemove.length) {
|
if (toRemove.length) {
|
||||||
chrome.storage.local.remove(toRemove.map(item => item.key), ignoreChromeError);
|
chromeLocal.remove(toRemove.map(item => item.key));
|
||||||
}
|
}
|
||||||
ignoreChromeError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
Loading…
Reference in New Issue
Block a user