Skip to content

Instantly share code, notes, and snippets.

@zeh
Last active October 26, 2016 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeh/a0c89903aaa7d4b6a85a770de45cfe6e to your computer and use it in GitHub Desktop.
Save zeh/a0c89903aaa7d4b6a85a770de45cfe6e to your computer and use it in GitHub Desktop.
/**
* Validate the scroll position on a container
* This is used to prevent overscrolling on iOS, and avoid flickering (which only happens from the edges)
* It does so by limiting the scroll inside an element to 1..(max-1) instead of 0..max, since attempts to scroll
* an element already at its scrolling ends will scroll the parent instead.
*
* Usage:
* let checker = new SafetyScrollChecker(document.querySelector(".someclass"));
* checker.stop(); // If you want to allow any scrolling
* checker.start(); // Start blocking again
* checker.forceCheck(); // If you update the content without changing the scroll position (e.g. going from non-scrollable to scrollable)
*/
export default class SafetyScrollChecker {
// ================================================================================================================
// CONSTRUCTOR ----------------------------------------------------------------------------------------------------
constructor(element) {
this._element = element;
this._onScrolledElementBound = this.onScrolledElement.bind(this);
this._isStarted = false;
this.start();
}
// ================================================================================================================
// PUBLIC INTERFACE -----------------------------------------------------------------------------------------------
start() {
if (!this._isStarted) {
this._element.addEventListener("scroll", this._onScrolledElementBound);
this._isStarted = true;
this.onScrolledElement(null);
}
}
forceCheck() {
this.validateScrollPosition();
}
stop() {
if (this._isStarted) {
this._element.removeEventListener("scroll", this._onScrolledElementBound);
this._isStarted = false;
}
}
// ================================================================================================================
// PRIVATE INTERFACE ----------------------------------------------------------------------------------------------
getScrollPosition() {
return this._element.scrollTop;
}
getMaxScrollPosition() {
return this._element.scrollHeight - this._element.clientHeight;
}
setScrollPosition(scrollPositionY) {
this._element.scrollTop = scrollPositionY;
}
validateScrollPosition() {
if (this.getScrollPosition() < 1) {
this.setScrollPosition(1);
} else if (this.getScrollPosition() > this.getMaxScrollPosition() - 1) {
this.setScrollPosition(this.getMaxScrollPosition() - 1);
}
}
// ================================================================================================================
// EVENT INTERFACE ------------------------------------------------------------------------------------------------
onScrolledElement() {
this.validateScrollPosition();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment