Add: implement bug 461
This commit is contained in:
parent
7ed39ab6ef
commit
c657d7e55c
|
@ -146,6 +146,8 @@ prefs.subscribe([
|
||||||
'iconset',
|
'iconset',
|
||||||
], () => debounce(refreshAllIcons));
|
], () => debounce(refreshAllIcons));
|
||||||
|
|
||||||
|
prefs.initializing.then(refreshIconBadgeColor);
|
||||||
|
|
||||||
// *************************************************************************
|
// *************************************************************************
|
||||||
chrome.runtime.onInstalled.addListener(({reason}) => {
|
chrome.runtime.onInstalled.addListener(({reason}) => {
|
||||||
if (reason !== 'update') return;
|
if (reason !== 'update') return;
|
||||||
|
|
180
content/apply.js
180
content/apply.js
|
@ -1,5 +1,6 @@
|
||||||
/* eslint no-var: 0 */
|
/* eslint no-var: 0 */
|
||||||
/* global msg API prefs */
|
/* global msg API prefs */
|
||||||
|
/* exported APPLY */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// some weird bug in new Chrome: the content script gets injected multiple times
|
// some weird bug in new Chrome: the content script gets injected multiple times
|
||||||
|
@ -12,17 +13,9 @@ const APPLY = (() => {
|
||||||
var disableAll = false;
|
var disableAll = false;
|
||||||
var styleElements = new Map();
|
var styleElements = new Map();
|
||||||
var disabledElements = new Map();
|
var disabledElements = new Map();
|
||||||
var retiredStyleTimers = new Map();
|
|
||||||
var docRewriteObserver;
|
var docRewriteObserver;
|
||||||
var docRootObserver;
|
var docRootObserver;
|
||||||
|
|
||||||
// FF59+ bug workaround
|
|
||||||
// See https://github.com/openstyles/stylus/issues/461
|
|
||||||
// Since it's easy to spoof the browser version in pre-Quantum FF we're checking
|
|
||||||
// for getPreventDefault which got removed in FF59 https://bugzil.la/691151
|
|
||||||
const FF_BUG461 = !CHROME && !isOwnPage && !Event.prototype.getPreventDefault;
|
|
||||||
const pageContextQueue = [];
|
|
||||||
|
|
||||||
// FIXME: styleViaAPI
|
// FIXME: styleViaAPI
|
||||||
// FIXME: getStylesFallback?
|
// FIXME: getStylesFallback?
|
||||||
if (!chrome.app && document instanceof XMLDocument) {
|
if (!chrome.app && document instanceof XMLDocument) {
|
||||||
|
@ -33,16 +26,19 @@ const APPLY = (() => {
|
||||||
const styles = Object.values(result);
|
const styles = Object.values(result);
|
||||||
// CSS transition bug workaround: since we insert styles asynchronously,
|
// CSS transition bug workaround: since we insert styles asynchronously,
|
||||||
// the browsers, especially Firefox, may apply all transitions on page load
|
// the browsers, especially Firefox, may apply all transitions on page load
|
||||||
if (styles.some(s => s.code.includes('transition'))) {
|
applyStyles(styles, () => {
|
||||||
applyTransitionPatch();
|
if (styles.some(s => s.code.includes('transition'))) {
|
||||||
}
|
applyTransitionPatch();
|
||||||
applyStyles(styles);
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
msg.onTab(applyOnMessage);
|
msg.onTab(applyOnMessage);
|
||||||
|
|
||||||
if (!isOwnPage) {
|
if (!isOwnPage) {
|
||||||
window.dispatchEvent(new CustomEvent(chrome.runtime.id));
|
window.dispatchEvent(new CustomEvent(chrome.runtime.id, {
|
||||||
|
detail: {method: 'orphan'}
|
||||||
|
}));
|
||||||
window.addEventListener(chrome.runtime.id, orphanCheck, true);
|
window.addEventListener(chrome.runtime.id, orphanCheck, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +50,66 @@ const APPLY = (() => {
|
||||||
prefs.subscribe(['exposeIframes'], updateExposeIframes);
|
prefs.subscribe(['exposeIframes'], updateExposeIframes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setStyleContent = createSetStyleContent();
|
||||||
|
|
||||||
|
function createSetStyleContent() {
|
||||||
|
// FF59+ bug workaround
|
||||||
|
// See https://github.com/openstyles/stylus/issues/461
|
||||||
|
// Since it's easy to spoof the browser version in pre-Quantum FF we're checking
|
||||||
|
// for getPreventDefault which got removed in FF59 https://bugzil.la/691151
|
||||||
|
// const FF_BUG461 = !CHROME && !isOwnPage && !Event.prototype.getPreventDefault;
|
||||||
|
const EVENT_NAME = chrome.runtime.id;
|
||||||
|
if (CHROME || isOwnPage || Event.prototype.getPreventDefault || !injectPageScript()) {
|
||||||
|
return (el, content) => {
|
||||||
|
// FIXME: do we have to keep el.sheet.disabled?
|
||||||
|
el.textContent = content;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return (el, content) => {
|
||||||
|
window.dispatchEvent(EVENT_NAME, new CustomEvent({detail: {
|
||||||
|
method: 'setStyleContent',
|
||||||
|
id: el.id,
|
||||||
|
content
|
||||||
|
}}));
|
||||||
|
};
|
||||||
|
|
||||||
|
function injectPageScript() {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
const scriptContent = EVENT_NAME => {
|
||||||
|
document.currentScript.remove();
|
||||||
|
window.dispatchEvent(new CustomEvent(EVENT_NAME, {
|
||||||
|
detail: {method: 'pageScriptOK'}
|
||||||
|
}));
|
||||||
|
window.addEventListener(EVENT_NAME, function handler(e) {
|
||||||
|
const {method, id, content} = e.detail;
|
||||||
|
if (method === 'setStyleContent') {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
if (!el) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const disabled = el.sheet.disabled;
|
||||||
|
el.textContent = content;
|
||||||
|
el.sheet.disabled = disabled;
|
||||||
|
} else if (method === 'orphan') {
|
||||||
|
window.removeEventListener(EVENT_NAME, handler);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
};
|
||||||
|
script.text = `(${scriptContent})(${JSON.stringify(EVENT_NAME)})`;
|
||||||
|
let ok = false;
|
||||||
|
const check = e => {
|
||||||
|
if (e.detail.method === 'pageScriptOK') {
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener(EVENT_NAME, check, true);
|
||||||
|
ROOT.appendChild(script);
|
||||||
|
window.removeEventListener(EVENT_NAME, check, true);
|
||||||
|
script.remove();
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getMatchUrl() {
|
function getMatchUrl() {
|
||||||
var matchUrl = location.href;
|
var matchUrl = location.href;
|
||||||
if (!matchUrl.match(/^(http|file|chrome|ftp)/)) {
|
if (!matchUrl.match(/^(http|file|chrome|ftp)/)) {
|
||||||
|
@ -222,30 +278,20 @@ const APPLY = (() => {
|
||||||
updateCount();
|
updateCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeStyle({id, retire = false}) {
|
function removeStyle({id}) {
|
||||||
const el = document.getElementById(ID_PREFIX + id);
|
const el = document.getElementById(ID_PREFIX + id);
|
||||||
if (el) {
|
if (el) {
|
||||||
if (retire) {
|
docRootObserver.evade(() => el.remove());
|
||||||
// to avoid page flicker when the style is updated
|
|
||||||
// instead of removing it immediately we rename its ID and queue it
|
|
||||||
// to be deleted in applyStyles after a new version is fetched and applied
|
|
||||||
const deadID = id + '-ghost';
|
|
||||||
el.id = ID_PREFIX + deadID;
|
|
||||||
// in case something went wrong and new style was never applied
|
|
||||||
retiredStyleTimers.set(deadID, setTimeout(removeStyle, 1000, {id: deadID}));
|
|
||||||
} else {
|
|
||||||
docRootObserver.evade(() => el.remove());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
disabledElements.delete(id);
|
disabledElements.delete(id);
|
||||||
retiredStyleTimers.delete(id);
|
if (styleElements.delete(id)) {
|
||||||
if (styleElements.delete(ID_PREFIX + id)) {
|
|
||||||
updateCount();
|
updateCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyStyles(styles) {
|
function applyStyles(styles, done) {
|
||||||
if (!styles.length) {
|
if (!styles.length) {
|
||||||
|
done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,23 +299,21 @@ const APPLY = (() => {
|
||||||
new MutationObserver((mutations, observer) => {
|
new MutationObserver((mutations, observer) => {
|
||||||
if (document.documentElement) {
|
if (document.documentElement) {
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
applyStyles(styles);
|
applyStyles(styles, done);
|
||||||
}
|
}
|
||||||
}).observe(document, {childList: true});
|
}).observe(document, {childList: true});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (styles.length) {
|
if (docRootObserver) {
|
||||||
if (docRootObserver) {
|
docRootObserver.stop();
|
||||||
docRootObserver.stop();
|
} else {
|
||||||
} else {
|
initDocRootObserver();
|
||||||
initDocRootObserver();
|
|
||||||
}
|
|
||||||
for (const section of styles) {
|
|
||||||
applySections(section.id, section.code);
|
|
||||||
}
|
|
||||||
docRootObserver.firstStart();
|
|
||||||
}
|
}
|
||||||
|
for (const section of styles) {
|
||||||
|
applySections(section.id, section.code);
|
||||||
|
}
|
||||||
|
docRootObserver.firstStart();
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
// if (FF_BUG461 && (gotNewStyles || styles.needTransitionPatch)) {
|
// if (FF_BUG461 && (gotNewStyles || styles.needTransitionPatch)) {
|
||||||
|
@ -280,34 +324,17 @@ const APPLY = (() => {
|
||||||
initDocRewriteObserver();
|
initDocRewriteObserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retiredStyleTimers.size) {
|
|
||||||
setTimeout(() => {
|
|
||||||
for (const [id, timer] of retiredStyleTimers.entries()) {
|
|
||||||
removeStyle({id});
|
|
||||||
clearTimeout(timer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateExposeIframes();
|
updateExposeIframes();
|
||||||
if (styles.length) {
|
updateCount();
|
||||||
updateCount();
|
done();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function applySections(styleId, code) {
|
function applySections(id, code) {
|
||||||
const id = ID_PREFIX + styleId;
|
let el = styleElements.get(id) || document.getElementById(ID_PREFIX + id);
|
||||||
let el = styleElements.get(id) || document.getElementById(id);
|
if (el && CHROME < 3321) {
|
||||||
if (el && el.textContent !== code) {
|
// workaround for Chrome devtools bug fixed in v65
|
||||||
if (CHROME < 3321) {
|
el.remove();
|
||||||
// workaround for Chrome devtools bug fixed in v65
|
el = null;
|
||||||
el.remove();
|
|
||||||
el = null;
|
|
||||||
} else if (FF_BUG461) {
|
|
||||||
pageContextQueue.push({id: el.id, el, code});
|
|
||||||
} else {
|
|
||||||
el.textContent = code;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!el) {
|
if (!el) {
|
||||||
if (document.documentElement instanceof SVGSVGElement) {
|
if (document.documentElement instanceof SVGSVGElement) {
|
||||||
|
@ -320,19 +347,17 @@ const APPLY = (() => {
|
||||||
// HTML document style; also works on HTML-embedded SVG
|
// HTML document style; also works on HTML-embedded SVG
|
||||||
el = document.createElement('style');
|
el = document.createElement('style');
|
||||||
}
|
}
|
||||||
el.id = id;
|
el.id = ID_PREFIX + id;
|
||||||
el.type = 'text/css';
|
el.type = 'text/css';
|
||||||
// SVG className is not a string, but an instance of SVGAnimatedString
|
// SVG className is not a string, but an instance of SVGAnimatedString
|
||||||
el.classList.add('stylus');
|
el.classList.add('stylus');
|
||||||
if (FF_BUG461) {
|
|
||||||
pageContextQueue.push({id: el.id, el, code});
|
|
||||||
} else {
|
|
||||||
el.textContent = code;
|
|
||||||
}
|
|
||||||
addStyleElement(el);
|
addStyleElement(el);
|
||||||
}
|
}
|
||||||
|
if (el.textContent !== code) {
|
||||||
|
setStyleContent(el, code);
|
||||||
|
}
|
||||||
styleElements.set(id, el);
|
styleElements.set(id, el);
|
||||||
disabledElements.delete(Number(styleId));
|
disabledElements.delete(id);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,12 +395,12 @@ const APPLY = (() => {
|
||||||
oldStyles.forEach(el => (el.id += '-ghost'));
|
oldStyles.forEach(el => (el.id += '-ghost'));
|
||||||
styleElements.clear();
|
styleElements.clear();
|
||||||
disabledElements.clear();
|
disabledElements.clear();
|
||||||
[...retiredStyleTimers.values()].forEach(clearTimeout);
|
|
||||||
retiredStyleTimers.clear();
|
|
||||||
applyStyles(newStyles);
|
applyStyles(newStyles);
|
||||||
|
const removeOld = () => oldStyles.forEach(el => el.remove());
|
||||||
if (docRewriteObserver) {
|
if (docRewriteObserver) {
|
||||||
docRootObserver.evade(() =>
|
docRootObserver.evade(removeOld);
|
||||||
oldStyles.forEach(el => el.remove()));
|
} else {
|
||||||
|
removeOld();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +425,10 @@ const APPLY = (() => {
|
||||||
return parseInt(el.id.substr(ID_PREFIX.length));
|
return parseInt(el.id.substr(ID_PREFIX.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
function orphanCheck() {
|
function orphanCheck(e) {
|
||||||
|
if (e && e.detail.method !== 'orphan') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (chrome.i18n && chrome.i18n.getUILanguage()) {
|
if (chrome.i18n && chrome.i18n.getUILanguage()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user