install usercss from raw.githubusercontent.com

This commit is contained in:
tophf 2017-11-24 19:33:50 +03:00
parent 59d32e6f2f
commit aedb02bbb1
5 changed files with 120 additions and 37 deletions

View File

@ -28,6 +28,16 @@ chrome.runtime.onMessage.addListener(onRuntimeMessage);
chrome.webNavigation.onReferenceFragmentUpdated.addListener(data => chrome.webNavigation.onReferenceFragmentUpdated.addListener(data =>
listener('styleReplaceAll', data)); listener('styleReplaceAll', data));
if (FIREFOX) {
// FF applies page CSP even to content scripts, https://bugzil.la/1267027
chrome.webNavigation.onCommitted.addListener(webNavUsercssInstallerFF, {
url: [
{urlPrefix: 'https://raw.githubusercontent.com/', urlSuffix: '.user.css'},
{urlPrefix: 'https://raw.githubusercontent.com/', urlSuffix: '.user.styl'},
]
});
}
} }
if (chrome.contextMenus) { if (chrome.contextMenus) {
@ -242,6 +252,21 @@ function webNavigationListenerChrome(method, data) {
} }
function webNavUsercssInstallerFF(data) {
const {tabId} = data;
Promise.all([
sendMessage({tabId, method: 'ping'}),
// we need tab index to open the installer next to the original one
// and also to skip the double-invocation in FF which assigns tab url later
getTab(tabId),
]).then(([pong, tab]) => {
if (pong !== true && tab.url !== 'about:blank') {
usercssHelper.openInstallPage(tab, {direct: true});
}
});
}
function updateIcon(tab, styles) { function updateIcon(tab, styles) {
if (tab.id < 0) { if (tab.id < 0) {
return; return;

View File

@ -203,12 +203,18 @@ function dbExecChromeStorage(method, data) {
case 'getAll': case 'getAll':
return chromeLocal.get(null).then(storage => { return chromeLocal.get(null).then(storage => {
const styles = []; const styles = [];
const leftovers = [];
for (const key in storage) { for (const key in storage) {
if (key.startsWith(STYLE_KEY_PREFIX) && if (key.startsWith(STYLE_KEY_PREFIX) &&
Number(key.substr(STYLE_KEY_PREFIX.length))) { Number(key.substr(STYLE_KEY_PREFIX.length))) {
styles.push(storage[key]); styles.push(storage[key]);
} else if (key.startsWith('tempUsercssCode')) {
leftovers.push(key);
} }
} }
if (leftovers.length) {
chromeLocal.remove(leftovers);
}
return {target: {result: styles}}; return {target: {result: styles}};
}); });
} }

View File

@ -1,4 +1,4 @@
/* global usercss saveStyle getStyles */ /* global usercss saveStyle getStyles chromeLocal */
'use strict'; 'use strict';
// eslint-disable-next-line no-var // eslint-disable-next-line no-var
@ -78,16 +78,29 @@ var usercssHelper = (() => {
); );
} }
function openInstallPage(tab, request) { function openInstallPage(tab, {url = tab.url, direct} = {}) {
const url = '/install-usercss.html' + if (direct) {
'?updateUrl=' + encodeURIComponent(request.updateUrl) + prefetchCodeForInstallation(tab.id, url);
'&tabId=' + tab.id; }
return wrapReject(openURL({ return wrapReject(openURL({
url, url: '/install-usercss.html' +
'?updateUrl=' + encodeURIComponent(url) +
'&tabId=' + (direct ? -tab.id : tab.id),
index: tab.index + 1, index: tab.index + 1,
openerTabId: tab.id, openerTabId: tab.id,
})); }));
} }
function prefetchCodeForInstallation(tabId, url) {
const key = 'tempUsercssCode' + tabId;
Promise.all([
download(url),
chromeLocal.setValue(key, {loading: true}),
]).then(([code]) => {
chromeLocal.setValue(key, code);
setTimeout(() => chromeLocal.remove(key), 60e3);
});
}
return {build, save, findDup, openInstallPage}; return {build, save, findDup, openInstallPage};
})(); })();

View File

@ -65,10 +65,6 @@ function initUsercssInstall() {
let watcher; let watcher;
chrome.runtime.onConnect.addListener(port => { chrome.runtime.onConnect.addListener(port => {
// FIXME: is this the correct way to reject a connection?
// https://developer.chrome.com/extensions/messaging#connect
console.assert(port.name === 'usercss-install');
port.onMessage.addListener(msg => { port.onMessage.addListener(msg => {
switch (msg.method) { switch (msg.method) {
case 'getSourceCode': case 'getSourceCode':
@ -102,7 +98,7 @@ function initUsercssInstall() {
}); });
chrome.runtime.sendMessage({ chrome.runtime.sendMessage({
method: 'openUsercssInstallPage', method: 'openUsercssInstallPage',
updateUrl: location.href, url: location.href,
}, r => r && r.__ERROR__ && alert(r.__ERROR__)); }, r => r && r.__ERROR__ && alert(r.__ERROR__));
} }

View File

@ -1,5 +1,5 @@
/* global CodeMirror semverCompare makeLink closeCurrentTab */ /* global CodeMirror semverCompare makeLink closeCurrentTab */
/* global messageBox */ /* global messageBox download chromeLocal */
'use strict'; 'use strict';
(() => { (() => {
@ -7,30 +7,35 @@
let liveReload = false; let liveReload = false;
let installed = false; let installed = false;
const port = chrome.tabs.connect( const tabId = Number(params.get('tabId'));
Number(params.get('tabId')), let port;
{name: 'usercss-install', frameId: 0}
); if (tabId < 0) {
port.postMessage({method: 'getSourceCode'}); $('.live-reload').remove();
port.onMessage.addListener(msg => { getCodeDirectly();
switch (msg.method) { } else {
case 'getSourceCodeResponse': port = chrome.tabs.connect(tabId);
if (msg.error) { port.postMessage({method: 'getSourceCode'});
messageBox.alert(msg.error); port.onMessage.addListener(msg => {
} else { switch (msg.method) {
initSourceCode(msg.sourceCode); case 'getSourceCodeResponse':
} if (msg.error) {
break; messageBox.alert(msg.error);
case 'sourceCodeChanged': } else {
if (msg.error) { initSourceCode(msg.sourceCode);
messageBox.alert(msg.error); }
} else { break;
liveReloadUpdate(msg.sourceCode); case 'sourceCodeChanged':
} if (msg.error) {
break; messageBox.alert(msg.error);
} } else {
}); liveReloadUpdate(msg.sourceCode);
port.onDisconnect.addListener(closeCurrentTab); }
break;
}
});
port.onDisconnect.addListener(closeCurrentTab);
}
const cm = CodeMirror($('.main'), {readOnly: true}); const cm = CodeMirror($('.main'), {readOnly: true});
let liveReloadPending = Promise.resolve(); let liveReloadPending = Promise.resolve();
@ -183,7 +188,7 @@
sendMessage({method: 'openEditor', id: style.id}); sendMessage({method: 'openEditor', id: style.id});
if (!liveReload) { if (!liveReload) {
port.postMessage({method: 'closeTab'}); chrome.runtime.sendMessage({method: 'closeTab'});
} }
window.dispatchEvent(new CustomEvent('installed')); window.dispatchEvent(new CustomEvent('installed'));
@ -252,6 +257,10 @@
} }
}; };
if (!port) {
return;
}
// live reload // live reload
const setLiveReload = $('.live-reload input[type=checkbox]'); const setLiveReload = $('.live-reload input[type=checkbox]');
if (updateUrl.protocol !== 'file:') { if (updateUrl.protocol !== 'file:') {
@ -299,4 +308,38 @@
cm.setSize(null, $('.main').offsetHeight - $('.warnings').offsetHeight); cm.setSize(null, $('.main').offsetHeight - $('.warnings').offsetHeight);
} }
} }
function getCodeDirectly() {
// FF applies page CSP even to content scripts, https://bugzil.la/1267027
// To circumvent that, the bg process downloads the code directly
const key = 'tempUsercssCode' + (-tabId);
chrome.storage.local.get(key, data => {
const code = data && data[key];
// bg already downloaded the code
if (typeof code === 'string') {
initSourceCode(code);
chrome.storage.local.remove(key);
return;
}
// bg still downloads the code
if (code && code.loading) {
const waitForCodeInStorage = (changes, area) => {
if (area === 'local' && key in changes) {
initSourceCode(changes[key].newValue);
chrome.storage.onChanged.removeListener(waitForCodeInStorage);
chrome.storage.local.remove(key);
}
};
chrome.storage.onChanged.addListener(waitForCodeInStorage);
return;
}
// on the off-chance dbExecChromeStorage.getAll ran right after bg download was saved
download(params.get('updateUrl'))
.then(initSourceCode)
.catch(err => messageBox.alert(t('styleInstallFailed', String(err))));
});
}
})(); })();