Instantly share code, notes, and snippets.
Last active
February 18, 2021 23:29
two-finger-history-navigation.js
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
// This script is responsible for implementing the functionality of | |
// going back/forward in the navigation history when the user scrolls | |
// the page left/right using the touchpad. | |
// Each horizontal scroll event is intercepted and if the total motion | |
// within a given time is greather than a threshold, the code triggers | |
// a history.back() or .forward() | |
// Settings are handled by the background script bg.js. | |
function twoFingerScroll() { | |
// define a motion accumulator | |
let counter = 0; | |
// define a variable to store the reset after timeout function | |
let timeout; | |
// get settings | |
let settings = { | |
threshold: 20, | |
timeout: 1000, | |
feedbackSize: 5, | |
feedbackColor: '#888888' | |
} | |
// create a visual feedback element to show the accumulator status | |
let feedback = document.createElement('DIV'); | |
feedback.style.position = 'fixed'; | |
feedback.style.bottom = '0'; | |
feedback.style.left = '0'; | |
feedback.style.opacity = '0'; | |
feedback.style.width = '100%'; | |
feedback.style.height = `${settings.feedbackSize || 5}px`; | |
feedback.style.backgroundColor = settings.feedbackColor || '#888888'; | |
feedback.style.transition = 'left 0.1s linear, opacity 0.5s'; | |
feedback.style.zIndex = 2147483647; | |
feedback.innerHTML = ' '; | |
document.body.appendChild(feedback); | |
// execute each time a page is scrolled | |
document.addEventListener('wheel', async e => { | |
// do nothing if scroll event is vertical | |
if (!e.deltaX) return; | |
// set the opacity to 100% | |
feedback.style.opacity = 1; | |
// get settings again (this code doesn't seem to hurt performances and | |
// it allows to apply the latest settings without needing to reload the | |
// current page) | |
// settings = await browser.runtime.sendMessage({ cmd: 'getSettings' }); | |
// cancel the reset timeout | |
clearTimeout(timeout); | |
// accumulates the motion from this event | |
counter += e.deltaX; | |
// move the feedback div to show the accumulator status | |
feedback.style.left = Math.floor((counter / (50 - settings.threshold)) * 100) + '%'; | |
// if the total motion is greather than threshold | |
if (Math.abs(counter) >= (50 - settings.threshold)) { | |
// move the feedback div out of the way | |
feedback.style.display = 'none'; | |
setTimeout(() => feedback.style.display = 'initial', settings.timeout + 400); | |
// navigate back/forward in history | |
if (counter > 0) { | |
setTimeout(window.history.forward(), 200); | |
} else { | |
setTimeout(window.history.back(), 200); | |
} | |
} | |
// in any case, reset the motion accumulator and the feedback after a timeout | |
timeout = setTimeout(() => feedback.style.opacity = feedback.style.left = counter = 0, settings.timeout); | |
}); | |
} | |
twoFingerScroll(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment