mirror of https://github.com/vector-im/riot-web
Fix issue with threads timelines with few events cropping events (#8392)
parent
bb4064ff43
commit
0c7a4dfcac
|
@ -70,10 +70,6 @@ limitations under the License.
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
overflow-anchor: none;
|
overflow-anchor: none;
|
||||||
|
|
||||||
&[data-scrollbar=false] {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomView_messagePanelSearchSpinner {
|
.mx_RoomView_messagePanelSearchSpinner {
|
||||||
|
|
|
@ -22,19 +22,17 @@ import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||||
import UIStore, { UI_EVENTS } from "../../stores/UIStore";
|
|
||||||
|
|
||||||
const DEBUG_SCROLL = false;
|
const DEBUG_SCROLL = false;
|
||||||
|
|
||||||
// The amount of extra scroll distance to allow prior to unfilling.
|
// The amount of extra scroll distance to allow prior to unfilling.
|
||||||
// See getExcessHeight.
|
// See getExcessHeight.
|
||||||
const UNPAGINATION_PADDING = 6000;
|
const UNPAGINATION_PADDING = 6000;
|
||||||
// The number of milliseconds to debounce calls to onUnfillRequest, to prevent
|
// The number of milliseconds to debounce calls to onUnfillRequest,
|
||||||
// many scroll events causing many unfilling requests.
|
// to prevent many scroll events causing many unfilling requests.
|
||||||
const UNFILL_REQUEST_DEBOUNCE_MS = 200;
|
const UNFILL_REQUEST_DEBOUNCE_MS = 200;
|
||||||
// _updateHeight makes the height a ceiled multiple of this so we
|
// updateHeight makes the height a ceiled multiple of this so we don't have to update the height too often.
|
||||||
// don't have to update the height too often. It also allows the user
|
// It also allows the user to scroll past the pagination spinner a bit so they don't feel blocked so
|
||||||
// to scroll past the pagination spinner a bit so they don't feel blocked so
|
|
||||||
// much while the content loads.
|
// much while the content loads.
|
||||||
const PAGE_SIZE = 400;
|
const PAGE_SIZE = 400;
|
||||||
|
|
||||||
|
@ -193,24 +191,20 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
private preventShrinkingState: IPreventShrinkingState;
|
private preventShrinkingState: IPreventShrinkingState;
|
||||||
private unfillDebouncer: number;
|
private unfillDebouncer: number;
|
||||||
private bottomGrowth: number;
|
private bottomGrowth: number;
|
||||||
private pages: number;
|
private minListHeight: number;
|
||||||
private heightUpdateInProgress: boolean;
|
private heightUpdateInProgress: boolean;
|
||||||
private divScroll: HTMLDivElement;
|
private divScroll: HTMLDivElement;
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
if (this.props.resizeNotifier) {
|
this.props.resizeNotifier?.on("middlePanelResizedNoisy", this.onResize);
|
||||||
this.props.resizeNotifier.on("middlePanelResizedNoisy", this.onResize);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.resetScrollState();
|
this.resetScrollState();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.checkScroll();
|
this.checkScroll();
|
||||||
|
|
||||||
UIStore.instance.on(UI_EVENTS.Resize, this.onUiResize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
|
@ -230,11 +224,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
// (We could use isMounted(), but facebook have deprecated that.)
|
// (We could use isMounted(), but facebook have deprecated that.)
|
||||||
this.unmounted = true;
|
this.unmounted = true;
|
||||||
|
|
||||||
if (this.props.resizeNotifier) {
|
this.props.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize);
|
||||||
this.props.resizeNotifier.removeListener("middlePanelResizedNoisy", this.onResize);
|
|
||||||
}
|
|
||||||
|
|
||||||
UIStore.instance.off(UI_EVENTS.Resize, this.onUiResize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onScroll = ev => {
|
private onScroll = ev => {
|
||||||
|
@ -546,7 +536,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
stuckAtBottom: this.props.startAtBottom,
|
stuckAtBottom: this.props.startAtBottom,
|
||||||
};
|
};
|
||||||
this.bottomGrowth = 0;
|
this.bottomGrowth = 0;
|
||||||
this.pages = 0;
|
this.minListHeight = 0;
|
||||||
this.scrollTimeout = new Timer(100);
|
this.scrollTimeout = new Timer(100);
|
||||||
this.heightUpdateInProgress = false;
|
this.heightUpdateInProgress = false;
|
||||||
};
|
};
|
||||||
|
@ -721,17 +711,6 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onUiResize = () => {
|
|
||||||
this.setDataScrollbar();
|
|
||||||
};
|
|
||||||
|
|
||||||
private setDataScrollbar(contentHeight = this.getMessagesHeight()) {
|
|
||||||
const sn = this.getScrollNode();
|
|
||||||
const minHeight = sn.clientHeight;
|
|
||||||
const displayScrollbar = contentHeight > minHeight;
|
|
||||||
sn.dataset.scrollbar = displayScrollbar.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// need a better name that also indicates this will change scrollTop? Rebalance height? Reveal content?
|
// need a better name that also indicates this will change scrollTop? Rebalance height? Reveal content?
|
||||||
private async updateHeight(): Promise<void> {
|
private async updateHeight(): Promise<void> {
|
||||||
// wait until user has stopped scrolling
|
// wait until user has stopped scrolling
|
||||||
|
@ -750,10 +729,13 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
const sn = this.getScrollNode();
|
const sn = this.getScrollNode();
|
||||||
const itemlist = this.itemlist.current;
|
const itemlist = this.itemlist.current;
|
||||||
const contentHeight = this.getMessagesHeight();
|
const contentHeight = this.getMessagesHeight();
|
||||||
const minHeight = sn.clientHeight;
|
// Only round to the nearest page when we're basing the height off the content, not off the scrollNode height
|
||||||
const height = Math.max(minHeight, contentHeight);
|
// otherwise it'll cause too much overscroll which makes it possible to entirely scroll content off-screen.
|
||||||
this.pages = Math.ceil(height / PAGE_SIZE);
|
if (contentHeight < sn.clientHeight - PAGE_SIZE) {
|
||||||
this.setDataScrollbar(contentHeight);
|
this.minListHeight = sn.clientHeight;
|
||||||
|
} else {
|
||||||
|
this.minListHeight = Math.ceil(contentHeight / PAGE_SIZE) * PAGE_SIZE;
|
||||||
|
}
|
||||||
this.bottomGrowth = 0;
|
this.bottomGrowth = 0;
|
||||||
const newHeight = `${this.getListHeight()}px`;
|
const newHeight = `${this.getListHeight()}px`;
|
||||||
|
|
||||||
|
@ -822,7 +804,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private getListHeight(): number {
|
private getListHeight(): number {
|
||||||
return this.bottomGrowth + (this.pages * PAGE_SIZE);
|
return this.bottomGrowth + this.minListHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMessagesHeight(): number {
|
private getMessagesHeight(): number {
|
||||||
|
|
Loading…
Reference in New Issue