apply: ensure style elements follow <body>

This commit is contained in:
tophf 2017-08-16 14:00:59 +03:00
parent f80f5612d6
commit 93fdd787d4

View File

@ -12,7 +12,7 @@ var styleElements = new Map();
var disabledElements = new Map(); var disabledElements = new Map();
var retiredStyleTimers = new Map(); var retiredStyleTimers = new Map();
var docRewriteObserver; var docRewriteObserver;
var docHeadObserver; var docRootObserver;
requestStyles(); requestStyles();
chrome.runtime.onMessage.addListener(applyOnMessage); chrome.runtime.onMessage.addListener(applyOnMessage);
@ -203,6 +203,7 @@ function applyStyles(styles) {
applySections(id, styles[id]); applySections(id, styles[id]);
} }
initDocRewriteObserver(); initDocRewriteObserver();
initDocRootObserver();
if (retiredStyleTimers.size) { if (retiredStyleTimers.size) {
setTimeout(() => { setTimeout(() => {
for (const [id, timer] of retiredStyleTimers.entries()) { for (const [id, timer] of retiredStyleTimers.entries()) {
@ -211,17 +212,6 @@ function applyStyles(styles) {
} }
}); });
} }
if (styleElements.size && !document.head && !docHeadObserver) {
// HEAD is not yet present so we'll wait for it and move the style elements
docHeadObserver = new MutationObserver(() => {
docHeadObserver.disconnect();
docHeadObserver = null;
for (const el of styleElements.values()) {
ROOT.insertBefore(el, document.body);
}
});
docHeadObserver.observe(ROOT, {childList: true});
}
} }
@ -310,6 +300,36 @@ function initDocRewriteObserver() {
} }
function initDocRootObserver() {
if (!styleElements.size || document.body || docRootObserver) {
return;
}
// wait for BODY and move all style elements after it
docRootObserver = new MutationObserver(() => {
let expectedPrevSibling = document.body || document.head;
if (!expectedPrevSibling) {
return;
}
docRootObserver.disconnect();
for (const el of styleElements.values()) {
if (el.previousElementSibling !== expectedPrevSibling) {
ROOT.insertBefore(el, expectedPrevSibling.nextSibling);
expectedPrevSibling = el;
}
}
if (document.body) {
docRootObserver = null;
} else {
docRootObserver.connect();
}
});
docRootObserver.connect = () => {
docRootObserver.observe(ROOT, {childList: true});
};
docRootObserver.connect();
}
function orphanCheck() { function orphanCheck() {
const port = chrome.runtime.connect(); const port = chrome.runtime.connect();
if (port) { if (port) {
@ -319,9 +339,7 @@ function orphanCheck() {
// we're orphaned due to an extension update // we're orphaned due to an extension update
// we can detach the mutation observer // we can detach the mutation observer
if (docRewriteObserver) { [docRewriteObserver, docRootObserver].forEach(ob => ob && ob.disconnect());
docRewriteObserver.disconnect();
}
// we can detach event listeners // we can detach event listeners
window.removeEventListener(chrome.runtime.id, orphanCheck, true); window.removeEventListener(chrome.runtime.id, orphanCheck, true);
// we can't detach chrome.runtime.onMessage because it's no longer connected internally // we can't detach chrome.runtime.onMessage because it's no longer connected internally
@ -334,6 +352,7 @@ function orphanCheck() {
'applyStyleState', 'applyStyleState',
'doDisableAll', 'doDisableAll',
'initDocRewriteObserver', 'initDocRewriteObserver',
'initDocRootObserver',
'orphanCheck', 'orphanCheck',
'removeStyle', 'removeStyle',
'replaceAll', 'replaceAll',
@ -344,5 +363,6 @@ function orphanCheck() {
'retiredStyleTimers', 'retiredStyleTimers',
'styleElements', 'styleElements',
'docRewriteObserver', 'docRewriteObserver',
'docRootObserver',
].forEach(fn => (window[fn] = null)); ].forEach(fn => (window[fn] = null));
} }