Minor code quality updates for ScrollPanel (#9639)
* Minor code quality updates for ScrollPanel and removal of unused function `scrollRelative` in MessagePanel (discovered when changing the scrollRelative types in ScrollPanel). Changes: * Clean up logging a bit, make it clearer * Remove dead code * Add extra types for tsc --strict compliance (not complete) * Fix IDE warnings around spelling and missing awaits/promise return values * Modernize usage of logging * Fix more tsc --strict errors while we're here * It's a good thing we have a linter * Fix even more strict errors
This commit is contained in:
parent
f642765149
commit
09282d9f36
2 changed files with 55 additions and 56 deletions
|
@ -183,7 +183,7 @@ interface IProps {
|
||||||
onFillRequest?(backwards: boolean): Promise<boolean>;
|
onFillRequest?(backwards: boolean): Promise<boolean>;
|
||||||
|
|
||||||
// helper function to access relations for an event
|
// helper function to access relations for an event
|
||||||
onUnfillRequest?(backwards: boolean, scrollToken: string): void;
|
onUnfillRequest?(backwards: boolean, scrollToken: string | null): void;
|
||||||
|
|
||||||
getRelationsForEvent?: GetRelationsForEvent;
|
getRelationsForEvent?: GetRelationsForEvent;
|
||||||
|
|
||||||
|
@ -413,17 +413,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Page up/down.
|
|
||||||
*
|
|
||||||
* @param {number} mult: -1 to page up, +1 to page down
|
|
||||||
*/
|
|
||||||
public scrollRelative(mult: number): void {
|
|
||||||
if (this.scrollPanel.current) {
|
|
||||||
this.scrollPanel.current.scrollRelative(mult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scroll up/down in response to a scroll key
|
* Scroll up/down in response to a scroll key
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
|
Copyright 2015 - 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -30,8 +30,8 @@ const UNPAGINATION_PADDING = 6000;
|
||||||
// The number of milliseconds to debounce calls to onUnfillRequest,
|
// The number of milliseconds to debounce calls to onUnfillRequest,
|
||||||
// to prevent 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 don't have to update the height too often.
|
// updateHeight makes the height a `Math.ceil` multiple of this, so we don't have to update the height too often.
|
||||||
// It also allows the user to scroll past the pagination spinner a bit so they don't feel blocked so
|
// It also allows the user 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;
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ interface IProps {
|
||||||
*
|
*
|
||||||
* - fixed, in which the viewport is conceptually tied at a specific scroll
|
* - fixed, in which the viewport is conceptually tied at a specific scroll
|
||||||
* offset. We don't save the absolute scroll offset, because that would be
|
* offset. We don't save the absolute scroll offset, because that would be
|
||||||
* affected by window width, zoom level, amount of scrollback, etc. Instead
|
* affected by window width, zoom level, amount of scrollback, etc. Instead,
|
||||||
* we save an identifier for the last fully-visible message, and the number
|
* we save an identifier for the last fully-visible message, and the number
|
||||||
* of pixels the window was scrolled below it - which is hopefully near
|
* of pixels the window was scrolled below it - which is hopefully near
|
||||||
* enough.
|
* enough.
|
||||||
|
@ -161,7 +161,8 @@ interface IPreventShrinkingState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ScrollPanel extends React.Component<IProps> {
|
export default class ScrollPanel extends React.Component<IProps> {
|
||||||
static defaultProps = {
|
// noinspection JSUnusedLocalSymbols
|
||||||
|
public static defaultProps = {
|
||||||
stickyBottom: true,
|
stickyBottom: true,
|
||||||
startAtBottom: true,
|
startAtBottom: true,
|
||||||
onFillRequest: function(backwards: boolean) { return Promise.resolve(false); },
|
onFillRequest: function(backwards: boolean) { return Promise.resolve(false); },
|
||||||
|
@ -200,21 +201,21 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
this.resetScrollState();
|
this.resetScrollState();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
public componentDidMount(): void {
|
||||||
this.checkScroll();
|
this.checkScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
public componentDidUpdate(): void {
|
||||||
// after adding event tiles, we may need to tweak the scroll (either to
|
// after adding event tiles, we may need to tweak the scroll (either to
|
||||||
// keep at the bottom of the timeline, or to maintain the view after
|
// keep at the bottom of the timeline, or to maintain the view after
|
||||||
// adding events to the top).
|
// adding events to the top).
|
||||||
//
|
//
|
||||||
// This will also re-check the fill state, in case the paginate was inadequate
|
// This will also re-check the fill state, in case the pagination was inadequate
|
||||||
this.checkScroll(true);
|
this.checkScroll(true);
|
||||||
this.updatePreventShrinking();
|
this.updatePreventShrinking();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
public componentWillUnmount(): void {
|
||||||
// set a boolean to say we've been unmounted, which any pending
|
// set a boolean to say we've been unmounted, which any pending
|
||||||
// promises can use to throw away their results.
|
// promises can use to throw away their results.
|
||||||
//
|
//
|
||||||
|
@ -224,19 +225,20 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
this.props.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize);
|
this.props.resizeNotifier?.removeListener("middlePanelResizedNoisy", this.onResize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onScroll = ev => {
|
private onScroll = (ev: Event | React.UIEvent): void => {
|
||||||
// skip scroll events caused by resizing
|
// skip scroll events caused by resizing
|
||||||
if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return;
|
if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return;
|
||||||
debuglog("onScroll", this.getScrollNode().scrollTop);
|
debuglog("onScroll called past resize gate; scroll node top:", this.getScrollNode().scrollTop);
|
||||||
this.scrollTimeout.restart();
|
this.scrollTimeout.restart();
|
||||||
this.saveScrollState();
|
this.saveScrollState();
|
||||||
this.updatePreventShrinking();
|
this.updatePreventShrinking();
|
||||||
this.props.onScroll(ev);
|
this.props.onScroll?.(ev as Event);
|
||||||
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
this.checkFillState();
|
this.checkFillState();
|
||||||
};
|
};
|
||||||
|
|
||||||
private onResize = () => {
|
private onResize = (): void => {
|
||||||
debuglog("onResize");
|
debuglog("onResize called");
|
||||||
this.checkScroll();
|
this.checkScroll();
|
||||||
// update preventShrinkingState if present
|
// update preventShrinkingState if present
|
||||||
if (this.preventShrinkingState) {
|
if (this.preventShrinkingState) {
|
||||||
|
@ -246,11 +248,14 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
|
|
||||||
// after an update to the contents of the panel, check that the scroll is
|
// after an update to the contents of the panel, check that the scroll is
|
||||||
// where it ought to be, and set off pagination requests if necessary.
|
// where it ought to be, and set off pagination requests if necessary.
|
||||||
public checkScroll = (isFromPropsUpdate = false) => {
|
public checkScroll = (isFromPropsUpdate = false): void => {
|
||||||
if (this.unmounted) {
|
if (this.unmounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// We don't care if these two conditions race - they're different trees.
|
||||||
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
this.restoreSavedScrollState();
|
this.restoreSavedScrollState();
|
||||||
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
this.checkFillState(0, isFromPropsUpdate);
|
this.checkFillState(0, isFromPropsUpdate);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -259,7 +264,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
// note that this is independent of the 'stuckAtBottom' state - it is simply
|
// note that this is independent of the 'stuckAtBottom' state - it is simply
|
||||||
// about whether the content is scrolled down right now, irrespective of
|
// about whether the content is scrolled down right now, irrespective of
|
||||||
// whether it will stay that way when the children update.
|
// whether it will stay that way when the children update.
|
||||||
public isAtBottom = () => {
|
public isAtBottom = (): boolean => {
|
||||||
const sn = this.getScrollNode();
|
const sn = this.getScrollNode();
|
||||||
// fractional values (both too big and too small)
|
// fractional values (both too big and too small)
|
||||||
// for scrollTop happen on certain browsers/platforms
|
// for scrollTop happen on certain browsers/platforms
|
||||||
|
@ -277,7 +282,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
|
|
||||||
// returns the vertical height in the given direction that can be removed from
|
// returns the vertical height in the given direction that can be removed from
|
||||||
// the content box (which has a height of scrollHeight, see checkFillState) without
|
// the content box (which has a height of scrollHeight, see checkFillState) without
|
||||||
// pagination occuring.
|
// pagination occurring.
|
||||||
//
|
//
|
||||||
// padding* = UNPAGINATION_PADDING
|
// padding* = UNPAGINATION_PADDING
|
||||||
//
|
//
|
||||||
|
@ -329,7 +334,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
const isFirstCall = depth === 0;
|
const isFirstCall = depth === 0;
|
||||||
const sn = this.getScrollNode();
|
const sn = this.getScrollNode();
|
||||||
|
|
||||||
// if there is less than a screenful of messages above or below the
|
// if there is less than a screen's worth of messages above or below the
|
||||||
// viewport, try to get some more messages.
|
// viewport, try to get some more messages.
|
||||||
//
|
//
|
||||||
// scrollTop is the number of pixels between the top of the content and
|
// scrollTop is the number of pixels between the top of the content and
|
||||||
|
@ -408,6 +413,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
const refillDueToPropsUpdate = this.pendingFillDueToPropsUpdate;
|
const refillDueToPropsUpdate = this.pendingFillDueToPropsUpdate;
|
||||||
this.fillRequestWhileRunning = false;
|
this.fillRequestWhileRunning = false;
|
||||||
this.pendingFillDueToPropsUpdate = false;
|
this.pendingFillDueToPropsUpdate = false;
|
||||||
|
// noinspection ES6MissingAwait
|
||||||
this.checkFillState(0, refillDueToPropsUpdate);
|
this.checkFillState(0, refillDueToPropsUpdate);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -424,7 +430,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
const tiles = this.itemlist.current.children;
|
const tiles = this.itemlist.current.children;
|
||||||
|
|
||||||
// The scroll token of the first/last tile to be unpaginated
|
// The scroll token of the first/last tile to be unpaginated
|
||||||
let markerScrollToken = null;
|
let markerScrollToken: string | null = null;
|
||||||
|
|
||||||
// Subtract heights of tiles to simulate the tiles being unpaginated until the
|
// Subtract heights of tiles to simulate the tiles being unpaginated until the
|
||||||
// excess height is less than the height of the next tile to subtract. This
|
// excess height is less than the height of the next tile to subtract. This
|
||||||
|
@ -434,7 +440,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
// If backwards is true, we unpaginate (remove) tiles from the back (top).
|
// If backwards is true, we unpaginate (remove) tiles from the back (top).
|
||||||
let tile;
|
let tile;
|
||||||
for (let i = 0; i < tiles.length; i++) {
|
for (let i = 0; i < tiles.length; i++) {
|
||||||
tile = tiles[backwards ? i : tiles.length - 1 - i];
|
tile = tiles[backwards ? i : (tiles.length - 1 - i)];
|
||||||
// Subtract height of tile as if it were unpaginated
|
// Subtract height of tile as if it were unpaginated
|
||||||
excessHeight -= tile.clientHeight;
|
excessHeight -= tile.clientHeight;
|
||||||
//If removing the tile would lead to future pagination, break before setting scroll token
|
//If removing the tile would lead to future pagination, break before setting scroll token
|
||||||
|
@ -455,8 +461,8 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
this.unfillDebouncer = setTimeout(() => {
|
this.unfillDebouncer = setTimeout(() => {
|
||||||
this.unfillDebouncer = null;
|
this.unfillDebouncer = null;
|
||||||
debuglog("unfilling now", backwards, origExcessHeight);
|
debuglog("unfilling now", { backwards, origExcessHeight });
|
||||||
this.props.onUnfillRequest(backwards, markerScrollToken);
|
this.props.onUnfillRequest?.(backwards, markerScrollToken!);
|
||||||
}, UNFILL_REQUEST_DEBOUNCE_MS);
|
}, UNFILL_REQUEST_DEBOUNCE_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -465,11 +471,11 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
private maybeFill(depth: number, backwards: boolean): Promise<void> {
|
private maybeFill(depth: number, backwards: boolean): Promise<void> {
|
||||||
const dir = backwards ? 'b' : 'f';
|
const dir = backwards ? 'b' : 'f';
|
||||||
if (this.pendingFillRequests[dir]) {
|
if (this.pendingFillRequests[dir]) {
|
||||||
debuglog("Already a "+dir+" fill in progress - not starting another");
|
debuglog("Already a fill in progress - not starting another; direction=", dir);
|
||||||
return;
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
debuglog("starting "+dir+" fill");
|
debuglog("starting fill; direction=", dir);
|
||||||
|
|
||||||
// onFillRequest can end up calling us recursively (via onScroll
|
// onFillRequest can end up calling us recursively (via onScroll
|
||||||
// events) so make sure we set this before firing off the call.
|
// events) so make sure we set this before firing off the call.
|
||||||
|
@ -490,7 +496,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
// Unpaginate once filling is complete
|
// Unpaginate once filling is complete
|
||||||
this.checkUnfillState(!backwards);
|
this.checkUnfillState(!backwards);
|
||||||
|
|
||||||
debuglog(""+dir+" fill complete; hasMoreResults:"+hasMoreResults);
|
debuglog("fill complete; hasMoreResults=", hasMoreResults, "direction=", dir);
|
||||||
if (hasMoreResults) {
|
if (hasMoreResults) {
|
||||||
// further pagination requests have been disabled until now, so
|
// further pagination requests have been disabled until now, so
|
||||||
// it's time to check the fill state again in case the pagination
|
// it's time to check the fill state again in case the pagination
|
||||||
|
@ -562,11 +568,12 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
/**
|
/**
|
||||||
* Page up/down.
|
* Page up/down.
|
||||||
*
|
*
|
||||||
* @param {number} mult: -1 to page up, +1 to page down
|
* @param {number} multiple: -1 to page up, +1 to page down
|
||||||
*/
|
*/
|
||||||
public scrollRelative = (mult: number): void => {
|
public scrollRelative = (multiple: -1 | 1): void => {
|
||||||
const scrollNode = this.getScrollNode();
|
const scrollNode = this.getScrollNode();
|
||||||
const delta = mult * scrollNode.clientHeight * 0.9;
|
// TODO: Document what magic number 0.9 is doing
|
||||||
|
const delta = multiple * scrollNode.clientHeight * 0.9;
|
||||||
scrollNode.scrollBy(0, delta);
|
scrollNode.scrollBy(0, delta);
|
||||||
this.saveScrollState();
|
this.saveScrollState();
|
||||||
};
|
};
|
||||||
|
@ -608,7 +615,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
pixelOffset = pixelOffset || 0;
|
pixelOffset = pixelOffset || 0;
|
||||||
offsetBase = offsetBase || 0;
|
offsetBase = offsetBase || 0;
|
||||||
|
|
||||||
// set the trackedScrollToken so we can get the node through getTrackedNode
|
// set the trackedScrollToken, so we can get the node through getTrackedNode
|
||||||
this.scrollState = {
|
this.scrollState = {
|
||||||
stuckAtBottom: false,
|
stuckAtBottom: false,
|
||||||
trackedScrollToken: scrollToken,
|
trackedScrollToken: scrollToken,
|
||||||
|
@ -621,7 +628,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
// would position the trackedNode towards the top of the viewport.
|
// would position the trackedNode towards the top of the viewport.
|
||||||
// This because when setting the scrollTop only 10 or so events might be loaded,
|
// This because when setting the scrollTop only 10 or so events might be loaded,
|
||||||
// not giving enough content below the trackedNode to scroll downwards
|
// not giving enough content below the trackedNode to scroll downwards
|
||||||
// enough so it ends up in the top of the viewport.
|
// enough, so it ends up in the top of the viewport.
|
||||||
debuglog("scrollToken: setting scrollTop", { offsetBase, pixelOffset, offsetTop: trackedNode.offsetTop });
|
debuglog("scrollToken: setting scrollTop", { offsetBase, pixelOffset, offsetTop: trackedNode.offsetTop });
|
||||||
scrollNode.scrollTop = (trackedNode.offsetTop - (scrollNode.clientHeight * offsetBase)) + pixelOffset;
|
scrollNode.scrollTop = (trackedNode.offsetTop - (scrollNode.clientHeight * offsetBase)) + pixelOffset;
|
||||||
this.saveScrollState();
|
this.saveScrollState();
|
||||||
|
@ -640,15 +647,16 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
|
|
||||||
const itemlist = this.itemlist.current;
|
const itemlist = this.itemlist.current;
|
||||||
const messages = itemlist.children;
|
const messages = itemlist.children;
|
||||||
let node = null;
|
let node: HTMLElement | null = null;
|
||||||
|
|
||||||
// TODO: do a binary search here, as items are sorted by offsetTop
|
// TODO: do a binary search here, as items are sorted by offsetTop
|
||||||
// loop backwards, from bottom-most message (as that is the most common case)
|
// loop backwards, from bottom-most message (as that is the most common case)
|
||||||
for (let i = messages.length - 1; i >= 0; --i) {
|
for (let i = messages.length - 1; i >= 0; --i) {
|
||||||
if (!(messages[i] as HTMLElement).dataset.scrollTokens) {
|
const htmlMessage = messages[i] as HTMLElement;
|
||||||
|
if (!htmlMessage.dataset?.scrollTokens) { // dataset is only specified on HTMLElements
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
node = messages[i];
|
node = htmlMessage;
|
||||||
// break at the first message (coming from the bottom)
|
// break at the first message (coming from the bottom)
|
||||||
// that has it's offsetTop above the bottom of the viewport.
|
// that has it's offsetTop above the bottom of the viewport.
|
||||||
if (this.topFromBottom(node) > viewportBottom) {
|
if (this.topFromBottom(node) > viewportBottom) {
|
||||||
|
@ -661,8 +669,8 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
debuglog("unable to save scroll state: found no children in the viewport");
|
debuglog("unable to save scroll state: found no children in the viewport");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const scrollToken = node.dataset.scrollTokens.split(',')[0];
|
const scrollToken = node!.dataset.scrollTokens.split(',')[0];
|
||||||
debuglog("saving anchored scroll state to message", node.innerText, scrollToken);
|
debuglog("saving anchored scroll state to message", scrollToken);
|
||||||
const bottomOffset = this.topFromBottom(node);
|
const bottomOffset = this.topFromBottom(node);
|
||||||
this.scrollState = {
|
this.scrollState = {
|
||||||
stuckAtBottom: false,
|
stuckAtBottom: false,
|
||||||
|
@ -714,12 +722,14 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
if (this.scrollTimeout.isRunning()) {
|
if (this.scrollTimeout.isRunning()) {
|
||||||
debuglog("updateHeight waiting for scrolling to end ... ");
|
debuglog("updateHeight waiting for scrolling to end ... ");
|
||||||
await this.scrollTimeout.finished();
|
await this.scrollTimeout.finished();
|
||||||
|
debuglog("updateHeight actually running now");
|
||||||
} else {
|
} else {
|
||||||
debuglog("updateHeight getting straight to business, no scrolling going on.");
|
debuglog("updateHeight running without delay");
|
||||||
}
|
}
|
||||||
|
|
||||||
// We might have unmounted since the timer finished, so abort if so.
|
// We might have unmounted since the timer finished, so abort if so.
|
||||||
if (this.unmounted) {
|
if (this.unmounted) {
|
||||||
|
debuglog("updateHeight: abort due to unmount");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,12 +778,12 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTrackedNode(): HTMLElement {
|
private getTrackedNode(): HTMLElement | undefined {
|
||||||
const scrollState = this.scrollState;
|
const scrollState = this.scrollState;
|
||||||
const trackedNode = scrollState.trackedNode;
|
const trackedNode = scrollState.trackedNode;
|
||||||
|
|
||||||
if (!trackedNode?.parentElement) {
|
if (!trackedNode?.parentElement) {
|
||||||
let node: HTMLElement;
|
let node: HTMLElement | undefined = undefined;
|
||||||
const messages = this.itemlist.current.children;
|
const messages = this.itemlist.current.children;
|
||||||
const scrollToken = scrollState.trackedScrollToken;
|
const scrollToken = scrollState.trackedScrollToken;
|
||||||
|
|
||||||
|
@ -781,19 +791,19 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
const m = messages[i] as HTMLElement;
|
const m = messages[i] as HTMLElement;
|
||||||
// 'data-scroll-tokens' is a DOMString of comma-separated scroll tokens
|
// 'data-scroll-tokens' is a DOMString of comma-separated scroll tokens
|
||||||
// There might only be one scroll token
|
// There might only be one scroll token
|
||||||
if (m.dataset.scrollTokens?.split(',').includes(scrollToken)) {
|
if (scrollToken && m.dataset.scrollTokens?.split(',').includes(scrollToken!)) {
|
||||||
node = m;
|
node = m;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node) {
|
if (node) {
|
||||||
debuglog("had to find tracked node again for " + scrollState.trackedScrollToken);
|
debuglog("had to find tracked node again for token:", scrollState.trackedScrollToken);
|
||||||
}
|
}
|
||||||
scrollState.trackedNode = node;
|
scrollState.trackedNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scrollState.trackedNode) {
|
if (!scrollState.trackedNode) {
|
||||||
debuglog("No node with ; '"+scrollState.trackedScrollToken+"'");
|
debuglog("No node with token:", scrollState.trackedScrollToken);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,7 +852,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Mark the bottom offset of the last tile so we can balance it out when
|
Mark the bottom offset of the last tile, so we can balance it out when
|
||||||
anything below it changes, by calling updatePreventShrinking, to keep
|
anything below it changes, by calling updatePreventShrinking, to keep
|
||||||
the same minimum bottom offset, effectively preventing the timeline to shrink.
|
the same minimum bottom offset, effectively preventing the timeline to shrink.
|
||||||
*/
|
*/
|
||||||
|
@ -921,7 +931,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
public render(): ReactNode {
|
||||||
// TODO: the classnames on the div and ol could do with being updated to
|
// TODO: the classnames on the div and ol could do with being updated to
|
||||||
// reflect the fact that we don't necessarily contain a list of messages.
|
// reflect the fact that we don't necessarily contain a list of messages.
|
||||||
// it's not obvious why we have a separate div and ol anyway.
|
// it's not obvious why we have a separate div and ol anyway.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue