diff --git a/public/src/forum/account/favourites.js b/public/src/forum/account/favourites.js index 67f12816a2..6a08a814a5 100644 --- a/public/src/forum/account/favourites.js +++ b/public/src/forum/account/favourites.js @@ -20,21 +20,24 @@ define('forum/account/favourites', ['forum/account/header', 'forum/infinitescrol infinitescroll.loadMore('posts.loadMoreFavourites', { after: $('.user-favourite-posts').attr('data-nextstart') - }, function(data) { + }, function(data, done) { if (data.posts && data.posts.length) { - onPostsLoaded(data.posts); + onPostsLoaded(data.posts, done); $('.user-favourite-posts').attr('data-nextstart', data.nextStart); + } else { + done(); } }); } - function onPostsLoaded(posts) { + function onPostsLoaded(posts, callback) { infinitescroll.parseAndTranslate('account/favourites', 'posts', {posts: posts}, function(html) { $('.user-favourite-posts').append(html); html.find('img').addClass('img-responsive'); html.find('span.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); + callback(); }); } diff --git a/public/src/forum/account/posts.js b/public/src/forum/account/posts.js index ffb5dc963b..70410e0819 100644 --- a/public/src/forum/account/posts.js +++ b/public/src/forum/account/posts.js @@ -21,21 +21,24 @@ define('forum/account/posts', ['forum/account/header', 'forum/infinitescroll'], infinitescroll.loadMore('posts.loadMoreUserPosts', { uid: $('.account-username-box').attr('data-uid'), after: $('.user-favourite-posts').attr('data-nextstart') - }, function(data) { + }, function(data, done) { if (data.posts && data.posts.length) { - onPostsLoaded(data.posts); + onPostsLoaded(data.posts, done); $('.user-favourite-posts').attr('data-nextstart', data.nextStart); + } else { + done(); } }); } - function onPostsLoaded(posts) { + function onPostsLoaded(posts, callback) { infinitescroll.parseAndTranslate('account/posts', 'posts', {posts: posts}, function(html) { $('.user-favourite-posts').append(html); html.find('img').addClass('img-responsive'); html.find('span.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); + callback(); }); } diff --git a/public/src/forum/account/topics.js b/public/src/forum/account/topics.js index 1ba31eae3c..231ddfd5ec 100644 --- a/public/src/forum/account/topics.js +++ b/public/src/forum/account/topics.js @@ -19,21 +19,24 @@ define('forum/account/topics', ['forum/account/header', 'forum/infinitescroll'], infinitescroll.loadMore('topics.loadMoreFromSet', { set: 'uid:' + $('.account-username-box').attr('data-uid') + ':topics', after: $('.user-topics').attr('data-nextstart') - }, function(data) { + }, function(data, done) { if (data.topics && data.topics.length) { - onTopicsLoaded(data.topics); + onTopicsLoaded(data.topics, done); $('.user-topics').attr('data-nextstart', data.nextStart); + } else { + done(); } }); } - function onTopicsLoaded(topics) { + function onTopicsLoaded(topics, callback) { infinitescroll.parseAndTranslate('account/topics', 'topics', {topics: topics}, function(html) { $('#topics-container').append(html); html.find('span.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); + callback(); }); } diff --git a/public/src/forum/category.js b/public/src/forum/category.js index a352221441..bb62c41dfe 100644 --- a/public/src/forum/category.js +++ b/public/src/forum/category.js @@ -294,11 +294,16 @@ define('forum/category', ['composer', 'forum/pagination', 'forum/infinitescroll' infinitescroll.loadMore('categories.loadMore', { cid: ajaxify.variables.get('category_id'), after: after - }, function (data) { + }, function (data, done) { if (data.topics && data.topics.length) { - Category.onTopicsLoaded(data, callback); + Category.onTopicsLoaded(data, function() { + done(); + callback(); + }); $('#topics-container').attr('data-nextstart', data.nextStart); + } else { + done(); } $(window).trigger('action:categories.loaded'); diff --git a/public/src/forum/infinitescroll.js b/public/src/forum/infinitescroll.js index c942102dac..a496ff02e9 100644 --- a/public/src/forum/infinitescroll.js +++ b/public/src/forum/infinitescroll.js @@ -34,10 +34,12 @@ define('forum/infinitescroll', function() { loadingMore = true; socket.emit(method, data, function(err, data) { if (err) { + loadingMore = false; return app.alertError(err.message); } - callback(data); - loadingMore = false; + callback(data, function() { + loadingMore = false; + }); }); }; diff --git a/public/src/forum/popular.js b/public/src/forum/popular.js index 145f78f28c..658c63b93e 100644 --- a/public/src/forum/popular.js +++ b/public/src/forum/popular.js @@ -33,11 +33,12 @@ define('forum/popular', ['forum/recent', 'forum/infinitescroll'], function(recen infinitescroll.loadMore('topics.loadMoreFromSet', { set: 'topics:' + $('.nav-pills .active a').html().toLowerCase(), after: $('#topics-container').attr('data-nextstart') - }, function(data) { + }, function(data, done) { if (data.topics && data.topics.length) { - recent.onTopicsLoaded('popular', data.topics, false); + recent.onTopicsLoaded('popular', data.topics, false, done); $('#topics-container').attr('data-nextstart', data.nextStart); } else { + done(); $('#load-more-btn').hide(); } }); diff --git a/public/src/forum/recent.js b/public/src/forum/recent.js index 6b43d303ec..3f0885690d 100644 --- a/public/src/forum/recent.js +++ b/public/src/forum/recent.js @@ -105,15 +105,17 @@ define('forum/recent', ['forum/infinitescroll'], function(infinitescroll) { infinitescroll.loadMore('topics.loadMoreRecentTopics', { after: $('#topics-container').attr('data-nextstart'), term: active - }, function(data) { + }, function(data, done) { if (data.topics && data.topics.length) { - Recent.onTopicsLoaded('recent', data.topics, false); + Recent.onTopicsLoaded('recent', data.topics, false, done); $('#topics-container').attr('data-nextstart', data.nextStart); + } else { + done(); } }); }; - Recent.onTopicsLoaded = function(templateName, topics, showSelect) { + Recent.onTopicsLoaded = function(templateName, topics, showSelect, callback) { infinitescroll.parseAndTranslate(templateName, 'topics', {topics: topics, showSelect: showSelect}, function(html) { $('#category-no-topics').remove(); @@ -121,6 +123,7 @@ define('forum/recent', ['forum/infinitescroll'], function(infinitescroll) { html.find('span.timeago').timeago(); app.createUserTooltips(); utils.makeNumbersHumanReadable(html.find('.human-readable-number')); + callback(); }); }; diff --git a/public/src/forum/tag.js b/public/src/forum/tag.js index ae8a45ac5a..f15af62f75 100644 --- a/public/src/forum/tag.js +++ b/public/src/forum/tag.js @@ -26,11 +26,12 @@ define('forum/tag', ['forum/recent', 'forum/infinitescroll'], function(recent, i infinitescroll.loadMore('topics.loadMoreFromSet', { set: 'tag:' + ajaxify.variables.get('tag') + ':topics', after: $('#topics-container').attr('data-nextstart') - }, function(data) { + }, function(data, done) { if (data.topics && data.topics.length) { - recent.onTopicsLoaded('tag', data.topics, false); + recent.onTopicsLoaded('tag', data.topics, false, done); $('#topics-container').attr('data-nextstart', data.nextStart); } else { + done(); $('#load-more-btn').hide(); } }); diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 0c7234782a..319feef24f 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -229,6 +229,8 @@ define('forum/topic', ['forum/pagination', 'forum/infinitescroll', 'forum/topic/ scrollingToPost = false; navigator.update(); highlightPost(); + $('body').scrollTop($('body').scrollTop() - 1); + $('html').scrollTop($('html').scrollTop() - 1); }); } @@ -394,15 +396,19 @@ define('forum/topic', ['forum/pagination', 'forum/infinitescroll', 'forum/topic/ infinitescroll.loadMore('topics.loadMore', { tid: tid, after: after - }, function (data) { + }, function (data, done) { indicatorEl.fadeOut(); if (data && data.posts && data.posts.length) { - createNewPosts(data, callback); + createNewPosts(data, function() { + done(); + callback(); + }); hidePostToolsForDeletedPosts(); } else { navigator.update(); + done(); } }); } diff --git a/public/src/forum/unread.js b/public/src/forum/unread.js index 44d1a24f8d..f8e1a9be63 100644 --- a/public/src/forum/unread.js +++ b/public/src/forum/unread.js @@ -94,11 +94,12 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll'], infinitescroll.loadMore('topics.loadMoreUnreadTopics', { after: $('#topics-container').attr('data-nextstart') - }, function(data) { + }, function(data, done) { if (data.topics && data.topics.length) { - recent.onTopicsLoaded('unread', data.topics, true); + recent.onTopicsLoaded('unread', data.topics, true, done); $('#topics-container').attr('data-nextstart', data.nextStart); } else { + done(); $('#load-more-btn').hide(); } }); diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 4c0cba514b..bed49056be 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -21,45 +21,37 @@ topicsController.get = function(req, res, next) { async.waterfall([ function (next) { - privileges.topics.get(tid, uid, function(err, privileges) { - if (err) { - return next(err); - } - - if (!privileges.read) { - return next(new Error('[[error:no-privileges]]')); - } - - userPrivileges = privileges; - next(); - }); + privileges.topics.get(tid, uid, next); }, - function (next) { - user.getSettings(uid, function(err, settings) { - if (err) { - return next(err); - } + function (privileges, next) { + if (!privileges.read) { + return next(new Error('[[error:no-privileges]]')); + } - var postIndex = 0; - if (!settings.usePagination) { - postIndex = Math.max((req.params.post_index || 1) - (settings.postsPerPage), 0); - } else if (!req.query.page) { - var index = Math.max(parseInt((req.params.post_index || 0), 10), 0); - page = Math.ceil((index + 1) / settings.postsPerPage); - } + userPrivileges = privileges; - var start = (page - 1) * settings.postsPerPage + postIndex, - end = start + settings.postsPerPage - 1 + postIndex; + user.getSettings(uid, next); + }, + function (settings, next) { + var postIndex = 0; + if (!settings.usePagination) { + postIndex = Math.max((req.params.post_index || 1) - (settings.postsPerPage - 1), 0); + } else if (!req.query.page) { + var index = Math.max(parseInt((req.params.post_index || 0), 10), 0); + page = Math.ceil((index + 1) / settings.postsPerPage); + } - topics.getTopicWithPosts(tid, uid, start, end, function (err, topicData) { - if (topicData) { - if (parseInt(topicData.deleted, 10) === 1 && !userPrivileges.view_deleted) { - return next(new Error('[[error:no-topic]]')); - } - topicData.currentPage = page; + var start = (page - 1) * settings.postsPerPage + postIndex, + end = start + settings.postsPerPage - 1; + + topics.getTopicWithPosts(tid, uid, start, end, function (err, topicData) { + if (topicData) { + if (parseInt(topicData.deleted, 10) === 1 && !userPrivileges.view_deleted) { + return next(new Error('[[error:no-topic]]')); } - next(err, topicData); - }); + topicData.currentPage = page; + } + next(err, topicData); }); }, function (topicData, next) { diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 7ab88f0570..369837cadc 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -79,6 +79,21 @@ middleware.addSlug = function(req, res, next) { next(); }; +middleware.checkPostIndex = function(req, res, next) { + topics.getPostCount(req.params.topic_id, function(err, postCount) { + if (err) { + return next(err); + } + var postIndex = parseInt(req.params.post_index, 10); + if (postIndex > postCount) { + return res.redirect('/topic/' + req.params.topic_id + '/' + req.params.slug + '/' + postCount); + } else if (postIndex <= 1) { + return res.redirect('/topic/' + req.params.topic_id + '/' + req.params.slug); + } + next(); + }); +}; + middleware.prepareAPI = function(req, res, next) { res.locals.isAPI = true; next(); diff --git a/src/routes/index.js b/src/routes/index.js index a1fd3d1965..737d3e2a39 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -51,8 +51,8 @@ function staticRoutes(app, middleware, controllers) { function topicRoutes(app, middleware, controllers) { app.get('/api/topic/teaser/:topic_id', controllers.topics.teaser); - app.get('/topic/:topic_id/:slug/:post_index?', middleware.buildHeader, middleware.addSlug, controllers.topics.get); - app.get('/api/topic/:topic_id/:slug/:post_index?', controllers.topics.get); + app.get('/topic/:topic_id/:slug/:post_index?', middleware.buildHeader, middleware.checkPostIndex, controllers.topics.get); + app.get('/api/topic/:topic_id/:slug/:post_index?', middleware.checkPostIndex, controllers.topics.get); app.get('/topic/:topic_id/:slug?', middleware.buildHeader, middleware.addSlug, controllers.topics.get); app.get('/api/topic/:topic_id/:slug?', controllers.topics.get); diff --git a/src/topics/posts.js b/src/topics/posts.js index 0f81a1f8e6..13cd8ca37c 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -157,5 +157,8 @@ module.exports = function(Topics) { }); }; + Topics.getPostCount = function(tid, callback) { + db.sortedSetCard('tid:' + tid + ':posts', callback); + }; };