diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-08-23 19:56:12 +0300 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-08-23 19:56:12 +0300 |
commit | 2898326a3d121f1b51cbd1c336526ba8ba1b0b7e (patch) | |
tree | adb36919b53fbc56ff206a21af15207e912bd9da | |
parent | f3f1c95aba97559c554c6154eee1e25e8df6189d (diff) |
Add some more random JS
-rw-r--r-- | assets/js/f1.js | 246 | ||||
-rw-r--r-- | assets/js/f2.js | 246 | ||||
-rw-r--r-- | assets/js/f3.js | 246 | ||||
-rw-r--r-- | assets/js/f4.js | 246 |
4 files changed, 984 insertions, 0 deletions
diff --git a/assets/js/f1.js b/assets/js/f1.js index 66eacd8..92e2029 100644 --- a/assets/js/f1.js +++ b/assets/js/f1.js @@ -4,3 +4,249 @@ document.writeln('This is ' + getName()); function getName() { return 'f1'; } + +/*! 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; + +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 = (callback) => { + requestIdleCallback(callback, { + timeout: 1500 + }); + }; + } else { + triggeringFunction = (callback) => { + callback(); + }; + } + + triggeringFunction(() => { + const intersectionObserver = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const linkElement = entry.target; + intersectionObserver.unobserve(linkElement); + preload(linkElement.href); + } + }); + }); + + document.querySelectorAll('a').forEach((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(() => { + 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 }); + 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 preload(url) { + if (prefetches.has(url)) { + return; + } + + const prefetcher = document.createElement('link'); + prefetcher.rel = 'prefetch'; + prefetcher.href = url; + document.head.appendChild(prefetcher); + + prefetches.add(url); +} diff --git a/assets/js/f2.js b/assets/js/f2.js index 2c93505..1df8874 100644 --- a/assets/js/f2.js +++ b/assets/js/f2.js @@ -4,3 +4,249 @@ document.writeln('This is ' + getName()); function getName() { return 'f2'; } + +/*! 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; + +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 = (callback) => { + requestIdleCallback(callback, { + timeout: 1500 + }); + }; + } else { + triggeringFunction = (callback) => { + callback(); + }; + } + + triggeringFunction(() => { + const intersectionObserver = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const linkElement = entry.target; + intersectionObserver.unobserve(linkElement); + preload(linkElement.href); + } + }); + }); + + document.querySelectorAll('a').forEach((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(() => { + 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 }); + 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 preload(url) { + if (prefetches.has(url)) { + return; + } + + const prefetcher = document.createElement('link'); + prefetcher.rel = 'prefetch'; + prefetcher.href = url; + document.head.appendChild(prefetcher); + + prefetches.add(url); +} diff --git a/assets/js/f3.js b/assets/js/f3.js index 6cb4698..c830eda 100644 --- a/assets/js/f3.js +++ b/assets/js/f3.js @@ -4,3 +4,249 @@ document.writeln('This is ' + getName()); function getName() { return 'f3'; } + +/*! 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; + +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 = (callback) => { + requestIdleCallback(callback, { + timeout: 1500 + }); + }; + } else { + triggeringFunction = (callback) => { + callback(); + }; + } + + triggeringFunction(() => { + const intersectionObserver = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const linkElement = entry.target; + intersectionObserver.unobserve(linkElement); + preload(linkElement.href); + } + }); + }); + + document.querySelectorAll('a').forEach((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(() => { + 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 }); + 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 preload(url) { + if (prefetches.has(url)) { + return; + } + + const prefetcher = document.createElement('link'); + prefetcher.rel = 'prefetch'; + prefetcher.href = url; + document.head.appendChild(prefetcher); + + prefetches.add(url); +} diff --git a/assets/js/f4.js b/assets/js/f4.js index ef429ac..c26bcb6 100644 --- a/assets/js/f4.js +++ b/assets/js/f4.js @@ -4,3 +4,249 @@ document.writeln('This is ' + getName()); function getName() { return 'f4'; } + +/*! 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; + +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 = (callback) => { + requestIdleCallback(callback, { + timeout: 1500 + }); + }; + } else { + triggeringFunction = (callback) => { + callback(); + }; + } + + triggeringFunction(() => { + const intersectionObserver = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const linkElement = entry.target; + intersectionObserver.unobserve(linkElement); + preload(linkElement.href); + } + }); + }); + + document.querySelectorAll('a').forEach((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(() => { + 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 }); + 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 preload(url) { + if (prefetches.has(url)) { + return; + } + + const prefetcher = document.createElement('link'); + prefetcher.rel = 'prefetch'; + prefetcher.href = url; + document.head.appendChild(prefetcher); + + prefetches.add(url); +} |