Refactor: pull out tab-manager and icon-manager

This commit is contained in:
eight04 2020-02-19 10:59:07 +08:00 committed by tophf
parent bef87f200e
commit 73f6e8a964
6 changed files with 173 additions and 132 deletions

View File

@ -1,7 +1,8 @@
/* global download prefs openURL FIREFOX CHROME VIVALDI /* global download prefs openURL FIREFOX CHROME
debounce URLS ignoreChromeError usercssHelper URLS ignoreChromeError usercssHelper
styleManager msg navigatorUtil iconUtil workerUtil contentScripts sync styleManager msg navigatorUtil workerUtil contentScripts sync
findExistingTab createTab activateTab isTabReplaceable getActiveTab */ findExistingTab createTab activateTab isTabReplaceable getActiveTab
iconManager */
'use strict'; 'use strict';
@ -49,14 +50,7 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, {
openEditor, openEditor,
updateIconBadge(count) { updateIconBadge(count) {
// TODO: remove once our manifest's minimum_chrome_version is 50+ iconManager.updateIconBadge(this.sender.tab.id, count);
// Chrome 49 doesn't report own extension pages in webNavigation apparently
// so we do a force update which doesn't use the cache.
if (CHROME && CHROME < 2661 && this.sender.tab.url.startsWith(URLS.ownOrigin)) {
updateIconBadgeForce(this.sender.tab.id, count);
} else {
updateIconBadge(this.sender.tab.id, count);
}
return true; return true;
}, },
@ -87,6 +81,14 @@ var browserCommands, contextMenus;
// register all listeners // register all listeners
msg.on(onRuntimeMessage); msg.on(onRuntimeMessage);
// tell apply.js to refresh styles for non-committed navigation
navigatorUtil.onUrlChange(({tabId, frameId}, type) => {
if (type !== 'committed') {
msg.sendTab(tabId, {method: 'urlChanged'}, {frameId})
.catch(msg.ignoreError);
}
});
if (FIREFOX) { if (FIREFOX) {
// FF misses some about:blank iframes so we inject our content script explicitly // FF misses some about:blank iframes so we inject our content script explicitly
navigatorUtil.onDOMContentLoaded(webNavIframeHelperFF, { navigatorUtil.onDOMContentLoaded(webNavIframeHelperFF, {
@ -106,55 +108,10 @@ if (chrome.commands) {
chrome.commands.onCommand.addListener(command => browserCommands[command]()); chrome.commands.onCommand.addListener(command => browserCommands[command]());
} }
const tabData = new Map(); // detect usercss and open the installer page
const tabDataFor = tabId => { navigatorUtil.onCommitted(({tabId, frameId, url}) => {
let data = tabData.get(tabId); if (!frameId && usercssHelper.testUrl(url)) {
if (!data) tabData.set(tabId, (data = {})); usercssHelper.openInstallerPage(tabId, url);
return data;
};
chrome.tabs.onRemoved.addListener(tabId => tabData.delete(tabId));
chrome.tabs.onReplaced.addListener((added, removed) => tabData.delete(removed));
prefs.subscribe([
'disableAll',
'badgeDisabled',
'badgeNormal',
], () => debounce(refreshIconBadgeColor));
prefs.subscribe([
'show-badge'
], () => debounce(refreshAllIconsBadgeText));
prefs.subscribe([
'disableAll',
'iconset',
], () => debounce(refreshAllIcons));
prefs.initializing.then(() => {
refreshIconBadgeColor();
refreshAllIconsBadgeText();
refreshAllIcons();
});
navigatorUtil.onUrlChange(({tabId, frameId, transitionQualifiers, url}, type) => {
if (type !== 'committed') {
msg.sendTab(tabId, {method: 'urlChanged'}, {frameId})
.catch(msg.ignoreError);
} else if (!frameId) {
if (usercssHelper.testUrl(url) && !`${tabDataFor(tabId).url}`.startsWith(URLS.installUsercss)) {
usercssHelper.openInstallerPage(tabId, url).then(newUrl => {
tabDataFor(tabId).url = newUrl || url;
});
}
// it seems that the tab icon would be reset by navigation. We
// invalidate the cache here so it would be refreshed by `apply.js`.
tabData.set(tabId, {url});
// however, if the tab was swapped in by forward/backward buttons,
// `apply.js` doesn't notify the background to update the icon,
// so we have to refresh it manually.
if (transitionQualifiers.includes('forward_back')) {
msg.sendTab(tabId, {method: 'updateCount'}).catch(msg.ignoreError);
}
} }
}); });
@ -307,74 +264,6 @@ function webNavIframeHelperFF({tabId, frameId}) {
}); });
} }
function updateIconBadge(tabId, count) {
const tabIcon = tabDataFor(tabId);
if (tabIcon.count === count) {
return;
}
const oldCount = tabIcon.count;
tabIcon.count = count;
refreshIconBadgeText(tabId, tabIcon);
if (Boolean(oldCount) !== Boolean(count)) {
refreshIcon(tabId, tabIcon);
}
}
function updateIconBadgeForce(tabId, count) {
refreshIconBadgeText(tabId, {count});
refreshIcon(tabId, {count});
}
function refreshIconBadgeText(tabId, icon) {
iconUtil.setBadgeText({
text: prefs.get('show-badge') && icon.count ? String(icon.count) : '',
tabId
});
}
function refreshIcon(tabId, icon) {
const disableAll = prefs.get('disableAll');
const iconset = prefs.get('iconset') === 1 ? 'light/' : '';
const postfix = disableAll ? 'x' : !icon.count ? 'w' : '';
const iconType = iconset + postfix;
if (icon.iconType === iconType) {
return;
}
icon.iconType = iconset + postfix;
const sizes = FIREFOX || CHROME >= 2883 && !VIVALDI ? [16, 32] : [19, 38];
iconUtil.setIcon({
path: sizes.reduce(
(obj, size) => {
obj[size] = `/images/icon/${iconset}${size}${postfix}.png`;
return obj;
},
{}
),
tabId
});
}
function refreshIconBadgeColor() {
const color = prefs.get(prefs.get('disableAll') ? 'badgeDisabled' : 'badgeNormal');
iconUtil.setBadgeBackgroundColor({
color
});
}
function refreshAllIcons() {
for (const [tabId, data] of tabData) {
refreshIcon(tabId, data);
}
refreshIcon(null, {}); // default icon
}
function refreshAllIconsBadgeText() {
for (const [tabId, data] of tabData) {
refreshIconBadgeText(tabId, data);
}
}
function onRuntimeMessage(msg, sender) { function onRuntimeMessage(msg, sender) {
if (msg.method !== 'invokeAPI') { if (msg.method !== 'invokeAPI') {
return; return;

101
background/icon-manager.js Normal file
View File

@ -0,0 +1,101 @@
/* global prefs debounce iconUtil FIREFOX CHROME VIVALDI tabManager */
/* exported iconManager */
'use strict';
const iconManager = (() => {
const ICON_SIZES = FIREFOX || CHROME >= 2883 && !VIVALDI ? [16, 32] : [19, 38];
prefs.subscribe([
'disableAll',
'badgeDisabled',
'badgeNormal',
], () => debounce(refreshIconBadgeColor));
prefs.subscribe([
'show-badge'
], () => debounce(refreshAllIconsBadgeText));
prefs.subscribe([
'disableAll',
'iconset',
], () => debounce(refreshAllIcons));
prefs.initializing.then(() => {
refreshIconBadgeColor();
refreshAllIconsBadgeText();
refreshAllIcons();
});
return {updateIconBadge};
// FIXME: in some cases, we only have to redraw the badge. is it worth a optimization?
function updateIconBadge(tabId, count, force = true) {
tabManager.setMeta(tabId, 'count', count);
refreshIconBadgeText(tabId);
refreshIcon(tabId, force);
}
function refreshIconBadgeText(tabId) {
const count = tabManager.getMeta(tabId, 'count');
iconUtil.setBadgeText({
text: prefs.get('show-badge') && count ? String(count) : '',
tabId
});
}
function getIconName(count = 0) {
const iconset = prefs.get('iconset') === 1 ? 'light/' : '';
const postfix = prefs.get('disableAll') ? 'x' : !count ? 'w' : '';
return `${iconset}$SIZE$${postfix}`;
}
function refreshIcon(tabId, force = false) {
const oldIcon = tabManager.getMeta(tabId, 'icon');
const newIcon = getIconName(tabManager.getMeta(tabId, 'count'));
if (!force && oldIcon === newIcon) {
return;
}
tabManager.setMeta(tabId, 'icon', newIcon);
iconUtil.setIcon({
path: getIconPath(newIcon),
tabId
});
}
function getIconPath(icon) {
return ICON_SIZES.reduce(
(obj, size) => {
obj[size] = `/images/icon/${icon.replace('$SIZE$', size)}.png`;
return obj;
},
{}
);
}
function refreshGlobalIcon() {
iconUtil.setIcon({
path: getIconPath(getIconName())
});
}
function refreshIconBadgeColor() {
const color = prefs.get(prefs.get('disableAll') ? 'badgeDisabled' : 'badgeNormal');
iconUtil.setBadgeBackgroundColor({
color
});
}
function refreshAllIcons() {
for (const tabId of tabManager.list()) {
refreshIcon(tabId);
}
refreshGlobalIcon();
}
function refreshAllIconsBadgeText() {
for (const tabId of tabManager.list()) {
refreshIconBadgeText(tabId);
}
}
})();

48
background/tab-manager.js Normal file
View File

@ -0,0 +1,48 @@
/* global navigatorUtil */
/* exported tabManager */
'use strict';
const tabManager = (() => {
const listeners = [];
const cache = new Map();
chrome.tabs.onRemoved.addListener(tabId => cache.delete(tabId));
chrome.tabs.onReplaced.addListener((added, removed) => cache.delete(removed));
navigatorUtil.onUrlChange(({tabId, frameId, url}) => {
if (frameId) return;
setMeta(tabId, 'url', url);
emitUpdate({tabId, url});
});
return {onUpdate, setMeta, getMeta, list};
function list() {
return cache.keys();
}
function onUpdate(callback) {
listeners.push(callback);
}
function emitUpdate(e) {
for (const callback of listeners) {
try {
callback(e);
} catch (err) {
console.error(err);
}
}
}
function setMeta(tabId, key, value) {
let meta = cache.get(tabId);
if (!meta) {
meta = new Map();
cache.set(tabId, meta);
}
meta.set(key, value);
}
function getMeta(tabId, key) {
return cache.get(tabId).get(key);
}
})();

View File

@ -30,7 +30,8 @@ const usercssHelper = (() => {
testUrl(url) { testUrl(url) {
return url.includes('.user.') && return url.includes('.user.') &&
/^(https?|file|ftps?):/.test(url) && /^(https?|file|ftps?):/.test(url) &&
/\.user\.(css|styl)$/.test(url.split(/[#?]/, 1)[0]); /\.user\.(css|styl)$/.test(url.split(/[#?]/, 1)[0]) &&
!url.startsWith(URLS.installUsercss);
}, },
openInstallerPage(tabId, url) { openInstallerPage(tabId, url) {

View File

@ -46,6 +46,8 @@
"background/style-manager.js", "background/style-manager.js",
"background/navigator-util.js", "background/navigator-util.js",
"background/icon-util.js", "background/icon-util.js",
"background/tab-manager.js",
"background/icon-manager.js",
"background/background.js", "background/background.js",
"background/usercss-helper.js", "background/usercss-helper.js",
"background/style-via-api.js", "background/style-via-api.js",

View File

@ -34,8 +34,8 @@
"update-transifex": "tx push -s", "update-transifex": "tx push -s",
"build-vendor": "shx rm -rf vendor/* && node tools/build-vendor", "build-vendor": "shx rm -rf vendor/* && node tools/build-vendor",
"zip": "node tools/zip.js", "zip": "node tools/zip.js",
"start": "web-ext run --bc", "start": "web-ext run",
"start-chrome": "web-ext run -t chromium --bc", "start-chrome": "web-ext run -t chromium",
"preversion": "npm test", "preversion": "npm test",
"version": "sync-version manifest.json && git add .", "version": "sync-version manifest.json && git add .",
"postversion": "npm run zip && git push --follow-tags" "postversion": "npm run zip && git push --follow-tags"