WIP: broadcastMessage
This commit is contained in:
parent
c01f93f62c
commit
f1639cc33e
|
@ -13,6 +13,7 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, {
|
||||||
// getStyles,
|
// getStyles,
|
||||||
getSectionsByUrl: styleManager.getSectionsByUrl,
|
getSectionsByUrl: styleManager.getSectionsByUrl,
|
||||||
getSectionsById: styleManager.getSectionsById,
|
getSectionsById: styleManager.getSectionsById,
|
||||||
|
getStylesInfo: styleManager.getStylesInfo,
|
||||||
// saveStyle,
|
// saveStyle,
|
||||||
// deleteStyle,
|
// deleteStyle,
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global createCache db calcStyleDigest normalizeStyleSections db */
|
/* global createCache db calcStyleDigest normalizeStyleSections db promisify */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const styleManager = (() => {
|
const styleManager = (() => {
|
||||||
|
@ -8,18 +8,37 @@ 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({
|
||||||
getSectionsForURL,
|
styles,
|
||||||
|
cachedStyleForUrl,
|
||||||
|
getStylesInfo,
|
||||||
|
getSectionsByUrl,
|
||||||
installStyle,
|
installStyle,
|
||||||
deleteStyle,
|
deleteStyle,
|
||||||
setStyleExclusions,
|
setStyleExclusions,
|
||||||
editSave
|
editSave,
|
||||||
|
toggleStyle
|
||||||
// TODO: get all styles API?
|
// TODO: get all styles API?
|
||||||
// TODO: get style by ID?
|
// 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 editSave() {}
|
||||||
|
|
||||||
function setStyleExclusions() {}
|
function setStyleExclusions() {}
|
||||||
|
@ -105,14 +124,14 @@ const styleManager = (() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSectionsForURL(url) {
|
function getSectionsByUrl(url) {
|
||||||
// if (!URLS.supported(url) || prefs.get('disableAll')) {
|
// if (!URLS.supported(url) || prefs.get('disableAll')) {
|
||||||
// return [];
|
// return [];
|
||||||
// }
|
// }
|
||||||
let result = cachedStyleForUrl.get(url);
|
let result = cachedStyleForUrl.get(url);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = [];
|
result = [];
|
||||||
for (const style of styles) {
|
for (const style of styles.values()) {
|
||||||
if (!urlMatchStyle(url, style)) {
|
if (!urlMatchStyle(url, style)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -213,4 +232,81 @@ const styleManager = (() => {
|
||||||
function getUrlNoHash(url) {
|
function getUrlNoHash(url) {
|
||||||
return url.split('#')[0];
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* global promisify */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const API = (() => {
|
const API = (() => {
|
||||||
|
@ -12,29 +13,13 @@ const API = (() => {
|
||||||
function sendMessage(msg) {
|
function sendMessage(msg) {
|
||||||
return runtimeSendMessage(msg)
|
return runtimeSendMessage(msg)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (result.__ERROR__) {
|
if (result && result.__ERROR__) {
|
||||||
throw new Error(result.__ERROR__);
|
throw new Error(result.__ERROR__);
|
||||||
}
|
}
|
||||||
return result;
|
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) {
|
function invokeBG(name, args) {
|
||||||
return preparing.then(BG => {
|
return preparing.then(BG => {
|
||||||
if (!BG) {
|
if (!BG) {
|
||||||
|
@ -48,7 +33,11 @@ const API = (() => {
|
||||||
if (BG !== window) {
|
if (BG !== window) {
|
||||||
args = BG.deepCopy(args);
|
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);
|
.then(BG.deepCopy);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'styleUpdated':
|
case 'styleUpdated':
|
||||||
if (request.codeIsUpdated === false) {
|
if (!request.codeIsUpdated) {
|
||||||
applyStyleState(request.style);
|
applyStyleState(request.style);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,71 +104,6 @@ if (FIREFOX_NO_DOM_STORAGE) {
|
||||||
Object.defineProperty(window, 'sessionStorage', {value: {}});
|
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) {
|
function sendMessage(msg, callback) {
|
||||||
/*
|
/*
|
||||||
Promise mode [default]:
|
Promise mode [default]:
|
||||||
|
|
17
js/promisify.js
Normal file
17
js/promisify.js
Normal 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
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -153,9 +153,11 @@
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<script src="content/api.js"></script>
|
||||||
<script src="content/apply.js"></script>
|
<script src="content/apply.js"></script>
|
||||||
<script src="js/localization.js"></script>
|
<script src="js/localization.js"></script>
|
||||||
<script src="manage/filters.js"></script>
|
<script src="manage/filters.js"></script>
|
||||||
|
|
|
@ -32,7 +32,7 @@ const OWN_ICON = chrome.runtime.getManifest().icons['16'];
|
||||||
const handleEvent = {};
|
const handleEvent = {};
|
||||||
|
|
||||||
Promise.all([
|
Promise.all([
|
||||||
API.getStyles({omitCode: !BG}),
|
API.getStylesInfo(),
|
||||||
urlFilterParam && API.searchDB({query: 'url:' + urlFilterParam}),
|
urlFilterParam && API.searchDB({query: 'url:' + urlFilterParam}),
|
||||||
onDOMready().then(initGlobalEvents),
|
onDOMready().then(initGlobalEvents),
|
||||||
]).then(args => {
|
]).then(args => {
|
||||||
|
@ -195,7 +195,7 @@ function createStyleElement({style, name}) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const parts = createStyleElement.parts;
|
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.checker.checked = style.enabled;
|
||||||
parts.nameLink.textContent = tWordBreak(style.name);
|
parts.nameLink.textContent = tWordBreak(style.name);
|
||||||
parts.nameLink.href = parts.editLink.href = parts.editHrefBase + style.id;
|
parts.nameLink.href = parts.editLink.href = parts.editHrefBase + style.id;
|
||||||
|
@ -403,10 +403,7 @@ Object.assign(handleEvent, {
|
||||||
},
|
},
|
||||||
|
|
||||||
toggle(event, entry) {
|
toggle(event, entry) {
|
||||||
API.saveStyle({
|
API.toggleStyle(entry.styleId, this.matches('.enable') || this.checked);
|
||||||
id: entry.styleId,
|
|
||||||
enabled: this.matches('.enable') || this.checked,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
check(event, entry) {
|
check(event, entry) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
],
|
],
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
|
"js/promisify.js",
|
||||||
"js/messaging.js",
|
"js/messaging.js",
|
||||||
"js/storage-util.js",
|
"js/storage-util.js",
|
||||||
"js/sections-equal.js",
|
"js/sections-equal.js",
|
||||||
|
@ -60,7 +61,7 @@
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true,
|
"all_frames": true,
|
||||||
"match_about_blank": 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/*"],
|
"matches": ["http://userstyles.org/*", "https://userstyles.org/*"],
|
||||||
|
|
Loading…
Reference in New Issue
Block a user