aboutsummaryrefslogtreecommitdiff
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
commit311f05450ea4860a6c9ba1cbeedf862284b8f223 (patch)
treed8f2b506d7505f15a01421563f7185596a8cd785
parentaf5c542b3ff6cbbdeec6da1b1a03e58b007fd941 (diff)
downloadcanory-311f05450ea4860a6c9ba1cbeedf862284b8f223.tar.gz
canory-311f05450ea4860a6c9ba1cbeedf862284b8f223.tar.bz2
canory-311f05450ea4860a6c9ba1cbeedf862284b8f223.zip
static/js/instantpage: Pare down
-rw-r--r--assets/js/index.js234
-rw-r--r--static/js/instantpage.ts222
2 files changed, 98 insertions, 358 deletions
diff --git a/assets/js/index.js b/assets/js/index.js
index f6c1686..4268a24 100644
--- a/assets/js/index.js
+++ b/assets/js/index.js
@@ -165,6 +165,21 @@
}
})();
(function() {
+ if (typeof Element !== "undefined") {
+ if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
+ }
+ if (!Element.prototype.closest) {
+ Element.prototype.closest = function(s) {
+ var el = this;
+ do {
+ if (el.matches(s)) return el;
+ el = el.parentElement || el.parentNode;
+ }while (el !== null && el.nodeType === 1)
+ return null;
+ };
+ }
+ }
function fetch(url, method, callback) {
const http = new XMLHttpRequest();
http.onreadystatechange = function() {
@@ -177,200 +192,47 @@
return http;
}
self.addEventListener("DOMContentLoaded", function() {
- 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;
- let mouseoverTimer;
- let lastTouchTimestamp;
- let delayOnHover = 65;
- let useMousedown = false;
- let useMousedownOnly = false;
- let useViewport = false;
- if ("instantIntensity" in document.body.dataset) {
- const intensity = document.body.dataset.instantIntensity;
- if (intensity.substr(0, "mousedown".length) == "mousedown") {
- useMousedown = 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 (intensity == "viewport") {
- 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 (isSupported) {
- const eventListenersOptions = {
- capture: true,
- passive: true
- };
- if (!useMousedownOnly) {
- document.addEventListener("touchstart", touchstartListener, eventListenersOptions);
- }
- if (!useMousedown) {
- document.addEventListener("mouseover", mouseoverListener, eventListenersOptions);
- } else if (!mousedownShortcut) {
- document.addEventListener("mousedown", mousedownListener, eventListenersOptions);
- }
- if (mousedownShortcut) {
- document.addEventListener("mousedown", mousedownShortcutListener, eventListenersOptions);
- }
- if (useViewport) {
- let triggeringFunction;
- if (window.requestIdleCallback) {
- triggeringFunction = function(callback) {
- requestIdleCallback(callback, {
- timeout: 1500
- });
- };
- } else {
- triggeringFunction = function(callback) {
- callback();
- };
- }
- triggeringFunction(function() {
- const intersectionObserver = new IntersectionObserver(function(entries) {
- entries.forEach(function(entry) {
- if (entry.isIntersecting) {
- const linkElement = entry.target;
- intersectionObserver.unobserve(linkElement);
- preload(linkElement.href);
- }
- });
- });
- document.querySelectorAll("a").forEach(function(linkElement) {
- if (isPreloadable(linkElement)) {
- intersectionObserver.observe(linkElement);
- }
- });
- });
- }
- }
- function touchstartListener(event) {
- lastTouchTimestamp = performance.now();
- const linkElement = event.target.closest("a");
- if (!isPreloadable(linkElement)) {
- return;
- }
- preload(linkElement.href);
- }
- function mouseoverListener(event) {
- if (performance.now() - lastTouchTimestamp < 1111) {
- return;
- }
- const linkElement = event.target.closest("a");
- if (!isPreloadable(linkElement)) {
- return;
- }
- linkElement.addEventListener("mouseout", mouseoutListener, {
- passive: true
+ [
+ "mouseout",
+ "mousedown",
+ "touchstart"
+ ].forEach(function(event) {
+ self.addEventListener(event, function(event) {
+ const url = event.target.closest("a");
+ if (preloadable(url) === undefined) return;
+ preload(url.href);
});
- mouseoverTimer = setTimeout(function() {
- preload(linkElement.href);
- mouseoverTimer = undefined;
- }, delayOnHover);
- }
- function mousedownListener(event) {
- const linkElement = event.target.closest("a");
- 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;
- }
- }
- function mousedownShortcutListener(event) {
- if (performance.now() - lastTouchTimestamp < 1111) {
- return;
- }
- const linkElement = event.target.closest("a");
- if (event.which > 1 || event.metaKey || event.ctrlKey) {
- return;
- }
- if (!linkElement) {
- return;
- }
- linkElement.addEventListener("click", function(event) {
- if (event.detail == 1337) {
+ });
+ function preloadable(url) {
+ switch(true){
+ case url === null || url.href === null:
return;
- }
- event.preventDefault();
- }, {
- capture: true,
- passive: false,
- once: true
- });
- const customEvent = new MouseEvent("click", {
- view: window,
- bubbles: true,
- cancelable: false,
- detail: 1337
- });
- linkElement.dispatchEvent(customEvent);
- }
- function isPreloadable(linkElement) {
- if (!linkElement || !linkElement.href) {
- return;
- }
- if (useWhitelist && !("instant" in linkElement.dataset)) {
- return;
- }
- if (!allowExternalLinks && linkElement.origin != location.origin && !("instant" in linkElement.dataset)) {
- return;
- }
- if (![
- "http:",
- "https:"
- ].includes(linkElement.protocol)) {
- return;
- }
- if (linkElement.protocol == "http:" && location.protocol == "https:") {
- return;
- }
- if (!allowQueryString && linkElement.search && !("instant" in linkElement.dataset)) {
- return;
- }
- if (linkElement.hash && linkElement.pathname + linkElement.search == location.pathname + location.search) {
- return;
- }
- if ("noInstant" in linkElement.dataset) {
- return;
+ case url.origin !== location.origin:
+ return;
+ case [
+ "http:",
+ "https:"
+ ].includes(url.protocol) === null:
+ return;
+ case url.protocol === "http:" && location.protocol === "https:":
+ return;
+ case url.hash && url.pathname + url.search == location.pathname + location.search:
+ return;
+ default:
+ return true;
}
- return true;
}
function preload(url) {
- if (prefetches.has(url)) {
- return;
- }
const prefetcher = document.createElement("link");
prefetcher.rel = "custom-prefetch";
prefetcher.href = url;
- fetch(url, "GET", function() {
- document.head.appendChild(prefetcher);
- prefetches.add(url);
- });
+ const selector = `link[rel="${prefetcher.rel}"][href="${prefetcher.href}"]`;
+ const prefetched = document.head.contains(document.querySelector(selector));
+ if (prefetched) {
+ return;
+ }
+ document.head.appendChild(prefetcher);
+ fetch(url, "GET", function() {});
}
});
})();
diff --git a/static/js/instantpage.ts b/static/js/instantpage.ts
index b76cef8..5d2f59a 100644
--- a/static/js/instantpage.ts
+++ b/static/js/instantpage.ts
@@ -6,6 +6,35 @@
(function () {
+ /*/
+ * Element.closest() polyfill
+ * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
+ * https://github.com/idmadj/element-closest-polyfill#readme
+ * Copyright (C) Abdelmadjid Hammou
+ * Licence: ISC | https://www.isc.org/licenses/
+ /*/
+
+ if (typeof Element !== "undefined") {
+ if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.msMatchesSelector ||
+ Element.prototype.webkitMatchesSelector;
+ }
+ if (!Element.prototype.closest) {
+ Element.prototype.closest = function (s) {
+ var el = this;
+ do {
+ if (el.matches(s)) return el;
+ el = el.parentElement || el.parentNode;
+ } while (el !== null && el.nodeType === 1);
+ return null;
+ };
+ }
+ }
+
+ /*/
+ * -----------------------------------------------------------------
+ /*/
+
function fetch(url, method, callback) {
const http = new XMLHttpRequest();
http.onreadystatechange = function () {
@@ -19,186 +48,35 @@
}
self.addEventListener("DOMContentLoaded", function () {
- 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 DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION = 1111;
-
- let mouseoverTimer;
- let lastTouchTimestamp;
- let delayOnHover = 65;
- let useMousedown = false;
- let useMousedownOnly = false;
- let useViewport = false;
-
- if ("instantIntensity" in document.body.dataset) {
- const intensity = document.body.dataset.instantIntensity;
-
- if (intensity.substr(0, "mousedown".length) == "mousedown") {
- useMousedown = 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 (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; }
- } else if (intensity == "viewport-all") {
- useViewport = true;
- }
- }
- } else {
- const milliseconds = parseInt(intensity);
- if (!isNaN(milliseconds)) { delayOnHover = milliseconds; }
- }
- }
-
- if (isSupported) {
- const eventListenersOptions = { capture: true, passive: true };
-
- if (!useMousedownOnly) { document.addEventListener( "touchstart", touchstartListener, eventListenersOptions,); }
-
- if (!useMousedown) {
- document.addEventListener( "mouseover", mouseoverListener, eventListenersOptions,);
- } else if (!mousedownShortcut) {
- document.addEventListener( "mousedown", mousedownListener, eventListenersOptions,);
- }
-
- if (mousedownShortcut) { document.addEventListener( "mousedown", mousedownShortcutListener, eventListenersOptions,); }
-
- if (useViewport) {
- let triggeringFunction;
- if (window.requestIdleCallback) {
- triggeringFunction = function (callback) { requestIdleCallback(callback, { timeout: 1500 }); }
- } else {
- triggeringFunction = function (callback) { callback(); }
- }
-
- triggeringFunction(function () {
- const intersectionObserver = new IntersectionObserver(
- function (entries) {
- entries.forEach(function (entry) {
- if (entry.isIntersecting) {
- const linkElement = entry.target;
- intersectionObserver.unobserve(linkElement);
- preload(linkElement.href);
- }
- });
- },
- );
-
- document.querySelectorAll("a").forEach(function (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.
- */
- lastTouchTimestamp = performance.now();
- const linkElement = event.target.closest("a");
- if (!isPreloadable(linkElement)) { return; }
- preload(linkElement.href);
- }
-
- function mouseoverListener(event) {
- 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 });
-
- mouseoverTimer = setTimeout(function () {
- preload(linkElement.href);
- mouseoverTimer = undefined;
- }, delayOnHover);
- }
-
- function mousedownListener(event) {
- const linkElement = event.target.closest("a");
- 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; }
- }
-
- function mousedownShortcutListener(event) {
- 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 (!linkElement) { return; }
-
- linkElement.addEventListener("click", function (event) {
- if (event.detail == 1337) { return; }
- event.preventDefault();
- }, { capture: true, passive: false, once: true });
-
- const customEvent = new MouseEvent("click", {
- view: window,
- bubbles: true,
- cancelable: false,
- detail: 1337,
+ ["mouseout", "mousedown", "touchstart"].forEach(function (event) {
+ self.addEventListener(event, function (event) {
+ const url = event.target.closest("a");
+ if (preloadable(url) === undefined) return;
+ preload(url.href);
});
-
- linkElement.dispatchEvent(customEvent);
- }
-
- function isPreloadable(linkElement) {
- if (!linkElement || !linkElement.href) { return; }
-
- if (useWhitelist && !("instant" in linkElement.dataset)) { return; }
-
- if (!allowExternalLinks && linkElement.origin != location.origin && !("instant" in linkElement.dataset)) { return; }
-
- if (!["http:", "https:"].includes(linkElement.protocol)) { return; }
-
- if (linkElement.protocol == "http:" && location.protocol == "https:") { return; }
-
- if (!allowQueryString && linkElement.search && !("instant" in linkElement.dataset)) { return; }
-
- if (linkElement.hash && linkElement.pathname + linkElement.search == location.pathname + location.search) { return; }
-
- if ("noInstant" in linkElement.dataset) { return; }
-
- return true;
+ });
+
+ function preloadable(url) {
+ switch (true) {
+ case (url === null || url.href === null): return;
+ case (url.origin !== location.origin): return;
+ case (["http:", "https:"].includes(url.protocol) === null): return;
+ case (url.protocol === "http:" && location.protocol === "https:"): return;
+ case (url.hash && url.pathname + url.search == location.pathname + location.search): return;
+ default: return true;
+ }
}
function preload(url) {
- if (prefetches.has(url)) { return; }
const prefetcher = document.createElement("link");
prefetcher.rel = "custom-prefetch";
prefetcher.href = url;
- fetch(url, "GET", function () {
- document.head.appendChild(prefetcher);
- prefetches.add(url);
- });
+ const selector = `link[rel="${prefetcher.rel}"][href="${prefetcher.href}"]`;
+ const prefetched = document.head.contains(document.querySelector(selector));
+ if (prefetched) { return; }
+ document.head.appendChild(prefetcher);
+ fetch(url, "GET", function () {});
}
});
})();