Last active
May 22, 2022 15:16
-
-
Save mjpieters/f4d3a250091a6626792e317d35c2d89d to your computer and use it in GitHub Desktop.
Touch support for h5ai previews
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Touch support for h5ai previews | |
* | |
* Maps left and right swiping gestures on the preview to next and previous controls, double-top to toggling full screen | |
* Place in the `public/ext` directory, then add `"touch.js"` to the `resources.scripts` list in your `private/conf/options.json` file. | |
* | |
* * Copyright: 2022 Martijn Pieters | |
* * License: The MIT License (MIT) | |
*/ | |
(function () { | |
const DISTANCE = 40 | |
const MAXTIME = 250 | |
const OVERLAY_ID = 'pv-overlay' | |
const CONTAINER_ID = 'pv-container' | |
const KEYS = { | |
left: { keyCode: 37 }, | |
right: { keyCode: 39 }, | |
f: { keyCode: 70 } | |
} | |
const doc = document | |
const waitForPrevOverlay = function () { | |
const ready = new Promise(resolve => (/^(i|c|loade)/).test(doc.readyState) ? resolve() : doc.addEventListener('DOMContentLoaded', () => resolve())) | |
const wait = () => { | |
return new Promise(resolve => { | |
let ov = doc.getElementById(OVERLAY_ID) | |
if (ov) return resolve(ov) | |
const obs = new MutationObserver(mut => { | |
ov = doc.getElementById(OVERLAY_ID) | |
if (ov) { | |
resolve(ov) | |
obs.disconnect() | |
} | |
}) | |
obs.observe(doc.body, { childList: true }) | |
}) | |
} | |
return ready.then(wait) | |
} | |
const previewTouchControls = function (overlay) { | |
const prevCont = doc.getElementById(CONTAINER_ID) | |
const state = {} | |
const onTouchStart = function (e) { | |
if (overlay.classList.contains('hidden')) return | |
const now = Date.now() | |
const deltaT = now - (state.last || now) | |
const touch = e.changedTouches | |
state.x = touch[0].pageX | |
state.y = touch[0].pageY | |
state.last = now | |
state.deltaX = 0 | |
state.deltaY = 0 | |
state.isHorizontal = null | |
state.isDoubleTap = touch.length === 1 && deltaT > 0 && deltaT <= MAXTIME | |
doc.addEventListener('touchmove', onTouchMove) | |
doc.addEventListener('touchend', onTouchEnd) | |
} | |
const onTouchMove = function (e) { | |
if (overlay.classList.contains('hidden')) { | |
doc.removeEventListener('touchmove', onTouchMove) | |
doc.removeEventListener('touchend', onTouchEnd) | |
return | |
} | |
const touch = e.changedTouches | |
if ((touch && touch.length > 1) || (e.scale && e.scale !== 1)) return | |
state.deltaX = touch[0].pageX - state.x | |
state.deltaY = touch[0].pageY - state.y | |
if (state.isHorizontal === null) state.isHorizontal = Math.abs(state.deltaX) >= Math.abs(state.deltaY) | |
e.preventDefault() | |
e.stopPropagation() | |
} | |
const onTouchEnd = function (e) { | |
if (!overlay.classList.contains('hidden')) { | |
const dX = Math.abs(state.deltaX) | |
const dY = Math.abs(state.deltaY) | |
if (state.isDoubleTap && dX <= DISTANCE && dY <= DISTANCE) { | |
e.preventDefault() | |
e.stopPropagation() | |
// map double-tap gestures to keyDown events that the preview code maps to fullscreen toggling | |
overlay.dispatchEvent(new KeyboardEvent('keydown', KEYS.f)) | |
} else if (state.isHorizontal && dX > DISTANCE) { | |
if ((Date.now() - state.last) < MAXTIME) { | |
e.preventDefault() | |
e.stopPropagation() | |
// map left or right sliding gestures to keyDown events that the preview code maps to next / prev | |
const opts = state.deltaX > 0 ? KEYS.left : KEYS.right | |
overlay.dispatchEvent(new KeyboardEvent('keydown', opts)) | |
} | |
} | |
} | |
doc.removeEventListener('touchmove', onTouchMove) | |
doc.removeEventListener('touchend', onTouchEnd) | |
} | |
prevCont.addEventListener('touchstart', onTouchStart) | |
} | |
// Wait for the preview div to be added to the DOM | |
waitForPrevOverlay().then((overlay) => previewTouchControls(overlay)) | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment