refactor: remove glance

assorted fixes to navigator
dont reduce remaning count if user scrolls down and up quickly
only call topic.navigatorCallback when index changes
This commit is contained in:
Barış Soner Uşaklı
2023-02-15 21:28:37 -05:00
parent 5f4f45c44e
commit 54505e7a47
4 changed files with 17 additions and 318 deletions

View File

@@ -30,7 +30,7 @@ define('forum/category', [
sort.handleSort('categoryTopicSort', 'category/' + ajaxify.data.slug);
if (!config.usePagination) {
navigator.init('[component="category/topic"]', ajaxify.data.topic_count, Category.toTop, Category.toBottom, Category.navigatorCallback);
navigator.init('[component="category/topic"]', ajaxify.data.topic_count, Category.toTop, Category.toBottom);
} else {
navigator.disable();
}
@@ -129,10 +129,6 @@ define('forum/category', [
});
};
Category.navigatorCallback = function (topIndex, bottomIndex) {
return bottomIndex;
};
function loadTopicsAfter(after, direction, callback) {
callback = callback || function () {};

View File

@@ -7,7 +7,6 @@ define('forum/topic', [
'forum/topic/postTools',
'forum/topic/events',
'forum/topic/posts',
'forum/topic/glance',
'navigator',
'sort',
'quickreply',
@@ -18,7 +17,7 @@ define('forum/topic', [
'alerts',
], function (
infinitescroll, threadTools, postTools,
events, posts, glance, navigator, sort, quickreply,
events, posts, navigator, sort, quickreply,
components, storage, hooks, api, alerts
) {
const Topic = {};
@@ -47,7 +46,7 @@ define('forum/topic', [
posts.signaturesShown = {};
}
await posts.onTopicPageLoad(components.get('post'));
navigator.init('[component="post"]', ajaxify.data.postcount, Topic.toTop, Topic.toBottom, utils.debounce(Topic.navigatorCallback, 500));
navigator.init('[component="post"]', ajaxify.data.postcount, Topic.toTop, Topic.toBottom, Topic.navigatorCallback);
postTools.init(tid);
threadTools.init(tid, $('.topic'));
@@ -66,7 +65,6 @@ define('forum/topic', [
addPostsPreviewHandler();
setupQuickReply();
handleBookmark(tid);
glance.default();
$(window).on('scroll', utils.debounce(updateTopicTitle, 250));
@@ -329,7 +327,6 @@ define('forum/topic', [
updateUserBookmark(index);
Topic.replaceURLTimeout = 0;
if (ajaxify.data.updateUrlWithPostIndex && history.replaceState) {
let search = window.location.search || '';
if (!config.usePagination) {

View File

@@ -1,296 +0,0 @@
/* eslint-disable import/no-unresolved */
import { render } from 'benchpress';
import { loadMore } from 'forum/infinitescroll';
import * as navigator from 'navigator';
import { onNewPostsAddedToDom } from 'forum/topic/posts';
import { onPage, one as once } from 'hooks';
import { translate } from 'translator';
let trackTop;
let trackBottom;
let trackHeight;
let handleEl;
export default function init() {
const topicEl = document.querySelector('[component="topic"]');
const navigatorEl = document.querySelector('[component="topic/navigator"]');
if (!ajaxify.data.template.topic || !topicEl || !navigatorEl) {
return;
}
enableButtons();
({ handleEl } = enableHandle());
updateHandleText(ajaxify.data.postIndex);
updateUnreadIndicator(ajaxify.data.postIndex);
once('action:ajaxify.cleanup', () => {
window.removeEventListener('resize', updateTrackPosition);
});
console.debug('[glance] At-a-glance navigator enabled.');
}
function updateTrackPosition() {
const trackEl = document.querySelector('[component="topic/navigator"] .track');
({ top: trackTop, bottom: trackBottom, height: trackHeight } = trackEl.getBoundingClientRect());
}
function enableButtons() {
const navigatorEl = document.querySelector('[component="topic/navigator"]');
navigatorEl.addEventListener('click', (e) => {
const subselector = e.target.closest('[data-action]');
if (!subselector) {
return;
}
const action = subselector.getAttribute('data-action');
navigator[action]();
});
}
function enableHandle() {
const handleEl = document.querySelector('[component="topic/navigator"] .handle');
let active = false;
updateTrackPosition();
window.addEventListener('resize', updateTrackPosition);
onPage('action:navigator.update', utils.debounce(({ newIndex }) => {
if (!active) {
repositionHandle(newIndex);
}
}, 150));
onPage('action:navigator.scrolled', ({ newIndex }) => {
if (!active) {
repositionHandle(newIndex);
}
});
handleEl.addEventListener('mousedown', (e) => {
// Only respond to left click
if (e.buttons !== 1) {
return;
}
const tUpdateHandleText = utils.throttle(() => {
updateHandleText(getIndexFromTrack());
}, 250);
toggle(true);
active = true;
document.addEventListener('mousemove', onHandleMove);
document.addEventListener('mousemove', tUpdateHandleText);
document.addEventListener('mouseup', () => {
toggle(false);
document.removeEventListener('mousemove', onHandleMove);
document.removeEventListener('mousemove', tUpdateHandleText);
active = false;
}, {
once: true,
});
});
return { handleEl };
}
function getIndexFromTrack() {
const { top: handleTop } = handleEl.getBoundingClientRect();
const delta = handleTop - trackTop;
const percentage = trackHeight > 0 ? delta / trackHeight : 0;
const index = Math.floor(ajaxify.data.postcount * percentage);
return index;
}
// https://stackoverflow.com/a/21696585/583363
const isHidden = el => el.offsetParent === null;
async function updateUnreadIndicator(index) {
if (ajaxify.data.postcount <= ajaxify.data.bookmarkThreshold) {
return;
}
index = Math.max(index, ajaxify.data.bookmark);
const unreadEl = document.querySelector('[component="topic/navigator"] .unread');
const meta = unreadEl.querySelector('.meta');
if (isHidden(meta)) {
return;
}
const percentage = 1 - (index / ajaxify.data.postcount);
unreadEl.style.height = `${trackHeight * percentage}px`;
const anchorEl = unreadEl.querySelector('.meta a');
const remaining = ajaxify.data.postcount - index;
if (remaining > 0) {
const text = await translate(`[[topic:navigator.unread, ${remaining}]]`);
anchorEl.href = `${config.relative_path}/topic/${ajaxify.data.slug}/${Math.min(index + 1, ajaxify.data.postcount)}`;
anchorEl.innerText = text;
} else {
anchorEl.href = ajaxify.data.url;
anchorEl.innerText = '';
}
}
function repositionHandle(index) {
const percentage = Math.max(0, (index - 1) / ajaxify.data.postcount);
handleEl.style.top = `${trackHeight * percentage}px`;
updateHandleText(index);
updateUnreadIndicator(index);
}
async function updateHandleText(index) {
const { tid } = ajaxify.data;
const meta = handleEl.querySelector('.meta');
if (isHidden(meta)) {
return;
}
const indexEl = meta.querySelector('.index');
const timestampEl = meta.querySelector('.timestamp');
const text = await translate(`[[topic:navigator.index, ${index}, ${ajaxify.data.postcount}]]`);
indexEl.innerText = text;
const { timestampISO } = await socket.emit('posts.getPostSummaryByIndex', { tid, index: index - 1 });
timestampEl.title = timestampISO;
$(timestampEl).timeago();
}
function onHandleMove(e) {
const top = Math.min(trackBottom, Math.max(trackTop, e.clientY)) - trackTop;
const percentage = top / trackHeight;
const documentHeight = document.documentElement.scrollHeight - window.innerHeight;
handleEl.style.top = `${top}px`;
window.scrollTo(0, documentHeight * percentage);
}
function toggle(state) {
const topicEl = document.querySelector('[component="topic"]');
if (state === undefined) {
state = app.flags._glance !== true;
}
topicEl.classList[state ? 'add' : 'remove']('minimal');
if (state) {
app.flags._glance = true;
generatePlaceholders();
registerScrollEvent();
} else {
removePlaceholders();
deregisterScrollEvent();
navigator.scrollToIndex(getIndexFromTrack(), true, 0);
delete app.flags._glance;
}
}
let ticking = false;
let scrollTimeout;
function onScrollTick() {
if (!ticking) {
window.requestAnimationFrame(() => {
if (scrollTimeout) {
clearTimeout(scrollTimeout);
}
scrollTimeout = setTimeout(onScrollEnd, 500);
ticking = false;
});
ticking = true;
}
}
async function onScrollEnd() {
const placeholders = Array.from(document.querySelectorAll('[component="post/placeholder"]')).filter((el) => {
const { top, bottom } = el.getBoundingClientRect();
return bottom > 0 && top < window.innerHeight;
});
if (!placeholders.length) {
return;
}
const firstIndex = placeholders[0].getAttribute('data-index');
const { data, done } = await new Promise((resolve) => {
loadMore('topics.loadMore', {
tid: ajaxify.data.tid,
after: firstIndex, // + (direction > 0 ? 1 : 0),
count: placeholders.length,
direction: 1,
topicPostSort: config.topicPostSort,
}, function (data, done) {
resolve({ data, done });
});
});
let jqueryElements = await app.parseAndTranslate('topic', 'posts', data);
jqueryElements = jqueryElements.filter((i, e) => e.nodeType === 1);
jqueryElements.each((i, el) => {
const index = el.getAttribute('data-index');
const placeholderEl = document.querySelector(`[component="post/placeholder"][data-index="${index}"]`);
if (!placeholderEl) {
return;
}
placeholderEl.replaceWith(el);
});
await onNewPostsAddedToDom(jqueryElements);
done();
}
function registerScrollEvent() {
document.addEventListener('scroll', onScrollTick);
}
function deregisterScrollEvent() {
document.removeEventListener('scroll', onScrollTick);
}
async function generatePlaceholders() {
const { postcount } = ajaxify.data;
const posts = document.querySelectorAll('[component="post"]');
if (!posts.length) {
throw new Error('[[error:no-post]]');
}
const firstPost = posts[0];
const lastPost = posts[posts.length - 1];
const firstIndex = parseInt(firstPost.getAttribute('data-index'), 10);
const lastIndex = parseInt(lastPost.getAttribute('data-index'), 10);
const numAbove = firstIndex;
const numBelow = postcount - lastIndex - 1;
const placeholderEl = document.createElement('li');
const html = await render('partials/topic/post-placeholder', {});
placeholderEl.classList.add('pt-4'); // harmony-specific
placeholderEl.setAttribute('component', 'post/placeholder');
const postsEl = document.querySelector('[component="topic"]');
for (let x = 0, index = firstIndex; x < numAbove; x++, index--) {
const node = placeholderEl.cloneNode();
node.setAttribute('data-index', index - 1);
node.innerHTML = html;
postsEl.prepend(node);
}
for (let x = 0, index = lastIndex; x < numBelow; x++, index++) {
const node = placeholderEl.cloneNode();
node.setAttribute('data-index', index + 1);
node.innerHTML = html;
postsEl.append(node);
}
}
function removePlaceholders() {
// todo: directionality
document.querySelectorAll('[component="post/placeholder"]').forEach(el => el.remove());
}

View File

@@ -4,6 +4,7 @@ define('navigator', ['forum/pagination', 'components', 'hooks', 'alerts', 'trans
const navigator = {};
let index = 0;
let count = 0;
let remaining = 0;
let navigatorUpdateTimeoutId;
let renderPostIntervalId;
@@ -86,13 +87,14 @@ define('navigator', ['forum/pagination', 'components', 'hooks', 'alerts', 'trans
if (ajaxify.data.template.topic) {
handleScrollNav();
remaining = ajaxify.data.postcount;
updateUnreadIndicator(ajaxify.data.postIndex);
}
handleKeys();
navigator.setCount(count);
navigator.update(0);
navigator.update();
};
let lastNextIndex = 0;
@@ -164,6 +166,7 @@ define('navigator', ['forum/pagination', 'components', 'hooks', 'alerts', 'trans
updateThumbTimestampToIndex(thumb, index);
});
updateUnreadIndicator(index);
renderPost(index);
}
@@ -361,10 +364,12 @@ define('navigator', ['forum/pagination', 'components', 'hooks', 'alerts', 'trans
unreadEl.style.height = `${trackHeight * percentage}px`;
const thumbEl = trackEl.querySelector('.scroller-thumb');
const thumbBottom = parseInt(thumbEl.style.top || 0, 10) + parseInt(thumbEl.style.height, 10);
const thumbHeight = parseInt(thumbEl.style.height, 10);
const thumbBottom = parseInt(thumbEl.style.top || 0, 10) + thumbHeight;
const anchorEl = unreadEl.querySelector('.meta a');
const remaining = ajaxify.data.postcount - index;
if (remaining > 0 && (trackHeight - thumbBottom) > 50) {
remaining = Math.min(remaining, ajaxify.data.postcount - index);
if (remaining > 0 && (trackHeight - thumbBottom) >= thumbHeight) {
const text = await translator.translate(`[[topic:navigator.unread, ${remaining}]]`);
anchorEl.href = `${config.relative_path}/topic/${ajaxify.data.slug}/${Math.min(index + 1, ajaxify.data.postcount)}`;
anchorEl.innerText = text;
@@ -503,16 +508,14 @@ define('navigator', ['forum/pagination', 'components', 'hooks', 'alerts', 'trans
newIndex = count;
}
if (typeof navigator.callback === 'function') {
navigator.callback(newIndex, count);
}
hooks.fire('action:navigator.update', { newIndex });
hooks.fire('action:navigator.update', { newIndex, index });
if (newIndex !== index) {
if (typeof navigator.callback === 'function') {
navigator.callback(newIndex, count);
}
index = newIndex;
navigator.updateTextAndProgressBar();
updateUnreadIndicator(index);
setThumbToIndex(index);
}
@@ -687,9 +690,8 @@ define('navigator', ['forum/pagination', 'components', 'hooks', 'alerts', 'trans
navigator.scrollActive = false;
highlightPost();
const scrollToRect = scrollTo.get(0).getBoundingClientRect();
if (!newIndex) {
navigator.update(scrollToRect.top);
navigator.update();
} else {
navigator.setIndex(newIndex);
}