Files
NodeBB/public/src/client/topic/posts.js

402 lines
12 KiB
JavaScript
Raw Normal View History

'use strict';
2016-09-15 00:50:24 +03:00
/* globals config, app, ajaxify, define, utils */
define('forum/topic/posts', [
'forum/pagination',
'forum/infinitescroll',
'forum/topic/postTools',
'navigator',
2017-02-17 19:31:21 -07:00
'components',
], function (pagination, infinitescroll, postTools, navigator, components) {
var Posts = {
2017-02-17 19:31:21 -07:00
_imageLoaderTimeout: undefined,
};
Posts.onNewPost = function (data) {
2015-09-29 17:09:41 -04:00
if (!data || !data.posts || !data.posts.length) {
return;
}
2015-09-29 17:09:41 -04:00
if (parseInt(data.posts[0].tid, 10) !== parseInt(ajaxify.data.tid, 10)) {
2015-09-13 15:14:29 -04:00
return;
}
2016-01-14 13:24:27 -05:00
data.loggedIn = app.user.uid ? true : false;
2016-06-15 21:04:36 +03:00
data.privileges = ajaxify.data.privileges;
2016-10-31 11:20:52 +03:00
Posts.modifyPostsByPrivileges(data.posts);
2015-09-29 16:36:37 -04:00
updatePostCounts(data.posts);
2016-05-09 23:39:00 +03:00
ajaxify.data.postcount ++;
postTools.updatePostCount(ajaxify.data.postcount);
if (config.usePagination) {
onNewPostPagination(data);
} else {
onNewPostInfiniteScroll(data);
}
require(['forum/topic/replies'], function (replies) {
replies.onNewPost(data);
});
};
2016-10-31 11:20:52 +03:00
Posts.modifyPostsByPrivileges = function (posts) {
posts.forEach(function (post) {
post.selfPost = !!app.user.uid && parseInt(post.uid, 10) === parseInt(app.user.uid, 10);
post.display_edit_tools = (ajaxify.data.privileges['posts:edit'] && post.selfPost) || ajaxify.data.privileges.isAdminOrMod;
post.display_delete_tools = (ajaxify.data.privileges['posts:delete'] && post.selfPost) || ajaxify.data.privileges.isAdminOrMod;
post.display_moderator_tools = post.display_edit_tools || post.display_delete_tools;
post.display_move_tools = ajaxify.data.privileges.isAdminOrMod;
post.display_post_menu = ajaxify.data.privileges.isAdminOrMod || (post.selfPost && !ajaxify.data.locked) || ((app.user.uid || ajaxify.data.postSharing.length) && !post.deleted);
});
};
function updatePostCounts(posts) {
2016-10-13 11:42:29 +02:00
for (var i = 0; i < posts.length; ++i) {
var cmp = components.get('user/postcount', posts[i].uid);
cmp.html(parseInt(cmp.attr('data-postcount'), 10) + 1);
2015-03-27 16:27:28 -04:00
utils.addCommasToNumbers(cmp);
}
2015-09-13 15:14:29 -04:00
}
function onNewPostPagination(data) {
2015-02-17 18:52:54 -05:00
function scrollToPost() {
2016-03-21 10:16:10 +02:00
scrollToPostIfSelf(data.posts[0]);
2016-08-29 16:12:27 +03:00
Posts.loadImages();
2015-02-17 18:52:54 -05:00
}
var posts = data.posts;
2015-02-17 18:52:54 -05:00
2015-10-07 16:13:37 -04:00
ajaxify.data.pagination.pageCount = Math.max(1, Math.ceil((posts[0].topic.postcount - 1) / config.postsPerPage));
var direction = config.topicPostSort === 'oldest_to_newest' || config.topicPostSort === 'most_votes' ? 1 : -1;
2016-05-09 23:39:00 +03:00
var isPostVisible = (ajaxify.data.pagination.currentPage === ajaxify.data.pagination.pageCount && direction === 1) ||
(ajaxify.data.pagination.currentPage === 1 && direction === -1);
2015-02-17 18:52:54 -05:00
if (isPostVisible) {
createNewPosts(data, components.get('post').not('[data-index=0]'), direction, scrollToPost);
} else if (ajaxify.data.scrollToMyPost && parseInt(posts[0].uid, 10) === parseInt(app.user.uid, 10)) {
2016-09-15 00:50:24 +03:00
// https://github.com/NodeBB/NodeBB/issues/5004#issuecomment-247157441
setTimeout(function () {
2016-09-15 00:50:24 +03:00
pagination.loadPage(ajaxify.data.pagination.pageCount, scrollToPost);
}, 250);
2016-05-09 23:39:00 +03:00
} else {
updatePagination();
}
}
2016-05-09 23:39:00 +03:00
function updatePagination() {
$.get(config.relative_path + '/api/topic/pagination/' + ajaxify.data.tid, {page: ajaxify.data.pagination.currentPage}, function (paginationData) {
app.parseAndTranslate('partials/paginator', {pagination: paginationData}, function (html) {
2016-05-09 23:39:00 +03:00
$('[component="pagination"]').after(html).remove();
});
});
}
function onNewPostInfiniteScroll(data) {
var direction = config.topicPostSort === 'oldest_to_newest' || config.topicPostSort === 'most_votes' ? 1 : -1;
2017-02-03 16:24:58 +03:00
var isPreviousPostAdded = $('[component="post"][data-index="' + (data.posts[0].index - 1) + '"]').length;
if (!isPreviousPostAdded && (!data.posts[0].selfPost || !ajaxify.data.scrollToMyPost)) {
return;
}
createNewPosts(data, components.get('post').not('[data-index=0]'), direction, function (html) {
if (html) {
html.addClass('new');
}
scrollToPostIfSelf(data.posts[0]);
2016-08-29 16:12:27 +03:00
Posts.loadImages();
});
}
function scrollToPostIfSelf(post) {
2017-02-03 16:24:58 +03:00
if (post.selfPost && ajaxify.data.scrollToMyPost) {
navigator.scrollBottom(post.index);
}
}
function createNewPosts(data, repliesSelector, direction, callback) {
callback = callback || function () {};
if (!data || (data.posts && !data.posts.length)) {
2015-02-26 15:14:27 -05:00
return callback();
}
function removeAlreadyAddedPosts() {
2015-10-04 01:13:47 -04:00
var newPosts = $('[component="post"].new');
if (newPosts.length === data.posts.length) {
var allSamePids = true;
newPosts.each(function (index, el) {
if (parseInt($(el).attr('data-pid'), 10) !== parseInt(data.posts[index].pid, 10)) {
allSamePids = false;
}
});
if (allSamePids) {
newPosts.each(function () {
$(this).removeClass('new');
});
data.posts.length = 0;
return;
}
}
if (newPosts.length && data.posts.length > 1) {
data.posts.forEach(function (post) {
var p = components.get('post', 'pid', post.pid);
if (p.hasClass('new')) {
2015-09-26 18:29:27 -04:00
p.remove();
}
});
}
2015-09-26 18:29:27 -04:00
data.posts = data.posts.filter(function (post) {
2015-10-04 01:13:47 -04:00
return $('[component="post"][data-pid="' + post.pid + '"]').length === 0;
});
}
removeAlreadyAddedPosts();
2015-02-26 15:14:27 -05:00
if (!data.posts.length) {
return callback();
}
2017-02-17 20:20:42 -07:00
var after;
var before;
if (direction > 0 && repliesSelector.length) {
after = repliesSelector.last();
} else if (direction < 0 && repliesSelector.length) {
before = repliesSelector.first();
}
2016-02-22 08:14:51 +00:00
data.slug = ajaxify.data.slug;
2016-03-18 10:33:10 +02:00
2015-07-20 17:12:41 -04:00
$(window).trigger('action:posts.loading', {posts: data.posts, after: after, before: before});
app.parseAndTranslate('topic', 'posts', data, function (html) {
2016-03-24 22:22:07 +02:00
html = html.filter(function () {
2016-03-24 22:22:07 +02:00
var pid = $(this).attr('data-pid');
return pid && $('[component="post"][data-pid="' + pid + '"]').length === 0;
});
2015-02-26 15:14:27 -05:00
if (after) {
html.insertAfter(after);
2015-02-26 15:14:27 -05:00
} else if (before) {
// Save document height and position for future reference (about 5 lines down)
2017-02-17 20:20:42 -07:00
var height = $(document).height();
var scrollTop = $(window).scrollTop();
html.insertBefore(before);
// Now restore the relative position the user was on prior to new post insertion
2015-09-26 18:29:27 -04:00
$(window).scrollTop(scrollTop + ($(document).height() - height));
} else {
components.get('topic').append(html);
}
2015-10-04 01:13:47 -04:00
infinitescroll.removeExtra($('[component="post"]'), direction, 40);
2015-09-26 18:29:27 -04:00
$(window).trigger('action:posts.loaded', {posts: data.posts});
2015-09-29 16:36:37 -04:00
Posts.processPage(html);
2015-09-29 16:36:37 -04:00
callback(html);
});
}
Posts.loadMorePosts = function (direction) {
if (!components.get('topic').length || navigator.scrollActive || Posts._infiniteScrollTimeout) {
return;
}
Posts._infiniteScrollTimeout = setTimeout(function () {
delete Posts._infiniteScrollTimeout;
}, 1000);
var replies = components.get('post').not('[data-index=0]').not('.new');
var afterEl = direction > 0 ? replies.last() : replies.first();
var after = parseInt(afterEl.attr('data-index'), 10) || 0;
2015-07-06 14:33:43 -04:00
var tid = ajaxify.data.tid;
if (!utils.isNumber(tid) || !utils.isNumber(after) || (direction < 0 && components.get('post', 'index', 0).length)) {
return;
}
var indicatorEl = $('.loading-indicator');
if (!indicatorEl.is(':animated')) {
indicatorEl.fadeIn();
}
infinitescroll.loadMore('topics.loadMore', {
tid: tid,
after: after,
2016-08-31 22:50:48 +03:00
direction: direction,
2017-02-17 19:31:21 -07:00
topicPostSort: config.topicPostSort,
}, function (data, done) {
indicatorEl.fadeOut();
if (data && data.posts && data.posts.length) {
2015-10-03 20:17:28 -04:00
createNewPosts(data, replies, direction, done);
} else {
navigator.update();
done();
}
});
};
Posts.processPage = function (posts) {
Posts.unloadImages(posts);
2015-10-24 22:29:22 -04:00
Posts.showBottomPostBar();
2015-11-10 13:18:06 -05:00
posts.find('[component="post/content"] img:not(.not-responsive)').addClass('img-responsive');
2015-10-04 01:13:47 -04:00
app.createUserTooltips(posts);
2015-05-29 16:19:04 -04:00
app.replaceSelfLinks(posts.find('a'));
utils.addCommasToNumbers(posts.find('.formatted-number'));
utils.makeNumbersHumanReadable(posts.find('.human-readable-number'));
posts.find('.timeago').timeago();
2015-10-28 15:16:14 -04:00
addBlockquoteEllipses(posts.find('[component="post/content"] > blockquote > blockquote'));
hidePostToolsForDeletedPosts(posts);
};
Posts.unloadImages = function (posts) {
2016-03-31 15:52:39 -04:00
var images = posts.find('[component="post/content"] img:not(.not-responsive)');
if (config.delayImageLoading) {
images.each(function () {
$(this).attr('data-src', $(this).attr('src'));
}).attr('data-state', 'unloaded').attr('src', 'about:blank');
} else {
images.attr('data-state', 'loaded');
Posts.wrapImagesInLinks(posts);
}
};
Posts.loadImages = function (threshold) {
if (Posts._imageLoaderTimeout) {
clearTimeout(Posts._imageLoaderTimeout);
}
Posts._imageLoaderTimeout = setTimeout(function () {
/*
If threshold is defined, images loaded above this threshold will modify
the user's scroll position so they are not scrolled away from content
they were reading. Images loaded below this threshold will push down content.
If no threshold is defined, loaded images will push down content, as per
default
*/
2017-02-17 20:20:42 -07:00
var images = components.get('post/content').find('img[data-state="unloaded"]');
var visible = images.filter(function () {
return utils.isElementInViewport(this);
2017-02-17 20:20:42 -07:00
});
var posts = $.unique(visible.map(function () {
2016-04-20 13:58:25 -04:00
return $(this).parents('[component="post"]').get(0);
2017-02-17 20:20:42 -07:00
}));
var scrollTop = $(window).scrollTop();
var adjusting = false;
var adjustQueue = [];
var oldHeight;
var newHeight;
function adjustPosition() {
adjusting = true;
oldHeight = document.body.clientHeight;
// Display the image
$(this).attr('data-state', 'loaded');
newHeight = document.body.clientHeight;
var imageRect = this.getBoundingClientRect();
if (imageRect.top < threshold) {
scrollTop = scrollTop + (newHeight - oldHeight);
$(window).scrollTop(scrollTop);
}
2017-02-17 20:20:42 -07:00
if (adjustQueue.length) {
adjustQueue.pop()();
} else {
adjusting = false;
2016-04-20 13:58:25 -04:00
2017-02-17 20:20:42 -07:00
Posts.wrapImagesInLinks(posts);
posts.length = 0;
}
};
// For each image, reset the source and adjust scrollTop when loaded
visible.attr('data-state', 'loading');
visible.each(function (index, image) {
image = $(image);
image.on('load', function () {
if (!adjusting) {
adjustPosition.call(this);
} else {
adjustQueue.push(adjustPosition.bind(this));
}
});
image.attr('src', image.attr('data-src'));
image.removeAttr('data-src');
});
}, 250);
};
Posts.wrapImagesInLinks = function (posts) {
posts.find('[component="post/content"] img:not(.emoji)').each(function () {
2017-02-17 20:20:42 -07:00
var $this = $(this);
var src = $this.attr('src');
var suffixRegex = /-resized(\.[\w]+)?$/;
2016-04-20 13:58:25 -04:00
if (src === 'about:blank') {
return;
}
2016-04-20 13:58:25 -04:00
if (utils.isRelativeUrl(src) && suffixRegex.test(src)) {
src = src.replace(suffixRegex, '$1');
}
if (!$this.parent().is('a')) {
2016-04-20 13:58:25 -04:00
$this.wrap('<a href="' + src + '" target="_blank">');
}
});
};
Posts.showBottomPostBar = function () {
2015-10-24 22:29:22 -04:00
var mainPost = components.get('post', 'index', 0);
2016-07-06 12:25:57 +03:00
var placeHolder = $('.post-bar-placeholder');
2015-10-24 23:03:12 -04:00
var posts = $('[component="post"]');
2016-07-06 12:25:57 +03:00
if (!!mainPost.length && posts.length > 1 && $('.post-bar').length < 2 && placeHolder.length) {
$('.post-bar').clone().insertAfter(placeHolder);
placeHolder.remove();
2015-10-24 23:03:12 -04:00
} else if (mainPost.length && posts.length < 2) {
mainPost.find('.post-bar').remove();
2015-10-24 22:29:22 -04:00
}
2015-10-15 12:18:21 -04:00
};
2015-05-29 16:19:04 -04:00
function hidePostToolsForDeletedPosts(posts) {
posts.each(function () {
2015-05-29 16:19:04 -04:00
if ($(this).hasClass('deleted')) {
2015-07-06 12:39:05 -04:00
postTools.toggle($(this).attr('data-pid'), true);
2015-05-29 16:19:04 -04:00
}
});
}
function addBlockquoteEllipses(blockquotes) {
blockquotes.each(function () {
var $this = $(this);
if ($this.find(':hidden:not(br)').length && !$this.find('.toggle').length) {
$this.append('<i class="fa fa-angle-down pointer toggle"></i>');
}
});
}
return Posts;
});