Refactor: openURL
This commit is contained in:
parent
24552269fe
commit
9c8cb9b928
|
@ -400,11 +400,13 @@ function onRuntimeMessage(msg, sender) {
|
|||
}
|
||||
|
||||
// FIXME: popup.js also open editor but it doesn't use this API.
|
||||
function openEditor({id}) {
|
||||
let url = '/edit.html';
|
||||
if (id) {
|
||||
url += `?id=${id}`;
|
||||
function openEditor(params) {
|
||||
const searchParams = new URLSearchParams(); // FIXME: use url.searchParams when Chrome >= 51
|
||||
for (const key in params) {
|
||||
searchParams.set(key, params[key]);
|
||||
}
|
||||
const search = searchParams.toString();
|
||||
const url = chrome.runtime.getURL('edit.html') + (search && `?${search}`);
|
||||
if (chrome.windows && prefs.get('openEditInWindow')) {
|
||||
chrome.windows.create(Object.assign({url}, prefs.get('windowPosition')));
|
||||
} else {
|
||||
|
|
|
@ -53,7 +53,7 @@ const contentScripts = (() => {
|
|||
}
|
||||
|
||||
function injectToAllTabs() {
|
||||
return queryTabs().then(tabs => {
|
||||
return queryTabs({}).then(tabs => {
|
||||
for (const tab of tabs) {
|
||||
// skip lazy-loaded aka unloaded tabs that seem to start loading on message in FF
|
||||
if (tab.width) {
|
||||
|
|
|
@ -66,7 +66,7 @@ const regExpTester = (() => {
|
|||
return rxData;
|
||||
});
|
||||
const getMatchInfo = m => m && {text: m[0], pos: m.index};
|
||||
queryTabs().then(tabs => {
|
||||
queryTabs({}).then(tabs => {
|
||||
const supported = tabs.map(tab => tab.url)
|
||||
.filter(url => URLS.supported(url));
|
||||
const unique = [...new Set(supported).values()];
|
||||
|
|
148
js/messaging.js
148
js/messaging.js
|
@ -1,7 +1,7 @@
|
|||
/* exported getActiveTab onTabReady stringAsRegExp getTabRealURL openURL
|
||||
getStyleWithNoCode tryRegExp sessionStorageHash download deepEqual
|
||||
closeCurrentTab capitalize */
|
||||
/* global prefs */
|
||||
closeCurrentTab capitalize CHROME_HAS_BORDER_BUG */
|
||||
/* global promisify */
|
||||
'use strict';
|
||||
|
||||
const CHROME = Boolean(chrome.app) && parseInt(navigator.userAgent.match(/Chrom\w+\/(?:\d+\.){2}(\d+)|$/)[1]);
|
||||
|
@ -93,12 +93,12 @@ if (IS_BG) {
|
|||
// Object.defineProperty(window, 'localStorage', {value: {}});
|
||||
// Object.defineProperty(window, 'sessionStorage', {value: {}});
|
||||
|
||||
function queryTabs(options = {}) {
|
||||
return new Promise(resolve =>
|
||||
chrome.tabs.query(options, tabs =>
|
||||
resolve(tabs)));
|
||||
}
|
||||
|
||||
const createTab = promisify(chrome.tabs.create.bind(chrome.tabs));
|
||||
const queryTabs = promisify(chrome.tabs.query.bind(chrome.tabs));
|
||||
const updateTab = promisify(chrome.tabs.update.bind(chrome.tabs));
|
||||
const moveTabs = promisify(chrome.tabs.move.bind(chrome.tabs));
|
||||
// FIXME: is it possible that chrome.windows is undefined?
|
||||
const updateWindow = promisify(chrome.windows.update.bind(chrome.windows));
|
||||
|
||||
function getTab(id) {
|
||||
return new Promise(resolve =>
|
||||
|
@ -194,6 +194,22 @@ function onTabReady(tabOrId) {
|
|||
});
|
||||
}
|
||||
|
||||
function urlToMatchPattern(url) {
|
||||
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns
|
||||
if (!/^(http|https|ws|wss|ftp|data|file)$/.test(url.protocol)) {
|
||||
return undefined;
|
||||
}
|
||||
// FIXME: is %2f allowed in pathname and search?
|
||||
return `${url.protocol}//${url.hostname}/${url.pathname}${url.search}`;
|
||||
}
|
||||
|
||||
function findExistTab(url, currentWindow) {
|
||||
url = new URL(url);
|
||||
const normalizedUrl = url.href.split('#')[0];
|
||||
return queryTabs({url: urlToMatchPattern(url), currentWindow})
|
||||
// FIXME: is tab.url always normalized?
|
||||
.then(tabs => tabs.find(tab => tab.url.split('#')[0] === normalizedUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a tab or activates an existing one,
|
||||
|
@ -213,75 +229,31 @@ function onTabReady(tabOrId) {
|
|||
* JSONifiable data to be sent to the tab via sendMessage()
|
||||
* @returns {Promise<Tab>} Promise that resolves to the opened/activated tab
|
||||
*/
|
||||
function openURL({
|
||||
// https://github.com/eslint/eslint/issues/10639
|
||||
// eslint-disable-next-line no-undef
|
||||
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');
|
||||
const editMatch = /edit\.html/.test(url);
|
||||
// ignore filtered manager URLs with params & edit URLs created from popup on manager page
|
||||
const manageMatch = !editMatch ? /manage\.html(#stylus-options)?$/.test(url) : null;
|
||||
// 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') ||
|
||||
url.startsWith('chrome:') ?
|
||||
undefined :
|
||||
FIREFOX && url.includes('%2F') ?
|
||||
url.replace(/%2F.*/, '*').replace(/#.*/, '') :
|
||||
url.replace(/#.*/, '');
|
||||
|
||||
return manageMatch || editMatch ? queryTabs().then(maybeSwitch) :
|
||||
queryTabs({url: urlQuery, currentWindow}).then(maybeSwitch);
|
||||
|
||||
function maybeSwitch(tabs = []) {
|
||||
const urlWithSlash = url + '/';
|
||||
const urlFF = FIREFOX && url.replace(/%2F/g, '/');
|
||||
const urlOptions = manageMatch ? URLS.ownOrigin + 'manage.html#stylus-options' : null;
|
||||
const urlManage = manageMatch ? URLS.ownOrigin + 'manage.html' : null;
|
||||
const tab = tabs.find(({url: u}) => u === url || u === urlFF || u === urlWithSlash ||
|
||||
u === urlOptions || u === urlManage);
|
||||
if (!tab && prefs.get('openEditInWindow') && chrome.windows && editMatch) {
|
||||
chrome.windows.create(
|
||||
Object.assign({
|
||||
url: url
|
||||
}, prefs.get('windowPosition', {}))
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (manageMatch) {
|
||||
if (tab) {
|
||||
const toggleOptions = url === urlOptions ? 'options-open' : 'options-close';
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
'name': 'options',
|
||||
'data': toggleOptions
|
||||
});
|
||||
}
|
||||
getActiveTab()
|
||||
.then(currentTab => {
|
||||
if (!(tab && FIREFOX && currentTab.windowId !== tab.windowId)) {
|
||||
chrome.runtime.sendMessage({
|
||||
'name': 'popup',
|
||||
'data': 'close-popup'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!tab) {
|
||||
return getActiveTab().then(maybeReplace);
|
||||
}
|
||||
if (index !== undefined && tab.index !== index) {
|
||||
chrome.tabs.move(tab.id, {index});
|
||||
}
|
||||
return activateTab(tab);
|
||||
function openURL(options) {
|
||||
if (typeof options === 'string') {
|
||||
options = {url: options};
|
||||
}
|
||||
let {
|
||||
url,
|
||||
index,
|
||||
active,
|
||||
currentWindow = true,
|
||||
} = options;
|
||||
|
||||
if (!url.includes('://')) {
|
||||
url = chrome.runtime.getURL(url);
|
||||
}
|
||||
return findExistTab(url, currentWindow)
|
||||
.then(tab => {
|
||||
if (!tab) {
|
||||
return getActiveTab().then(maybeReplace);
|
||||
}
|
||||
// update url if only hash is different
|
||||
if (tab.url !== url && tab.url.split('#')[0] === url.split('#')[0]) {
|
||||
return activateTab(tab, {url, index});
|
||||
}
|
||||
return activateTab(tab, {index});
|
||||
});
|
||||
|
||||
// update current NTP or about:blank
|
||||
// except when 'url' is chrome:// or chrome-extension:// in incognito
|
||||
|
@ -289,29 +261,29 @@ function openURL({
|
|||
const chromeInIncognito = tab && tab.incognito && url.startsWith('chrome');
|
||||
const emptyTab = tab && URLS.emptyTab.includes(tab.url);
|
||||
if (emptyTab && !chromeInIncognito) {
|
||||
return new Promise(resolve =>
|
||||
chrome.tabs.update({url}, resolve));
|
||||
return activateTab(tab, {url, index}); // FIXME: should we move current empty tab?
|
||||
}
|
||||
const options = {url, index, active};
|
||||
// FF57+ supports openerTabId, but not in Android (indicated by the absence of chrome.windows)
|
||||
// FIXME: is it safe to assume that the current tab is the opener?
|
||||
if (tab && (!FIREFOX || FIREFOX >= 57 && chrome.windows) && !chromeInIncognito) {
|
||||
options.openerTabId = tab.id;
|
||||
}
|
||||
return new Promise(resolve =>
|
||||
chrome.tabs.create(options, resolve));
|
||||
return createTab(options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function activateTab(tab) {
|
||||
function activateTab(tab, {url, index}) {
|
||||
const options = {active: true};
|
||||
if (url) {
|
||||
options.url = url;
|
||||
}
|
||||
return Promise.all([
|
||||
new Promise(resolve => {
|
||||
chrome.tabs.update(tab.id, {active: true}, resolve);
|
||||
}),
|
||||
chrome.windows && new Promise(resolve => {
|
||||
chrome.windows.update(tab.windowId, {focused: true}, resolve);
|
||||
}),
|
||||
]).then(([tab]) => tab);
|
||||
updateTab(tab.id, options),
|
||||
updateWindow(tab.windowId, {focused: true}),
|
||||
index != null && moveTabs(tab.id, {index})
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
<script src="js/polyfill.js"></script>
|
||||
<script src="js/dom.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/promisify.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/msg.js"></script>
|
||||
<script src="js/localization.js"></script>
|
||||
<script src="js/prefs.js"></script>
|
||||
|
@ -33,7 +33,7 @@
|
|||
</head>
|
||||
|
||||
<body id="stylus-options">
|
||||
|
||||
|
||||
<div id="options-header">
|
||||
<div id="options-title">
|
||||
<div id="options-close-icon"><svg viewBox="0 0 20 20" class="svg-icon"><path d="M11.69,10l4.55,4.55-1.69,1.69L10,11.69,5.45,16.23,3.77,14.55,8.31,10,3.77,5.45,5.45,3.77,10,8.31l4.55-4.55,1.69,1.69Z"></path></svg></div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* global configDialog hotkeys onTabReady msg
|
||||
getActiveTab FIREFOX getTabRealURL URLS API onDOMready $ $$ prefs CHROME
|
||||
getActiveTab FIREFOX getTabRealURL URLS API onDOMready $ $$ prefs
|
||||
setupLivePrefs template t $create animateElement
|
||||
tryJSONparse debounce CHROME_HAS_BORDER_BUG */
|
||||
|
||||
|
@ -187,7 +187,7 @@ function initPopup() {
|
|||
? new URL(tabURL).pathname.slice(1)
|
||||
// this URL
|
||||
: t('writeStyleForURL').replace(/ /g, '\u00a0'),
|
||||
onclick: handleEvent.openLink,
|
||||
onclick: e => handleEvent.openEditor(e, {'url-prefix': tabURL}),
|
||||
});
|
||||
if (prefs.get('popup.breadcrumbs')) {
|
||||
urlLink.onmouseenter =
|
||||
|
@ -210,7 +210,7 @@ function initPopup() {
|
|||
href: 'edit.html?domain=' + encodeURIComponent(domain),
|
||||
textContent: numParts > 2 ? domain.split('.')[0] : domain,
|
||||
title: `domain("${domain}")`,
|
||||
onclick: handleEvent.openLink,
|
||||
onclick: e => handleEvent.openEditor(e, {domain}),
|
||||
});
|
||||
domainLink.setAttribute('subdomain', numParts > 1 ? 'true' : '');
|
||||
matchTargets.appendChild(domainLink);
|
||||
|
@ -296,7 +296,7 @@ function createStyleElement(style) {
|
|||
const editLink = $('.style-edit-link', entry);
|
||||
Object.assign(editLink, {
|
||||
href: editLink.getAttribute('href') + style.id,
|
||||
onclick: handleEvent.openLink,
|
||||
onclick: e => handleEvent.openEditor(e, {id: style.id}),
|
||||
});
|
||||
const styleName = $('.style-name', entry);
|
||||
Object.assign(styleName, {
|
||||
|
@ -535,9 +535,9 @@ Object.assign(handleEvent, {
|
|||
$('#regexp-explanation').remove();
|
||||
},
|
||||
|
||||
openLink(event) {
|
||||
openEditor(event, options) {
|
||||
event.preventDefault();
|
||||
API.openURL({url: this.href});
|
||||
API.openEditor(options);
|
||||
if (!(FIREFOX && prefs.get('openEditInWindow'))) window.close();
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user