Update Image Loader Placeholder Remover to 1.23.2
- *Actually* fix page slowdowns by ferociously caching CSS properties
This commit is contained in:
parent
9a64f71505
commit
ed2fbde27a
|
@ -4,7 +4,7 @@
|
||||||
// @match http*://*/*
|
// @match http*://*/*
|
||||||
// @exclude-match http*://solar.lowtechmagazine.com/*
|
// @exclude-match http*://solar.lowtechmagazine.com/*
|
||||||
// @grant none
|
// @grant none
|
||||||
// @version 1.23.1
|
// @version 1.23.2
|
||||||
// @author blankie
|
// @author blankie
|
||||||
// @run-at document-end
|
// @run-at document-end
|
||||||
// @description Removes image loading placeholders
|
// @description Removes image loading placeholders
|
||||||
|
@ -18,25 +18,21 @@ const URL_RE = new RegExp(`^${URL_RE_STR}$`);
|
||||||
const SRCSET_COMPONENT = `${URL_RE_STR}(?:\\s+\\d+w|\\s+\\d+(?:\\.\\d+)?x)?`;
|
const SRCSET_COMPONENT = `${URL_RE_STR}(?:\\s+\\d+w|\\s+\\d+(?:\\.\\d+)?x)?`;
|
||||||
const SRCSET_RE = new RegExp(`^${SRCSET_COMPONENT}(?:,\\s*${SRCSET_COMPONENT})*$`);
|
const SRCSET_RE = new RegExp(`^${SRCSET_COMPONENT}(?:,\\s*${SRCSET_COMPONENT})*$`);
|
||||||
|
|
||||||
|
let cachedCSSProperties = new Map();
|
||||||
|
|
||||||
function isUrlLike(url) {
|
function isUrlLike(url) {
|
||||||
// Example of ./path:
|
// Example of ./path:
|
||||||
// - https://projects.apnews.com/features/2023/missing-students-chronic-absenteeism/index.html
|
// - https://projects.apnews.com/features/2023/missing-students-chronic-absenteeism/index.html
|
||||||
return url && URL_RE.test(url);
|
return url && URL_RE.test(url);
|
||||||
}
|
}
|
||||||
function findUrl(element) {
|
|
||||||
if (window.location.host === "www.vice.com") {
|
function getUrlAttributes(element) {
|
||||||
let picture = element.parentElement;
|
let attributes = [];
|
||||||
let source = picture && picture.localName === "picture" ? picture.querySelector("source") : null;
|
|
||||||
if (source) {
|
|
||||||
return source.srcset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://blog.google/
|
// https://blog.google/
|
||||||
// https://blog.google/threat-analysis-group/active-north-korean-campaign-targeting-security-researchers/
|
// https://blog.google/threat-analysis-group/active-north-korean-campaign-targeting-security-researchers/
|
||||||
if (window.location.host === "blog.google" && element.hasAttribute("data-loading")) {
|
if (window.location.host === "blog.google" && element.hasAttribute("data-loading")) {
|
||||||
let data = JSON.parse(element.getAttribute("data-loading"));
|
attributes.push(element.getAttributeNode("data-loading"));
|
||||||
return data.desktop || data.mobile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Examples of data-src:
|
// Examples of data-src:
|
||||||
|
@ -51,7 +47,7 @@ function findUrl(element) {
|
||||||
// - https://knowyourmeme.com/
|
// - https://knowyourmeme.com/
|
||||||
// - https://knowyourmeme.com/memes/saddam-husseins-hiding-place
|
// - https://knowyourmeme.com/memes/saddam-husseins-hiding-place
|
||||||
if (isUrlLike(element.dataset.src)) {
|
if (isUrlLike(element.dataset.src)) {
|
||||||
return element.dataset.src;
|
attributes.push(element.getAttributeNode("data-src"));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let attr of element.attributes) {
|
for (let attr of element.attributes) {
|
||||||
|
@ -79,7 +75,31 @@ function findUrl(element) {
|
||||||
if (!isUrlLike(attr.value)) {
|
if (!isUrlLike(attr.value)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return attr.value;
|
attributes.push(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findUrl(element) {
|
||||||
|
if (window.location.host === "www.vice.com") {
|
||||||
|
let picture = element.parentElement;
|
||||||
|
let source = picture && picture.localName === "picture" ? picture.querySelector("source") : null;
|
||||||
|
if (source) {
|
||||||
|
return source.srcset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://blog.google/
|
||||||
|
// https://blog.google/threat-analysis-group/active-north-korean-campaign-targeting-security-researchers/
|
||||||
|
if (window.location.host === "blog.google" && element.hasAttribute("data-loading")) {
|
||||||
|
let data = JSON.parse(element.getAttribute("data-loading"));
|
||||||
|
return data.desktop || data.mobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
let urlAttributes = getUrlAttributes(element);
|
||||||
|
if (urlAttributes.length !== 0) {
|
||||||
|
return urlAttributes[0].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -98,6 +118,17 @@ function findSrcset(element) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCachedCSSProperties(element, key) {
|
||||||
|
if (cachedCSSProperties.has(key)) {
|
||||||
|
return cachedCSSProperties.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
let {opacity, display, visibility, filter} = getComputedStyle(element);
|
||||||
|
let ret = {opacity, display, visibility, filter};
|
||||||
|
cachedCSSProperties.set(key, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
function getLazyloaderClasses(element) {
|
function getLazyloaderClasses(element) {
|
||||||
let classes = [];
|
let classes = [];
|
||||||
|
|
||||||
|
@ -172,6 +203,7 @@ function cloneLazyloaderTree(element, elementLazyLoaderClasses) {
|
||||||
for (let attr of getLazyloaderAttributes(followingTopMostParent)) {
|
for (let attr of getLazyloaderAttributes(followingTopMostParent)) {
|
||||||
clone.setAttribute(attr.name, attr.value);
|
clone.setAttribute(attr.name, attr.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topMostParent) {
|
if (topMostParent) {
|
||||||
clone.append(topMostParent);
|
clone.append(topMostParent);
|
||||||
}
|
}
|
||||||
|
@ -185,8 +217,12 @@ function cloneLazyloaderTree(element, elementLazyLoaderClasses) {
|
||||||
|
|
||||||
let clone = document.createElement(element.localName);
|
let clone = document.createElement(element.localName);
|
||||||
clone.classList.add(...elementLazyLoaderClasses);
|
clone.classList.add(...elementLazyLoaderClasses);
|
||||||
|
let urlAttributeNames = new Set(["src", "href"]);
|
||||||
|
for (let attr of getUrlAttributes(element)) {
|
||||||
|
urlAttributeNames.add(attr.name);
|
||||||
|
}
|
||||||
for (let attr of getLazyloaderAttributes(element)) {
|
for (let attr of getLazyloaderAttributes(element)) {
|
||||||
clone.setAttribute(attr.name, attr.value);
|
clone.setAttribute(attr.name, !urlAttributeNames.has(attr.name) ? attr.value : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bottomMostChild) {
|
if (bottomMostChild) {
|
||||||
|
@ -200,9 +236,19 @@ function cloneLazyloaderTree(element, elementLazyLoaderClasses) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function unhideElement(element, lazyLoaderClasses) {
|
function unhideElement(element, lazyLoaderClasses) {
|
||||||
let style = getComputedStyle(element);
|
// We no longer/don't check the styles of each element individually, but rather their "generified" version
|
||||||
|
// (i.e., only lazy classes), because checking each actual element causes a lot of cache busts
|
||||||
|
|
||||||
// Examples of opacity:
|
// We check if the classes discriminate lazyloaded images, just in case
|
||||||
|
// We can't remove the lazyload classes from the image, because:
|
||||||
|
// - https://legendsoflocalization.com/japans-mysterious-love-of-the-word-lets/#why-lets-is-so-common
|
||||||
|
// - https://www.wired.com/story/why-do-printers-still-suck/
|
||||||
|
// However, some sites use the classes to blur and/or change the opacity of images
|
||||||
|
let [toRemove, toExamine] = cloneLazyloaderTree(element, lazyLoaderClasses);
|
||||||
|
document.body.append(toRemove);
|
||||||
|
let classStyle = getCachedCSSProperties(toExamine, toRemove.outerHTML);
|
||||||
|
|
||||||
|
// Examples of opacity === "0":
|
||||||
// - https://closeronline.co.uk
|
// - https://closeronline.co.uk
|
||||||
// - https://closeronline.co.uk/real-life/news/ever-used-excuses-documented-spreadsheet-man-used-expose-wife-s-lack-sex
|
// - https://closeronline.co.uk/real-life/news/ever-used-excuses-documented-spreadsheet-man-used-expose-wife-s-lack-sex
|
||||||
// - https://www.vice.com/en/article/dy73n7/ehallpass-1000-thousand-schools-monitor-bathroom
|
// - https://www.vice.com/en/article/dy73n7/ehallpass-1000-thousand-schools-monitor-bathroom
|
||||||
|
@ -210,14 +256,16 @@ function unhideElement(element, lazyLoaderClasses) {
|
||||||
// - https://daramiblog.com/how-to-group-irregular-verbs-for-more-efficient-learning/
|
// - https://daramiblog.com/how-to-group-irregular-verbs-for-more-efficient-learning/
|
||||||
// - https://www.wired.com/
|
// - https://www.wired.com/
|
||||||
// - https://www.wired.com/story/researcher-fooled-a-google-ai-into-thinking-a-rifle-was-a-helicopter/
|
// - https://www.wired.com/story/researcher-fooled-a-google-ai-into-thinking-a-rifle-was-a-helicopter/
|
||||||
if (style.opacity === "0") {
|
// Example of opacity === "0.75":
|
||||||
|
// https://www.404media.co/welcome-to-404-media/
|
||||||
|
if (classStyle.opacity !== "1") {
|
||||||
element.style.opacity = 1;
|
element.style.opacity = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Examples of display:
|
// Examples of display:
|
||||||
// - https://closeronline.co.uk
|
// - https://closeronline.co.uk
|
||||||
// - https://closeronline.co.uk/real-life/news/ever-used-excuses-documented-spreadsheet-man-used-expose-wife-s-lack-sex
|
// - https://closeronline.co.uk/real-life/news/ever-used-excuses-documented-spreadsheet-man-used-expose-wife-s-lack-sex
|
||||||
if (style.display === "none") {
|
if (classStyle.display === "none") {
|
||||||
element.style.display = "block";
|
element.style.display = "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,16 +274,6 @@ function unhideElement(element, lazyLoaderClasses) {
|
||||||
element.style.paddingBottom = 0;
|
element.style.paddingBottom = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We check if the classes discriminate lazyloaded images, just in case
|
|
||||||
// We can't remove the lazyload classes from the image, because:
|
|
||||||
// - https://legendsoflocalization.com/japans-mysterious-love-of-the-word-lets/#why-lets-is-so-common
|
|
||||||
// - https://www.wired.com/story/why-do-printers-still-suck/
|
|
||||||
// However, some sites use the classes to blur and/or change the opacity of images
|
|
||||||
|
|
||||||
let [toRemove, toExamine] = cloneLazyloaderTree(element, lazyLoaderClasses);
|
|
||||||
document.body.append(toRemove);
|
|
||||||
let classStyle = getComputedStyle(toExamine);
|
|
||||||
|
|
||||||
// Examples of visibility:
|
// Examples of visibility:
|
||||||
// - https://www.edinburghlive.co.uk/
|
// - https://www.edinburghlive.co.uk/
|
||||||
// - https://www.edinburghlive.co.uk/news/edinburgh-news/edinburgh-couple-fume-handed-17k-27906242
|
// - https://www.edinburghlive.co.uk/news/edinburgh-news/edinburgh-couple-fume-handed-17k-27906242
|
||||||
|
@ -243,12 +281,6 @@ function unhideElement(element, lazyLoaderClasses) {
|
||||||
element.style.visibility = "visible";
|
element.style.visibility = "visible";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example of opacity === "0.75":
|
|
||||||
// https://www.404media.co/welcome-to-404-media/
|
|
||||||
if (classStyle.opacity !== "1") {
|
|
||||||
element.style.opacity = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Examples of blur:
|
// Examples of blur:
|
||||||
// - https://www.404media.co/welcome-to-404-media/
|
// - https://www.404media.co/welcome-to-404-media/
|
||||||
// - https://restofworld.org/
|
// - https://restofworld.org/
|
||||||
|
@ -350,15 +382,15 @@ function removePlaceholder(img) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (let img of document.querySelectorAll("img")) {
|
||||||
for (let img of Array.from(document.querySelectorAll("img"))) {
|
|
||||||
removePlaceholder(img);
|
removePlaceholder(img);
|
||||||
}
|
}
|
||||||
// the reason we reunhide images after 1s after the page loads is because of <noscript> elements being faked by umatrix
|
// the reason we reunhide images after 1s after the page loads is because of <noscript> elements being faked by umatrix
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
for (let img of Array.from(document.querySelectorAll("img")) {
|
for (let img of document.querySelectorAll("img")) {
|
||||||
removePlaceholder(img);
|
removePlaceholder(img);
|
||||||
}
|
}
|
||||||
|
cachedCSSProperties.clear();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue