diff --git a/ts/reviewer/images.ts b/ts/reviewer/images.ts new file mode 100644 index 000000000..d98635cf1 --- /dev/null +++ b/ts/reviewer/images.ts @@ -0,0 +1,49 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +function injectPreloadLink(href: string, as: string): void { + const link = document.createElement("link"); + link.rel = "preload"; + link.href = href; + link.as = as; + document.head.appendChild(link); +} + +export function allImagesLoaded(): Promise { + return Promise.all( + Array.from(document.getElementsByTagName("img")).map(imageLoaded) + ); +} + +function imageLoaded(img: HTMLImageElement): Promise { + return img.complete + ? Promise.resolve() + : new Promise((resolve) => { + img.addEventListener("load", () => resolve()); + img.addEventListener("error", () => resolve()); + }); +} + +function clearPreloadLinks(): void { + document.head + .querySelectorAll("link[rel='preload']") + .forEach((link) => link.remove()); +} + +function extractImageSrcs(html: string): string[] { + const fragment = document.createRange().createContextualFragment(html); + const srcs = [...fragment.querySelectorAll("img[src]")].map( + (img) => (img as HTMLImageElement).src + ); + return srcs; +} + +export function preloadAnswerImages(qHtml: string, aHtml: string): void { + clearPreloadLinks(); + const aSrcs = extractImageSrcs(aHtml); + if (aSrcs.length) { + const qSrcs = extractImageSrcs(qHtml); + const diff = aSrcs.filter((src) => !qSrcs.includes(src)); + diff.forEach((src) => injectPreloadLink(src, "image")); + } +} diff --git a/ts/reviewer/index.ts b/ts/reviewer/index.ts index 3735c497d..20577d1ff 100644 --- a/ts/reviewer/index.ts +++ b/ts/reviewer/index.ts @@ -4,9 +4,11 @@ import "css-browser-selector/css_browser_selector"; import "jquery/dist/jquery"; -import { bridgeCommand } from "lib/bridgecommand"; export { mutateNextCardStates } from "./answering"; +import { bridgeCommand } from "lib/bridgecommand"; +import { allImagesLoaded, preloadAnswerImages } from "./images"; + declare const MathJax: any; type Callback = () => void | Promise; @@ -202,53 +204,6 @@ export function _emulateMobile(enabled: boolean): void { } } -function allImagesLoaded(): Promise { - return Promise.all( - Array.from(document.getElementsByTagName("img")).map(imageLoaded) - ); -} - -function imageLoaded(img: HTMLImageElement): Promise { - return img.complete - ? Promise.resolve() - : new Promise((resolve) => { - img.addEventListener("load", () => resolve()); - img.addEventListener("error", () => resolve()); - }); -} - function scrollToAnswer(): void { document.getElementById("answer")?.scrollIntoView(); } - -function injectPreloadLink(href: string, as: string): void { - const link = document.createElement("link"); - link.rel = "preload"; - link.href = href; - link.as = as; - document.head.appendChild(link); -} - -function clearPreloadLinks(): void { - document.head - .querySelectorAll("link[rel='preload']") - .forEach((link) => link.remove()); -} - -function extractImageSrcs(html: string): string[] { - const fragment = document.createRange().createContextualFragment(html); - const srcs = [...fragment.querySelectorAll("img[src]")].map( - (img) => (img as HTMLImageElement).src - ); - return srcs; -} - -function preloadAnswerImages(qHtml: string, aHtml: string): void { - clearPreloadLinks(); - const aSrcs = extractImageSrcs(aHtml); - if (aSrcs.length) { - const qSrcs = extractImageSrcs(qHtml); - const diff = aSrcs.filter((src) => !qSrcs.includes(src)); - diff.forEach((src) => injectPreloadLink(src, "image")); - } -}