Change: switch to msg.js

This commit is contained in:
eight 2018-10-06 13:02:45 +08:00
parent 05d582c726
commit fa3127d988
12 changed files with 123 additions and 128 deletions

View File

@ -53,7 +53,7 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, {
optionsCustomizeHotkeys() { optionsCustomizeHotkeys() {
return browser.runtime.openOptionsPage() return browser.runtime.openOptionsPage()
.then(() => new Promise(resolve => setTimeout(resolve, 100))) .then(() => new Promise(resolve => setTimeout(resolve, 100)))
.then(() => sendMessage({method: 'optionsCustomizeHotkeys'})); .then(() => msg.broadcastExtension({method: 'optionsCustomizeHotkeys'}));
}, },
}); });
@ -62,7 +62,7 @@ var browserCommands, contextMenus;
// ************************************************************************* // *************************************************************************
// register all listeners // register all listeners
chrome.runtime.onMessage.addListener(onRuntimeMessage); msg.on(onRuntimeMessage);
if (FIREFOX) { if (FIREFOX) {
// see notes in apply.js for getStylesFallback // see notes in apply.js for getStylesFallback
@ -196,7 +196,7 @@ contextMenus = {
contexts: ['editable'], contexts: ['editable'],
documentUrlPatterns: [URLS.ownOrigin + 'edit*'], documentUrlPatterns: [URLS.ownOrigin + 'edit*'],
click: (info, tab) => { click: (info, tab) => {
sendMessage({tabId: tab.id, method: 'editDeleteText'}); msg.sendTab(tab.id, {method: 'editDeleteText'});
}, },
} }
}; };
@ -280,11 +280,12 @@ window.addEventListener('storageReady', function _() {
}; };
const pingCS = (cs, {id, url}) => { const pingCS = (cs, {id, url}) => {
const maybeInject = pong => !pong && injectCS(cs, id); const maybeInject = ;
cs.matches.some(match => { cs.matches.some(match => {
if ((match === ALL_URLS || url.match(match)) && if ((match === ALL_URLS || url.match(match)) &&
(!url.startsWith('chrome') || url === NTP)) { (!url.startsWith('chrome') || url === NTP)) {
sendMessage({method: 'ping', tabId: id}, maybeInject); msg.sendTab(id, {method: 'ping'})
.then(pong => !pong && injectCS(cs, id));
return true; return true;
} }
}); });
@ -332,13 +333,15 @@ function webNavigationListener(method, {url, tabId, frameId}) {
handleCssTransitionBug({tabId, frameId, url, styles}); handleCssTransitionBug({tabId, frameId, url, styles});
} }
if (tab) styles.exposeIframes = tab.url.replace(/(\/\/[^/]*).*/, '$1'); if (tab) styles.exposeIframes = tab.url.replace(/(\/\/[^/]*).*/, '$1');
sendMessage({ msg.sendTab(
tabId, tabId,
frameId, {
method, method,
// ping own page so it retrieves the styles directly // ping own page so it retrieves the styles directly
styles: url.startsWith(URLS.ownOrigin) ? 'DIY' : styles, styles: url.startsWith(URLS.ownOrigin) ? 'DIY' : styles,
}); },
{frameId}
);
} }
// main page frame id is 0 // main page frame id is 0
if (frameId === 0) { if (frameId === 0) {
@ -370,7 +373,7 @@ function webNavigationListenerChrome(method, data) {
function webNavUsercssInstallerFF(data) { function webNavUsercssInstallerFF(data) {
const {tabId} = data; const {tabId} = data;
Promise.all([ Promise.all([
sendMessage({tabId, method: 'ping'}), msg.sendTab(tabId, {method: 'ping'}),
// we need tab index to open the installer next to the original one // we need tab index to open the installer next to the original one
// and also to skip the double-invocation in FF which assigns tab url later // and also to skip the double-invocation in FF which assigns tab url later
getTab(tabId), getTab(tabId),
@ -384,15 +387,15 @@ function webNavUsercssInstallerFF(data) {
function webNavIframeHelperFF({tabId, frameId}) { function webNavIframeHelperFF({tabId, frameId}) {
if (!frameId) return; if (!frameId) return;
sendMessage({method: 'ping', tabId, frameId}, pong => { msg.sendTab(tabId, {method: 'ping'}, {frameId})
ignoreChromeError(); .then(pong => {
if (pong) return; if (pong) return;
chrome.tabs.executeScript(tabId, { chrome.tabs.executeScript(tabId, {
frameId, frameId,
file: '/content/apply.js', file: '/content/apply.js',
matchAboutBlank: true, matchAboutBlank: true,
}, ignoreChromeError); }, ignoreChromeError);
}); });
} }
@ -498,35 +501,14 @@ function updateIcon({tab, styles}) {
} }
} }
function onRuntimeMessage(msg, sender) {
function onRuntimeMessage(msg, sender, sendResponse) {
if (msg.method !== 'invokeAPI') { if (msg.method !== 'invokeAPI') {
// FIXME: switch everything to api.js then throw an error when msg.method is unknown.
return; return;
} }
invoke() const fn = window.API_METHODS[msg.name];
.catch(err => if (!fn) {
// wrap 'Error' object instance as {__ERROR__: message}, throw new Error(`unknown API: ${msg.name}`);
// which will be unwrapped by api.js,
({
__ERROR__: err.message || String(err)
})
)
// prevent exceptions on sending to a closed tab
.then(output => tryCatch(sendResponse, output));
// keep channel open
return true;
function invoke() {
try {
const fn = window.API_METHODS[msg.name];
if (!fn) {
throw new Error(`unknown API: ${msg.name}`);
}
const context = {msg, sender};
return Promise.resolve(fn.apply(context, msg.args));
} catch (err) {
return Promise.reject(err);
}
} }
const context = {msg, sender};
return fn.apply(context, msg.args);
} }

View File

@ -1,6 +1,8 @@
/* eslint no-eq-null: 0, eqeqeq: [2, "smart"] */ /* eslint no-eq-null: 0, eqeqeq: [2, "smart"] */
/* global createCache db calcStyleDigest normalizeStyleSections db promisify /*
getStyleWithNoCode */ global createCache db calcStyleDigest normalizeStyleSections db promisify
getStyleWithNoCode msg
*/
'use strict'; 'use strict';
const styleManager = (() => { const styleManager = (() => {
@ -10,9 +12,6 @@ const styleManager = (() => {
const compiledRe = createCache(); const compiledRe = createCache();
const compiledExclusion = createCache(); const compiledExclusion = createCache();
const BAD_MATCHER = {test: () => false}; const BAD_MATCHER = {test: () => false};
const tabQuery = promisify(chrome.tabs.query.bind(chrome.tabs));
const tabSendMessage = promisify(chrome.tabs.sendMessage.bind(chrome.tabs));
const runtimeSendMessage = promisify(chrome.runtime.sendMessage.bind(chrome.runtime));
// FIXME: do we have to prepare `styles` map for all methods? // FIXME: do we have to prepare `styles` map for all methods?
return ensurePrepared({ return ensurePrepared({
@ -42,11 +41,15 @@ const styleManager = (() => {
return saveStyle(newData) return saveStyle(newData)
.then(newData => { .then(newData => {
style.data = newData; style.data = newData;
return emitChanges({ const message = {
method: 'styleUpdated', method: 'styleUpdated',
codeIsUpdated: false, codeIsUpdated: false,
style: {id, enabled} style: {id, enabled}
}, style.appliesTo); };
if ([...style.appliesTo].every(isExtensionUrl)) {
return msg.broadcastExtension(message);
}
return msg.broadcast(message);
}) })
.then(() => id); .then(() => id);
} }
@ -120,6 +123,7 @@ const styleManager = (() => {
} }
function editSave(style) { function editSave(style) {
// const style =
return saveStyle(style); return saveStyle(style);
} }
@ -142,9 +146,9 @@ const styleManager = (() => {
delete cache[id]; delete cache[id];
} }
styles.delete(id); styles.delete(id);
return emitChanges({ return msg.broadcast({
method: 'styleDeleted', method: 'styleDeleted',
data: {id} style: {id}
}); });
}) })
.then(() => id); .then(() => id);
@ -182,28 +186,9 @@ const styleManager = (() => {
appliesTo, appliesTo,
data: newData data: newData
}); });
return Promise.all([ return Promis.all([
// manager and editor might be notified twice... msg.broadcastExtension({method: 'styleAdded', style: getStyleWithNoCode(newData)}),
runtimeSendMessage({method: 'styleAdded', style: getStyleWithNoCode(newData)}), msg.broadcastTab(tab => emitStyleAdded(tab, newData, appliesTo))
emitChangesToTabs(tab => {
const code = getAppliedCode(tab.url, newData);
if (!code) {
return;
}
const cache = cachedStyleForUrl.get(tab.url);
if (cache) {
cache[newData.id] = code;
}
appliesTo.add(tab.url);
return {
method: 'styleAdded',
style: {
id: newData.id,
enabled: newData.enabled,
sections: code
}
};
})
]); ]);
} else { } else {
const excluded = new Set(); const excluded = new Set();
@ -223,14 +208,51 @@ const styleManager = (() => {
} }
style.appliesTo = new Set(updated.keys()); style.appliesTo = new Set(updated.keys());
return Promise.all([ return Promise.all([
// FIXME: don't sendMessage msg.broadcastExtension({method: 'styleUpdated', style: getStyleWithNoCode(newData)})
runtimeSendMessage({method: 'styleUpdated', }) msg.broadcastTab(tab => {
if (excluded.has(tab.url)) {
return {
method: 'styleDeleted',
style: {id: newData.id}
};
}
if (updated.has(tab.url)) {
return {
method: 'styleUpdated',
style: {
id: newData.id,
sections: updated.get(tab.url)
};
};
}
return emitStyleAdded(tab, newData, style.appliesTo);
})
]) ])
} }
return style; return style;
}); });
} }
function emitStyleAdded(tab, data, appliesTo) {
const code = getAppliedCode(tab.url, data);
if (!code) {
return;
}
const cache = cachedStyleForUrl.get(tab.url);
if (cache) {
cache[data.id] = code;
}
appliesTo.add(tab.url);
return {
method: 'styleAdded',
style: {
id: data.id,
enabled: data.enabled,
sections: code
}
};
}
function importStyle(style) { function importStyle(style) {
// FIXME: move this to importer // FIXME: move this to importer
// style.originalDigest = style.originalDigest || style.styleDigest; // TODO: remove in the future // style.originalDigest = style.originalDigest || style.styleDigest; // TODO: remove in the future
@ -241,35 +263,16 @@ const styleManager = (() => {
} }
function saveStyle(style) { function saveStyle(style) {
return (style.id == null ? getNewStyle() : getOldStyle()) if (!style.name) {
.then(oldStyle => { throw new Error('style name is empty');
style = Object.assign(oldStyle, style); }
// FIXME: why we always run `normalizeStyleSections` at each `saveStyle`? return db.exec('put', style);
style.sections = normalizeStyleSections(style);
return db.exec('put', style);
})
.then(event => { .then(event => {
if (style.id == null) { if (style.id == null) {
style.id = event.target.result; style.id = event.target.result;
} }
return style; return style;
}); });
function getOldStyle() {
return db.exec('get', style.id)
.then((event, store) => {
if (!event.target.result) {
throw new Error(`Unknown style id: ${style.id}`);
}
return event.target.result;
});
}
// FIXME: don't overwrite style name when the name is empty
function getNewStyle() {
return Promise.resolve();
}
} }
function getStylesInfoForUrl(url) { function getStylesInfoForUrl(url) {

View File

@ -32,7 +32,7 @@
// } // }
applyStyles(styles); applyStyles(styles);
}); });
chrome.runtime.onMessage.addListener(applyOnMessage); msg.onTab(applyOnMessage);
window.applyOnMessage = applyOnMessage; window.applyOnMessage = applyOnMessage;
if (!isOwnPage) { if (!isOwnPage) {
@ -92,7 +92,7 @@
} }
} }
function applyOnMessage(request, sender, sendResponse) { function applyOnMessage(request) {
if (request.styles === 'DIY') { if (request.styles === 'DIY') {
// Do-It-Yourself tells our built-in pages to fetch the styles directly // Do-It-Yourself tells our built-in pages to fetch the styles directly
// which is faster because IPC messaging JSON-ifies everything internally // which is faster because IPC messaging JSON-ifies everything internally
@ -160,8 +160,7 @@
break; break;
case 'ping': case 'ping':
sendResponse(true); return true;
break;
} }
} }
@ -447,7 +446,7 @@
[docRewriteObserver, docRootObserver].forEach(ob => ob && ob.disconnect()); [docRewriteObserver, docRootObserver].forEach(ob => ob && ob.disconnect());
window.removeEventListener(chrome.runtime.id, orphanCheck, true); window.removeEventListener(chrome.runtime.id, orphanCheck, true);
try { try {
chrome.runtime.onMessage.removeListener(applyOnMessage); msg.off(applyOnMessage);
} catch (e) {} } catch (e) {}
} }

View File

@ -8,7 +8,7 @@
document.addEventListener('stylishInstallChrome', onClick); document.addEventListener('stylishInstallChrome', onClick);
document.addEventListener('stylishUpdateChrome', onClick); document.addEventListener('stylishUpdateChrome', onClick);
chrome.runtime.onMessage.addListener(onMessage); msg.on(onMessage);
onDOMready().then(() => { onDOMready().then(() => {
window.postMessage({ window.postMessage({
@ -43,16 +43,14 @@
} }
} }
function onMessage(msg, sender, sendResponse) { function onMessage(msg) {
switch (msg.method) { switch (msg.method) {
case 'ping': case 'ping':
// orphaned content script check // orphaned content script check
sendResponse(true); return true;
break;
case 'openSettings': case 'openSettings':
openSettings(); openSettings();
sendResponse(true); return true;
break;
} }
} }
@ -328,7 +326,7 @@
document.removeEventListener('stylishInstallChrome', onClick); document.removeEventListener('stylishInstallChrome', onClick);
document.removeEventListener('stylishUpdateChrome', onClick); document.removeEventListener('stylishUpdateChrome', onClick);
try { try {
chrome.runtime.onMessage.removeListener(onMessage); msg.off(onMessage);
} catch (e) {} } catch (e) {}
} }
})(); })();

View File

@ -131,7 +131,7 @@ function createAppliesToLineWidget(cm) {
cm.on('change', onChange); cm.on('change', onChange);
cm.on('optionChange', onOptionChange); cm.on('optionChange', onOptionChange);
chrome.runtime.onMessage.addListener(onRuntimeMessage); msg.onExtension(onRuntimeMessage);
requestAnimationFrame(updateWidgetStyle); requestAnimationFrame(updateWidgetStyle);
update(); update();
@ -144,7 +144,7 @@ function createAppliesToLineWidget(cm) {
widgets.length = 0; widgets.length = 0;
cm.off('change', onChange); cm.off('change', onChange);
cm.off('optionChange', onOptionChange); cm.off('optionChange', onOptionChange);
chrome.runtime.onMessage.removeListener(onRuntimeMessage); msg.off(onRuntimeMessage);
actualStyle.remove(); actualStyle.remove();
} }

View File

@ -27,7 +27,7 @@ let editor;
document.addEventListener('visibilitychange', beforeUnload); document.addEventListener('visibilitychange', beforeUnload);
chrome.runtime.onMessage.addListener(onRuntimeMessage); msg.on(onRuntimeMessage);
preinit(); preinit();

View File

@ -34,7 +34,8 @@ const msg = (() => {
broadcastExtension: send, // alias of send broadcastExtension: send, // alias of send
on, on,
onTab, onTab,
onExtension onExtension,
off
}; };
function send(data, target = 'extension') { function send(data, target = 'extension') {
@ -67,6 +68,7 @@ const msg = (() => {
throw new Error('there is no bg handler'); throw new Error('there is no bg handler');
} }
const handlers = bg._msg.handler.extension.concat(bg._msg.handler.both); const handlers = bg._msg.handler.extension.concat(bg._msg.handler.both);
// FIXME: do we want to deepCopy `data`?
return Promise.resolve(executeCallbacks(handlers, data, {url: location.href})) return Promise.resolve(executeCallbacks(handlers, data, {url: location.href}))
.then(deepCopy); .then(deepCopy);
} }
@ -88,6 +90,7 @@ const msg = (() => {
for (const tab of tabs) { for (const tab of tabs) {
const isExtension = tab.url.startsWith(EXTENSION_URL); const isExtension = tab.url.startsWith(EXTENSION_URL);
if ( if (
tab.discarded ||
!/^(http|ftp|file)/.test(tab.url) && !/^(http|ftp|file)/.test(tab.url) &&
!tab.url.startsWith('chrome://newtab/') && !tab.url.startsWith('chrome://newtab/') &&
!isExtension || !isExtension ||
@ -129,6 +132,15 @@ const msg = (() => {
handler.extension.push(fn); handler.extension.push(fn);
} }
function off(fn) {
for (const type of ['both', 'tab', 'extension']) {
const index = handler[type].indexOf(fn);
if (index >= 0) {
handler[type].splice(index, 1);
}
}
}
function initHandler() { function initHandler() {
if (handler) { if (handler) {
return; return;
@ -266,7 +278,7 @@ const msg = (() => {
const API = new Proxy({}, { const API = new Proxy({}, {
get: (target, name) => get: (target, name) =>
(...args) => msg.send({ (...args) => msg.sendBg({
method: 'invokeAPI', method: 'invokeAPI',
name, name,
args args

View File

@ -39,7 +39,7 @@ Promise.all([
showStyles(...args); showStyles(...args);
}); });
chrome.runtime.onMessage.addListener(onRuntimeMessage); msg.onExtension(onRuntimeMessage);
function onRuntimeMessage(msg) { function onRuntimeMessage(msg) {
switch (msg.method) { switch (msg.method) {

View File

@ -25,6 +25,7 @@
"scripts": [ "scripts": [
"js/promisify.js", "js/promisify.js",
"js/messaging.js", "js/messaging.js",
"js/msg.js",
"js/storage-util.js", "js/storage-util.js",
"js/sections-equal.js", "js/sections-equal.js",
"background/storage-dummy.js", "background/storage-dummy.js",

View File

@ -21,6 +21,8 @@
<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/promisify.js"></script>
<script src="js/msg.js"></script>
<script src="js/localization.js"></script> <script src="js/localization.js"></script>
<script src="js/prefs.js"></script> <script src="js/prefs.js"></script>
<script src="js/storage-util.js" async></script> <script src="js/storage-util.js" async></script>

View File

@ -21,7 +21,7 @@ if (!FIREFOX && !OPERA && CHROME < 3343) {
if (FIREFOX && 'update' in (chrome.commands || {})) { if (FIREFOX && 'update' in (chrome.commands || {})) {
$('[data-cmd="open-keyboard"]').classList.remove('chromium-only'); $('[data-cmd="open-keyboard"]').classList.remove('chromium-only');
chrome.runtime.onMessage.addListener(msg => { msg.onExtension(msg => {
if (msg.method === 'optionsCustomizeHotkeys') { if (msg.method === 'optionsCustomizeHotkeys') {
customizeHotkeys(); customizeHotkeys();
} }

View File

@ -26,7 +26,7 @@ getActiveTab().then(tab =>
showStyles(styles); showStyles(styles);
}); });
chrome.runtime.onMessage.addListener(onRuntimeMessage); msg.onExtension(onRuntimeMessage);
function onRuntimeMessage(msg) { function onRuntimeMessage(msg) {
switch (msg.method) { switch (msg.method) {
@ -112,8 +112,7 @@ function initPopup() {
} }
getActiveTab().then(function ping(tab, retryCountdown = 10) { getActiveTab().then(function ping(tab, retryCountdown = 10) {
const sendMessage = promisify(chrome.tabs.sendMessage.bind(chrome.tabs)); msg.sendTab(tab.id, {method: 'ping'}, {frameId: 0}).then(pong => {
sendMessage(tab.id, {method: 'ping'}, {frameId: 0}).then(pong => {
if (pong) { if (pong) {
return; return;
} }
@ -459,9 +458,8 @@ Object.assign(handleEvent, {
})) }))
.then(tab => { .then(tab => {
if (message) { if (message) {
const sendMessage = promisify(chrome.tabs.sendMessage.bind(chrome.tabs.sendMessage));
return onTabReady(tab) return onTabReady(tab)
.then(() => sendMessage(tab.id, message)); .then(() => msg.sendTab(tab.id, message));
} }
}) })
.then(window.close); .then(window.close);