aboutsummaryrefslogtreecommitdiff
path: root/static/js/instantpage.ts
diff options
context:
space:
mode:
Diffstat (limited to 'static/js/instantpage.ts')
-rw-r--r--static/js/instantpage.ts330
1 files changed, 60 insertions, 270 deletions
diff --git a/static/js/instantpage.ts b/static/js/instantpage.ts
index 7c78a6f..1b5ed36 100644
--- a/static/js/instantpage.ts
+++ b/static/js/instantpage.ts
@@ -1,292 +1,82 @@
-(function () {
- self.addEventListener("DOMContentLoaded", function () {
- /*! instant.page v5.1.0 - (C) 2019-2020 Alexandre Dieulot - https://instant.page/license */
-
- 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 DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION = 1111;
+/*
+ * Instant Page Copyright (C) 2019-2023 Alexandre Dieulot
+ * https://github.com/instantpage/instant.page/blob/master/LICENSE
+ * Licence: MIT | https://mit-license.org/
+*/
- let delayOnHover = 65;
- let useMousedown = false;
- let useMousedownOnly = false;
- let useViewport = false;
-
- if ("instantIntensity" in document.body.dataset) {
- const intensity = document.body.dataset.instantIntensity;
+(function () {
- 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;
- }
- }
+ /*/
+ * 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 (isSupported) {
- const eventListenersOptions = {
- capture: true,
- passive: true,
+ 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;
};
-
- 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;
+ 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;
+ }
- 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 });
+ self.addEventListener("DOMContentLoaded", function () {
- 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;
+ 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;
}
-
- 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 preload(url) {
- if (prefetches.has(url)) {
- return;
- }
-
const prefetcher = document.createElement("link");
- prefetcher.rel = "prefetch";
+ prefetcher.rel = "custom-prefetch";
prefetcher.href = url;
+ const selector = 'link[rel="'.concat(prefetcher.rel, '"][href="').concat(prefetcher.href, '"]');
+ const prefetched = document.head.contains(document.querySelector(selector));
+ if (prefetched) { return; }
document.head.appendChild(prefetcher);
-
- prefetches.add(url);
+ fetch(url, "GET", function () {});
}
});
})();