mirror of
https://github.com/ancsemi/Haven.git
synced 2026-10-28 01:26:14 +00:00
Every new reply scrolled the thread to the bottom. It now follows only a reader within 40px of the end (or their own reply); otherwise the view stays put and a button at the foot counts the new replies and jumps to the latest.
77 lines
2.8 KiB
JavaScript
77 lines
2.8 KiB
JavaScript
// The thread panel follows new replies only while you are reading the newest.
|
|
//
|
|
// Every reply used to scroll the panel to the bottom, so someone reading a
|
|
// busy thread from the start was pulled away each time the others posted.
|
|
// Now a reply keeps the view where it is unless the reader was already at
|
|
// the bottom (the same 40px rule the chat feed uses, app-feed-anchor.js).
|
|
// Your own reply always takes you down. Replies that arrive while you are
|
|
// scrolled up are counted on a button at the foot of the panel, which also
|
|
// works as "jump to latest" once you are far from the end. The pop-out
|
|
// thread is the same panel, so it behaves the same.
|
|
|
|
// How far from the end the jump button appears with nothing new to count.
|
|
const JUMP_SHOW_PX = 400;
|
|
|
|
export default {
|
|
|
|
_setupThreadScroll() {
|
|
const box = document.getElementById('thread-messages');
|
|
const btn = document.getElementById('thread-jump-latest');
|
|
if (!box || !btn) return;
|
|
this._threadUnseen = 0;
|
|
box.addEventListener('scroll', () => {
|
|
if (this._threadGap(box) <= 40) this._threadUnseen = 0;
|
|
this._updateThreadJump();
|
|
}, { passive: true });
|
|
btn.addEventListener('click', () => this._threadJumpToLatest());
|
|
},
|
|
|
|
_threadGap(box) {
|
|
return box.scrollHeight - box.scrollTop - box.clientHeight;
|
|
},
|
|
|
|
// A reply was just added at the end. gapBefore is how far from the end the
|
|
// reader was before it went in.
|
|
_threadAfterLiveReply(box, gapBefore, msg) {
|
|
const mine = !!(msg && this.user && msg.user_id != null && msg.user_id === this.user.id);
|
|
const blog = !!this._forumBlogThread;
|
|
const follow = this._feedShouldStick({ live: true, coupled: mine, gapBefore, startsAtEnd: !blog, scrolled: box.scrollTop > 0 });
|
|
if (follow) {
|
|
box.scrollTop = box.scrollHeight;
|
|
this._threadUnseen = 0;
|
|
} else if (!mine) {
|
|
this._threadUnseen = (this._threadUnseen || 0) + 1;
|
|
}
|
|
this._updateThreadJump();
|
|
},
|
|
|
|
// A thread was just opened or loaded again: nothing is waiting.
|
|
_resetThreadJump() {
|
|
this._threadUnseen = 0;
|
|
this._updateThreadJump();
|
|
},
|
|
|
|
_threadJumpToLatest() {
|
|
const box = document.getElementById('thread-messages');
|
|
if (!box) return;
|
|
box.scrollTop = box.scrollHeight;
|
|
this._threadUnseen = 0;
|
|
this._updateThreadJump();
|
|
},
|
|
|
|
_updateThreadJump() {
|
|
const box = document.getElementById('thread-messages');
|
|
const btn = document.getElementById('thread-jump-latest');
|
|
const label = document.getElementById('thread-jump-count');
|
|
if (!box || !btn) return;
|
|
const n = this._threadUnseen || 0;
|
|
const show = n > 0 || this._threadGap(box) > JUMP_SHOW_PX;
|
|
btn.classList.toggle('visible', show);
|
|
btn.classList.toggle('has-count', n > 0);
|
|
const text = n > 0 ? t(n === 1 ? 'thread_runtime.new_replies_one' : 'thread_runtime.new_replies_other', { count: n > 99 ? '99+' : n }) : '';
|
|
if (label) label.textContent = text;
|
|
btn.title = text || t('thread_runtime.jump_latest');
|
|
},
|
|
|
|
};
|