Last active
October 26, 2016 14:07
-
-
Save zeh/a0c89903aaa7d4b6a85a770de45cfe6e to your computer and use it in GitHub Desktop.
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
/** | |
* 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