mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 19:15:58 +01:00 
			
		
		
		
	Recent refactor (#6879)
* wip * fix inf scroll * remove duplicated code * remove dupe code in /unread * use topicList * update tag page to use topicList * fix tests * combine ifs * remove more dupe code * disable timeout
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							aa301f27a1
						
					
				
				
					commit
					c27be9db5a
				
			| @@ -1,18 +1,13 @@ | ||||
| 'use strict'; | ||||
|  | ||||
|  | ||||
| define('forum/category', [ | ||||
| 	'forum/infinitescroll', | ||||
| 	'share', | ||||
| 	'navigator', | ||||
| 	'forum/category/tools', | ||||
| 	'forum/recent', | ||||
| 	'topicList', | ||||
| 	'sort', | ||||
| 	'components', | ||||
| 	'translator', | ||||
| 	'topicSelect', | ||||
| 	'handleBack', | ||||
| ], function (infinitescroll, share, navigator, categoryTools, recent, sort, components, translator, topicSelect, handleBack) { | ||||
| ], function (infinitescroll, share, navigator, categoryTools, topicList, sort) { | ||||
| 	var Category = {}; | ||||
|  | ||||
| 	$(window).on('action:ajaxify.start', function (ev, data) { | ||||
| @@ -25,7 +20,7 @@ define('forum/category', [ | ||||
|  | ||||
| 	function removeListeners() { | ||||
| 		categoryTools.removeListeners(); | ||||
| 		recent.removeListeners(); | ||||
| 		topicList.removeListeners(); | ||||
| 	} | ||||
|  | ||||
| 	Category.init = function () { | ||||
| @@ -36,15 +31,16 @@ define('forum/category', [ | ||||
| 		share.addShareHandlers(ajaxify.data.name); | ||||
|  | ||||
| 		categoryTools.init(cid); | ||||
| 		recent.watchForNewPosts(); | ||||
|  | ||||
| 		topicList.init('category', loadTopicsAfter); | ||||
|  | ||||
| 		sort.handleSort('categoryTopicSort', 'user.setCategorySort', 'category/' + ajaxify.data.slug); | ||||
|  | ||||
| 		enableInfiniteLoadingOrPagination(); | ||||
|  | ||||
| 		handleBack.init(function (after, cb) { | ||||
| 			loadTopicsAfter(after, 1, cb); | ||||
| 		}); | ||||
| 		if (!config.usePagination) { | ||||
| 			navigator.init('[component="category/topic"]', ajaxify.data.topic_count, Category.toTop, Category.toBottom, Category.navigatorCallback); | ||||
| 		} else { | ||||
| 			navigator.disable(); | ||||
| 		} | ||||
|  | ||||
| 		handleScrollToTopicIndex(); | ||||
|  | ||||
| @@ -104,32 +100,8 @@ define('forum/category', [ | ||||
| 		return bottomIndex; | ||||
| 	}; | ||||
|  | ||||
| 	function enableInfiniteLoadingOrPagination() { | ||||
| 		if (!config.usePagination) { | ||||
| 			navigator.init('[component="category/topic"]', ajaxify.data.topic_count, Category.toTop, Category.toBottom, Category.navigatorCallback); | ||||
| 			infinitescroll.init($('[component="category"]'), Category.loadMoreTopics); | ||||
| 		} else { | ||||
| 			navigator.disable(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	Category.loadMoreTopics = function (direction) { | ||||
| 		if (!$('[component="category"]').length || !$('[component="category"]').children().length) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		var topics = $('[component="category/topic"]'); | ||||
| 		var afterEl = direction > 0 ? topics.last() : topics.first(); | ||||
| 		var after = (parseInt(afterEl.attr('data-index'), 10) || 0) + (direction > 0 ? 1 : 0); | ||||
|  | ||||
| 		loadTopicsAfter(after, direction); | ||||
| 	}; | ||||
|  | ||||
| 	function loadTopicsAfter(after, direction, callback) { | ||||
| 		callback = callback || function () {}; | ||||
| 		if (!utils.isNumber(after) || (after === 0 && components.get('category/topic', 'index', 0).length)) { | ||||
| 			return callback(); | ||||
| 		} | ||||
|  | ||||
| 		$(window).trigger('action:category.loading'); | ||||
| 		var params = utils.params(); | ||||
| @@ -140,78 +112,10 @@ define('forum/category', [ | ||||
| 			query: params, | ||||
| 			categoryTopicSort: config.categoryTopicSort, | ||||
| 		}, function (data, done) { | ||||
| 			if (data.topics && data.topics.length) { | ||||
| 				Category.onTopicsLoaded(data, direction, done); | ||||
| 			} else { | ||||
| 				done(); | ||||
| 			} | ||||
|  | ||||
| 			$(window).trigger('action:category.loaded'); | ||||
| 			callback(); | ||||
| 			callback(data, done); | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	Category.onTopicsLoaded = function (data, direction, callback) { | ||||
| 		if (!data || !data.topics.length) { | ||||
| 			return callback(); | ||||
| 		} | ||||
|  | ||||
| 		function removeAlreadyAddedTopics(topics) { | ||||
| 			return topics.filter(function (topic) { | ||||
| 				return components.get('category/topic', 'tid', topic.tid).length === 0; | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		data.topics = removeAlreadyAddedTopics(data.topics); | ||||
| 		if (!data.topics.length) { | ||||
| 			return callback(); | ||||
| 		} | ||||
|  | ||||
| 		data.showSelect = data.privileges.editable; | ||||
|  | ||||
| 		var after; | ||||
| 		var before; | ||||
| 		var topics = $('[component="category/topic"]'); | ||||
|  | ||||
| 		if (direction > 0 && topics.length) { | ||||
| 			after = topics.last(); | ||||
| 		} else if (direction < 0 && topics.length) { | ||||
| 			before = topics.first(); | ||||
| 		} | ||||
|  | ||||
| 		app.parseAndTranslate('category', 'topics', data, function (html) { | ||||
| 			$('[component="category"]').removeClass('hidden'); | ||||
| 			$('.category-sidebar').removeClass('hidden'); | ||||
|  | ||||
| 			$('#category-no-topics').remove(); | ||||
|  | ||||
| 			if (after) { | ||||
| 				html.insertAfter(after); | ||||
| 			} else if (before) { | ||||
| 				var height = $(document).height(); | ||||
| 				var scrollTop = $(window).scrollTop(); | ||||
|  | ||||
| 				html.insertBefore(before); | ||||
|  | ||||
| 				$(window).scrollTop(scrollTop + ($(document).height() - height)); | ||||
| 			} else { | ||||
| 				$('[component="category"]').append(html); | ||||
| 			} | ||||
|  | ||||
| 			if (!topicSelect.getSelectedTids().length) { | ||||
| 				infinitescroll.removeExtra($('[component="category/topic"]'), direction, config.topicsPerPage * 3); | ||||
| 			} | ||||
|  | ||||
| 			html.find('.timeago').timeago(); | ||||
| 			app.createUserTooltips(); | ||||
| 			utils.makeNumbersHumanReadable(html.find('.human-readable-number')); | ||||
|  | ||||
| 			$(window).trigger('action:topics.loaded', { topics: data.topics }); | ||||
|  | ||||
| 			callback(); | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	return Category; | ||||
| }); | ||||
|   | ||||
| @@ -16,7 +16,7 @@ define('forum/infinitescroll', function () { | ||||
| 			callback = cb; | ||||
| 			container = el || $('body'); | ||||
| 		} | ||||
|  | ||||
| 		previousScrollTop = $(window).scrollTop(); | ||||
| 		$(window).off('scroll', onScroll).on('scroll', onScroll); | ||||
| 	}; | ||||
|  | ||||
|   | ||||
| @@ -1,40 +1,14 @@ | ||||
| 'use strict'; | ||||
|  | ||||
|  | ||||
| define('forum/popular', ['forum/recent', 'components', 'forum/infinitescroll'], function (recent, components, infinitescroll) { | ||||
| define('forum/popular', ['topicList'], function (topicList) { | ||||
| 	var Popular = {}; | ||||
|  | ||||
| 	Popular.init = function () { | ||||
| 		app.enterRoom('popular_topics'); | ||||
|  | ||||
| 		recent.handleCategorySelection(); | ||||
|  | ||||
| 		if (!config.usePagination) { | ||||
| 			infinitescroll.init(loadMoreTopics); | ||||
| 		} | ||||
| 		topicList.init('popular'); | ||||
| 	}; | ||||
|  | ||||
| 	function loadMoreTopics(direction) { | ||||
| 		if (direction < 0 || !$('[component="category"]').length) { | ||||
| 			return; | ||||
| 		} | ||||
| 		var query = utils.params(); | ||||
| 		infinitescroll.loadMore('topics.loadMorePopularTopics', { | ||||
| 			after: $('[component="category"]').attr('data-nextstart'), | ||||
| 			count: config.topicsPerPage, | ||||
| 			cid: query.cid, | ||||
| 			query: query, | ||||
| 			term: ajaxify.data.selectedTerm.term, | ||||
| 			filter: ajaxify.data.selectedFilter.filter, | ||||
| 		}, function (data, done) { | ||||
| 			if (data.topics && data.topics.length) { | ||||
| 				recent.onTopicsLoaded('popular', data.topics, false, direction, done); | ||||
| 				$('[component="category"]').attr('data-nextstart', data.nextStart); | ||||
| 			} else { | ||||
| 				done(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	return Popular; | ||||
| }); | ||||
|   | ||||
| @@ -1,268 +1,12 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| define('forum/recent', ['forum/infinitescroll', 'components', 'handleBack'], function (infinitescroll, components, handleBack) { | ||||
| define('forum/recent', ['topicList'], function (topicList) { | ||||
| 	var	Recent = {}; | ||||
|  | ||||
| 	var newTopicCount = 0; | ||||
| 	var newPostCount = 0; | ||||
|  | ||||
| 	$(window).on('action:ajaxify.start', function (ev, data) { | ||||
| 		if (ajaxify.currentPage !== data.url) { | ||||
| 			Recent.removeListeners(); | ||||
| 		} | ||||
| 	}); | ||||
|  | ||||
| 	Recent.init = function () { | ||||
| 		app.enterRoom('recent_topics'); | ||||
|  | ||||
| 		Recent.watchForNewPosts(); | ||||
|  | ||||
| 		Recent.handleCategorySelection(); | ||||
|  | ||||
| 		handleBack.init(function (after, cb) { | ||||
| 			loadTopicsAfter(after, 1, cb); | ||||
| 		}); | ||||
|  | ||||
| 		$('#new-topics-alert').on('click', function () { | ||||
| 			$(this).addClass('hide'); | ||||
| 		}); | ||||
|  | ||||
| 		if (!config.usePagination) { | ||||
| 			infinitescroll.init(Recent.loadMoreTopics); | ||||
| 		} | ||||
|  | ||||
| 		$(window).trigger('action:topics.loaded', { topics: ajaxify.data.topics }); | ||||
| 	}; | ||||
|  | ||||
| 	Recent.watchForNewPosts = function () { | ||||
| 		newPostCount = 0; | ||||
| 		newTopicCount = 0; | ||||
| 		Recent.removeListeners(); | ||||
| 		socket.on('event:new_topic', onNewTopic); | ||||
| 		socket.on('event:new_post', onNewPost); | ||||
| 	}; | ||||
|  | ||||
| 	function onNewTopic(data) { | ||||
| 		if (ajaxify.data.selectedCids && ajaxify.data.selectedCids.indexOf(parseInt(data.cid, 10)) === -1) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(data.cid, 10)) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		newTopicCount += 1; | ||||
| 		Recent.updateAlertText(); | ||||
| 	} | ||||
|  | ||||
| 	function onNewPost(data) { | ||||
| 		function showAlert() { | ||||
| 			newPostCount += 1; | ||||
| 			Recent.updateAlertText(); | ||||
| 		} | ||||
|  | ||||
| 		var post = data.posts[0]; | ||||
| 		if (!post || !post.topic) { | ||||
| 			return; | ||||
| 		} | ||||
| 		if (parseInt(post.topic.mainPid, 10) === parseInt(post.pid, 10)) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (ajaxify.data.selectedCids && ajaxify.data.selectedCids.indexOf(parseInt(post.topic.cid, 10)) === -1) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'new') { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(post.topic.cid, 10)) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') { | ||||
| 			socket.emit('topics.isFollowed', post.tid, function (err, isFollowed) { | ||||
| 				if (err) { | ||||
| 					app.alertError(err.message); | ||||
| 				} | ||||
| 				if (isFollowed) { | ||||
| 					showAlert(); | ||||
| 				} | ||||
| 			}); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		showAlert(); | ||||
| 	} | ||||
|  | ||||
| 	Recent.handleCategorySelection = function () { | ||||
| 		function getSelectedCids() { | ||||
| 			var cids = []; | ||||
| 			$('[component="category/list"] [data-cid]').each(function (index, el) { | ||||
| 				if ($(el).find('i.fa-check').length) { | ||||
| 					cids.push(parseInt($(el).attr('data-cid'), 10)); | ||||
| 				} | ||||
| 			}); | ||||
| 			cids.sort(function (a, b) { | ||||
| 				return a - b; | ||||
| 			}); | ||||
| 			return cids; | ||||
| 		} | ||||
|  | ||||
| 		$('[component="category/dropdown"]').on('hidden.bs.dropdown', function () { | ||||
| 			var cids = getSelectedCids(); | ||||
| 			var changed = ajaxify.data.selectedCids.length !== cids.length; | ||||
| 			ajaxify.data.selectedCids.forEach(function (cid, index) { | ||||
| 				if (cid !== cids[index]) { | ||||
| 					changed = true; | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 			if (changed) { | ||||
| 				var url = window.location.pathname; | ||||
| 				var currentParams = utils.params(); | ||||
| 				if (cids.length) { | ||||
| 					currentParams.cid = cids; | ||||
| 					url += '?' + decodeURIComponent($.param(currentParams)); | ||||
| 				} | ||||
| 				ajaxify.go(url); | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		$('[component="category/list"]').on('click', '[data-cid]', function (ev) { | ||||
| 			function selectChildren(parentCid, flag) { | ||||
| 				$('[component="category/list"] [data-parent-cid="' + parentCid + '"] [component="category/select/icon"]').toggleClass('fa-check', flag); | ||||
| 				$('[component="category/list"] [data-parent-cid="' + parentCid + '"]').each(function (index, el) { | ||||
| 					selectChildren($(el).attr('data-cid'), flag); | ||||
| 				}); | ||||
| 			} | ||||
| 			var categoryEl = $(this); | ||||
| 			var cid = $(this).attr('data-cid'); | ||||
| 			if (ev.ctrlKey) { | ||||
| 				selectChildren(cid, !categoryEl.find('[component="category/select/icon"]').hasClass('fa-check')); | ||||
| 			} | ||||
| 			categoryEl.find('[component="category/select/icon"]').toggleClass('fa-check'); | ||||
| 			$('[component="category/list"] li').first().find('i').toggleClass('fa-check', !getSelectedCids().length); | ||||
| 			return false; | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	Recent.removeListeners = function () { | ||||
| 		socket.removeListener('event:new_topic', onNewTopic); | ||||
| 		socket.removeListener('event:new_post', onNewPost); | ||||
| 	}; | ||||
|  | ||||
| 	Recent.updateAlertText = function () { | ||||
| 		var text = ''; | ||||
|  | ||||
| 		if (newTopicCount === 0) { | ||||
| 			if (newPostCount === 1) { | ||||
| 				text = '[[recent:there-is-a-new-post]]'; | ||||
| 			} else if (newPostCount > 1) { | ||||
| 				text = '[[recent:there-are-new-posts, ' + newPostCount + ']]'; | ||||
| 			} | ||||
| 		} else if (newTopicCount === 1) { | ||||
| 			if (newPostCount === 0) { | ||||
| 				text = '[[recent:there-is-a-new-topic]]'; | ||||
| 			} else if (newPostCount === 1) { | ||||
| 				text = '[[recent:there-is-a-new-topic-and-a-new-post]]'; | ||||
| 			} else if (newPostCount > 1) { | ||||
| 				text = '[[recent:there-is-a-new-topic-and-new-posts, ' + newPostCount + ']]'; | ||||
| 			} | ||||
| 		} else if (newTopicCount > 1) { | ||||
| 			if (newPostCount === 0) { | ||||
| 				text = '[[recent:there-are-new-topics, ' + newTopicCount + ']]'; | ||||
| 			} else if (newPostCount === 1) { | ||||
| 				text = '[[recent:there-are-new-topics-and-a-new-post, ' + newTopicCount + ']]'; | ||||
| 			} else if (newPostCount > 1) { | ||||
| 				text = '[[recent:there-are-new-topics-and-new-posts, ' + newTopicCount + ', ' + newPostCount + ']]'; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		text += ' [[recent:click-here-to-reload]]'; | ||||
|  | ||||
| 		$('#new-topics-alert').translateText(text).removeClass('hide').fadeIn('slow'); | ||||
| 		$('#category-no-topics').addClass('hide'); | ||||
| 	}; | ||||
|  | ||||
| 	Recent.loadMoreTopics = function (direction) { | ||||
| 		if (!$('[component="category"]').length) { | ||||
| 			return; | ||||
| 		} | ||||
| 		var topics = $('[component="category/topic"]'); | ||||
| 		var afterEl = direction > 0 ? topics.last() : topics.first(); | ||||
| 		var after = (parseInt(afterEl.attr('data-index'), 10) || 0) + (direction > 0 ? 1 : 0); | ||||
| 		loadTopicsAfter(after, direction); | ||||
| 	}; | ||||
|  | ||||
| 	function loadTopicsAfter(after, direction, callback) { | ||||
| 		callback = callback || function () {}; | ||||
| 		var query = utils.params(); | ||||
| 		infinitescroll.loadMore('topics.loadMoreRecentTopics', { | ||||
| 			after: after, | ||||
| 			direction: direction, | ||||
| 			count: config.topicsPerPage, | ||||
| 			cid: query.cid, | ||||
| 			query: query, | ||||
| 			filter: ajaxify.data.selectedFilter.filter, | ||||
| 			set: $('[component="category"]').attr('data-set') ? $('[component="category"]').attr('data-set') : 'topics:recent', | ||||
| 		}, function (data, done) { | ||||
| 			if (data.topics && data.topics.length) { | ||||
| 				Recent.onTopicsLoaded('recent', data.topics, false, direction, done); | ||||
| 			} else { | ||||
| 				done(); | ||||
| 			} | ||||
| 			$('[component="category"]').attr('data-nextstart', data.nextStart); | ||||
| 			callback(); | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	Recent.onTopicsLoaded = function (templateName, topics, showSelect, direction, callback) { | ||||
| 		topics = topics.filter(function (topic) { | ||||
| 			return !components.get('category/topic', 'tid', topic.tid).length; | ||||
| 		}); | ||||
|  | ||||
| 		if (!topics.length) { | ||||
| 			return callback(); | ||||
| 		} | ||||
|  | ||||
| 		var after; | ||||
| 		var before; | ||||
| 		var topicsList = $('[component="category/topic"]'); | ||||
|  | ||||
| 		if (direction > 0 && topics.length) { | ||||
| 			after = topicsList.last(); | ||||
| 		} else if (direction < 0 && topics.length) { | ||||
| 			before = topicsList.first(); | ||||
| 		} | ||||
|  | ||||
| 		app.parseAndTranslate(templateName, 'topics', { topics: topics, showSelect: showSelect }, function (html) { | ||||
| 			$('#category-no-topics').remove(); | ||||
|  | ||||
| 			if (after && after.length) { | ||||
| 				html.insertAfter(after); | ||||
| 			} else if (before && before.length) { | ||||
| 				var height = $(document).height(); | ||||
| 				var scrollTop = $(window).scrollTop(); | ||||
|  | ||||
| 				html.insertBefore(before); | ||||
|  | ||||
| 				$(window).scrollTop(scrollTop + ($(document).height() - height)); | ||||
| 			} else { | ||||
| 				$('[component="category"]').append(html); | ||||
| 			} | ||||
|  | ||||
| 			html.find('.timeago').timeago(); | ||||
| 			app.createUserTooltips(); | ||||
| 			utils.makeNumbersHumanReadable(html.find('.human-readable-number')); | ||||
| 			$(window).trigger('action:topics.loaded', { topics: topics }); | ||||
| 			callback(); | ||||
| 		}); | ||||
| 		topicList.init('recent'); | ||||
| 	}; | ||||
|  | ||||
| 	return Recent; | ||||
|   | ||||
| @@ -1,42 +1,21 @@ | ||||
| 'use strict'; | ||||
|  | ||||
|  | ||||
| define('forum/tag', ['forum/recent', 'forum/infinitescroll'], function (recent, infinitescroll) { | ||||
| define('forum/tag', ['topicList', 'forum/infinitescroll'], function (topicList, infinitescroll) { | ||||
| 	var Tag = {}; | ||||
|  | ||||
| 	Tag.init = function () { | ||||
| 		app.enterRoom('tags'); | ||||
|  | ||||
| 		if ($('body').height() <= $(window).height() && $('[component="category"]').children().length >= 20) { | ||||
| 			$('#load-more-btn').show(); | ||||
| 		} | ||||
|  | ||||
| 		$('#load-more-btn').on('click', function () { | ||||
| 			loadMoreTopics(); | ||||
| 		}); | ||||
|  | ||||
| 		if (!config.usePagination) { | ||||
| 			infinitescroll.init(loadMoreTopics); | ||||
| 		} | ||||
|  | ||||
| 		function loadMoreTopics(direction) { | ||||
| 			if (direction < 0 || !$('[component="category"]').length) { | ||||
| 				return; | ||||
| 			} | ||||
| 		topicList.init('tag', loadMoreTopics); | ||||
|  | ||||
| 		function loadMoreTopics(after, direction, callback) { | ||||
| 			infinitescroll.loadMore('topics.loadMoreFromSet', { | ||||
| 				set: 'tag:' + ajaxify.data.tag + ':topics', | ||||
| 				after: $('[component="category"]').attr('data-nextstart'), | ||||
| 				after: after, | ||||
| 				direction: direction, | ||||
| 				count: config.topicsPerPage, | ||||
| 			}, function (data, done) { | ||||
| 				if (data.topics && data.topics.length) { | ||||
| 					recent.onTopicsLoaded('tag', data.topics, false, direction, done); | ||||
| 				} else { | ||||
| 					done(); | ||||
| 					$('#load-more-btn').hide(); | ||||
| 				} | ||||
| 				$('[component="category"]').attr('data-nextstart', data.nextStart); | ||||
| 			}); | ||||
| 			}, callback); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
|   | ||||
| @@ -1,54 +1,13 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| define('forum/top', ['forum/recent', 'forum/infinitescroll'], function (recent, infinitescroll) { | ||||
| define('forum/top', ['topicList'], function (topicList) { | ||||
| 	var	Top = {}; | ||||
|  | ||||
| 	$(window).on('action:ajaxify.start', function (ev, data) { | ||||
| 		if (ajaxify.currentPage !== data.url) { | ||||
| 			recent.removeListeners(); | ||||
| 		} | ||||
| 	}); | ||||
|  | ||||
| 	Top.init = function () { | ||||
| 		app.enterRoom('top_topics'); | ||||
|  | ||||
| 		recent.watchForNewPosts(); | ||||
|  | ||||
| 		recent.handleCategorySelection(); | ||||
|  | ||||
| 		$('#new-topics-alert').on('click', function () { | ||||
| 			$(this).addClass('hide'); | ||||
| 		}); | ||||
|  | ||||
| 		if (!config.usePagination) { | ||||
| 			infinitescroll.init(loadMoreTopics); | ||||
| 		} | ||||
|  | ||||
| 		$(window).trigger('action:topics.loaded', { topics: ajaxify.data.topics }); | ||||
| 		topicList.init('top'); | ||||
| 	}; | ||||
|  | ||||
| 	function loadMoreTopics(direction) { | ||||
| 		if (direction < 0 || !$('[component="category"]').length) { | ||||
| 			return; | ||||
| 		} | ||||
| 		var query = utils.params(); | ||||
| 		infinitescroll.loadMore('topics.loadMoreTopTopics', { | ||||
| 			after: $('[component="category"]').attr('data-nextstart'), | ||||
| 			count: config.topicsPerPage, | ||||
| 			cid: query.cid, | ||||
| 			query: query, | ||||
| 			term: ajaxify.data.selectedTerm.term, | ||||
| 			filter: ajaxify.data.selectedFilter.filter, | ||||
| 		}, function (data, done) { | ||||
| 			if (data.topics && data.topics.length) { | ||||
| 				recent.onTopicsLoaded('top', data.topics, true, direction, done); | ||||
| 				$('[component="category"]').attr('data-nextstart', data.nextStart); | ||||
| 			} else { | ||||
| 				done(); | ||||
| 				$('#load-more-btn').hide(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	return Top; | ||||
| }); | ||||
|   | ||||
| @@ -1,27 +1,14 @@ | ||||
| 'use strict'; | ||||
|  | ||||
|  | ||||
| define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', 'components'], function (recent, topicSelect, infinitescroll, components) { | ||||
| define('forum/unread', ['topicSelect', 'components', 'topicList'], function (topicSelect, components, topicList) { | ||||
| 	var Unread = {}; | ||||
|  | ||||
| 	$(window).on('action:ajaxify.start', function (ev, data) { | ||||
| 		if (ajaxify.currentPage !== data.url) { | ||||
| 			recent.removeListeners(); | ||||
| 		} | ||||
| 	}); | ||||
|  | ||||
| 	Unread.init = function () { | ||||
| 		app.enterRoom('unread_topics'); | ||||
|  | ||||
| 		$('#new-topics-alert').on('click', function () { | ||||
| 			$(this).addClass('hide'); | ||||
| 		}); | ||||
|  | ||||
| 		recent.watchForNewPosts(); | ||||
|  | ||||
| 		recent.handleCategorySelection(); | ||||
|  | ||||
| 		$(window).trigger('action:topics.loaded', { topics: ajaxify.data.topics }); | ||||
| 		topicList.init('unread'); | ||||
| 		topicSelect.init(); | ||||
|  | ||||
| 		$('#markSelectedRead').on('click', function () { | ||||
| 			var tids = topicSelect.getSelectedTids(); | ||||
| @@ -71,42 +58,6 @@ define('forum/unread', ['forum/recent', 'topicSelect', 'forum/infinitescroll', ' | ||||
| 				doneRemovingTids(tids); | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		topicSelect.init(); | ||||
|  | ||||
| 		if ($('body').height() <= $(window).height() && $('[component="category"]').children().length >= 20) { | ||||
| 			$('#load-more-btn').show(); | ||||
| 		} | ||||
|  | ||||
| 		$('#load-more-btn').on('click', function () { | ||||
| 			loadMoreTopics(); | ||||
| 		}); | ||||
|  | ||||
| 		if (!config.usePagination) { | ||||
| 			infinitescroll.init(loadMoreTopics); | ||||
| 		} | ||||
|  | ||||
| 		function loadMoreTopics(direction) { | ||||
| 			if (direction < 0 || !$('[component="category"]').length) { | ||||
| 				return; | ||||
| 			} | ||||
| 			var query = utils.params(); | ||||
| 			infinitescroll.loadMore('topics.loadMoreUnreadTopics', { | ||||
| 				after: $('[component="category"]').attr('data-nextstart'), | ||||
| 				count: config.topicsPerPage, | ||||
| 				cid: query.cid, | ||||
| 				query: query, | ||||
| 				filter: ajaxify.data.selectedFilter.filter, | ||||
| 			}, function (data, done) { | ||||
| 				if (data.topics && data.topics.length) { | ||||
| 					recent.onTopicsLoaded('unread', data.topics, true, direction, done); | ||||
| 					$('[component="category"]').attr('data-nextstart', data.nextStart); | ||||
| 				} else { | ||||
| 					done(); | ||||
| 					$('#load-more-btn').hide(); | ||||
| 				} | ||||
| 			}); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	function doneRemovingTids(tids) { | ||||
|   | ||||
							
								
								
									
										290
									
								
								public/src/modules/topicList.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								public/src/modules/topicList.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,290 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| define('topicList', ['forum/infinitescroll', 'handleBack', 'topicSelect'], function (infinitescroll, handleBack, topicSelect) { | ||||
| 	var TopicList = {}; | ||||
| 	var templateName = ''; | ||||
|  | ||||
| 	var tplToSort = { | ||||
| 		recent: 'recent', | ||||
| 		unread: 'unread', | ||||
| 		popular: 'posts', | ||||
| 		top: 'votes', | ||||
| 	}; | ||||
|  | ||||
| 	var newTopicCount = 0; | ||||
| 	var newPostCount = 0; | ||||
|  | ||||
| 	var loadTopicsCallback; | ||||
|  | ||||
| 	$(window).on('action:ajaxify.start', function () { | ||||
| 		TopicList.removeListeners(); | ||||
| 		loadTopicsCallback = null; | ||||
| 	}); | ||||
|  | ||||
| 	TopicList.init = function (template, cb) { | ||||
| 		templateName = template; | ||||
| 		loadTopicsCallback = cb; | ||||
|  | ||||
| 		TopicList.watchForNewPosts(); | ||||
|  | ||||
| 		TopicList.handleCategorySelection(); | ||||
|  | ||||
| 		if (!config.usePagination) { | ||||
| 			infinitescroll.init(TopicList.loadMoreTopics); | ||||
| 		} | ||||
|  | ||||
| 		handleBack.init(function (after, cb) { | ||||
| 			loadTopicsAfter(after, 1, cb); | ||||
| 		}); | ||||
|  | ||||
| 		if ($('body').height() <= $(window).height() && $('[component="category"]').children().length >= 20) { | ||||
| 			$('#load-more-btn').show(); | ||||
| 		} | ||||
|  | ||||
| 		$('#load-more-btn').on('click', function () { | ||||
| 			TopicList.loadMoreTopics(1); | ||||
| 		}); | ||||
|  | ||||
| 		$(window).trigger('action:topics.loaded', { topics: ajaxify.data.topics }); | ||||
| 	}; | ||||
|  | ||||
| 	TopicList.watchForNewPosts = function () { | ||||
| 		$('#new-topics-alert').on('click', function () { | ||||
| 			$(this).addClass('hide'); | ||||
| 		}); | ||||
| 		newPostCount = 0; | ||||
| 		newTopicCount = 0; | ||||
| 		TopicList.removeListeners(); | ||||
| 		socket.on('event:new_topic', onNewTopic); | ||||
| 		socket.on('event:new_post', onNewPost); | ||||
| 	}; | ||||
|  | ||||
| 	TopicList.removeListeners = function () { | ||||
| 		socket.removeListener('event:new_topic', onNewTopic); | ||||
| 		socket.removeListener('event:new_post', onNewPost); | ||||
| 	}; | ||||
|  | ||||
| 	function onNewTopic(data) { | ||||
| 		if ((ajaxify.data.selectedCids && ajaxify.data.selectedCids.indexOf(parseInt(data.cid, 10)) === -1) || | ||||
| 			(ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') || | ||||
| 			(ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(data.cid, 10))) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		newTopicCount += 1; | ||||
| 		updateAlertText(); | ||||
| 	} | ||||
|  | ||||
| 	function onNewPost(data) { | ||||
| 		function showAlert() { | ||||
| 			newPostCount += 1; | ||||
| 			updateAlertText(); | ||||
| 		} | ||||
|  | ||||
| 		var post = data.posts[0]; | ||||
| 		if ((!post || !post.topic) || | ||||
| 			(parseInt(post.topic.mainPid, 10) === parseInt(post.pid, 10)) || | ||||
| 			(ajaxify.data.selectedCids && ajaxify.data.selectedCids.indexOf(parseInt(post.topic.cid, 10)) === -1) || | ||||
| 			(ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'new') || | ||||
| 			(ajaxify.data.template.category && parseInt(ajaxify.data.cid, 10) !== parseInt(post.topic.cid, 10))) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') { | ||||
| 			socket.emit('topics.isFollowed', post.tid, function (err, isFollowed) { | ||||
| 				if (err) { | ||||
| 					app.alertError(err.message); | ||||
| 				} | ||||
| 				if (isFollowed) { | ||||
| 					showAlert(); | ||||
| 				} | ||||
| 			}); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		showAlert(); | ||||
| 	} | ||||
|  | ||||
| 	function updateAlertText() { | ||||
| 		var text = ''; | ||||
|  | ||||
| 		if (newTopicCount === 0) { | ||||
| 			if (newPostCount === 1) { | ||||
| 				text = '[[recent:there-is-a-new-post]]'; | ||||
| 			} else if (newPostCount > 1) { | ||||
| 				text = '[[recent:there-are-new-posts, ' + newPostCount + ']]'; | ||||
| 			} | ||||
| 		} else if (newTopicCount === 1) { | ||||
| 			if (newPostCount === 0) { | ||||
| 				text = '[[recent:there-is-a-new-topic]]'; | ||||
| 			} else if (newPostCount === 1) { | ||||
| 				text = '[[recent:there-is-a-new-topic-and-a-new-post]]'; | ||||
| 			} else if (newPostCount > 1) { | ||||
| 				text = '[[recent:there-is-a-new-topic-and-new-posts, ' + newPostCount + ']]'; | ||||
| 			} | ||||
| 		} else if (newTopicCount > 1) { | ||||
| 			if (newPostCount === 0) { | ||||
| 				text = '[[recent:there-are-new-topics, ' + newTopicCount + ']]'; | ||||
| 			} else if (newPostCount === 1) { | ||||
| 				text = '[[recent:there-are-new-topics-and-a-new-post, ' + newTopicCount + ']]'; | ||||
| 			} else if (newPostCount > 1) { | ||||
| 				text = '[[recent:there-are-new-topics-and-new-posts, ' + newTopicCount + ', ' + newPostCount + ']]'; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		text += ' [[recent:click-here-to-reload]]'; | ||||
|  | ||||
| 		$('#new-topics-alert').translateText(text).removeClass('hide').fadeIn('slow'); | ||||
| 		$('#category-no-topics').addClass('hide'); | ||||
| 	} | ||||
|  | ||||
| 	TopicList.handleCategorySelection = function () { | ||||
| 		function getSelectedCids() { | ||||
| 			var cids = []; | ||||
| 			$('[component="category/list"] [data-cid]').each(function (index, el) { | ||||
| 				if ($(el).find('i.fa-check').length) { | ||||
| 					cids.push(parseInt($(el).attr('data-cid'), 10)); | ||||
| 				} | ||||
| 			}); | ||||
| 			cids.sort(function (a, b) { | ||||
| 				return a - b; | ||||
| 			}); | ||||
| 			return cids; | ||||
| 		} | ||||
|  | ||||
| 		$('[component="category/dropdown"]').on('hidden.bs.dropdown', function () { | ||||
| 			var cids = getSelectedCids(); | ||||
| 			var changed = ajaxify.data.selectedCids.length !== cids.length; | ||||
| 			ajaxify.data.selectedCids.forEach(function (cid, index) { | ||||
| 				if (cid !== cids[index]) { | ||||
| 					changed = true; | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 			if (changed) { | ||||
| 				var url = window.location.pathname; | ||||
| 				var currentParams = utils.params(); | ||||
| 				if (cids.length) { | ||||
| 					currentParams.cid = cids; | ||||
| 					url += '?' + decodeURIComponent($.param(currentParams)); | ||||
| 				} | ||||
| 				ajaxify.go(url); | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		$('[component="category/list"]').on('click', '[data-cid]', function (ev) { | ||||
| 			function selectChildren(parentCid, flag) { | ||||
| 				$('[component="category/list"] [data-parent-cid="' + parentCid + '"] [component="category/select/icon"]').toggleClass('fa-check', flag); | ||||
| 				$('[component="category/list"] [data-parent-cid="' + parentCid + '"]').each(function (index, el) { | ||||
| 					selectChildren($(el).attr('data-cid'), flag); | ||||
| 				}); | ||||
| 			} | ||||
| 			var categoryEl = $(this); | ||||
| 			var cid = $(this).attr('data-cid'); | ||||
| 			if (ev.ctrlKey) { | ||||
| 				selectChildren(cid, !categoryEl.find('[component="category/select/icon"]').hasClass('fa-check')); | ||||
| 			} | ||||
| 			categoryEl.find('[component="category/select/icon"]').toggleClass('fa-check'); | ||||
| 			$('[component="category/list"] li').first().find('i').toggleClass('fa-check', !getSelectedCids().length); | ||||
| 			return false; | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	TopicList.loadMoreTopics = function (direction) { | ||||
| 		if (!$('[component="category"]').length || !$('[component="category"]').children().length) { | ||||
| 			return; | ||||
| 		} | ||||
| 		var topics = $('[component="category/topic"]'); | ||||
| 		var afterEl = direction > 0 ? topics.last() : topics.first(); | ||||
| 		var after = (parseInt(afterEl.attr('data-index'), 10) || 0) + (direction > 0 ? 1 : 0); | ||||
|  | ||||
| 		if (!utils.isNumber(after) || (after === 0 && $('[component="category/topic"][data-index="0"]').length)) { | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		var loadFn = loadTopicsCallback || loadTopicsAfter; | ||||
| 		loadFn(after, direction, function (data, done) { | ||||
| 			if (data.topics && data.topics.length) { | ||||
| 				TopicList.onTopicsLoaded(templateName, data.topics, data.privileges && data.privileges.editable, direction, done); | ||||
| 			} else { | ||||
| 				done(); | ||||
| 				$('#load-more-btn').hide(); | ||||
| 			} | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	function loadTopicsAfter(after, direction, callback) { | ||||
| 		callback = callback || function () {}; | ||||
| 		var query = utils.params(); | ||||
| 		infinitescroll.loadMore('topics.loadMoreSortedTopics', { | ||||
| 			after: after, | ||||
| 			direction: direction, | ||||
| 			sort: tplToSort[templateName], | ||||
| 			count: config.topicsPerPage, | ||||
| 			cid: query.cid, | ||||
| 			query: query, | ||||
| 			term: ajaxify.data.selectedTerm.term, | ||||
| 			filter: ajaxify.data.selectedFilter.filter, | ||||
| 			set: $('[component="category"]').attr('data-set') ? $('[component="category"]').attr('data-set') : 'topics:recent', | ||||
| 		}, callback); | ||||
| 	} | ||||
|  | ||||
| 	TopicList.onTopicsLoaded = function (templateName, topics, showSelect, direction, callback) { | ||||
| 		topics = topics.filter(function (topic) { | ||||
| 			return !$('[component="category/topic"][data-tid="' + topic.tid + '"]').length; | ||||
| 		}); | ||||
|  | ||||
| 		if (!topics.length) { | ||||
| 			return callback(); | ||||
| 		} | ||||
|  | ||||
| 		var after; | ||||
| 		var before; | ||||
| 		var topicsList = $('[component="category/topic"]'); | ||||
|  | ||||
| 		if (direction > 0 && topics.length) { | ||||
| 			after = topicsList.last(); | ||||
| 		} else if (direction < 0 && topics.length) { | ||||
| 			before = topicsList.first(); | ||||
| 		} | ||||
|  | ||||
| 		var tplData = { | ||||
| 			topics: topics, | ||||
| 			showSelect: showSelect, | ||||
| 			template: { | ||||
| 				name: templateName, | ||||
| 			}, | ||||
| 		}; | ||||
| 		tplData.template[templateName] = true; | ||||
|  | ||||
| 		app.parseAndTranslate(templateName, 'topics', tplData, function (html) { | ||||
| 			$('[component="category"]').removeClass('hidden'); | ||||
| 			$('#category-no-topics').remove(); | ||||
|  | ||||
| 			if (after && after.length) { | ||||
| 				html.insertAfter(after); | ||||
| 			} else if (before && before.length) { | ||||
| 				var height = $(document).height(); | ||||
| 				var scrollTop = $(window).scrollTop(); | ||||
|  | ||||
| 				html.insertBefore(before); | ||||
|  | ||||
| 				$(window).scrollTop(scrollTop + ($(document).height() - height)); | ||||
| 			} else { | ||||
| 				$('[component="category"]').append(html); | ||||
| 			} | ||||
|  | ||||
| 			if (!topicSelect.getSelectedTids().length) { | ||||
| 				infinitescroll.removeExtra($('[component="category/topic"]'), direction, config.topicsPerPage * 3); | ||||
| 			} | ||||
|  | ||||
| 			html.find('.timeago').timeago(); | ||||
| 			app.createUserTooltips(); | ||||
| 			utils.makeNumbersHumanReadable(html.find('.human-readable-number')); | ||||
| 			$(window).trigger('action:topics.loaded', { topics: topics, template: templateName }); | ||||
| 			callback(); | ||||
| 		}); | ||||
| 	}; | ||||
|  | ||||
| 	return TopicList; | ||||
| }); | ||||
| @@ -22,16 +22,13 @@ module.exports = function (Categories) { | ||||
| 				topics.getTopicsByTids(tids, data.uid, next); | ||||
| 			}, | ||||
| 			async.apply(user.blocks.filter, data.uid), | ||||
| 			function (topics, next) { | ||||
| 				if (!topics.length) { | ||||
| 			function (topicsData, next) { | ||||
| 				if (!topicsData.length) { | ||||
| 					return next(null, { topics: [], uid: data.uid }); | ||||
| 				} | ||||
| 				topics.calculateTopicIndices(topicsData, data.start); | ||||
|  | ||||
| 				for (var i = 0; i < topics.length; i += 1) { | ||||
| 					topics[i].index = data.start + i; | ||||
| 				} | ||||
|  | ||||
| 				plugins.fireHook('filter:category.topics.get', { cid: data.cid, topics: topics, uid: data.uid }, next); | ||||
| 				plugins.fireHook('filter:category.topics.get', { cid: data.cid, topics: topicsData, uid: data.uid }, next); | ||||
| 			}, | ||||
| 			function (results, next) { | ||||
| 				next(null, { topics: results.topics, nextStart: data.stop + 1 }); | ||||
|   | ||||
| @@ -52,7 +52,7 @@ exports.handleErrors = function (err, req, res, next) { // eslint-disable-line n | ||||
| 			return res.locals.isAPI ? res.set('X-Redirect', err.path).status(200).json(err.path) : res.redirect(err.path); | ||||
| 		} | ||||
|  | ||||
| 		winston.error(req.path + '\n', err.stack); | ||||
| 		winston.error(req.path + '\n', err); | ||||
|  | ||||
| 		res.status(status || 500); | ||||
|  | ||||
|   | ||||
| @@ -79,7 +79,6 @@ recentController.getData = function (req, url, sort, callback) { | ||||
| 			data.allCategoriesUrl = url + helpers.buildQueryString('', filter, ''); | ||||
| 			data.selectedCategory = categoryData.selectedCategory; | ||||
| 			data.selectedCids = categoryData.selectedCids; | ||||
| 			data.nextStart = stop + 1; | ||||
| 			data['feeds:disableRSS'] = meta.config['feeds:disableRSS']; | ||||
| 			data.rssFeedUrl = nconf.get('relative_path') + '/' + url + '.rss'; | ||||
| 			if (req.loggedIn) { | ||||
|   | ||||
| @@ -23,15 +23,16 @@ tagsController.getTag = function (req, res, next) { | ||||
| 	}; | ||||
| 	var settings; | ||||
| 	var topicCount = 0; | ||||
| 	var start; | ||||
|  | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			user.getSettings(req.uid, next); | ||||
| 		}, | ||||
| 		function (_settings, next) { | ||||
| 			settings = _settings; | ||||
| 			var start = Math.max(0, (page - 1) * settings.topicsPerPage); | ||||
| 			start = Math.max(0, (page - 1) * settings.topicsPerPage); | ||||
| 			var stop = start + settings.topicsPerPage - 1; | ||||
| 			templateData.nextStart = stop + 1; | ||||
| 			async.parallel({ | ||||
| 				topicCount: function (next) { | ||||
| 					topics.getTagTopicCount(req.params.tag, next); | ||||
| @@ -48,7 +49,8 @@ tagsController.getTag = function (req, res, next) { | ||||
| 			topicCount = results.topicCount; | ||||
| 			topics.getTopics(results.tids, req.uid, next); | ||||
| 		}, | ||||
| 		function (topics) { | ||||
| 		function (topicsData) { | ||||
| 			topics.calculateTopicIndices(topicsData, start); | ||||
| 			res.locals.metaTags = [ | ||||
| 				{ | ||||
| 					name: 'title', | ||||
| @@ -59,7 +61,7 @@ tagsController.getTag = function (req, res, next) { | ||||
| 					content: tag, | ||||
| 				}, | ||||
| 			]; | ||||
| 			templateData.topics = topics; | ||||
| 			templateData.topics = topicsData; | ||||
|  | ||||
| 			var pageCount =	Math.max(1, Math.ceil(topicCount / settings.topicsPerPage)); | ||||
| 			templateData.pagination = pagination.create(page, pageCount); | ||||
|   | ||||
| @@ -100,7 +100,7 @@ mongoModule.getConnectionOptions = function () { | ||||
| 		reconnectTries: 3600, | ||||
| 		reconnectInterval: 1000, | ||||
| 		autoReconnect: true, | ||||
| 		connectTimeoutMS: 60000, | ||||
| 		connectTimeoutMS: 90000, | ||||
| 		useNewUrlParser: true, | ||||
| 	}; | ||||
|  | ||||
|   | ||||
| @@ -67,6 +67,7 @@ JS.scripts = { | ||||
| 		'public/src/modules/sort.js', | ||||
| 		'public/src/modules/navigator.js', | ||||
| 		'public/src/modules/topicSelect.js', | ||||
| 		'public/src/modules/topicList.js', | ||||
| 		'public/src/modules/categorySelector.js', | ||||
| 		'public/src/modules/share.js', | ||||
| 		'public/src/modules/search.js', | ||||
|   | ||||
| @@ -87,59 +87,43 @@ module.exports = function (SocketTopics) { | ||||
| 		], callback); | ||||
| 	}; | ||||
|  | ||||
| 	SocketTopics.loadMoreUnreadTopics = function (socket, data, callback) { | ||||
| 		loadData(socket.uid, data, 'unread', callback); | ||||
| 	}; | ||||
|  | ||||
| 	SocketTopics.loadMoreRecentTopics = function (socket, data, callback) { | ||||
| 		loadData(socket.uid, data, 'recent', callback); | ||||
| 	}; | ||||
|  | ||||
| 	SocketTopics.loadMorePopularTopics = function (socket, data, callback) { | ||||
| 		loadData(socket.uid, data, 'posts', callback); | ||||
| 	}; | ||||
|  | ||||
| 	SocketTopics.loadMoreTopTopics = function (socket, data, callback) { | ||||
| 		loadData(socket.uid, data, 'votes', callback); | ||||
| 	}; | ||||
|  | ||||
| 	function loadData(uid, data, sort, callback) { | ||||
| 	SocketTopics.loadMoreSortedTopics = function (socket, data, callback) { | ||||
| 		if (!data || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { | ||||
| 			return callback(new Error('[[error:invalid-data]]')); | ||||
| 		} | ||||
| 		const { start, stop } = calculateStartStop(data); | ||||
| 		const params = { | ||||
| 			uid: socket.uid, | ||||
| 			start: start, | ||||
| 			stop: stop, | ||||
| 			filter: data.filter, | ||||
| 			query: data.query, | ||||
| 		}; | ||||
| 		if (data.sort === 'unread') { | ||||
| 			params.cid = data.cid; | ||||
| 			return topics.getUnreadTopics(params, callback); | ||||
| 		} | ||||
| 		params.cids = data.cid; | ||||
| 		params.sort = data.sort; | ||||
| 		params.term = data.term; | ||||
| 		topics.getSortedTopics(params, callback); | ||||
| 	}; | ||||
|  | ||||
| 	SocketTopics.loadMoreFromSet = function (socket, data, callback) { | ||||
| 		if (!data || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0 || !data.set) { | ||||
| 			return callback(new Error('[[error:invalid-data]]')); | ||||
| 		} | ||||
| 		const { start, stop } = calculateStartStop(data); | ||||
| 		topics.getTopicsFromSet(data.set, socket.uid, start, stop, callback); | ||||
| 	}; | ||||
|  | ||||
| 	function calculateStartStop(data) { | ||||
| 		var itemsPerPage = Math.min(meta.config.topicsPerPage || 20, parseInt(data.count, 10) || meta.config.topicsPerPage || 20); | ||||
| 		var start = Math.max(0, parseInt(data.after, 10)); | ||||
| 		if (data.direction === -1) { | ||||
| 			start -= itemsPerPage; | ||||
| 		} | ||||
| 		var stop = start + Math.max(0, itemsPerPage - 1); | ||||
| 		start = Math.max(0, start); | ||||
| 		stop = Math.max(0, stop); | ||||
| 		const params = { | ||||
| 			uid: uid, | ||||
| 			start: start, | ||||
| 			stop: stop, | ||||
| 			filter: data.filter, | ||||
| 			query: data.query, | ||||
| 		}; | ||||
| 		if (sort === 'unread') { | ||||
| 			params.cid = data.cid; | ||||
| 			return topics.getUnreadTopics(params, callback); | ||||
| 		} | ||||
| 		params.cids = data.cid; | ||||
| 		params.sort = sort; | ||||
| 		params.term = data.term; | ||||
| 		topics.getSortedTopics(params, callback); | ||||
| 		return { start: Math.max(0, start), stop: Math.max(0, stop) }; | ||||
| 	} | ||||
|  | ||||
| 	SocketTopics.loadMoreFromSet = function (socket, data, callback) { | ||||
| 		if (!data || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0 || !data.set) { | ||||
| 			return callback(new Error('[[error:invalid-data]]')); | ||||
| 		} | ||||
|  | ||||
| 		var start = parseInt(data.after, 10); | ||||
| 		var stop = start + Math.max(0, Math.min(meta.config.topicsPerPage || 20, parseInt(data.count, 10) || meta.config.topicsPerPage || 20) - 1); | ||||
|  | ||||
| 		topics.getTopicsFromSet(data.set, socket.uid, start, stop, callback); | ||||
| 	}; | ||||
| }; | ||||
|   | ||||
| @@ -46,6 +46,7 @@ Topics.getTopicsFromSet = function (set, uid, start, stop, callback) { | ||||
| 			Topics.getTopics(tids, uid, next); | ||||
| 		}, | ||||
| 		function (topics, next) { | ||||
| 			Topics.calculateTopicIndices(topics, start); | ||||
| 			next(null, { topics: topics, nextStart: stop + 1 }); | ||||
| 		}, | ||||
| 	], callback); | ||||
| @@ -237,7 +238,7 @@ function getMainPostAndReplies(topic, set, uid, start, stop, reverse, callback) | ||||
| 				replies = posts.slice(1); | ||||
| 			} | ||||
|  | ||||
| 			Topics.calculatePostIndices(replies, start, stop, topic.postcount, reverse); | ||||
| 			Topics.calculatePostIndices(replies, start, topic.postcount, reverse); | ||||
|  | ||||
| 			Topics.addPostData(posts, uid, next); | ||||
| 		}, | ||||
|   | ||||
| @@ -37,7 +37,7 @@ module.exports = function (Topics) { | ||||
| 				}, next); | ||||
| 			}, | ||||
| 			function (results, next) { | ||||
| 				Topics.calculatePostIndices(results.posts, start, stop, results.postCount, reverse); | ||||
| 				Topics.calculatePostIndices(results.posts, start, results.postCount, reverse); | ||||
|  | ||||
| 				Topics.addPostData(results.posts, uid, next); | ||||
| 			}, | ||||
| @@ -183,7 +183,7 @@ module.exports = function (Topics) { | ||||
| 		], callback); | ||||
| 	}; | ||||
|  | ||||
| 	Topics.calculatePostIndices = function (posts, start, stop, postCount, reverse) { | ||||
| 	Topics.calculatePostIndices = function (posts, start, postCount, reverse) { | ||||
| 		posts.forEach(function (post, index) { | ||||
| 			if (reverse) { | ||||
| 				post.index = postCount - (start + index + 1); | ||||
|   | ||||
| @@ -178,11 +178,17 @@ module.exports = function (Topics) { | ||||
| 				Topics.getTopicsByTids(tids, params.uid, next); | ||||
| 			}, | ||||
| 			function (topicData, next) { | ||||
| 				topicData.forEach(function (topicObj, i) { | ||||
| 					topicObj.index = params.start + i; | ||||
| 				}); | ||||
| 				Topics.calculateTopicIndices(topicData, params.start); | ||||
| 				next(null, topicData); | ||||
| 			}, | ||||
| 		], callback); | ||||
| 	} | ||||
|  | ||||
| 	Topics.calculateTopicIndices = function (topicData, start) { | ||||
| 		topicData.forEach((topic, index) => { | ||||
| 			if (topic) { | ||||
| 				topic.index = start + index; | ||||
| 			} | ||||
| 		}); | ||||
| 	}; | ||||
| }; | ||||
|   | ||||
| @@ -468,6 +468,7 @@ describe('socket.io', function () { | ||||
| 	}); | ||||
|  | ||||
| 	it('should toggle plugin install', function (done) { | ||||
| 		this.timeout(0); | ||||
| 		socketAdmin.plugins.toggleInstall({ uid: adminUid }, { id: 'nodebb-plugin-location-to-map', version: 'latest' }, function (err, data) { | ||||
| 			assert.ifError(err); | ||||
| 			assert.equal(data.name, 'nodebb-plugin-location-to-map'); | ||||
|   | ||||
| @@ -1064,7 +1064,7 @@ describe('Topic\'s', function () { | ||||
| 		}); | ||||
|  | ||||
| 		it('should error with invalid data', function (done) { | ||||
| 			socketTopics.loadMoreUnreadTopics({ uid: adminUid }, { after: 'invalid' }, function (err) { | ||||
| 			socketTopics.loadMoreSortedTopics({ uid: adminUid }, { after: 'invalid' }, function (err) { | ||||
| 				assert.equal(err.message, '[[error:invalid-data]]'); | ||||
| 				done(); | ||||
| 			}); | ||||
| @@ -1073,7 +1073,7 @@ describe('Topic\'s', function () { | ||||
| 		it('should load more unread topics', function (done) { | ||||
| 			socketTopics.markUnread({ uid: adminUid }, tid, function (err) { | ||||
| 				assert.ifError(err); | ||||
| 				socketTopics.loadMoreUnreadTopics({ uid: adminUid }, { cid: topic.categoryId, after: 0, count: 10 }, function (err, data) { | ||||
| 				socketTopics.loadMoreSortedTopics({ uid: adminUid }, { cid: topic.categoryId, after: 0, count: 10, sort: 'unread' }, function (err, data) { | ||||
| 					assert.ifError(err); | ||||
| 					assert(data); | ||||
| 					assert(Array.isArray(data.topics)); | ||||
| @@ -1083,7 +1083,7 @@ describe('Topic\'s', function () { | ||||
| 		}); | ||||
|  | ||||
| 		it('should error with invalid data', function (done) { | ||||
| 			socketTopics.loadMoreRecentTopics({ uid: adminUid }, { after: 'invalid' }, function (err) { | ||||
| 			socketTopics.loadMoreSortedTopics({ uid: adminUid }, { after: 'invalid' }, function (err) { | ||||
| 				assert.equal(err.message, '[[error:invalid-data]]'); | ||||
| 				done(); | ||||
| 			}); | ||||
| @@ -1091,7 +1091,7 @@ describe('Topic\'s', function () { | ||||
|  | ||||
|  | ||||
| 		it('should load more recent topics', function (done) { | ||||
| 			socketTopics.loadMoreRecentTopics({ uid: adminUid }, { cid: topic.categoryId, after: 0, count: 10 }, function (err, data) { | ||||
| 			socketTopics.loadMoreSortedTopics({ uid: adminUid }, { cid: topic.categoryId, after: 0, count: 10, sort: 'recent' }, function (err, data) { | ||||
| 				assert.ifError(err); | ||||
| 				assert(data); | ||||
| 				assert(Array.isArray(data.topics)); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user