Avoid flicker when updating applied styles

This commit is contained in:
tophf 2015-07-12 23:02:17 +03:00
parent b4eaac4ef9
commit 99a956c383

View File

@ -1,6 +1,7 @@
var g_disableAll = false; var g_disableAll = false;
var g_styleElements = {}; var g_styleElements = {};
var iframeObserver; var iframeObserver;
var retiredStyleIds = [];
initObserver(); initObserver();
requestStyles(); requestStyles();
@ -28,8 +29,13 @@ chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
removeStyle(request.id, document); removeStyle(request.id, document);
break; break;
case "styleUpdated": case "styleUpdated":
if (request.style.enabled == "true") {
retireStyle(request.style.id);
// fallthrough to "styleAdded"
} else {
removeStyle(request.style.id, document); removeStyle(request.style.id, document);
//fallthrough break;
}
case "styleAdded": case "styleAdded":
if (request.style.enabled == "true") { if (request.style.enabled == "true") {
chrome.extension.sendMessage({method: "getStyles", matchUrl: location.href, enabled: true, id: request.style.id, asHash: true}, applyStyles); chrome.extension.sendMessage({method: "getStyles", matchUrl: location.href, enabled: true, id: request.style.id, asHash: true}, applyStyles);
@ -92,6 +98,27 @@ function removeStyle(id, doc) {
}); });
} }
// 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
function retireStyle(id, doc) {
var deadID = "ghost-" + id;
if (!doc) {
doc = document;
retiredStyleIds.push(deadID);
delete g_styleElements["stylish-" + id];
// in case something went wrong and new style was never applied
setTimeout(removeStyle.bind(null, deadID, doc), 1000);
}
var e = doc.getElementById("stylish-" + id);
if (e) {
e.id = "stylish-" + deadID;
}
getDynamicIFrames(doc).forEach(function(iframe) {
retireStyle(id, iframe.contentDocument);
});
}
function applyStyles(styleHash) { function applyStyles(styleHash) {
if (!styleHash) { // Chrome is starting up if (!styleHash) { // Chrome is starting up
requestStyles(); requestStyles();
@ -112,6 +139,14 @@ function applyStyles(styleHash) {
}); });
iframeObserver.start(); iframeObserver.start();
} }
if (retiredStyleIds.length) {
setTimeout(function() {
while (retiredStyleIds.length) {
removeStyle(retiredStyleIds.shift(), document);
}
}, 0);
}
} }
function applySections(styleId, sections) { function applySections(styleId, sections) {
@ -194,17 +229,22 @@ function addStyleToIFrameSrcDoc(iframe, styleElement) {
setTimeout(addStyleElement.bind(null, styleElement, iframe.contentDocument), 100); setTimeout(addStyleElement.bind(null, styleElement, iframe.contentDocument), 100);
} }
function replaceAll(newStyles, doc) { function replaceAll(newStyles, doc, pass2) {
Array.prototype.forEach.call(doc.querySelectorAll("STYLE.stylish"), function(style) { var oldStyles = [].slice.call(doc.querySelectorAll("STYLE.stylish" + (pass2 ? "[id$='-ghost']" : "")));
style.remove(); if (!pass2) {
}); oldStyles.forEach(function(style) { style.id += "-ghost"; });
if (doc == document) {
g_styleElements = {};
applyStyles(newStyles);
} }
getDynamicIFrames(doc).forEach(function(iframe) { getDynamicIFrames(doc).forEach(function(iframe) {
replaceAll(newStyles, iframe.contentDocument); replaceAll(newStyles, iframe.contentDocument, pass2);
}); });
if (doc == document && !pass2) {
g_styleElements = {};
applyStyles(newStyles);
replaceAll(newStyles, doc, true);
}
if (pass2) {
oldStyles.forEach(function(style) { style.remove(); });
}
} }
// Observe dynamic IFRAMEs being added // Observe dynamic IFRAMEs being added