reuse existing usercss installer tab

A few additional checks were needed to circumvent FF bugs
so openURL was refactored to keep the code readable
This commit is contained in:
tophf 2017-12-31 17:58:35 +03:00
parent 0368759081
commit 5bc4206593
3 changed files with 74 additions and 36 deletions

View File

@ -116,6 +116,7 @@ var usercssHelper = (() => {
(direct ? '&direct=yes' : ''), (direct ? '&direct=yes' : ''),
index: tab.index + 1, index: tab.index + 1,
openerTabId: tab.id, openerTabId: tab.id,
currentWindow: null,
})); }));
} }

View File

@ -9,6 +9,7 @@
let installed = false; let installed = false;
const tabId = Number(params.get('tabId')); const tabId = Number(params.get('tabId'));
let tabUrl;
let port; let port;
if (params.has('direct')) { if (params.has('direct')) {
@ -35,7 +36,7 @@
break; break;
} }
}); });
port.onDisconnect.addListener(closeCurrentTab); port.onDisconnect.addListener(onPortDisconnected);
} }
const cm = CodeMirror($('.main'), {readOnly: true}); const cm = CodeMirror($('.main'), {readOnly: true});
@ -49,6 +50,12 @@
} }
}, 200); }, 200);
getTab(tabId).then(tab => (tabUrl = tab.url));
chrome.tabs.onUpdated.addListener((id, {url}) =>
id === tabId &&
url && url !== tabUrl &&
closeCurrentTab());
function liveReloadUpdate(sourceCode) { function liveReloadUpdate(sourceCode) {
liveReloadPending = liveReloadPending.then(() => { liveReloadPending = liveReloadPending.then(() => {
const scrollInfo = cm.getScrollInfo(); const scrollInfo = cm.getScrollInfo();
@ -391,4 +398,14 @@
.catch(err => messageBox.alert(t('styleInstallFailed', String(err)))); .catch(err => messageBox.alert(t('styleInstallFailed', String(err))));
}); });
} }
function onPortDisconnected() {
chrome.tabs.get(tabId, tab => {
if (chrome.runtime.lastError) {
closeCurrentTab();
} else if (tab.url === tabUrl) {
location.reload();
}
});
}
})(); })();

View File

@ -210,43 +210,63 @@ function getTabRealURL(tab) {
}); });
} }
/**
* Opens a tab or activates an existing one,
* reuses the New Tab page or about:blank if it's focused now
* @param {Object} params - or just a string e.g. openURL('foo')
* @param {string} params.url - if relative, it's auto-expanded to the full extension URL
* @param {number} [params.index] - move the tab to this index in the tab strip, -1 = last
* @param {Boolean} [params.active=tue] - true to activate the tab, false to open in background
* @param {?Boolean} [params.currentWindow=true] - pass null to check all windows
* @returns {Promise}
*/
function openURL({
url = arguments[0],
index,
active,
currentWindow = true,
}) {
url = url.includes('://') ? url : chrome.runtime.getURL(url);
// [some] chromium forks don't handle their fake branded protocols
url = url.replace(/^(opera|vivaldi)/, 'chrome');
// FF doesn't handle moz-extension:// URLs (bug)
// FF decodes %2F in encoded parameters (bug)
// API doesn't handle the hash-fragment part
const urlQuery = url.startsWith('moz-extension') ? undefined :
FIREFOX && url.includes('%2F') ?
url.replace(/%2F.*/, '*').replace(/#.*/, '') :
url.replace(/#.*/, '');
return queryTabs({url: urlQuery, currentWindow}).then(maybeSwitch);
// opens a tab or activates the already opened one, function maybeSwitch(tabs = []) {
// reuses the New Tab page if it's focused now const urlFF = FIREFOX && url.replace(/%2F/g, '/');
function openURL({url, index, active, currentWindow = true}) { const tab = tabs.find(tab => tab.url === url || tab.url === urlFF);
if (!url.includes('://')) { if (!tab) {
url = chrome.runtime.getURL(url); return getActiveTab().then(maybeReplace);
}
if (index !== undefined && tab.index !== index) {
chrome.tabs.move(tab.id, {index});
}
return activateTab(tab);
}
// update current NTP or about:blank
// except when 'url' is chrome:// or chrome-extension:// in incognito
function maybeReplace(tab) {
const chromeInIncognito = tab && tab.incognito && url.startsWith('chrome');
const emptyTab = tab && (tab.url === 'chrome://newtab/' || tab.url === 'about:newtab');
if (emptyTab && !chromeInIncognito) {
return new Promise(resolve =>
chrome.tabs.update({url}, resolve));
}
const options = {url, index, active};
// FF57+ supports openerTabId, but not in Android (indicated by the absence of chrome.windows)
if (tab && (!FIREFOX || FIREFOX >= 57 && chrome.windows) && !chromeInIncognito) {
options.openerTabId = tab.id;
}
return new Promise(resolve =>
chrome.tabs.create(options, resolve));
} }
return new Promise(resolve => {
// [some] chromium forks don't handle their fake branded protocols
url = url.replace(/^(opera|vivaldi)/, 'chrome');
// FF doesn't handle moz-extension:// URLs (bug)
// API doesn't handle the hash-fragment part
const urlQuery = url.startsWith('moz-extension') ? undefined : url.replace(/#.*/, '');
queryTabs({url: urlQuery, currentWindow}).then(tabs => {
for (const tab of tabs) {
if (tab.url === url) {
activateTab(tab).then(resolve);
return;
}
}
getActiveTab().then(tab => {
const chromeInIncognito = tab && tab.incognito && url.startsWith('chrome');
if (tab && (tab.url === 'chrome://newtab/' || tab.url === 'about:newtab') && !chromeInIncognito) {
// update current NTP, except for chrome:// or chrome-extension:// in incognito
chrome.tabs.update({url}, resolve);
} else {
// create a new tab
const options = {url, index, active};
// FF57+ supports openerTabId, but not in Android (indicated by the absence of chrome.windows)
if (tab && (!FIREFOX || FIREFOX >= 57 && chrome.windows) && !chromeInIncognito) {
options.openerTabId = tab.id;
}
chrome.tabs.create(options, resolve);
}
});
});
});
} }