You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nodebb/public/src/modules/topicList.js

284 lines
7.9 KiB
JavaScript

'use strict';
6 years ago
define('topicList', [
'forum/infinitescroll',
'handleBack',
'topicSelect',
'categoryFilter',
'forum/category/tools',
], function (infinitescroll, handleBack, topicSelect, categoryFilter, categoryTools) {
var TopicList = {};
var templateName = '';
var tplToSort = {
recent: 'recent',
unread: 'unread',
popular: 'posts',
top: 'votes',
};
var newTopicCount = 0;
var newPostCount = 0;
var loadTopicsCallback;
6 years ago
var topicListEl;
const scheduledTopics = [];
$(window).on('action:ajaxify.start', function () {
TopicList.removeListeners();
categoryTools.removeListeners();
});
TopicList.init = function (template, cb) {
6 years ago
topicListEl = findTopicListElement();
templateName = template;
6 years ago
loadTopicsCallback = cb || loadTopicsAfter;
categoryTools.init();
TopicList.watchForNewPosts();
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
4 years ago
var states = ['watching'];
if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') {
states.push('notwatching', 'ignoring');
} else if (template !== 'unread') {
states.push('notwatching');
}
Categories refactor (#9257) * feat: wip categories pagination * feat: add subCategoriesPerPage setting * feat: add load more sub categories button to category page * fix: openapi spec * feat: show sub categories left on category page hide button when no more categories left * breaking: rename categories to allCategories on /search categories contains the search results * fix: spec * refactor: remove cidsPerPage * fix: tests * feat: use component for subcategories * fix: prevent negative subCategoriesLeft * feat: new category filter/search WIP * feat: remove categories from /tag * fix: dont load all categories when showing move modal * feat: allow adding custom categories to list * breaking: dont load entire category tree on post queue removed unused code add hooks to filter/selector add options to filter/selector * feat: make selector modal work again * feat: replace old search module * fix: topic move selector * feat: dont load all categories on create category modal * fix: fix more categorySelectors * feat: dont load entire category tree on group details page * feat: dont load all categories on home page and user settings page * feat: add pagination to /user/:userslug/categories * fix: update schemas * fix: more tests * fix: test * feat: flags page, dont return entire category tree * fix: flag test * feat: categories manage page dont load all categories allow changing root category clear caches properly * fix: spec * feat: admins&mods page dont load all categories * fix: spec * fix: dont load all children when opening dropdown * fix: on search results dont return all children * refactor: pass all options, rename options.cids to options.selectedCids * fix: #9266 * fix: index 0 * fix: spec * feat: #9265, add setObjectBulk * refactor: shoter updateOrder * feat: selectors on categories/category * fix: tests and search filter * fix: category update test * feat: pagination on acp categories page show order in set order modal * fix: allow drag&drop on pages > 1 in /admin/manage/categories * fix: teasers for deep nested categories fix sub category display on /category page * fix: spec * refactor: use eslint-disable-next-line * refactor: shorter
4 years ago
categoryFilter.init($('[component="category/dropdown"]'), {
states: states,
});
if (!config.usePagination) {
infinitescroll.init(TopicList.loadMoreTopics);
}
6 years ago
handleBack.init(function (after, handleBackCallback) {
loadTopicsCallback(after, 1, function (data, loadCallback) {
TopicList.onTopicsLoaded(templateName, data.topics, ajaxify.data.showSelect, 1, function () {
handleBackCallback();
loadCallback();
});
});
});
6 years ago
if ($('body').height() <= $(window).height() && topicListEl.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 });
};
6 years ago
function findTopicListElement() {
return $('[component="category"]').filter(function (i, e) {
return !$(e).parents('[widget-area],[data-widget-area]').length;
6 years ago
});
}
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) {
const d = ajaxify.data;
const categories = d.selectedCids &&
d.selectedCids.length &&
d.selectedCids.indexOf(parseInt(data.cid, 10)) === -1;
const filterWatched = d.selectedFilter &&
d.selectedFilter.filter === 'watched';
const category = d.template.category &&
parseInt(d.cid, 10) !== parseInt(data.cid, 10);
if (categories || filterWatched || category || scheduledTopics.includes(data.tid)) {
return;
}
if (data.scheduled && data.tid) {
scheduledTopics.push(data.tid);
}
newTopicCount += 1;
updateAlertText();
}
function onNewPost(data) {
var post = data.posts[0];
if (!post || !post.topic || post.topic.isFollowing) {
return;
}
const d = ajaxify.data;
const isMain = parseInt(post.topic.mainPid, 10) === parseInt(post.pid, 10);
const categories = d.selectedCids &&
d.selectedCids.length &&
d.selectedCids.indexOf(parseInt(post.topic.cid, 10)) === -1;
const filterNew = d.selectedFilter &&
d.selectedFilter.filter === 'new';
const filterWatched = d.selectedFilter &&
d.selectedFilter.filter === 'watched' &&
!post.topic.isFollowing;
const category = d.template.category &&
parseInt(d.cid, 10) !== parseInt(post.topic.cid, 10);
if (isMain || categories || filterNew || filterWatched || category) {
return;
}
newPostCount += 1;
updateAlertText();
}
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.loadMoreTopics = function (direction) {
6 years ago
if (!topicListEl.length || !topicListEl.children().length) {
return;
}
6 years ago
var topics = topicListEl.find('[component="category/topic"]');
var afterEl = direction > 0 ? topics.last() : topics.first();
var after = (parseInt(afterEl.attr('data-index'), 10) || 0) + (direction > 0 ? 1 : 0);
6 years ago
if (!utils.isNumber(after) || (after === 0 && topicListEl.find('[component="category/topic"][data-index="0"]').length)) {
return;
}
6 years ago
loadTopicsCallback(after, direction, function (data, done) {
TopicList.onTopicsLoaded(templateName, data.topics, ajaxify.data.showSelect, direction, done);
});
};
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,
tags: query.tags,
query: query,
6 years ago
term: ajaxify.data.selectedTerm && ajaxify.data.selectedTerm.term,
filter: ajaxify.data.selectedFilter.filter,
6 years ago
set: topicListEl.attr('data-set') ? topicListEl.attr('data-set') : 'topics:recent',
}, callback);
}
6 years ago
function filterTopicsOnDom(topics) {
return topics.filter(function (topic) {
6 years ago
return !topicListEl.find('[component="category/topic"][data-tid="' + topic.tid + '"]').length;
});
6 years ago
}
TopicList.onTopicsLoaded = function (templateName, topics, showSelect, direction, callback) {
if (!topics || !topics.length) {
$('#load-more-btn').hide();
return callback();
}
topics = filterTopicsOnDom(topics);
if (!topics.length) {
6 years ago
$('#load-more-btn').hide();
return callback();
}
var after;
var before;
6 years ago
var topicEls = topicListEl.find('[component="category/topic"]');
if (direction > 0 && topics.length) {
6 years ago
after = topicEls.last();
} else if (direction < 0 && topics.length) {
6 years ago
before = topicEls.first();
}
var tplData = {
topics: topics,
showSelect: showSelect,
template: {
name: templateName,
},
};
tplData.template[templateName] = true;
app.parseAndTranslate(templateName, 'topics', tplData, function (html) {
6 years ago
topicListEl.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 {
6 years ago
topicListEl.append(html);
}
if (!topicSelect.getSelectedTids().length) {
4 years ago
infinitescroll.removeExtra(topicListEl.find('[component="category/topic"]'), direction, Math.max(60, config.topicsPerPage * 3));
}
html.find('.timeago').timeago();
6 years ago
app.createUserTooltips(html);
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
$(window).trigger('action:topics.loaded', { topics: topics, template: templateName });
callback();
});
};
return TopicList;
});