WIP: broadcastMessage

This commit is contained in:
eight 2018-10-05 01:03:40 +08:00
parent c01f93f62c
commit f1639cc33e
9 changed files with 134 additions and 96 deletions

View File

@ -13,6 +13,7 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, {
// getStyles,
getSectionsByUrl: styleManager.getSectionsByUrl,
getSectionsById: styleManager.getSectionsById,
getStylesInfo: styleManager.getStylesInfo,
// saveStyle,
// deleteStyle,

View File

@ -1,4 +1,4 @@
/* global createCache db calcStyleDigest normalizeStyleSections db */
/* global createCache db calcStyleDigest normalizeStyleSections db promisify */
'use strict';
const styleManager = (() => {
@ -8,18 +8,37 @@ const styleManager = (() => {
const compiledRe = createCache();
const compiledExclusion = createCache();
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?
return ensurePrepared({
getSectionsForURL,
styles,
cachedStyleForUrl,
getStylesInfo,
getSectionsByUrl,
installStyle,
deleteStyle,
setStyleExclusions,
editSave
editSave,
toggleStyle
// TODO: get all styles API?
// TODO: get style by ID?
});
function toggleStyle(id, enabled) {
const style = styles.get(id);
style.enabled = enabled;
return saveStyle(style)
.then(() => broadcastMessage('styleUpdated', {id, enabled}));
}
function getStylesInfo() {
// FIXME: remove code?
return [...styles.values()];
}
function editSave() {}
function setStyleExclusions() {}
@ -105,14 +124,14 @@ const styleManager = (() => {
}
}
function getSectionsForURL(url) {
function getSectionsByUrl(url) {
// if (!URLS.supported(url) || prefs.get('disableAll')) {
// return [];
// }
let result = cachedStyleForUrl.get(url);
if (!result) {
result = [];
for (const style of styles) {
for (const style of styles.values()) {
if (!urlMatchStyle(url, style)) {
continue;
}
@ -213,4 +232,81 @@ const styleManager = (() => {
function getUrlNoHash(url) {
return url.split('#')[0];
}
function cleanData(method, data) {
if (
(method === 'styleUpdated' || method === 'styleAdded') &&
(data.sections || data.sourceCode)
) {
// apply/popup/manage use only meta for these two methods,
// editor may need the full code but can fetch it directly,
// so we send just the meta to avoid spamming lots of tabs with huge styles
return getStyleWithNoCode(data);
}
return output;
}
function isExtensionStyle(id) {
// TODO
// const style = styles.get(id);
// if (!style)
return false;
}
function broadcastMessage(method, data) {
const pendingPrivilage = runtimeSendMessage({method, cleanData(method, data)});
// const affectsAll = !msg.affects || msg.affects.all;
// const affectsOwnOriginOnly =
// !affectsAll && (msg.affects.editor || msg.affects.manager);
// const affectsTabs = affectsAll || affectsOwnOriginOnly;
// const affectsIcon = affectsAll || msg.affects.icon;
// const affectsPopup = affectsAll || msg.affects.popup;
// const affectsSelf = affectsPopup || msg.prefs;
// notify all open extension pages and popups
// if (affectsSelf) {
// msg.tabId = undefined;
// sendMessage(msg, ignoreChromeError);
// }
// notify tabs
if (affectsTabs || affectsIcon) {
const notifyTab = tab => {
if (!styleUpdated
&& (affectsTabs || URLS.optionsUI.includes(tab.url))
// own pages are already notified via sendMessage
&& !(affectsSelf && tab.url.startsWith(URLS.ownOrigin))
// skip lazy-loaded aka unloaded tabs that seem to start loading on message in FF
&& (!FIREFOX || tab.width)) {
msg.tabId = tab.id;
sendMessage(msg, ignoreChromeError);
}
if (affectsIcon) {
// eslint-disable-next-line no-use-before-define
// debounce(API.updateIcon, 0, {tab});
}
};
// list all tabs including chrome-extension:// which can be ours
Promise.all([
queryTabs(isExtensionStyle(data.id) ? {url: URLS.ownOrigin + '*'} : {}),
getActiveTab(),
]).then(([tabs, activeTab]) => {
const activeTabId = activeTab && activeTab.id;
for (const tab of tabs) {
invokeOrPostpone(tab.id === activeTabId, notifyTab, tab);
}
});
}
// notify self: the message no longer is sent to the origin in new Chrome
if (typeof onRuntimeMessage !== 'undefined') {
onRuntimeMessage(originalMessage);
}
// notify apply.js on own pages
if (typeof applyOnMessage !== 'undefined') {
applyOnMessage(originalMessage);
}
// propagate saved style state/code efficiently
if (styleUpdated) {
msg.refreshOwnTabs = false;
API.refreshAllTabs(msg);
}
}
})();

View File

@ -1,3 +1,4 @@
/* global promisify */
'use strict';
const API = (() => {
@ -12,29 +13,13 @@ const API = (() => {
function sendMessage(msg) {
return runtimeSendMessage(msg)
.then(result => {
if (result.__ERROR__) {
if (result && result.__ERROR__) {
throw new Error(result.__ERROR__);
}
return result;
});
}
function promisify(fn) {
return (...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[1] : result
);
});
});
}
function invokeBG(name, args) {
return preparing.then(BG => {
if (!BG) {
@ -48,7 +33,11 @@ const API = (() => {
if (BG !== window) {
args = BG.deepCopy(args);
}
return BG.API_METHODS[name](...args)
const fn = BG.API_METHODS[name];
if (!fn) {
throw new Error(`unknown API method: ${name}`);
}
return Promise.resolve(fn(...args))
.then(BG.deepCopy);
});
}

View File

@ -116,7 +116,7 @@
break;
case 'styleUpdated':
if (request.codeIsUpdated === false) {
if (!request.codeIsUpdated) {
applyStyleState(request.style);
break;
}

View File

@ -104,71 +104,6 @@ if (FIREFOX_NO_DOM_STORAGE) {
Object.defineProperty(window, 'sessionStorage', {value: {}});
}
function notifyAllTabs(msg) {
const originalMessage = msg;
const styleUpdated = msg.method === 'styleUpdated' || msg.method === 'exclusionsUpdated';
if (styleUpdated || msg.method === 'styleAdded') {
// apply/popup/manage use only meta for these two methods,
// editor may need the full code but can fetch it directly,
// so we send just the meta to avoid spamming lots of tabs with huge styles
msg = Object.assign({}, msg, {
style: getStyleWithNoCode(msg.style)
});
}
const affectsAll = !msg.affects || msg.affects.all;
const affectsOwnOriginOnly = !affectsAll && (msg.affects.editor || msg.affects.manager);
const affectsTabs = affectsAll || affectsOwnOriginOnly;
const affectsIcon = affectsAll || msg.affects.icon;
const affectsPopup = affectsAll || msg.affects.popup;
const affectsSelf = affectsPopup || msg.prefs;
// notify all open extension pages and popups
if (affectsSelf) {
msg.tabId = undefined;
sendMessage(msg, ignoreChromeError);
}
// notify tabs
if (affectsTabs || affectsIcon) {
const notifyTab = tab => {
if (!styleUpdated
&& (affectsTabs || URLS.optionsUI.includes(tab.url))
// own pages are already notified via sendMessage
&& !(affectsSelf && tab.url.startsWith(URLS.ownOrigin))
// skip lazy-loaded aka unloaded tabs that seem to start loading on message in FF
&& (!FIREFOX || tab.width)) {
msg.tabId = tab.id;
sendMessage(msg, ignoreChromeError);
}
if (affectsIcon) {
// eslint-disable-next-line no-use-before-define
debounce(API.updateIcon, 0, {tab});
}
};
// list all tabs including chrome-extension:// which can be ours
Promise.all([
queryTabs(affectsOwnOriginOnly ? {url: URLS.ownOrigin + '*'} : {}),
getActiveTab(),
]).then(([tabs, activeTab]) => {
const activeTabId = activeTab && activeTab.id;
for (const tab of tabs) {
invokeOrPostpone(tab.id === activeTabId, notifyTab, tab);
}
});
}
// notify self: the message no longer is sent to the origin in new Chrome
if (typeof onRuntimeMessage !== 'undefined') {
onRuntimeMessage(originalMessage);
}
// notify apply.js on own pages
if (typeof applyOnMessage !== 'undefined') {
applyOnMessage(originalMessage);
}
// propagate saved style state/code efficiently
if (styleUpdated) {
msg.refreshOwnTabs = false;
API.refreshAllTabs(msg);
}
}
function sendMessage(msg, callback) {
/*
Promise mode [default]:

17
js/promisify.js Normal file
View File

@ -0,0 +1,17 @@
'use strict';
function promisify(fn) {
return (...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
);
});
});
}

View File

@ -153,9 +153,11 @@
</p>
</template>
<script src="js/promisify.js"></script>
<script src="js/dom.js"></script>
<script src="js/messaging.js"></script>
<script src="js/prefs.js"></script>
<script src="content/api.js"></script>
<script src="content/apply.js"></script>
<script src="js/localization.js"></script>
<script src="manage/filters.js"></script>

View File

@ -32,7 +32,7 @@ const OWN_ICON = chrome.runtime.getManifest().icons['16'];
const handleEvent = {};
Promise.all([
API.getStyles({omitCode: !BG}),
API.getStylesInfo(),
urlFilterParam && API.searchDB({query: 'url:' + urlFilterParam}),
onDOMready().then(initGlobalEvents),
]).then(args => {
@ -195,7 +195,7 @@ function createStyleElement({style, name}) {
};
}
const parts = createStyleElement.parts;
const configurable = style.usercssData && Object.keys(style.usercssData.vars).length > 0;
const configurable = style.usercssData && style.usercssData.vars && Object.keys(style.usercssData.vars).length > 0;
parts.checker.checked = style.enabled;
parts.nameLink.textContent = tWordBreak(style.name);
parts.nameLink.href = parts.editLink.href = parts.editHrefBase + style.id;
@ -403,10 +403,7 @@ Object.assign(handleEvent, {
},
toggle(event, entry) {
API.saveStyle({
id: entry.styleId,
enabled: this.matches('.enable') || this.checked,
});
API.toggleStyle(entry.styleId, this.matches('.enable') || this.checked);
},
check(event, entry) {

View File

@ -23,6 +23,7 @@
],
"background": {
"scripts": [
"js/promisify.js",
"js/messaging.js",
"js/storage-util.js",
"js/sections-equal.js",
@ -60,7 +61,7 @@
"run_at": "document_start",
"all_frames": true,
"match_about_blank": true,
"js": ["content/api.js", "content/apply.js"]
"js": ["js/promisify.js", "content/api.js", "content/apply.js"]
},
{
"matches": ["http://userstyles.org/*", "https://userstyles.org/*"],