protect own style elements (100 times max to avoid deadlocks)
fixes #252
This commit is contained in:
parent
5d905c2952
commit
8a1908b760
|
@ -224,8 +224,12 @@ function applyStyles(styles) {
|
|||
for (const id in styles) {
|
||||
applySections(id, styles[id].map(section => section.code).join('\n'));
|
||||
}
|
||||
if (!isOwnPage && !docRewriteObserver && styleElements.size) {
|
||||
initDocRewriteObserver();
|
||||
}
|
||||
if (!docRootObserver && styleElements.size) {
|
||||
initDocRootObserver();
|
||||
}
|
||||
if (retiredStyleTimers.size) {
|
||||
setTimeout(() => {
|
||||
for (const [id, timer] of retiredStyleTimers.entries()) {
|
||||
|
@ -290,9 +294,6 @@ function replaceAll(newStyles) {
|
|||
|
||||
|
||||
function initDocRewriteObserver() {
|
||||
if (isOwnPage || docRewriteObserver || !styleElements.size) {
|
||||
return;
|
||||
}
|
||||
// re-add styles if we detect documentElement being recreated
|
||||
const reinjectStyles = () => {
|
||||
if (!styleElements) {
|
||||
|
@ -327,36 +328,57 @@ function initDocRewriteObserver() {
|
|||
|
||||
|
||||
function initDocRootObserver() {
|
||||
if (!styleElements.size || document.body || docRootObserver) {
|
||||
return;
|
||||
let lastRestorationTime = 0;
|
||||
let restorationCounter = 0;
|
||||
|
||||
docRootObserver = new MutationObserver(findMisplacedStyles);
|
||||
connectObserver();
|
||||
|
||||
function connectObserver() {
|
||||
docRootObserver.observe(ROOT, {childList: true});
|
||||
}
|
||||
// wait for BODY and move all style elements after it
|
||||
docRootObserver = new MutationObserver(() => {
|
||||
|
||||
function findMisplacedStyles() {
|
||||
let expectedPrevSibling = document.body || document.head;
|
||||
if (!expectedPrevSibling) {
|
||||
return;
|
||||
}
|
||||
docRootObserver.disconnect();
|
||||
const list = [];
|
||||
for (const el of styleElements.values()) {
|
||||
if (el.previousElementSibling !== expectedPrevSibling) {
|
||||
ROOT.insertBefore(el, expectedPrevSibling.nextSibling);
|
||||
list.push({el, before: expectedPrevSibling.nextSibling});
|
||||
}
|
||||
expectedPrevSibling = el;
|
||||
}
|
||||
if (list.length && !restorationLimitExceeded()) {
|
||||
restoreMisplacedStyles(list);
|
||||
}
|
||||
}
|
||||
|
||||
function restoreMisplacedStyles(list) {
|
||||
docRootObserver.disconnect();
|
||||
for (const {el, before} of list) {
|
||||
ROOT.insertBefore(el, before);
|
||||
if (el.disabled !== disableAll) {
|
||||
// moving an element resets its 'disabled' state
|
||||
el.disabled = disableAll;
|
||||
}
|
||||
}
|
||||
expectedPrevSibling = el;
|
||||
connectObserver();
|
||||
}
|
||||
|
||||
function restorationLimitExceeded() {
|
||||
const t = performance.now();
|
||||
if (t - lastRestorationTime > 1000) {
|
||||
restorationCounter = 0;
|
||||
}
|
||||
lastRestorationTime = t;
|
||||
if (++restorationCounter > 100) {
|
||||
console.error('Stylus stopped restoring userstyle elements after 100 failed attempts.\n' +
|
||||
'Please report on https://github.com/openstyles/stylus/issues');
|
||||
return true;
|
||||
}
|
||||
if (document.body) {
|
||||
docRootObserver = null;
|
||||
} else {
|
||||
docRootObserver.connect();
|
||||
}
|
||||
});
|
||||
docRootObserver.connect = () => {
|
||||
docRootObserver.observe(ROOT, {childList: true});
|
||||
};
|
||||
docRootObserver.connect();
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user