aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2019-04-14 16:19:20 +0200
committerMarvin Borner2019-04-14 16:19:20 +0200
commita12e7139a8df8303c9fef79f3f20a170ea0af278 (patch)
tree580b70e777bf60714a6f6ab288f8cf085b166e16
parentc6e874ed068a640ad5ca2406b9abf93123bfb92e (diff)
Added prefetching of pages/files
-rw-r--r--src/main/resources/js/prefetch.js127
-rw-r--r--src/main/resources/views/layout.rocker.html2
2 files changed, 129 insertions, 0 deletions
diff --git a/src/main/resources/js/prefetch.js b/src/main/resources/js/prefetch.js
new file mode 100644
index 0000000..a239446
--- /dev/null
+++ b/src/main/resources/js/prefetch.js
@@ -0,0 +1,127 @@
+/*! instant.page v1.2.2 - (C) 2019 Alexandre Dieulot - https://instant.page/license */
+
+let urlToPreload;
+let mouseoverTimer;
+let lastTouchTimestamp;
+
+const prefetcher = document.createElement('link');
+const isSupported = prefetcher.relList && prefetcher.relList.supports && prefetcher.relList.supports('prefetch');
+const isDataSaverEnabled = navigator.connection && navigator.connection.saveData;
+const allowQueryString = 'instantAllowQueryString' in document.body.dataset;
+const allowExternalLinks = 'instantAllowExternalLinks' in document.body.dataset;
+
+if (isSupported && !isDataSaverEnabled) {
+ prefetcher.rel = 'prefetch';
+ document.head.appendChild(prefetcher);
+
+ const eventListenersOptions = {
+ capture: true,
+ passive: true,
+ };
+ document.addEventListener('touchstart', touchstartListener, eventListenersOptions);
+ document.addEventListener('mouseover', mouseoverListener, eventListenersOptions)
+}
+
+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
+ }
+
+ linkElement.addEventListener('touchcancel', touchendAndTouchcancelListener, {passive: true});
+ linkElement.addEventListener('touchend', touchendAndTouchcancelListener, {passive: true});
+
+ urlToPreload = linkElement.href;
+ preload(linkElement.href)
+}
+
+function touchendAndTouchcancelListener() {
+ urlToPreload = undefined;
+ stopPreloading()
+}
+
+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});
+
+ urlToPreload = linkElement.href;
+
+ mouseoverTimer = setTimeout(() => {
+ preload(linkElement.href);
+ mouseoverTimer = undefined
+ }, 65)
+}
+
+function mouseoutListener(event) {
+ if (event.relatedTarget && event.target.closest('a') === event.relatedTarget.closest('a')) {
+ return
+ }
+
+ if (mouseoverTimer) {
+ clearTimeout(mouseoverTimer);
+ mouseoverTimer = undefined
+ } else {
+ urlToPreload = undefined;
+ stopPreloading()
+ }
+}
+
+function isPreloadable(linkElement) {
+ if (!linkElement || !linkElement.href) {
+ return
+ }
+
+ if (urlToPreload === linkElement.href) {
+ return
+ }
+
+ const preloadLocation = new URL(linkElement.href);
+
+ if (!allowExternalLinks && preloadLocation.origin !== location.origin && !('instant' in linkElement.dataset)) {
+ return
+ }
+
+ if (!['http:', 'https:'].includes(preloadLocation.protocol)) {
+ return
+ }
+
+ if (preloadLocation.protocol === 'http:' && location.protocol === 'https:') {
+ return
+ }
+
+ if (!allowQueryString && preloadLocation.search && !('instant' in linkElement.dataset)) {
+ return
+ }
+
+ if (preloadLocation.hash && preloadLocation.pathname + preloadLocation.search === location.pathname + location.search) {
+ return
+ }
+
+ if ('noInstant' in linkElement.dataset) {
+ return
+ }
+
+ return true
+}
+
+function preload(url) {
+ prefetcher.href = url
+}
+
+function stopPreloading() {
+ prefetcher.removeAttribute('href')
+}
diff --git a/src/main/resources/views/layout.rocker.html b/src/main/resources/views/layout.rocker.html
index c7c7bc3..bfd2206 100644
--- a/src/main/resources/views/layout.rocker.html
+++ b/src/main/resources/views/layout.rocker.html
@@ -13,6 +13,8 @@
</head>
<body>
@content
+
+<script src="/js/prefetch.js"></script>
@js
</body>
</html>