aboutsummaryrefslogtreecommitdiff
path: root/static
diff options
context:
space:
mode:
authortdro <tdro@noreply.example.com>2024-03-16 15:22:06 -0400
committertdro <tdro@noreply.example.com>2024-03-16 15:22:06 -0400
commitaf5c542b3ff6cbbdeec6da1b1a03e58b007fd941 (patch)
treed700e5502847c82996fb21a9065d9eb91acb61ba /static
parentd1ef2e9cda26ec517b59e7e410f223b043029127 (diff)
downloadcanory-af5c542b3ff6cbbdeec6da1b1a03e58b007fd941.tar.gz
canory-af5c542b3ff6cbbdeec6da1b1a03e58b007fd941.tar.bz2
canory-af5c542b3ff6cbbdeec6da1b1a03e58b007fd941.zip
static/js/instantpage: Add custom prefetch
Diffstat (limited to 'static')
-rw-r--r--static/js/instantpage.ts248
1 files changed, 78 insertions, 170 deletions
diff --git a/static/js/instantpage.ts b/static/js/instantpage.ts
index aa290cd..b76cef8 100644
--- a/static/js/instantpage.ts
+++ b/static/js/instantpage.ts
@@ -5,24 +5,38 @@
*/
(function () {
+
+ function fetch(url, method, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function () {
+ if (http.readyState === 4 && http.status === 200) {
+ if (callback) callback(http);
+ }
+ };
+ http.open(method, url);
+ http.send();
+ return http;
+ }
+
self.addEventListener("DOMContentLoaded", function () {
- let mouseoverTimer;
- let lastTouchTimestamp;
const prefetches = new Set();
const prefetchElement = document.createElement("link");
- const isSupported = prefetchElement.relList &&
- prefetchElement.relList.supports &&
- prefetchElement.relList.supports("prefetch") &&
- window.IntersectionObserver &&
- "isIntersecting" in IntersectionObserverEntry.prototype;
- const allowQueryString = "instantAllowQueryString" in document.body.dataset;
- const allowExternalLinks = "instantAllowExternalLinks" in
- document.body.dataset;
- const useWhitelist = "instantWhitelist" in document.body.dataset;
- const mousedownShortcut = "instantMousedownShortcut" in
- document.body.dataset;
+
+ const isSupported = prefetchElement.relList
+ && prefetchElement.relList.supports
+ && prefetchElement.relList.supports("prefetch")
+ && window.IntersectionObserver
+ && "isIntersecting" in IntersectionObserverEntry.prototype;
+
+ const allowQueryString = "instantAllowQueryString" in document.body.dataset;
+ const allowExternalLinks = "instantAllowExternalLinks" in document.body.dataset;
+ const useWhitelist = "instantWhitelist" in document.body.dataset;
+ const mousedownShortcut = "instantMousedownShortcut" in document.body.dataset;
+
const DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION = 1111;
+ let mouseoverTimer;
+ let lastTouchTimestamp;
let delayOnHover = 65;
let useMousedown = false;
let useMousedownOnly = false;
@@ -33,86 +47,48 @@
if (intensity.substr(0, "mousedown".length) == "mousedown") {
useMousedown = true;
- if (intensity == "mousedown-only") {
- useMousedownOnly = true;
- }
+ if (intensity == "mousedown-only") { useMousedownOnly = true; }
} else if (intensity.substr(0, "viewport".length) == "viewport") {
- if (
- !(navigator.connection &&
- (navigator.connection.saveData ||
- (navigator.connection.effectiveType &&
- navigator.connection.effectiveType.includes("2g"))))
- ) {
+ if (!(navigator.connection
+ && (navigator.connection.saveData
+ || (navigator.connection.effectiveType
+ && navigator.connection.effectiveType.includes("2g"))))) {
if (intensity == "viewport") {
- /* Biggest iPhone resolution (which we want): 414 × 896 = 370944
- * Small 7" tablet resolution (which we don’t want): 600 × 1024 = 614400
- * Note that the viewport (which we check here) is smaller than the resolution due to the UI’s chrome */
- if (
- document.documentElement.clientWidth *
- document.documentElement.clientHeight < 450000
- ) {
- useViewport = true;
- }
+ /*
+ Biggest iPhone resolution (which we want): 414 × 896 = 370944
+ Small 7" tablet resolution (which we don’t want): 600 × 1024 = 614400
+ Note that the viewport (which we check here) is smaller than the resolution due to the UI’s chrome
+ */
+ if (document.documentElement.clientWidth * document.documentElement.clientHeight < 450000) { useViewport = true; }
} else if (intensity == "viewport-all") {
useViewport = true;
}
}
} else {
const milliseconds = parseInt(intensity);
- if (!isNaN(milliseconds)) {
- delayOnHover = milliseconds;
- }
+ if (!isNaN(milliseconds)) { delayOnHover = milliseconds; }
}
}
if (isSupported) {
- const eventListenersOptions = {
- capture: true,
- passive: true,
- };
-
- if (!useMousedownOnly) {
- document.addEventListener(
- "touchstart",
- touchstartListener,
- eventListenersOptions,
- );
- }
+ const eventListenersOptions = { capture: true, passive: true };
+
+ if (!useMousedownOnly) { document.addEventListener( "touchstart", touchstartListener, eventListenersOptions,); }
if (!useMousedown) {
- document.addEventListener(
- "mouseover",
- mouseoverListener,
- eventListenersOptions,
- );
+ document.addEventListener( "mouseover", mouseoverListener, eventListenersOptions,);
} else if (!mousedownShortcut) {
- document.addEventListener(
- "mousedown",
- mousedownListener,
- eventListenersOptions,
- );
+ document.addEventListener( "mousedown", mousedownListener, eventListenersOptions,);
}
- if (mousedownShortcut) {
- document.addEventListener(
- "mousedown",
- mousedownShortcutListener,
- eventListenersOptions,
- );
- }
+ if (mousedownShortcut) { document.addEventListener( "mousedown", mousedownShortcutListener, eventListenersOptions,); }
if (useViewport) {
let triggeringFunction;
if (window.requestIdleCallback) {
- triggeringFunction = function (callback) {
- requestIdleCallback(callback, {
- timeout: 1500,
- });
- };
+ triggeringFunction = function (callback) { requestIdleCallback(callback, { timeout: 1500 }); }
} else {
- triggeringFunction = function (callback) {
- callback();
- };
+ triggeringFunction = function (callback) { callback(); }
}
triggeringFunction(function () {
@@ -129,45 +105,29 @@
);
document.querySelectorAll("a").forEach(function (linkElement) {
- if (isPreloadable(linkElement)) {
- intersectionObserver.observe(linkElement);
- }
+ if (isPreloadable(linkElement)) { intersectionObserver.observe(linkElement); }
});
});
}
}
function touchstartListener(event) {
- /* Chrome on Android calls mouseover before touchcancel so `lastTouchTimestamp`
- * must be assigned on touchstart to be measured on mouseover. */
+ /*
+ Chrome on Android calls mouseover before touchcancel so `lastTouchTimestamp`
+ must be assigned on touchstart to be measured on mouseover.
+ */
lastTouchTimestamp = performance.now();
-
const linkElement = event.target.closest("a");
-
- if (!isPreloadable(linkElement)) {
- return;
- }
-
+ if (!isPreloadable(linkElement)) { return; }
preload(linkElement.href);
}
function mouseoverListener(event) {
- if (
- performance.now() - lastTouchTimestamp <
- DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION
- ) {
- return;
- }
+ if (performance.now() - lastTouchTimestamp < DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION) { return; }
const linkElement = event.target.closest("a");
-
- if (!isPreloadable(linkElement)) {
- return;
- }
-
- linkElement.addEventListener("mouseout", mouseoutListener, {
- passive: true,
- });
+ if (!isPreloadable(linkElement)) { return; }
+ linkElement.addEventListener("mouseout", mouseoutListener, { passive: true });
mouseoverTimer = setTimeout(function () {
preload(linkElement.href);
@@ -177,51 +137,26 @@
function mousedownListener(event) {
const linkElement = event.target.closest("a");
-
- if (!isPreloadable(linkElement)) {
- return;
- }
-
+ if (!isPreloadable(linkElement)) { return; }
preload(linkElement.href);
}
function mouseoutListener(event) {
- if (
- event.relatedTarget &&
- event.target.closest("a") == event.relatedTarget.closest("a")
- ) {
- return;
- }
-
- if (mouseoverTimer) {
- clearTimeout(mouseoverTimer);
- mouseoverTimer = undefined;
- }
+ if (event.relatedTarget && event.target.closest("a") == event.relatedTarget.closest("a")) { return; }
+ if (mouseoverTimer) { clearTimeout(mouseoverTimer); mouseoverTimer = undefined; }
}
function mousedownShortcutListener(event) {
- if (
- performance.now() - lastTouchTimestamp <
- DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION
- ) {
- return;
- }
+ if (performance.now() - lastTouchTimestamp < DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION) { return; }
const linkElement = event.target.closest("a");
- if (event.which > 1 || event.metaKey || event.ctrlKey) {
- return;
- }
+ if (event.which > 1 || event.metaKey || event.ctrlKey) { return; }
- if (!linkElement) {
- return;
- }
+ if (!linkElement) { return; }
linkElement.addEventListener("click", function (event) {
- if (event.detail == 1337) {
- return;
- }
-
+ if (event.detail == 1337) { return; }
event.preventDefault();
}, { capture: true, passive: false, once: true });
@@ -231,66 +166,39 @@
cancelable: false,
detail: 1337,
});
+
linkElement.dispatchEvent(customEvent);
}
function isPreloadable(linkElement) {
- if (!linkElement || !linkElement.href) {
- return;
- }
+ if (!linkElement || !linkElement.href) { return; }
- if (useWhitelist && !("instant" in linkElement.dataset)) {
- return;
- }
+ if (useWhitelist && !("instant" in linkElement.dataset)) { return; }
- if (
- !allowExternalLinks && linkElement.origin != location.origin &&
- !("instant" in linkElement.dataset)
- ) {
- return;
- }
+ if (!allowExternalLinks && linkElement.origin != location.origin && !("instant" in linkElement.dataset)) { return; }
- if (!["http:", "https:"].includes(linkElement.protocol)) {
- return;
- }
+ if (!["http:", "https:"].includes(linkElement.protocol)) { return; }
- if (linkElement.protocol == "http:" && location.protocol == "https:") {
- return;
- }
+ if (linkElement.protocol == "http:" && location.protocol == "https:") { return; }
- if (
- !allowQueryString && linkElement.search &&
- !("instant" in linkElement.dataset)
- ) {
- return;
- }
+ if (!allowQueryString && linkElement.search && !("instant" in linkElement.dataset)) { return; }
- if (
- linkElement.hash &&
- linkElement.pathname + linkElement.search ==
- location.pathname + location.search
- ) {
- return;
- }
+ if (linkElement.hash && linkElement.pathname + linkElement.search == location.pathname + location.search) { return; }
- if ("noInstant" in linkElement.dataset) {
- return;
- }
+ if ("noInstant" in linkElement.dataset) { return; }
return true;
}
function preload(url) {
- if (prefetches.has(url)) {
- return;
- }
-
+ if (prefetches.has(url)) { return; }
const prefetcher = document.createElement("link");
- prefetcher.rel = "prefetch";
+ prefetcher.rel = "custom-prefetch";
prefetcher.href = url;
- document.head.appendChild(prefetcher);
-
- prefetches.add(url);
+ fetch(url, "GET", function () {
+ document.head.appendChild(prefetcher);
+ prefetches.add(url);
+ });
}
});
})();