Save and restore buffer scroll position

This commit is contained in:
Simon Ser 2020-06-25 12:03:05 +02:00
parent 96f33019f8
commit 544303923c
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48
2 changed files with 83 additions and 3 deletions

View file

@ -4,6 +4,7 @@ import Buffer from "/components/buffer.js";
import BufferList from "/components/buffer-list.js";
import Connect from "/components/connect.js";
import Composer from "/components/composer.js";
import ScrollManager from "/components/scroll-manager.js";
import { html, Component, createRef } from "/lib/index.js";
import { SERVER_BUFFER, Status, Unread } from "/state.js";
@ -37,6 +38,7 @@ export default class App extends Component {
buffers: new Map(),
activeBuffer: null,
};
buffer = createRef();
composer = createRef();
constructor(props) {
@ -414,9 +416,11 @@ export default class App extends Component {
<section id="sidebar">
<${BufferList} buffers=${this.state.buffers} activeBuffer=${this.state.activeBuffer} onBufferClick=${this.handleBufferListClick}/>
</section>
<section id="buffer">
<${ScrollManager} target=${this.buffer} scrollKey=${this.state.activeBuffer}>
<section id="buffer" ref=${this.buffer}>
<${Buffer} buffer=${activeBuffer}/>
</section>
</>
<${Composer} ref=${this.composer} readOnly=${this.state.activeBuffer == SERVER_BUFFER} onSubmit=${this.handleComposerSubmit}/>
`;
}

View file

@ -0,0 +1,76 @@
import { html, Component } from "/lib/index.js";
var store = new Map();
export default class ScrollManager extends Component {
stickToBottom = false;
constructor(props) {
super(props);
this.handleScroll = this.handleScroll.bind(this);
}
isAtBottom() {
var target = this.props.target.current;
return target.scrollTop >= target.scrollHeight - target.offsetHeight;
}
scroll(pos) {
var target = this.props.target.current;
if (pos.bottom) {
pos.y = target.scrollHeight - target.offsetHeight;
}
target.scrollTop = pos.y;
}
saveScrollPosition() {
var target = this.props.target.current;
store.set(this.props.scrollKey, {
y: target.scrollTop,
bottom: this.isAtBottom(),
});
}
restoreScrollPosition() {
var target = this.props.target.current;
var pos = store.get(this.props.scrollKey);
if (!pos) {
pos = { bottom: true };
}
this.scroll(pos);
this.stickToBottom = pos.bottom;
}
handleScroll() {
this.stickToBottom = this.isAtBottom();
}
componentDidMount() {
this.restoreScrollPosition();
this.props.target.current.addEventListener("scroll", this.handleScroll);
}
componentWillReceiveProps(nextProps) {
if (this.props.scrollKey !== nextProps.scrollKey) {
this.saveScrollPosition();
}
}
componentDidUpdate(prevProps) {
if (this.props.scrollKey !== prevProps.scrollKey) {
this.restoreScrollPosition();
} else if (this.stickToBottom) {
this.scroll({ bottom: true });
}
}
componentWillUnmount() {
this.props.target.current.removeEventListener("scroll", this.handleScroll);
this.saveScrollPosition();
}
render() {
return this.props.children;
}
}