FEATURE: Lazily Load Images as they scroll into the viewport.

This feature uses the Intersection Observer API

https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

It should be compatible with all modern browsers. Non-Edge IE is *NOT*
supported, so in that particular browser images are loaded by default.
This commit is contained in:
Robin Ward 2018-12-10 15:44:38 -05:00 committed by Sam
parent 5358f25fc6
commit 6797a710aa
3 changed files with 62 additions and 0 deletions

View File

@ -1,5 +1,6 @@
import highlightSyntax from "discourse/lib/highlight-syntax"; import highlightSyntax from "discourse/lib/highlight-syntax";
import lightbox from "discourse/lib/lightbox"; import lightbox from "discourse/lib/lightbox";
import { setupLazyLoading } from "discourse/lib/lazy-load-images";
import { setTextDirections } from "discourse/lib/text-direction"; import { setTextDirections } from "discourse/lib/text-direction";
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
@ -14,6 +15,8 @@ export default {
api.decorateCooked(setTextDirections); api.decorateCooked(setTextDirections);
} }
setupLazyLoading(api);
api.decorateCooked($elem => { api.decorateCooked($elem => {
const players = $("audio", $elem); const players = $("audio", $elem);
if (players.length) { if (players.length) {

View File

@ -0,0 +1,49 @@
const OBSERVER_OPTIONS = {
rootMargin: "50%" // load images slightly before they're visible
};
// We hide an image by replacing it with a transparent gif
function hide(image) {
image.classList.add("d-lazyload");
image.classList.add("d-lazyload-hidden");
image.setAttribute("data-src", image.getAttribute("src"));
image.setAttribute(
"src",
"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
);
}
// Restore an image from the `data-src` attribute
function show(image) {
let dataSrc = image.getAttribute("data-src");
if (dataSrc) {
image.setAttribute("src", dataSrc);
image.classList.remove("d-lazyload-hidden");
}
}
export function setupLazyLoading(api) {
// Old IE don't support this API
if (!("IntersectionObserver" in window)) {
return;
}
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
const { target } = entry;
if (entry.isIntersecting) {
show(target);
observer.unobserve(target);
} else {
// The Observer is triggered when entries are added. This allows
// us to hide things that start off screen.
hide(target);
}
});
}, OBSERVER_OPTIONS);
api.decorateCooked($post => {
$(".lightbox img", $post).each((_, $img) => observer.observe($img));
});
}

View File

@ -6,6 +6,16 @@
opacity: 0.9; opacity: 0.9;
transition: opacity 0.5s; transition: opacity 0.5s;
} }
background: rgba($primary, 0.25);
}
.d-lazyload-hidden {
opacity: 0;
box-sizing: border-box;
}
.cooked img.d-lazyload {
transition: opacity 0.4s 0.75s ease;
} }
.lightbox-wrapper { .lightbox-wrapper {