diff options
author | Thedro Neely <thedroneely@gmail.com> | 2019-11-09 03:00:33 -0500 |
---|---|---|
committer | Thedro Neely <thedroneely@gmail.com> | 2019-11-09 03:00:33 -0500 |
commit | c5255a0249489f44c83a95cd57b5643b8e03f31e (patch) | |
tree | 45fda90bc822a1e5fe0a8d105667e152980085f1 /public | |
parent | b7b84be10bf6a7bf094d67b67f91304b4f0477f9 (diff) | |
download | thedroneely.com-c5255a0249489f44c83a95cd57b5643b8e03f31e.tar.gz thedroneely.com-c5255a0249489f44c83a95cd57b5643b8e03f31e.tar.bz2 thedroneely.com-c5255a0249489f44c83a95cd57b5643b8e03f31e.zip |
public/js/app: Add instant page
Diffstat (limited to 'public')
-rw-r--r-- | public/js/app.js | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/public/js/app.js b/public/js/app.js index 5804fab..ddfdc3e 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -608,3 +608,209 @@ window.onscroll = function() { imageZoom = mediumZoom('[data-image-zoom]'); imageZoom.on('open', function(event) { addClass(navbar, 'navbar__headroom'); }); imageZoom.on('close', function(event) { remClass(navbar, 'navbar__headroom'); }); + + +/** + * instant.page v3.0.0 - (C) 2019 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 + +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.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 { + document.addEventListener('mousedown', mousedownListener, 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 < 1100) { + 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 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) +} |