~emersion/gamja

a83d3f742513976a02f765faa831fdcc9fa84704 — Simon Ser a month ago 6c40561
Improve scroll position save/restore mechanism
3 files changed, 30 insertions(+), 27 deletions(-)

M components/app.js
M components/buffer.js
M components/scroll-manager.js
M components/app.js => components/app.js +1 -1
@@ 943,7 943,7 @@ export default class App extends Component {
				<${BufferList} buffers=${this.state.buffers} networks=${this.state.networks} activeBuffer=${this.state.activeBuffer} onBufferClick=${this.handleBufferListClick}/>
			</section>
			${bufferHeader}
			<${ScrollManager} target=${this.buffer} scrollKey=${this.state.activeBuffer} onScrollTop=${this.handleBufferScrollTop}>
			<${ScrollManager} target=${this.buffer} stickTo=".logline" scrollKey=${this.state.activeBuffer} onScrollTop=${this.handleBufferScrollTop}>
				<section id="buffer" ref=${this.buffer}>
					<${Buffer} buffer=${activeBuffer} onNickClick=${this.handleNickClick}/>
				</section>

M components/buffer.js => components/buffer.js +1 -1
@@ 118,7 118,7 @@ class LogLine extends Component {
		}

		return html`
			<div class="logline ${lineClass}">
			<div class="logline ${lineClass}" data-key=${msg.key}>
				<${Timestamp} date=${new Date(msg.tags.time)} url=${getMessageURL(this.props.buffer, msg)}/>
				${" "}
				${content}

M components/scroll-manager.js => components/scroll-manager.js +28 -25
@@ 3,8 3,6 @@ import { html, Component } from "/lib/index.js";
var store = new Map();

export default class ScrollManager extends Component {
	stickToBottom = false;

	constructor(props) {
		super(props);



@@ 16,37 14,43 @@ export default class ScrollManager extends Component {
		return target.scrollTop >= target.scrollHeight - target.offsetHeight;
	}

	scroll(pos) {
	saveScrollPosition() {
		var target = this.props.target.current;
		if (pos.bottom) {
			pos.y = target.scrollHeight - target.offsetHeight;

		var sticky = target.querySelectorAll(this.props.stickTo);
		var stickToKey = null;
		if (!this.isAtBottom()) {
			for (var i = 0; i < sticky.length; i++) {
				var el = sticky[i];
				if (el.offsetTop >= target.scrollTop + target.offsetTop) {
					stickToKey = el.dataset.key;
					break;
				}
			}
		}
		target.scrollTop = pos.y;
	}

	saveScrollPosition() {
		var target = this.props.target.current;
		store.set(this.props.scrollKey, {
			y: target.scrollTop,
			bottom: this.isAtBottom(),
		});
		store.set(this.props.scrollKey, stickToKey);
	}

	restoreScrollPosition() {
		var target = this.props.target.current;
		var pos = store.get(this.props.scrollKey);
		if (!pos) {
			pos = { bottom: true };

		var stickToKey = store.get(this.props.scrollKey);
		if (!stickToKey) {
			target.firstChild.scrollIntoView({ block: "end" });
		} else {
			var stickTo = target.querySelector("[data-key=\"" + stickToKey + "\"]");
			if (stickTo) {
				stickTo.scrollIntoView();
			}
		}
		this.scroll(pos);
		this.stickToBottom = pos.bottom;
		if (this.props.target.current.scrollTop == 0) {

		if (target.scrollTop == 0) {
			this.props.onScrollTop();
		}
	}

	handleScroll() {
		this.stickToBottom = this.isAtBottom();
		if (this.props.target.current.scrollTop == 0) {
			this.props.onScrollTop();
		}


@@ 58,17 62,16 @@ export default class ScrollManager extends Component {
	}

	componentWillReceiveProps(nextProps) {
		if (this.props.scrollKey !== nextProps.scrollKey) {
		if (this.props.scrollKey !== nextProps.scrollKey || this.props.children !== nextProps.children) {
			this.saveScrollPosition();
		}
	}

	componentDidUpdate(prevProps) {
		if (this.props.scrollKey !== prevProps.scrollKey) {
			this.restoreScrollPosition();
		} else if (this.stickToBottom) {
			this.scroll({ bottom: true });
		if (!this.props.target.current) {
			return;
		}
		this.restoreScrollPosition();
	}

	componentWillUnmount() {