fixups for Opera/Vivaldi/Firefox-compatibility

This commit is contained in:
tophf 2017-04-09 09:43:51 +03:00
parent c8e8b94d28
commit 2bb7d31042
15 changed files with 97 additions and 53 deletions

View File

@ -10,10 +10,11 @@ env:
globals: globals:
# messaging.js # messaging.js
OWN_ORIGIN: false
KEEP_CHANNEL_OPEN: false KEEP_CHANNEL_OPEN: false
RX_SUPPORTED_URLS: false RX_SUPPORTED_URLS: false
configureCommands: false FIREFOX: false
OPERA: false
URLS: false
notifyAllTabs: false notifyAllTabs: false
refreshAllTabs: false refreshAllTabs: false
updateIcon: false updateIcon: false

View File

@ -23,8 +23,8 @@ function webNavigationListener(method, data) {
// we can't inject chrome:// and chrome-extension:// pages // we can't inject chrome:// and chrome-extension:// pages
// so we'll only inform our page of the change // so we'll only inform our page of the change
// and it'll retrieve the styles directly // and it'll retrieve the styles directly
if (method && !data.url.startsWith('chrome:')) { if (method && !data.url.startsWith('chrome:') && data.tabId >= 0) {
const isOwnPage = data.url.startsWith(OWN_ORIGIN); const isOwnPage = data.url.startsWith(URLS.ownOrigin);
chrome.tabs.sendMessage( chrome.tabs.sendMessage(
data.tabId, data.tabId,
{method, styles: isOwnPage ? 'DIY' : styles}, {method, styles: isOwnPage ? 'DIY' : styles},
@ -127,7 +127,7 @@ if (/Vivaldi\/[\d.]+$/.test(navigator.userAgent)
contextMenus.editDeleteText = { contextMenus.editDeleteText = {
title: 'editDeleteText', title: 'editDeleteText',
contexts: ['editable'], contexts: ['editable'],
documentUrlPatterns: [OWN_ORIGIN + 'edit*'], documentUrlPatterns: [URLS.ownOrigin + 'edit*'],
click: (info, tab) => { click: (info, tab) => {
chrome.tabs.sendMessage(tab.id, {method: 'editDeleteText'}); chrome.tabs.sendMessage(tab.id, {method: 'editDeleteText'});
}, },
@ -160,7 +160,7 @@ getDatabase(function() {}, reportError);
// When an edit page gets attached or detached, remember its state // When an edit page gets attached or detached, remember its state
// so we can do the same to the next one to open. // so we can do the same to the next one to open.
const editFullUrl = OWN_ORIGIN + 'edit.html'; const editFullUrl = URLS.ownOrigin + 'edit.html';
chrome.tabs.onAttached.addListener((tabId, data) => { chrome.tabs.onAttached.addListener((tabId, data) => {
chrome.tabs.get(tabId, tabData => { chrome.tabs.get(tabId, tabData => {
if (tabData.url.startsWith(editFullUrl)) { if (tabData.url.startsWith(editFullUrl)) {
@ -198,7 +198,7 @@ chrome.storage.local.get('version', prefs => {
injectContentScripts(); injectContentScripts();
function injectContentScripts() { function injectContentScripts() {
const contentScripts = chrome.app.getDetails().content_scripts; const contentScripts = chrome.runtime.getManifest().content_scripts;
for (const cs of contentScripts) { for (const cs of contentScripts) {
cs.matches = cs.matches.map(m => ( cs.matches = cs.matches.map(m => (
m == '<all_urls>' ? m : wildcardAsRegExp(m) m == '<all_urls>' ? m : wildcardAsRegExp(m)

View File

@ -1648,8 +1648,8 @@ function showLintHelp() {
function showRegExpTester(event, section = getSectionForChild(this)) { function showRegExpTester(event, section = getSectionForChild(this)) {
const GET_FAVICON_URL = 'https://www.google.com/s2/favicons?domain='; const GET_FAVICON_URL = 'https://www.google.com/s2/favicons?domain=';
const OWN_ICON = chrome.app.getDetails().icons['16']; const OWN_ICON = chrome.runtime.getManifest().icons['16'];
const RX_SUPPORTED_URLS = new RegExp(`^(file|https?|ftps?):|^${OWN_ORIGIN}`); const RX_SUPPORTED_URLS = new RegExp(`^(file|https?|ftps?):|^${URLS.ownOrigin}`);
const cachedRegexps = showRegExpTester.cachedRegexps = const cachedRegexps = showRegExpTester.cachedRegexps =
showRegExpTester.cachedRegexps || new Map(); showRegExpTester.cachedRegexps || new Map();
const regexps = [...section.querySelector('.applies-to-list').children] const regexps = [...section.querySelector('.applies-to-list').children]
@ -1713,7 +1713,7 @@ function showRegExpTester(event, section = getSectionForChild(this)) {
const full = []; const full = [];
const partial = []; const partial = [];
for (const [url, match] of urls.entries()) { for (const [url, match] of urls.entries()) {
const faviconUrl = url.startsWith(OWN_ORIGIN) const faviconUrl = url.startsWith(URLS.ownOrigin)
? OWN_ICON ? OWN_ICON
: GET_FAVICON_URL + new URL(url).hostname; : GET_FAVICON_URL + new URL(url).hostname;
const icon = `<img src="${faviconUrl}">`; const icon = `<img src="${faviconUrl}">`;

View File

@ -28,7 +28,7 @@ function tHTML(html) {
const node = document.createElement('div'); const node = document.createElement('div');
node.innerHTML = html.replace(/>\s+</g, '><'); // spaces are removed; use &nbsp; for an explicit space node.innerHTML = html.replace(/>\s+</g, '><'); // spaces are removed; use &nbsp; for an explicit space
if (html.includes('i18n-')) { if (html.includes('i18n-')) {
tNodeList(node.querySelectorAll('*')); tNodeList(node.getElementsByTagName('*'));
} }
return node.firstElementChild; return node.firstElementChild;
} }
@ -70,7 +70,7 @@ function tNodeList(nodes) {
function tDocLoader() { function tDocLoader() {
// localize HEAD // localize HEAD
tNodeList(document.all); tNodeList(document.getElementsByTagName('*'));
// localize BODY // localize BODY
const process = mutations => { const process = mutations => {

View File

@ -1,6 +1,9 @@
body { body {
margin: 0; margin: 0;
font: 12px arial, sans-serif; font: 12px arial, sans-serif;
/* Firefox: fill the entire page for drag'n'drop to work */
display: flex;
height: 100%;
} }
a { a {
@ -29,6 +32,10 @@ a:hover {
margin-top: 0; margin-top: 0;
} }
.firefox .chromium-only {
display: none;
}
#installed { #installed {
position: relative; position: relative;
margin-left: 280px; margin-left: 280px;
@ -274,6 +281,10 @@ summary {
letter-spacing: .1ex; letter-spacing: .1ex;
} }
.newUI .has-favicons .applies-to .expander {
padding-left: 20px;
}
.newUI .target:hover { .newUI .target:hover {
background-color: inherit; background-color: inherit;
} }

View File

@ -162,7 +162,7 @@
</div> </div>
<p> <p>
<button id="manage-options-button" i18n-text="openOptionsManage"></button> <button id="manage-options-button" i18n-text="openOptionsManage"></button>
<button id="manage-shortcuts-button" i18n-text="openOptionsShortcuts"></button> <button id="manage-shortcuts-button" class="chromium-only" i18n-text="openOptionsShortcuts"></button>
</p> </p>
<p> <p>
<a id="find-editor-styles" i18n-text="editorStylesButton" <a id="find-editor-styles" i18n-text="editorStylesButton"

View File

@ -15,7 +15,7 @@ newUI.renderClass();
const TARGET_TYPES = ['domains', 'urls', 'urlPrefixes', 'regexps']; const TARGET_TYPES = ['domains', 'urls', 'urlPrefixes', 'regexps'];
const GET_FAVICON_URL = 'https://www.google.com/s2/favicons?domain='; const GET_FAVICON_URL = 'https://www.google.com/s2/favicons?domain=';
const OWN_ICON = chrome.app.getDetails().icons['16']; const OWN_ICON = chrome.runtime.getManifest().icons['16'];
const handleEvent = {}; const handleEvent = {};
@ -47,7 +47,7 @@ function initGlobalEvents() {
$('#apply-all-updates').onclick = applyUpdateAll; $('#apply-all-updates').onclick = applyUpdateAll;
$('#search').oninput = searchStyles; $('#search').oninput = searchStyles;
$('#manage-options-button').onclick = () => chrome.runtime.openOptionsPage(); $('#manage-options-button').onclick = () => chrome.runtime.openOptionsPage();
$('#manage-shortcuts-button').onclick = configureCommands.open; $('#manage-shortcuts-button').onclick = () => openURL({url: URLS.configureCommands});
$$('#header a[href^="http"]').forEach(a => (a.onclick = handleEvent.external)); $$('#header a[href^="http"]').forEach(a => (a.onclick = handleEvent.external));
// focus search field on / key // focus search field on / key

View File

@ -3,8 +3,21 @@
// keep message channel open for sendResponse in chrome.runtime.onMessage listener // keep message channel open for sendResponse in chrome.runtime.onMessage listener
const KEEP_CHANNEL_OPEN = true; const KEEP_CHANNEL_OPEN = true;
const OWN_ORIGIN = chrome.runtime.getURL(''); const FIREFOX = /Firefox/.test(navigator.userAgent);
const RX_SUPPORTED_URLS = new RegExp(`^(file|https?|ftps?):|^${OWN_ORIGIN}`); const OPERA = /OPR/.test(navigator.userAgent);
const URLS = {
ownOrigin: chrome.runtime.getURL(''),
optionsUI: new Set([
chrome.runtime.getURL('options/index.html'),
'chrome://extensions/?options=' + chrome.runtime.id,
]),
configureCommands: OPERA ? 'opera://settings/configureCommands'
: 'chrome://extensions/configureCommands',
};
const RX_SUPPORTED_URLS = new RegExp(`^(file|https?|ftps?):|^${URLS.ownOrigin}`);
document.documentElement.classList.toggle('firefox', FIREFOX);
document.documentElement.classList.toggle('opera', OPERA);
function notifyAllTabs(request) { function notifyAllTabs(request) {
@ -20,9 +33,9 @@ function notifyAllTabs(request) {
const affectsIcon = affectsAll || request.affects.icon; const affectsIcon = affectsAll || request.affects.icon;
const affectsPopup = affectsAll || request.affects.popup; const affectsPopup = affectsAll || request.affects.popup;
if (affectsTabs || affectsIcon) { if (affectsTabs || affectsIcon) {
chrome.tabs.query(affectsOwnOrigin ? {url: OWN_ORIGIN + '*'} : {}, tabs => { chrome.tabs.query(affectsOwnOrigin ? {url: URLS.ownOrigin + '*'} : {}, tabs => {
for (const tab of tabs) { for (const tab of tabs) {
if (affectsTabs || tab.url.startsWith(OWN_ORIGIN + 'options')) { if (affectsTabs || URLS.optionsUI.has(tab.url)) {
chrome.tabs.sendMessage(tab.id, request); chrome.tabs.sendMessage(tab.id, request);
} }
if (affectsIcon) { if (affectsIcon) {
@ -38,7 +51,7 @@ function notifyAllTabs(request) {
onBackgroundMessage(request); onBackgroundMessage(request);
} }
// notify background page and all open popups // notify background page and all open popups
if (affectsPopup) { if (affectsPopup || request.prefs) {
chrome.runtime.sendMessage(request); chrome.runtime.sendMessage(request);
} }
} }
@ -72,7 +85,7 @@ function updateIcon(tab, styles) {
// while NTP is still loading only process the request for its main frame with a real url // while NTP is still loading only process the request for its main frame with a real url
// (but when it's loaded we should process style toggle requests from popups, for example) // (but when it's loaded we should process style toggle requests from popups, for example)
const isNTP = tab.url == 'chrome://newtab/'; const isNTP = tab.url == 'chrome://newtab/';
if (isNTP && tab.status != 'complete') { if (isNTP && tab.status != 'complete' || tab.id < 0) {
return; return;
} }
if (styles) { if (styles) {
@ -167,11 +180,13 @@ function openURL({url, currentWindow = true}) {
return; return;
} }
} }
getActiveTab().then(tab => ( getActiveTab().then(tab => {
tab && tab.url == 'chrome://newtab/' if (tab && tab.url == 'chrome://newtab/') {
? chrome.tabs.update({url}, resolve) chrome.tabs.update({url}, resolve);
: chrome.tabs.create({url, openerTabId: tab.id}, resolve) } else {
)); chrome.tabs.create(tab && !FIREFOX ? {url, openerTabId: tab.id} : {url}, resolve);
}
});
}); });
}); });
} }
@ -203,11 +218,3 @@ function wildcardAsRegExp(s, flags) {
function ignoreChromeError() { function ignoreChromeError() {
chrome.runtime.lastError; // eslint-disable-line no-unused-expressions chrome.runtime.lastError; // eslint-disable-line no-unused-expressions
} }
const configureCommands = {
url: navigator.userAgent.includes('OPR')
? 'opera://settings/configureCommands'
: 'chrome://extensions/configureCommands',
open: () => openURL({url: configureCommands.url}),
};

View File

@ -1,3 +1,8 @@
html {
max-width: 40em;
margin: auto;
}
body { body {
margin: 0; margin: 0;
font-family: "Helvetica Neue", Helvetica, sans-serif; font-family: "Helvetica Neue", Helvetica, sans-serif;
@ -14,6 +19,10 @@ body > *:first-child {
padding-top: .75rem; padding-top: .75rem;
} }
.firefox .chromium-only {
display: none;
}
table { table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
@ -34,6 +43,7 @@ input[type="color"],
.onoffswitch, .onoffswitch,
#update-counter { #update-counter {
width: 80px; width: 80px;
box-sizing: border-box;
} }
a { a {
@ -46,7 +56,6 @@ button {
input[type=number] { input[type=number] {
text-align: right; text-align: right;
padding-right: 1em;
} }
#actions { #actions {

View File

@ -58,7 +58,7 @@
<h1 i18n-text="optionsActions"></h1> <h1 i18n-text="optionsActions"></h1>
<table> <table>
<tr> <tr>
<td i18n-text="optionsOpenManager"><sup>2</sup></td> <td i18n-text="optionsOpenManager"><sup class="chromium-only">2</sup></td>
<td><button type="button" data-cmd="open-manage" i18n-text="optionsOpen"></button></td> <td><button type="button" data-cmd="open-manage" i18n-text="optionsOpen"></button></td>
</tr> </tr>
<tr> <tr>
@ -74,9 +74,10 @@
<div id="notes"> <div id="notes">
<ol> <ol>
<li i18n-text="optionsUpdateIntervalNote"></li> <li i18n-text="optionsUpdateIntervalNote"></li>
<li><a data-cmd="open-keyboard" <li class="chromium-only">
i18n-text="optionsOpenManagerNote" <a data-cmd="open-keyboard"
href="chrome://extensions/configureCommands"></a> i18n-text="optionsOpenManagerNote"
href="chrome://extensions/configureCommands"></a>
</li> </li>
</ol> </ol>
</div> </div>

View File

@ -13,7 +13,7 @@ setupLivePrefs([
enforceInputRange($('#popupWidth')); enforceInputRange($('#popupWidth'));
// overwrite the default URL if browser is Opera // overwrite the default URL if browser is Opera
$('[data-cmd="open-keyboard"]').href = configureCommands.url; $('[data-cmd="open-keyboard"]').href = URLS.configureCommands;
// actions // actions
document.onclick = e => { document.onclick = e => {
@ -68,7 +68,8 @@ document.onclick = e => {
break; break;
case 'open-keyboard': case 'open-keyboard':
configureCommands.open(); openURL({url: e.target.href});
e.preventDefault();
break; break;
case 'reset': case 'reset':

View File

@ -10,6 +10,10 @@ body > div:not(#installed) {
margin-right: 0.75em; margin-right: 0.75em;
} }
.firefox .chromium-only {
display: none;
}
input[type=checkbox] { input[type=checkbox] {
outline: none; outline: none;
} }

View File

@ -105,9 +105,9 @@
</div> </div>
<!-- Actions --> <!-- Actions -->
<div id="popup-options"> <div id="popup-options">
<button id="popup-manage-button" i18n-text="openManage"></button> <button id="popup-manage-button" i18n-text="openManage" data-href="manage.html"></button>
<button id="popup-options-button" i18n-text="openOptionsPopup"></button> <button id="popup-options-button" i18n-text="openOptionsPopup"></button>
<button id="popup-shortcuts-button" i18n-text="openShortcutsPopup"></button> <button id="popup-shortcuts-button" class="chromium-only" i18n-text="openShortcutsPopup"></button>
</div> </div>
</div> </div>
</body> </body>

View File

@ -53,17 +53,27 @@ function initPopup(url) {
setPopupWidth(); setPopupWidth();
// force Chrome to resize the popup // force Chrome to resize the popup
document.body.style.height = '10px'; if (!FIREFOX) {
document.documentElement.style.height = '10px'; document.body.style.height = '10px';
document.documentElement.style.height = '10px';
}
// action buttons // action buttons
$('#disableAll').onchange = () => $('#disableAll').onchange = () =>
installed.classList.toggle('disabled', prefs.get('disableAll')); installed.classList.toggle('disabled', prefs.get('disableAll'));
setupLivePrefs(['disableAll']); setupLivePrefs(['disableAll']);
$('#find-styles-link').onclick = handleEvent.openURLandHide; $('#find-styles-link').onclick = handleEvent.openURLandHide;
$('#popup-manage-button').onclick = () => openURL({url: 'manage.html'}); $('#popup-manage-button').onclick = handleEvent.openURLandHide;
$('#popup-options-button').onclick = () => chrome.runtime.openOptionsPage();
$('#popup-shortcuts-button').onclick = configureCommands.open; $('#popup-options-button').onclick = () => {
chrome.runtime.openOptionsPage();
window.close();
};
const shortcutsButton = $('#popup-shortcuts-button');
shortcutsButton.dataset.href = URLS.configureCommands;
shortcutsButton.onclick = handleEvent.openURLandHide;
if (!prefs.get('popup.stylesFirst')) { if (!prefs.get('popup.stylesFirst')) {
document.body.insertBefore( document.body.insertBefore(
@ -317,8 +327,8 @@ Object.assign(handleEvent, {
openURLandHide(event) { openURLandHide(event) {
event.preventDefault(); event.preventDefault();
openURL({url: this.href}) openURL({url: this.href || this.dataset.href})
.then(close); .then(window.close);
}, },
}); });

View File

@ -441,9 +441,9 @@ function getApplicableSections({style, matchUrl, strictRegexp = true, stopOnFirs
do { do {
// only http, https, file, ftp, and chrome-extension://OWN_EXTENSION_ID allowed // only http, https, file, ftp, and chrome-extension://OWN_EXTENSION_ID allowed
if (!matchUrl.startsWith('http') if (!matchUrl.startsWith('http')
&& !matchUrl.startsWith('ftp') && !matchUrl.startsWith('ftp')
&& !matchUrl.startsWith('file') && !matchUrl.startsWith('file')
&& !matchUrl.startsWith(OWN_ORIGIN)) { && !matchUrl.startsWith(URLS.ownOrigin)) {
continue checkingSections; continue checkingSections;
} }
if (section.urls.length == 0 if (section.urls.length == 0