WIP
This commit is contained in:
parent
0f148eac32
commit
6d32ffb76b
|
@ -4,15 +4,17 @@ global handleCssTransitionBug detectSloppyRegexps
|
||||||
global openEditor
|
global openEditor
|
||||||
global styleViaAPI
|
global styleViaAPI
|
||||||
global loadScript
|
global loadScript
|
||||||
global usercss
|
global usercss styleManager
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
window.API_METHODS = Object.assign(window.API_METHODS || {}, {
|
window.API_METHODS = Object.assign(window.API_METHODS || {}, {
|
||||||
|
|
||||||
getStyles,
|
// getStyles,
|
||||||
saveStyle,
|
getSectionsByUrl: styleManager.getSectionsByUrl,
|
||||||
deleteStyle,
|
getSectionsById: styleManager.getSectionsById,
|
||||||
|
// saveStyle,
|
||||||
|
// deleteStyle,
|
||||||
|
|
||||||
getStyleFromDB: id =>
|
getStyleFromDB: id =>
|
||||||
dbExec('get', id).then(event => event.target.result),
|
dbExec('get', id).then(event => event.target.result),
|
||||||
|
@ -495,25 +497,33 @@ function updateIcon({tab, styles}) {
|
||||||
|
|
||||||
|
|
||||||
function onRuntimeMessage(msg, sender, sendResponse) {
|
function onRuntimeMessage(msg, sender, sendResponse) {
|
||||||
const fn = window.API_METHODS[msg.method];
|
if (msg.method !== 'invokeAPI') {
|
||||||
if (!fn) return;
|
// FIXME: switch everything to api.js then throw an error when msg.method is unknown.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
invoke()
|
||||||
|
.catch(err =>
|
||||||
// wrap 'Error' object instance as {__ERROR__: message},
|
// wrap 'Error' object instance as {__ERROR__: message},
|
||||||
// which will be unwrapped by sendMessage,
|
// which will be unwrapped by api.js,
|
||||||
// and prevent exceptions on sending to a closed tab
|
({
|
||||||
const respond = data =>
|
__ERROR__: err.message || String(err)
|
||||||
tryCatch(sendResponse,
|
})
|
||||||
data instanceof Error ? {__ERROR__: data.message} : data);
|
)
|
||||||
|
// prevent exceptions on sending to a closed tab
|
||||||
|
.then(output => tryCatch(sendResponse, output));
|
||||||
|
// keep channel open
|
||||||
|
return true;
|
||||||
|
|
||||||
const result = fn(msg, sender, respond);
|
function invoke() {
|
||||||
if (result instanceof Promise) {
|
try {
|
||||||
result
|
const fn = window.API_METHODS[msg.name];
|
||||||
.catch(e => ({__ERROR__: e instanceof Error ? e.message : e}))
|
if (!fn) {
|
||||||
.then(respond);
|
throw new Error(`unknown API: ${msg.name}`);
|
||||||
return KEEP_CHANNEL_OPEN;
|
}
|
||||||
} else if (result === KEEP_CHANNEL_OPEN) {
|
const context = {msg, sender};
|
||||||
return KEEP_CHANNEL_OPEN;
|
return Promise.resolve(fn.apply(context, msg.args));
|
||||||
} else if (result !== undefined) {
|
} catch (err) {
|
||||||
respond(result);
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
const db = (() => {
|
const db = (() => {
|
||||||
let exec;
|
let exec;
|
||||||
const preparing = prepare();
|
const preparing = prepare();
|
||||||
|
@ -103,9 +105,9 @@ const db = (() => {
|
||||||
|
|
||||||
case 'put':
|
case 'put':
|
||||||
if (!data.id) {
|
if (!data.id) {
|
||||||
return getStyles().then(() => {
|
return getAllStyles().then(styles => {
|
||||||
data.id = 1;
|
data.id = 1;
|
||||||
for (const style of cachedStyles.list) {
|
for (const style of styles) {
|
||||||
data.id = Math.max(data.id, style.id + 1);
|
data.id = Math.max(data.id, style.id + 1);
|
||||||
}
|
}
|
||||||
return dbExecChromeStorage('put', data);
|
return dbExecChromeStorage('put', data);
|
||||||
|
@ -118,6 +120,12 @@ const db = (() => {
|
||||||
return chromeLocal.remove(STYLE_KEY_PREFIX + data);
|
return chromeLocal.remove(STYLE_KEY_PREFIX + data);
|
||||||
|
|
||||||
case 'getAll':
|
case 'getAll':
|
||||||
|
return getAllStyles()
|
||||||
|
.then(styles => ({target: {result: styles}}));
|
||||||
|
}
|
||||||
|
return Promise.reject();
|
||||||
|
|
||||||
|
function getAllStyles() {
|
||||||
return chromeLocal.get(null).then(storage => {
|
return chromeLocal.get(null).then(storage => {
|
||||||
const styles = [];
|
const styles = [];
|
||||||
for (const key in storage) {
|
for (const key in storage) {
|
||||||
|
@ -126,9 +134,8 @@ const db = (() => {
|
||||||
styles.push(storage[key]);
|
styles.push(storage[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {target: {result: styles}};
|
return styles;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.reject();
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
/* global createCache db calcStyleDigest normalizeStyleSections db */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
const styleManager = (() => {
|
const styleManager = (() => {
|
||||||
const preparing = prepare();
|
const preparing = prepare();
|
||||||
const styles = new Map;
|
const styles = new Map();
|
||||||
const cachedStyleForUrl = createCache();
|
const cachedStyleForUrl = createCache();
|
||||||
const compiledRe = createCache();
|
const compiledRe = createCache();
|
||||||
const compiledExclusion = createCache();
|
const compiledExclusion = createCache();
|
||||||
|
@ -50,6 +53,7 @@ const styleManager = (() => {
|
||||||
cachedStyleForUrl.clear();
|
cachedStyleForUrl.clear();
|
||||||
// FIXME: invalid signature
|
// FIXME: invalid signature
|
||||||
notifyAllTabs();
|
notifyAllTabs();
|
||||||
|
return style;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +72,7 @@ const styleManager = (() => {
|
||||||
// FIXME: update installDate?
|
// FIXME: update installDate?
|
||||||
style = Object.assign(oldStyle, style);
|
style = Object.assign(oldStyle, style);
|
||||||
style.sections = normalizeStyleSections(style);
|
style.sections = normalizeStyleSections(style);
|
||||||
return dbExec('put', style);
|
return db.exec('put', style);
|
||||||
})
|
})
|
||||||
.then(event => {
|
.then(event => {
|
||||||
if (style.id == null) {
|
if (style.id == null) {
|
||||||
|
@ -142,7 +146,7 @@ const styleManager = (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function urlMatchStyle(url, style) {
|
function urlMatchStyle(url, style) {
|
||||||
if (style.exclusions && style.exclusions.some(e => compileExclusion(e).test(url)) {
|
if (style.exclusions && style.exclusions.some(e => compileExclusion(e).test(url))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -22,10 +22,10 @@ API_METHODS.styleViaAPI = !CHROME && (() => {
|
||||||
|
|
||||||
let observingTabs = false;
|
let observingTabs = false;
|
||||||
|
|
||||||
return (request, sender) => {
|
return function (request) {
|
||||||
const action = ACTIONS[request.action];
|
const action = ACTIONS[request.action];
|
||||||
return !action ? NOP :
|
return !action ? NOP :
|
||||||
action(request, sender)
|
action(request, this.sender)
|
||||||
.catch(onError)
|
.catch(onError)
|
||||||
.then(maybeToggleObserver);
|
.then(maybeToggleObserver);
|
||||||
};
|
};
|
||||||
|
|
55
content/api.js
Normal file
55
content/api.js
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const API = (() => {
|
||||||
|
const preparing = promisify(chrome.runtime.getBackgroundPage.bind(chrome.runtime))()
|
||||||
|
.catch(() => null);
|
||||||
|
const runtimeSendMessage = promisify(chrome.runtime.sendMessage.bind(chrome.runtime));
|
||||||
|
return new Proxy(() => {}, {
|
||||||
|
get: (target, name) =>
|
||||||
|
(...args) => invokeBG(name, args),
|
||||||
|
});
|
||||||
|
|
||||||
|
function sendMessage(msg) {
|
||||||
|
return runtimeSendMessage(msg)
|
||||||
|
.then(result => {
|
||||||
|
if (result.__ERROR__) {
|
||||||
|
throw new Error(result.__ERROR__);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function promisify(fn) {
|
||||||
|
return (...args) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
fn(...args, (...result) => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
reject(chrome.runtime.lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(
|
||||||
|
result.length === 0 ? undefined :
|
||||||
|
result.length === 1 ? result[1] : result
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function invokeBG(name, args) {
|
||||||
|
return preparing.then(BG => {
|
||||||
|
if (!BG) {
|
||||||
|
return sendMessage({
|
||||||
|
method: 'invokeAPI',
|
||||||
|
name,
|
||||||
|
args
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// FIXME: why deep-copying input/output?
|
||||||
|
if (BG !== window) {
|
||||||
|
args = BG.deepCopy(args);
|
||||||
|
}
|
||||||
|
return BG.API_METHODS[name](...args)
|
||||||
|
.then(BG.deepCopy);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
|
@ -25,7 +25,13 @@
|
||||||
const FF_BUG461 = !CHROME && !isOwnPage && !Event.prototype.getPreventDefault;
|
const FF_BUG461 = !CHROME && !isOwnPage && !Event.prototype.getPreventDefault;
|
||||||
const pageContextQueue = [];
|
const pageContextQueue = [];
|
||||||
|
|
||||||
requestStyles();
|
requestStyles({}, styles => {
|
||||||
|
// FIXME: need transition patch?
|
||||||
|
// if (needTransitionPatch(styles)) {
|
||||||
|
// applyTransitionPatch();
|
||||||
|
// }
|
||||||
|
applyStyles(styles);
|
||||||
|
});
|
||||||
chrome.runtime.onMessage.addListener(applyOnMessage);
|
chrome.runtime.onMessage.addListener(applyOnMessage);
|
||||||
window.applyOnMessage = applyOnMessage;
|
window.applyOnMessage = applyOnMessage;
|
||||||
|
|
||||||
|
@ -36,7 +42,7 @@
|
||||||
|
|
||||||
function requestStyles(options, callback = applyStyles) {
|
function requestStyles(options, callback = applyStyles) {
|
||||||
if (!chrome.app && document instanceof XMLDocument) {
|
if (!chrome.app && document instanceof XMLDocument) {
|
||||||
chrome.runtime.sendMessage({method: 'styleViaAPI', action: 'styleApply'});
|
API.styleViaAPI({action: 'styleApply'});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var matchUrl = location.href;
|
var matchUrl = location.href;
|
||||||
|
@ -49,19 +55,15 @@
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
const request = Object.assign({
|
// const request = Object.assign({
|
||||||
method: 'getStylesForFrame',
|
// method: 'getStylesForFrame',
|
||||||
asHash: true,
|
// asHash: true,
|
||||||
matchUrl,
|
// matchUrl,
|
||||||
}, options);
|
// }, options);
|
||||||
// On own pages we request the styles directly to minimize delay and flicker
|
// FIXME: options?
|
||||||
if (typeof API === 'function') {
|
// FIXME: getStylesFallback?
|
||||||
API.getStyles(request).then(callback);
|
API.getSectionsByUrl(matchUrl)
|
||||||
} else if (!CHROME && getStylesFallback(request)) {
|
.then(callback);
|
||||||
// NOP
|
|
||||||
} else {
|
|
||||||
chrome.runtime.sendMessage(request, callback);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,12 +101,12 @@
|
||||||
|
|
||||||
if (!chrome.app && document instanceof XMLDocument && request.method !== 'ping') {
|
if (!chrome.app && document instanceof XMLDocument && request.method !== 'ping') {
|
||||||
request.action = request.method;
|
request.action = request.method;
|
||||||
request.method = 'styleViaAPI';
|
request.method = null;
|
||||||
request.styles = null;
|
request.styles = null;
|
||||||
if (request.style) {
|
if (request.style) {
|
||||||
request.style.sections = null;
|
request.style.sections = null;
|
||||||
}
|
}
|
||||||
chrome.runtime.sendMessage(request);
|
API.styleViaAPI(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +122,7 @@
|
||||||
}
|
}
|
||||||
if (request.style.enabled) {
|
if (request.style.enabled) {
|
||||||
removeStyle({id: request.style.id, retire: true});
|
removeStyle({id: request.style.id, retire: true});
|
||||||
requestStyles({id: request.style.id});
|
API.getSectionsById(request.style.id).then(applyStyles);
|
||||||
} else {
|
} else {
|
||||||
removeStyle(request.style);
|
removeStyle(request.style);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +130,7 @@
|
||||||
|
|
||||||
case 'styleAdded':
|
case 'styleAdded':
|
||||||
if (request.style.enabled) {
|
if (request.style.enabled) {
|
||||||
requestStyles({id: request.style.id});
|
API.getSectionsById(request.style.id).then(applyStyles);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -193,7 +195,7 @@
|
||||||
addStyleElement(inCache);
|
addStyleElement(inCache);
|
||||||
disabledElements.delete(id);
|
disabledElements.delete(id);
|
||||||
} else {
|
} else {
|
||||||
requestStyles({id});
|
API.getSectionsById(id).then(applyStyles);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (inDoc) {
|
if (inDoc) {
|
||||||
|
@ -224,11 +226,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyStyles(styles) {
|
function applyStyles(styles) {
|
||||||
if (!styles) {
|
// if (!styles) {
|
||||||
// Chrome is starting up
|
// Chrome is starting up
|
||||||
requestStyles();
|
// requestStyles();
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!document.documentElement) {
|
if (!document.documentElement) {
|
||||||
new MutationObserver((mutations, observer) => {
|
new MutationObserver((mutations, observer) => {
|
||||||
|
@ -240,12 +242,13 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('disableAll' in styles) {
|
// FIXME: switch to prefs
|
||||||
doDisableAll(styles.disableAll);
|
// if ('disableAll' in styles) {
|
||||||
}
|
// doDisableAll(styles.disableAll);
|
||||||
if ('exposeIframes' in styles) {
|
// }
|
||||||
doExposeIframes(styles.exposeIframes);
|
// if ('exposeIframes' in styles) {
|
||||||
}
|
// doExposeIframes(styles.exposeIframes);
|
||||||
|
// }
|
||||||
|
|
||||||
const gotNewStyles = styles.length || styles.needTransitionPatch;
|
const gotNewStyles = styles.length || styles.needTransitionPatch;
|
||||||
if (gotNewStyles) {
|
if (gotNewStyles) {
|
||||||
|
@ -256,22 +259,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (styles.needTransitionPatch) {
|
|
||||||
applyTransitionPatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gotNewStyles) {
|
if (gotNewStyles) {
|
||||||
for (const id in styles) {
|
for (const section of styles) {
|
||||||
const sections = styles[id];
|
applySections(section.id, section.code);
|
||||||
if (!Array.isArray(sections)) continue;
|
|
||||||
applySections(id, sections.map(({code}) => code).join('\n'));
|
|
||||||
}
|
}
|
||||||
docRootObserver.firstStart();
|
docRootObserver.firstStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FF_BUG461 && (gotNewStyles || styles.needTransitionPatch)) {
|
// FIXME
|
||||||
setContentsInPageContext();
|
// if (FF_BUG461 && (gotNewStyles || styles.needTransitionPatch)) {
|
||||||
}
|
// setContentsInPageContext();
|
||||||
|
// }
|
||||||
|
|
||||||
if (!isOwnPage && !docRewriteObserver && styleElements.size) {
|
if (!isOwnPage && !docRewriteObserver && styleElements.size) {
|
||||||
initDocRewriteObserver();
|
initDocRewriteObserver();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
function createCache(size = 1000) {
|
function createCache(size = 1000) {
|
||||||
const map = new Map;
|
const map = new Map();
|
||||||
const buffer = Array(size);
|
const buffer = Array(size);
|
||||||
let index = 0;
|
let index = 0;
|
||||||
let lastIndex = 0;
|
let lastIndex = 0;
|
||||||
|
@ -9,7 +11,9 @@ function createCache(size = 1000) {
|
||||||
delete: delete_,
|
delete: delete_,
|
||||||
clear,
|
clear,
|
||||||
has: id => map.has(id),
|
has: id => map.has(id),
|
||||||
get size: () => map.size
|
get size() {
|
||||||
|
return map.size;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function get(id) {
|
function get(id) {
|
||||||
|
|
|
@ -104,61 +104,6 @@ if (FIREFOX_NO_DOM_STORAGE) {
|
||||||
Object.defineProperty(window, 'sessionStorage', {value: {}});
|
Object.defineProperty(window, 'sessionStorage', {value: {}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-var
|
|
||||||
var API = (() => {
|
|
||||||
return new Proxy(() => {}, {
|
|
||||||
get: (target, name) =>
|
|
||||||
name === 'remoteCall' ?
|
|
||||||
remoteCall :
|
|
||||||
arg => invokeBG(name, arg),
|
|
||||||
});
|
|
||||||
|
|
||||||
function remoteCall(name, arg, remoteWindow) {
|
|
||||||
let thing = window[name] || window.API_METHODS[name];
|
|
||||||
if (typeof thing === 'function') {
|
|
||||||
thing = thing(arg);
|
|
||||||
}
|
|
||||||
if (!thing || typeof thing !== 'object') {
|
|
||||||
return thing;
|
|
||||||
} else if (thing instanceof Promise) {
|
|
||||||
return thing.then(product => remoteWindow.deepCopy(product));
|
|
||||||
} else {
|
|
||||||
return remoteWindow.deepCopy(thing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function invokeBG(name, arg = {}) {
|
|
||||||
if (BG && (name in BG || name in BG.API_METHODS)) {
|
|
||||||
const call = BG !== window ?
|
|
||||||
BG.API.remoteCall(name, BG.deepCopy(arg), window) :
|
|
||||||
remoteCall(name, arg, BG);
|
|
||||||
return Promise.resolve(call);
|
|
||||||
}
|
|
||||||
if (BG && BG.getStyles) {
|
|
||||||
throw new Error('Bad API method', name, arg);
|
|
||||||
}
|
|
||||||
if (FIREFOX) {
|
|
||||||
arg.method = name;
|
|
||||||
return sendMessage(arg);
|
|
||||||
}
|
|
||||||
return onBackgroundReady().then(() => invokeBG(name, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
function onBackgroundReady() {
|
|
||||||
return BG && BG.getStyles ? Promise.resolve() : new Promise(function ping(resolve) {
|
|
||||||
sendMessage({method: 'healthCheck'}, health => {
|
|
||||||
if (health !== undefined) {
|
|
||||||
BG = chrome.extension.getBackgroundPage();
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
setTimeout(ping, 0, resolve);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
function notifyAllTabs(msg) {
|
function notifyAllTabs(msg) {
|
||||||
const originalMessage = msg;
|
const originalMessage = msg;
|
||||||
const styleUpdated = msg.method === 'styleUpdated' || msg.method === 'exclusionsUpdated';
|
const styleUpdated = msg.method === 'styleUpdated' || msg.method === 'exclusionsUpdated';
|
||||||
|
@ -224,7 +169,6 @@ function notifyAllTabs(msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function sendMessage(msg, callback) {
|
function sendMessage(msg, callback) {
|
||||||
/*
|
/*
|
||||||
Promise mode [default]:
|
Promise mode [default]:
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true,
|
"all_frames": true,
|
||||||
"match_about_blank": true,
|
"match_about_blank": true,
|
||||||
"js": ["content/apply.js"]
|
"js": ["content/api.js", "content/apply.js"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"matches": ["http://userstyles.org/*", "https://userstyles.org/*"],
|
"matches": ["http://userstyles.org/*", "https://userstyles.org/*"],
|
||||||
|
|
Loading…
Reference in New Issue
Block a user