mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 19:46:01 +01:00
Navigator (#9049)
* feat: navigator changes * fix: remove extra code * feat: add lang keys
This commit is contained in:
committed by
GitHub
parent
648f6215ef
commit
6669496dba
@@ -180,5 +180,7 @@
|
||||
"diffs.post-restored": "Post successfully restored to earlier revision",
|
||||
|
||||
"timeago_later": "%1 later",
|
||||
"timeago_earlier": "%1 earlier"
|
||||
"timeago_earlier": "%1 earlier",
|
||||
"first-post": "First post",
|
||||
"last-post": "Last post"
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ define('forum/topic', [
|
||||
|
||||
posts.onTopicPageLoad(components.get('post'));
|
||||
|
||||
navigator.init('[component="post"]', ajaxify.data.postcount, Topic.toTop, Topic.toBottom, Topic.navigatorCallback);
|
||||
|
||||
postTools.init(tid);
|
||||
threadTools.init(tid, $('.topic'));
|
||||
events.init();
|
||||
@@ -60,7 +62,7 @@ define('forum/topic', [
|
||||
addDropupHandler();
|
||||
addRepliesHandler();
|
||||
|
||||
navigator.init('[component="post"]', ajaxify.data.postcount, Topic.toTop, Topic.toBottom, Topic.navigatorCallback);
|
||||
|
||||
|
||||
handleBookmark(tid);
|
||||
|
||||
@@ -213,12 +215,12 @@ define('forum/topic', [
|
||||
}
|
||||
|
||||
var newUrl = 'topic/' + ajaxify.data.slug + (index > 1 ? ('/' + index) : '');
|
||||
|
||||
if (newUrl !== currentUrl) {
|
||||
if (Topic.replaceURLTimeout) {
|
||||
clearTimeout(Topic.replaceURLTimeout);
|
||||
Topic.replaceURLTimeout = 0;
|
||||
}
|
||||
|
||||
currentUrl = newUrl;
|
||||
Topic.replaceURLTimeout = setTimeout(function () {
|
||||
if (index >= elementCount && app.user.uid) {
|
||||
socket.emit('topics.markAsRead', [ajaxify.data.tid]);
|
||||
@@ -237,7 +239,6 @@ define('forum/topic', [
|
||||
url: newUrl + search,
|
||||
}, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + newUrl + search);
|
||||
}
|
||||
currentUrl = newUrl;
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
|
||||
define('navigator', ['forum/pagination', 'components'], function (pagination, components) {
|
||||
var navigator = {};
|
||||
var index = 1;
|
||||
var index = 0;
|
||||
var count = 0;
|
||||
var navigatorUpdateTimeoutId;
|
||||
|
||||
var touchTooltipEl;
|
||||
var touchIntervalId;
|
||||
var renderPostIntervalId;
|
||||
var touchX;
|
||||
var touchY;
|
||||
var touchIndex;
|
||||
var renderPostIndex;
|
||||
var isNavigating = false;
|
||||
var firstMove = true;
|
||||
|
||||
@@ -20,13 +19,14 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
var paginationTextEl = paginationBlockEl.find('.pagination-text');
|
||||
var paginationBlockMeterEl = paginationBlockEl.find('meter');
|
||||
var paginationBlockProgressEl = paginationBlockEl.find('.progress-bar');
|
||||
var thumb;
|
||||
|
||||
$(window).on('action:ajaxify.start', function () {
|
||||
$(window).off('keydown', onKeyDown);
|
||||
});
|
||||
|
||||
navigator.init = function (selector, count, toTop, toBottom, callback) {
|
||||
index = 1;
|
||||
index = 0;
|
||||
navigator.selector = selector;
|
||||
navigator.callback = callback;
|
||||
navigator.toTop = toTop || function () {};
|
||||
@@ -37,6 +37,8 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
paginationBlockMeterEl = paginationBlockEl.find('meter');
|
||||
paginationBlockProgressEl = paginationBlockEl.find('.progress-bar');
|
||||
|
||||
thumb = $('.scroller-thumb');
|
||||
|
||||
$(window).off('scroll', navigator.delayedUpdate).on('scroll', navigator.delayedUpdate);
|
||||
|
||||
paginationBlockEl.find('.dropdown-menu').off('click').on('click', function (e) {
|
||||
@@ -69,48 +71,9 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
}
|
||||
});
|
||||
|
||||
$('.pagination-block.visible-xs').on('touchstart', function (e) {
|
||||
touchTooltipEl = $('.navigator-thumb');
|
||||
touchX = Math.min($(window).width(), Math.max(0, e.touches[0].clientX));
|
||||
touchY = Math.min($(window).height(), Math.max(0, e.touches[0].clientY));
|
||||
firstMove = true;
|
||||
}).on('touchmove', function (e) {
|
||||
var windowWidth = $(window).width();
|
||||
var windowHeight = $(window).height();
|
||||
var deltaX = Math.abs(touchX - Math.min(windowWidth, Math.max(0, e.touches[0].clientX)));
|
||||
var deltaY = Math.abs(touchY - Math.min(windowHeight, Math.max(0, e.touches[0].clientY)));
|
||||
touchX = Math.min(windowWidth, Math.max(0, e.touches[0].clientX));
|
||||
touchY = Math.min(windowHeight, Math.max(0, e.touches[0].clientY));
|
||||
if (deltaX >= deltaY && firstMove) {
|
||||
isNavigating = true;
|
||||
touchIntervalId = setInterval(updateTooltip, 100);
|
||||
if (ajaxify.data.template.topic) {
|
||||
handleScrollNav();
|
||||
}
|
||||
if (isNavigating) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var percent = touchX / windowWidth;
|
||||
index = Math.max(1, Math.ceil(count * percent));
|
||||
index = index > count ? count : index;
|
||||
if (firstMove) {
|
||||
updateTooltip(function () {
|
||||
touchTooltipEl.removeClass('hidden');
|
||||
});
|
||||
}
|
||||
navigator.updateTextAndProgressBar();
|
||||
}
|
||||
firstMove = false;
|
||||
}).on('touchend', function () {
|
||||
if (touchIntervalId) {
|
||||
clearInterval(touchIntervalId);
|
||||
touchIntervalId = 0;
|
||||
}
|
||||
|
||||
if (isNavigating) {
|
||||
touchTooltipEl.addClass('hidden');
|
||||
navigator.scrollToIndex(index - 1, true, 0);
|
||||
isNavigating = false;
|
||||
}
|
||||
});
|
||||
|
||||
handleKeys();
|
||||
|
||||
@@ -118,27 +81,174 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
navigator.update(0);
|
||||
};
|
||||
|
||||
function updateTooltip(callback) {
|
||||
callback = callback || function () {};
|
||||
if (touchIndex === index) {
|
||||
function clampTop(newTop) {
|
||||
var parent = thumb.parent();
|
||||
var parentOffset = parent.offset();
|
||||
if (newTop < parentOffset.top) {
|
||||
newTop = parentOffset.top;
|
||||
} else if (newTop > parentOffset.top + parent.height() - thumb.height()) {
|
||||
newTop = parentOffset.top + parent.height() - thumb.height();
|
||||
}
|
||||
return newTop;
|
||||
}
|
||||
|
||||
function setThumbToIndex(index) {
|
||||
if (!thumb.length || thumb.is(':hidden')) {
|
||||
return;
|
||||
}
|
||||
touchIndex = index;
|
||||
touchTooltipEl.css({ left: Math.min($(window).width() - touchTooltipEl.outerWidth(), Math.max(touchX - (touchTooltipEl.outerWidth() / 2), 0)) });
|
||||
var parent = thumb.parent();
|
||||
var thumbText = thumb.find('.thumb-text');
|
||||
var parentOffset = parent.offset();
|
||||
var percent = (index - 1) / ajaxify.data.postcount;
|
||||
if (index === count) {
|
||||
percent = 1;
|
||||
}
|
||||
var newTop = clampTop(parentOffset.top + ((parent.height() - thumb.height()) * percent));
|
||||
|
||||
socket.emit('posts.getTimestampByIndex', { tid: ajaxify.data.tid, index: index - 1 }, function (err, timestamp) {
|
||||
var offset = { top: newTop, left: thumb.offset().left };
|
||||
thumb.offset(offset);
|
||||
thumbText.text(index + '/' + ajaxify.data.postcount);
|
||||
renderPost(index);
|
||||
}
|
||||
|
||||
function handleScrollNav() {
|
||||
if (!thumb.length) {
|
||||
return;
|
||||
}
|
||||
var thumbText = thumb.find('.thumb-text');
|
||||
var thumbHeight = thumb.height();
|
||||
var thumbHalfHeight = thumbHeight / 2;
|
||||
var parent = thumb.parent();
|
||||
var parentHeight = parent.height();
|
||||
var mouseDragging = false;
|
||||
$(window).on('action:ajaxify.end', function () {
|
||||
renderPostIndex = null;
|
||||
});
|
||||
$('.pagination-block .dropdown-menu').parent().on('shown.bs.dropdown', function () {
|
||||
setThumbToIndex(index);
|
||||
});
|
||||
|
||||
thumb.on('mousedown', function () {
|
||||
mouseDragging = true;
|
||||
$(window).on('mousemove', mousemove);
|
||||
firstMove = true;
|
||||
});
|
||||
|
||||
function mouseup() {
|
||||
$(window).off('mousemove', mousemove);
|
||||
if (mouseDragging) {
|
||||
navigator.scrollToIndex(index - 1, true, 0);
|
||||
paginationBlockEl.find('[data-toggle="dropdown"]').trigger('click');
|
||||
}
|
||||
clearRenderInterval();
|
||||
mouseDragging = false;
|
||||
firstMove = false;
|
||||
}
|
||||
|
||||
function mousemove(ev) {
|
||||
var newTop = clampTop(ev.pageY - thumbHalfHeight);
|
||||
var parentOffset = parent.offset();
|
||||
|
||||
var offset = { top: newTop, left: thumb.offset().left };
|
||||
thumb.offset(offset);
|
||||
|
||||
var percent = (newTop - parentOffset.top) / (parentHeight - thumbHeight);
|
||||
index = Math.max(1, Math.ceil(ajaxify.data.postcount * percent));
|
||||
navigator.updateTextAndProgressBar();
|
||||
thumbText.text(index + '/' + ajaxify.data.postcount);
|
||||
if (firstMove) {
|
||||
delayedRenderPost();
|
||||
}
|
||||
firstMove = false;
|
||||
ev.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
function delayedRenderPost() {
|
||||
clearRenderInterval();
|
||||
renderPostIntervalId = setInterval(function () {
|
||||
renderPost(index);
|
||||
}, 250);
|
||||
}
|
||||
|
||||
$(window).off('mousemove', mousemove);
|
||||
$(window).off('mouseup', mouseup).on('mouseup', mouseup);
|
||||
|
||||
thumb.on('touchstart', function (ev) {
|
||||
isNavigating = true;
|
||||
touchX = Math.min($(window).width(), Math.max(0, ev.touches[0].clientX));
|
||||
touchY = Math.min($(window).height(), Math.max(0, ev.touches[0].clientY));
|
||||
firstMove = true;
|
||||
});
|
||||
|
||||
thumb.on('touchmove', function (ev) {
|
||||
var windowWidth = $(window).width();
|
||||
var windowHeight = $(window).height();
|
||||
var deltaX = Math.abs(touchX - Math.min(windowWidth, Math.max(0, ev.touches[0].clientX)));
|
||||
var deltaY = Math.abs(touchY - Math.min(windowHeight, Math.max(0, ev.touches[0].clientY)));
|
||||
touchX = Math.min(windowWidth, Math.max(0, ev.touches[0].clientX));
|
||||
touchY = Math.min(windowHeight, Math.max(0, ev.touches[0].clientY));
|
||||
|
||||
if (deltaY >= deltaX && firstMove) {
|
||||
isNavigating = true;
|
||||
delayedRenderPost();
|
||||
}
|
||||
|
||||
if (isNavigating) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
var newTop = clampTop(touchY + $(window).scrollTop() - thumbHalfHeight);
|
||||
var parentOffset = thumb.parent().offset();
|
||||
var offset = { top: newTop, left: thumb.offset().left };
|
||||
thumb.offset(offset);
|
||||
|
||||
var percent = (newTop - parentOffset.top) / (parentHeight - thumbHeight);
|
||||
index = Math.max(1, Math.ceil(count * percent));
|
||||
index = index > count ? count : index;
|
||||
|
||||
thumbText.text(index + '/' + ajaxify.data.postcount);
|
||||
|
||||
if (firstMove) {
|
||||
renderPost(index);
|
||||
}
|
||||
navigator.updateTextAndProgressBar();
|
||||
}
|
||||
firstMove = false;
|
||||
});
|
||||
|
||||
thumb.on('touchend', function () {
|
||||
clearRenderInterval();
|
||||
if (isNavigating) {
|
||||
navigator.scrollToIndex(index - 1, true, 0);
|
||||
isNavigating = false;
|
||||
paginationBlockEl.find('[data-toggle="dropdown"]').trigger('click');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearRenderInterval() {
|
||||
if (renderPostIntervalId) {
|
||||
clearInterval(renderPostIntervalId);
|
||||
renderPostIntervalId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function renderPost(index, callback) {
|
||||
callback = callback || function () {};
|
||||
if (renderPostIndex === index || paginationBlockEl.find('.post-content').is(':hidden')) {
|
||||
return;
|
||||
}
|
||||
renderPostIndex = index;
|
||||
|
||||
socket.emit('posts.getPostSummaryByIndex', { tid: ajaxify.data.tid, index: index - 1 }, function (err, postData) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
app.parseAndTranslate('partials/topic/navigation-post', { post: postData }, function (html) {
|
||||
html.find('.timeago').timeago();
|
||||
paginationBlockEl.find('.post-content').html(html);
|
||||
});
|
||||
|
||||
var date = new Date(timestamp);
|
||||
var ds = date.toLocaleString(config.userLang, { month: 'long' });
|
||||
touchTooltipEl.find('.text').translateText('[[global:pagination.out_of, ' + index + ', ' + count + ']]');
|
||||
if (timestamp > Date.now() - (30 * 24 * 60 * 60 * 1000)) {
|
||||
touchTooltipEl.find('.time').text(ds + ' ' + date.getDate());
|
||||
} else {
|
||||
touchTooltipEl.find('.time').text(ds + ' ' + date.getFullYear());
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
@@ -171,7 +281,11 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
}
|
||||
|
||||
navigator.setCount = function (value) {
|
||||
count = parseInt(value, 10);
|
||||
value = parseInt(value, 10);
|
||||
if (value === count) {
|
||||
return;
|
||||
}
|
||||
count = value;
|
||||
navigator.updateTextAndProgressBar();
|
||||
};
|
||||
|
||||
@@ -213,10 +327,10 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
a spot where a user is expecting to begin reading.
|
||||
*/
|
||||
threshold = typeof threshold === 'number' ? threshold : undefined;
|
||||
|
||||
var newIndex = index;
|
||||
var els = $(navigator.selector);
|
||||
if (els.length) {
|
||||
index = parseInt(els.first().attr('data-index'), 10) + 1;
|
||||
newIndex = parseInt(els.first().attr('data-index'), 10) + 1;
|
||||
}
|
||||
|
||||
var scrollTop = $(window).scrollTop();
|
||||
@@ -235,7 +349,7 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
}
|
||||
|
||||
if (distanceToMiddle < previousDistance) {
|
||||
index = elIndex + 1;
|
||||
newIndex = elIndex + 1;
|
||||
previousDistance = distanceToMiddle;
|
||||
}
|
||||
}
|
||||
@@ -245,13 +359,13 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
var nearBottom = scrollTop + windowHeight > documentHeight - 100 && parseInt(els.last().attr('data-index'), 10) === count - 1;
|
||||
|
||||
if (atTop) {
|
||||
index = 1;
|
||||
newIndex = 1;
|
||||
} else if (nearBottom) {
|
||||
index = count;
|
||||
newIndex = count;
|
||||
}
|
||||
|
||||
// If a threshold is undefined, try to determine one based on new index
|
||||
if (threshold === undefined && ajaxify.data.template.topic === true) {
|
||||
if (threshold === undefined && ajaxify.data.template.topic) {
|
||||
if (atTop) {
|
||||
threshold = 0;
|
||||
} else {
|
||||
@@ -264,10 +378,15 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
}
|
||||
|
||||
if (typeof navigator.callback === 'function') {
|
||||
navigator.callback(index, count, threshold);
|
||||
navigator.callback(newIndex, count, threshold);
|
||||
}
|
||||
|
||||
if (newIndex !== index) {
|
||||
index = newIndex;
|
||||
navigator.updateTextAndProgressBar();
|
||||
setThumbToIndex(index);
|
||||
}
|
||||
|
||||
toggle(!!count);
|
||||
};
|
||||
|
||||
@@ -422,7 +541,7 @@ define('navigator', ['forum/pagination', 'components'], function (pagination, co
|
||||
|
||||
var scrollTop = 0;
|
||||
if (postHeight < viewportHeight) {
|
||||
scrollTop = (scrollTo.offset().top - (viewportHeight / 2) + (postHeight / 2)) - topicHeaderHeight;
|
||||
scrollTop = (scrollTo.offset().top - (viewportHeight / 2) + (postHeight)) - topicHeaderHeight;
|
||||
} else {
|
||||
scrollTop = scrollTo.offset().top - navbarHeight - topicHeaderHeight;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ SocketPosts.getRawPost = async function (socket, pid) {
|
||||
return result.postData.content;
|
||||
};
|
||||
|
||||
SocketPosts.getTimestampByIndex = async function (socket, data) {
|
||||
SocketPosts.getPostSummaryByIndex = async function (socket, data) {
|
||||
if (data.index < 0) {
|
||||
data.index = 0;
|
||||
}
|
||||
@@ -90,7 +90,9 @@ SocketPosts.getTimestampByIndex = async function (socket, data) {
|
||||
if (!canRead) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
return await posts.getPostField(pid, 'timestamp');
|
||||
|
||||
const postsData = await posts.getPostSummaryByPids([pid], socket.uid, { stripTags: true });
|
||||
return postsData[0];
|
||||
};
|
||||
|
||||
SocketPosts.getPost = async function (socket, pid) {
|
||||
|
||||
Reference in New Issue
Block a user