forward checkOverflow to AutoHideScrollbar, fix over/underflow detection

the overflow/underflow events are not always reliable in nooverlay
browsers (FF), so forward the checkOverflow call we need anyway
for the scroll indicator gradients to see if we need to do the
margin trick for the on-hover scrollbar we use in nooverlay browsers.

this fixes on hover jumping in a subroomlist
pull/21833/head
Bruno Windels 2018-12-18 14:29:42 +01:00
parent 3ddc8baed1
commit e67d9c6d4f
2 changed files with 48 additions and 22 deletions

View File

@ -69,6 +69,7 @@ export default class AutoHideScrollbar extends React.Component {
this.onOverflow = this.onOverflow.bind(this);
this.onUnderflow = this.onUnderflow.bind(this);
this._collectContainerRef = this._collectContainerRef.bind(this);
this._needsOverflowListener = null;
}
onOverflow() {
@ -81,21 +82,32 @@ export default class AutoHideScrollbar extends React.Component {
this.containerRef.classList.add("mx_AutoHideScrollbar_underflow");
}
checkOverflow() {
if (!this._needsOverflowListener) {
return;
}
if (this.containerRef.scrollHeight > this.containerRef.clientHeight) {
this.onOverflow();
} else {
this.onUnderflow();
}
}
componentDidUpdate() {
this.checkOverflow();
}
componentDidMount() {
this.checkOverflow();
}
_collectContainerRef(ref) {
if (ref && !this.containerRef) {
this.containerRef = ref;
const needsOverflowListener =
document.body.classList.contains("mx_scrollbar_nooverlay");
if (needsOverflowListener) {
if (this._needsOverflowListener) {
this.containerRef.addEventListener("overflow", this.onOverflow);
this.containerRef.addEventListener("underflow", this.onUnderflow);
}
if (ref.scrollHeight > ref.clientHeight) {
this.onOverflow();
} else {
this.onUnderflow();
}
}
if (this.props.wrappedRef) {
this.props.wrappedRef(ref);
@ -111,6 +123,9 @@ export default class AutoHideScrollbar extends React.Component {
render() {
installBodyClassesIfNeeded();
if (this._needsOverflowListener === null) {
this._needsOverflowListener = document.body.classList.contains("mx_scrollbar_nooverlay");
}
return (<div
ref={this._collectContainerRef}
className={["mx_AutoHideScrollbar", this.props.className].join(" ")}

View File

@ -21,41 +21,52 @@ export default class IndicatorScrollbar extends React.Component {
constructor(props) {
super(props);
this._collectScroller = this._collectScroller.bind(this);
this._collectScrollerComponent = this._collectScrollerComponent.bind(this);
this.checkOverflow = this.checkOverflow.bind(this);
this._scrollElement = null;
this._autoHideScrollbar = null;
}
_collectScroller(scroller) {
if (scroller && !this._scroller) {
this._scroller = scroller;
this._scroller.addEventListener("scroll", this.checkOverflow);
if (scroller && !this._scrollElement) {
this._scrollElement = scroller;
this._scrollElement.addEventListener("scroll", this.checkOverflow);
this.checkOverflow();
}
}
_collectScrollerComponent(autoHideScrollbar) {
this._autoHideScrollbar = autoHideScrollbar;
}
checkOverflow() {
const hasTopOverflow = this._scroller.scrollTop > 0;
const hasBottomOverflow = this._scroller.scrollHeight >
(this._scroller.scrollTop + this._scroller.clientHeight);
const hasTopOverflow = this._scrollElement.scrollTop > 0;
const hasBottomOverflow = this._scrollElement.scrollHeight >
(this._scrollElement.scrollTop + this._scrollElement.clientHeight);
if (hasTopOverflow) {
this._scroller.classList.add("mx_IndicatorScrollbar_topOverflow");
this._scrollElement.classList.add("mx_IndicatorScrollbar_topOverflow");
} else {
this._scroller.classList.remove("mx_IndicatorScrollbar_topOverflow");
this._scrollElement.classList.remove("mx_IndicatorScrollbar_topOverflow");
}
if (hasBottomOverflow) {
this._scroller.classList.add("mx_IndicatorScrollbar_bottomOverflow");
this._scrollElement.classList.add("mx_IndicatorScrollbar_bottomOverflow");
} else {
this._scroller.classList.remove("mx_IndicatorScrollbar_bottomOverflow");
this._scrollElement.classList.remove("mx_IndicatorScrollbar_bottomOverflow");
}
if (this._autoHideScrollbar) {
this._autoHideScrollbar.checkOverflow();
}
}
componentWillUnmount() {
if (this._scroller) {
this._scroller.removeEventListener("scroll", this.checkOverflow);
if (this._scrollElement) {
this._scrollElement.removeEventListener("scroll", this.checkOverflow);
}
}
render() {
return (<AutoHideScrollbar wrappedRef={this._collectScroller} {... this.props}>
return (<AutoHideScrollbar ref={this._collectScrollerComponent} wrappedRef={this._collectScroller} {... this.props}>
{ this.props.children }
</AutoHideScrollbar>);
}