mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-02 12:05:57 +01:00
search newer/older than and better pagination
This commit is contained in:
@@ -8,5 +8,16 @@
|
||||
"search-child-categories": "Search child categories",
|
||||
"reply-count": "Reply Count",
|
||||
"at-least": "At least",
|
||||
"at-most": "At most"
|
||||
"at-most": "At most",
|
||||
"post-time": "Post time",
|
||||
"newer-than": "Newer than",
|
||||
"older-than": "Older than",
|
||||
"any-date": "Any date",
|
||||
"yesterday": "Yesterday",
|
||||
"one-week": "One week",
|
||||
"two-weeks": "Two weeks",
|
||||
"one-month": "One month",
|
||||
"three-months": "Three months",
|
||||
"six-months": "Six months",
|
||||
"one-year": "One year"
|
||||
}
|
||||
|
||||
@@ -9,29 +9,10 @@ define('forum/search', ['search'], function(searchModule) {
|
||||
var searchQuery = $('#results').attr('data-search-query');
|
||||
|
||||
$('#advanced-search #search-input').val(searchQuery);
|
||||
var params = utils.params();
|
||||
|
||||
var searchIn = $('#advanced-search #search-in');
|
||||
if (params && params.in) {
|
||||
searchIn.val(params.in);
|
||||
$('.post-search-item').toggleClass('hide', params.in !== 'posts');
|
||||
}
|
||||
|
||||
if (params && params.by) {
|
||||
$('#posted-by-user').val(params.by);
|
||||
}
|
||||
|
||||
if (params && (params['categories[]'] || params.categories)) {
|
||||
$('#posted-in-categories').val(params['categories[]'] || params.categories);
|
||||
}
|
||||
|
||||
if (params && params.searchChildren) {
|
||||
$('#search-children').prop('checked', true);
|
||||
}
|
||||
|
||||
if (params && params.replies) {
|
||||
$('#reply-count').val(params.replies);
|
||||
$('#reply-count-filter').val(params.repliesFilter);
|
||||
}
|
||||
fillOutFormFromQueryParams();
|
||||
|
||||
searchIn.on('change', function() {
|
||||
$('.post-search-item').toggleClass('hide', searchIn.val() !== 'posts');
|
||||
@@ -50,7 +31,9 @@ define('forum/search', ['search'], function(searchModule) {
|
||||
categories: $(this).find('#posted-in-categories').val(),
|
||||
searchChildren: $(this).find('#search-children').is(':checked'),
|
||||
replies: $(this).find('#reply-count').val(),
|
||||
repliesFilter: $(this).find('#reply-count-filter').val()
|
||||
repliesFilter: $(this).find('#reply-count-filter').val(),
|
||||
timeFilter: $(this).find('#post-time-filter').val(),
|
||||
timeRange: $(this).find('#post-time-range').val()
|
||||
}, function() {
|
||||
input.val('');
|
||||
});
|
||||
@@ -59,6 +42,38 @@ define('forum/search', ['search'], function(searchModule) {
|
||||
enableAutoComplete();
|
||||
};
|
||||
|
||||
function fillOutFormFromQueryParams() {
|
||||
var params = utils.params();
|
||||
if (params) {
|
||||
if (params.in) {
|
||||
$('#search-in').val(params.in);
|
||||
$('.post-search-item').toggleClass('hide', params.in !== 'posts');
|
||||
}
|
||||
|
||||
if (params.by) {
|
||||
$('#posted-by-user').val(params.by);
|
||||
}
|
||||
|
||||
if ((params['categories[]'] || params.categories)) {
|
||||
$('#posted-in-categories').val(params['categories[]'] || params.categories);
|
||||
}
|
||||
|
||||
if (params.searchChildren) {
|
||||
$('#search-children').prop('checked', true);
|
||||
}
|
||||
|
||||
if (params.replies) {
|
||||
$('#reply-count').val(params.replies);
|
||||
$('#reply-count-filter').val(params.repliesFilter);
|
||||
}
|
||||
|
||||
if (params.timeRange) {
|
||||
$('#post-time-range').val(params.timeRange);
|
||||
$('#post-time-filter').val(params.timeFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function highlightMatches(searchQuery) {
|
||||
var searchTerms = searchQuery.split(' ');
|
||||
var regexes = [];
|
||||
|
||||
@@ -40,6 +40,11 @@ define('search', ['navigator'], function(nav) {
|
||||
query.repliesFilter = data.repliesFilter || 'atleast';
|
||||
}
|
||||
|
||||
if (data.timeRange) {
|
||||
query.timeRange = data.timeRange;
|
||||
query.timeFilter = data.timeFilter || 'newer';
|
||||
}
|
||||
|
||||
ajaxify.go('search/' + term + '?' + decodeURIComponent($.param(query)));
|
||||
callback();
|
||||
} else {
|
||||
|
||||
@@ -260,8 +260,7 @@ categoriesController.get = function(req, res, next) {
|
||||
data.currentPage = page;
|
||||
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
||||
data['rssFeedUrl'] = nconf.get('relative_path') + '/category/' + data.cid + '.rss';
|
||||
|
||||
pagination.create(data.currentPage, data.pageCount, data);
|
||||
data.pagination = pagination.create(data.currentPage, data.pageCount);
|
||||
|
||||
data.pagination.rel.forEach(function(rel) {
|
||||
res.locals.linkTags.push(rel);
|
||||
|
||||
@@ -37,6 +37,7 @@ searchController.search = function(req, res, next) {
|
||||
}
|
||||
|
||||
req.params.term = validator.escape(req.params.term);
|
||||
var page = Math.max(1, parseInt(req.query.page, 10)) || 1;
|
||||
|
||||
search.search({
|
||||
query: req.params.term,
|
||||
@@ -46,18 +47,17 @@ searchController.search = function(req, res, next) {
|
||||
searchChildren: req.query.searchChildren,
|
||||
replies: req.query.replies,
|
||||
repliesFilter: req.query.repliesFilter,
|
||||
timeRange: req.query.timeRange,
|
||||
timeFilter: req.query.timeFilter,
|
||||
page: page,
|
||||
uid: uid
|
||||
}, function(err, results) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
var currentPage = Math.max(1, parseInt(req.query.page, 10)) || 1;
|
||||
var pageCount = Math.max(1, Math.ceil(results.matchCount / 10));
|
||||
var searchIn = req.query.in || 'posts';
|
||||
var start = Math.max(0, (currentPage - 1)) * 10;
|
||||
results[searchIn] = results[searchIn].slice(start, start + 10);
|
||||
|
||||
pagination.create(currentPage, pageCount, results, req.query);
|
||||
var pageCount = Math.max(1, Math.ceil(results.matchCount / 10));
|
||||
results.pagination = pagination.create(page, pageCount, req.query);
|
||||
|
||||
results.breadcrumbs = breadcrumbs;
|
||||
results.categories = categories;
|
||||
|
||||
@@ -256,15 +256,12 @@ topicsController.get = function(req, res, next) {
|
||||
data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1;
|
||||
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
||||
data['rssFeedUrl'] = nconf.get('relative_path') + '/topic/' + data.tid + '.rss';
|
||||
|
||||
topics.increaseViewCount(tid);
|
||||
|
||||
pagination.create(data.currentPage, data.pageCount, data);
|
||||
|
||||
data.pagination = pagination.create(data.currentPage, data.pageCount);
|
||||
data.pagination.rel.forEach(function(rel) {
|
||||
res.locals.linkTags.push(rel);
|
||||
});
|
||||
|
||||
topics.increaseViewCount(tid);
|
||||
res.render('topic', data);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -4,15 +4,14 @@ var qs = require('querystring');
|
||||
|
||||
var pagination = {};
|
||||
|
||||
pagination.create = function(currentPage, pageCount, data, queryObj) {
|
||||
pagination.create = function(currentPage, pageCount, queryObj) {
|
||||
if (pageCount <= 1) {
|
||||
data.pagination = {
|
||||
return {
|
||||
prev: {page: 1, active: currentPage > 1},
|
||||
next: {page: 1, active: currentPage < pageCount},
|
||||
rel: [],
|
||||
pages: []
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
var pagesToShow = [1];
|
||||
@@ -43,7 +42,7 @@ pagination.create = function(currentPage, pageCount, data, queryObj) {
|
||||
return {page: page, active: page === currentPage, qs: qs.stringify(queryObj)};
|
||||
});
|
||||
|
||||
data.pagination = {
|
||||
var data = {
|
||||
prev: {page: previous, active: currentPage > 1},
|
||||
next: {page: next, active: currentPage < pageCount},
|
||||
rel: [],
|
||||
@@ -51,19 +50,19 @@ pagination.create = function(currentPage, pageCount, data, queryObj) {
|
||||
};
|
||||
|
||||
if (currentPage < pageCount) {
|
||||
data.pagination.rel.push({
|
||||
data.rel.push({
|
||||
rel: 'next',
|
||||
href: '?page=' + next
|
||||
});
|
||||
}
|
||||
|
||||
if (currentPage > 1) {
|
||||
data.pagination.rel.push({
|
||||
data.rel.push({
|
||||
rel: 'prev',
|
||||
href: '?page=' + previous
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
175
src/search.js
175
src/search.js
@@ -1,6 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async'),
|
||||
|
||||
db = require('./database'),
|
||||
posts = require('./posts'),
|
||||
topics = require('./topics'),
|
||||
categories = require('./categories'),
|
||||
@@ -19,8 +21,8 @@ search.search = function(data, callback) {
|
||||
}
|
||||
|
||||
result.search_query = query;
|
||||
result[searchIn] = data;
|
||||
result.matchCount = data.length;
|
||||
result[searchIn] = data.matches;
|
||||
result.matchCount = data.matchCount;
|
||||
result.hidePostedBy = searchIn !== 'posts';
|
||||
result.time = (process.elapsedTimeSince(start) / 1000).toFixed(2);
|
||||
callback(null, result);
|
||||
@@ -65,8 +67,9 @@ function searchInPosts(query, data, callback) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var matchCount = 0;
|
||||
if (!results || (!results.pids.length && !results.tids.length)) {
|
||||
return callback(null, []);
|
||||
return callback(null, {matches: [], matchCount: matchCount});
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
@@ -82,31 +85,162 @@ function searchInPosts(query, data, callback) {
|
||||
privileges.posts.filter('read', mainPids, data.uid, next);
|
||||
},
|
||||
function(pids, next) {
|
||||
filterAndSort(pids, data, results.searchCategories, next);
|
||||
},
|
||||
function(pids, next) {
|
||||
matchCount = pids.length;
|
||||
if (data.page) {
|
||||
var start = Math.max(0, (data.page - 1)) * 10;
|
||||
pids = pids.slice(start, start + 10);
|
||||
}
|
||||
|
||||
posts.getPostSummaryByPids(pids, data.uid, {stripTags: true, parse: false}, next);
|
||||
},
|
||||
function(posts, next) {
|
||||
posts = filterPosts(data, results.searchCategories, posts);
|
||||
next(null, posts);
|
||||
next(null, {matches: posts, matchCount: matchCount});
|
||||
}
|
||||
], callback);
|
||||
});
|
||||
}
|
||||
|
||||
function filterPosts(data, searchCategories, posts) {
|
||||
var postedBy = data.postedBy;
|
||||
var isAtLeast = data.repliesFilter === 'atleast';
|
||||
data.replies = parseInt(data.replies, 10);
|
||||
if (postedBy || searchCategories.length || data.replies) {
|
||||
function filterAndSort(pids, data, searchCategories, callback) {
|
||||
var postFields = ['pid', 'tid', 'timestamp'];
|
||||
var topicFields = [];
|
||||
|
||||
if (data.postedBy) {
|
||||
postFields.push('uid');
|
||||
}
|
||||
|
||||
if (searchCategories.length) {
|
||||
topicFields.push('cid');
|
||||
}
|
||||
|
||||
if (data.replies) {
|
||||
topicFields.push('postcount');
|
||||
}
|
||||
|
||||
async.parallel({
|
||||
posts: function(next) {
|
||||
getMatchedPosts(pids, postFields, topicFields, next);
|
||||
},
|
||||
postedByUid: function(next) {
|
||||
if (data.postedBy) {
|
||||
user.getUidByUsername(data.postedBy, next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
}, function(err, results) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
if (!results.posts) {
|
||||
return callback(null, pids);
|
||||
}
|
||||
var posts = results.posts.filter(Boolean);
|
||||
|
||||
posts = filterByUser(posts, results.postedByUid);
|
||||
posts = filterByCategories(posts, searchCategories);
|
||||
posts = filterByPostcount(posts, data.replies, data.repliesFilter);
|
||||
posts = filterByTimerange(posts, data.timeRange, data.timeFilter);
|
||||
|
||||
sortPosts(posts, data);
|
||||
|
||||
pids = posts.map(function(post) {
|
||||
return post && post.pid;
|
||||
});
|
||||
|
||||
callback(null, pids);
|
||||
});
|
||||
}
|
||||
|
||||
function getMatchedPosts(pids, postFields, topicFields, callback) {
|
||||
var keys = pids.map(function(pid) {
|
||||
return 'post:' + pid;
|
||||
});
|
||||
var posts;
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
db.getObjectsFields(keys, postFields, next);
|
||||
},
|
||||
function(_posts, next) {
|
||||
posts = _posts;
|
||||
if (!topicFields.length) {
|
||||
return callback(null, posts);
|
||||
}
|
||||
var topicKeys = posts.map(function(post) {
|
||||
return 'topic:' + post.tid;
|
||||
});
|
||||
db.getObjectsFields(topicKeys, topicFields, next);
|
||||
},
|
||||
function(topics, next) {
|
||||
posts.forEach(function(post, index) {
|
||||
post.topic = topics[index];
|
||||
});
|
||||
|
||||
next(null, posts);
|
||||
}
|
||||
], callback);
|
||||
}
|
||||
|
||||
function filterByUser(posts, postedByUid) {
|
||||
if (postedByUid) {
|
||||
postedByUid = parseInt(postedByUid, 10);
|
||||
posts = posts.filter(function(post) {
|
||||
return post &&
|
||||
(postedBy ? post.user && (post.user.username === postedBy) : true) &&
|
||||
(searchCategories.length ? (post.category && searchCategories.indexOf(post.category.cid) !== -1) : true) &&
|
||||
(data.replies ? (isAtLeast ? post.topic.postcount >= data.replies : post.topic.postcount <= data.replies) : true);
|
||||
return parseInt(post.uid, 10) === postedByUid;
|
||||
});
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
function filterByCategories(posts, searchCategories) {
|
||||
if (searchCategories.length) {
|
||||
posts = posts.filter(function(post) {
|
||||
return post.topic && searchCategories.indexOf(post.topic.cid) !== -1;
|
||||
});
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
function filterByPostcount(posts, postCount, repliesFilter) {
|
||||
postCount = parseInt(postCount, 10);
|
||||
if (postCount) {
|
||||
if (repliesFilter === 'atleast') {
|
||||
posts = posts.filter(function(post) {
|
||||
return post.topic && post.topic.postcount >= postCount;
|
||||
});
|
||||
} else {
|
||||
posts = posts.filter(function(post) {
|
||||
return post.topic && post.topic.postcount <= postCount;
|
||||
});
|
||||
}
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
function filterByTimerange(posts, timeRange, timeFilter) {
|
||||
timeRange = parseInt(timeRange) * 1000;
|
||||
if (timeRange) {
|
||||
var time = Date.now() - timeRange;
|
||||
if (timeFilter === 'newer') {
|
||||
posts = posts.filter(function(post) {
|
||||
return post.timestamp >= time;
|
||||
});
|
||||
} else {
|
||||
posts = posts.filter(function(post) {
|
||||
return post.timestamp <= time;
|
||||
});
|
||||
}
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
function sortPosts(posts, data) {
|
||||
posts.sort(function(p1, p2) {
|
||||
return p2.timestamp - p1.timestamp;
|
||||
});
|
||||
}
|
||||
|
||||
function getSearchCategories(data, callback) {
|
||||
if (!Array.isArray(data.categories) || !data.categories.length || data.categories.indexOf('all') !== -1) {
|
||||
return callback(null, []);
|
||||
@@ -159,12 +293,21 @@ function getChildrenCids(cids, uid, callback) {
|
||||
|
||||
function searchInUsers(query, callback) {
|
||||
user.search({query: query}, function(err, results) {
|
||||
callback(err, results ? results.users : null);
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback(null, {matches: results.users, matchCount: results.matchCount});
|
||||
});
|
||||
}
|
||||
|
||||
function searchInTags(query, callback) {
|
||||
topics.searchAndLoadTags({query: query}, callback);
|
||||
topics.searchAndLoadTags({query: query}, function(err, tags) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, {matches: tags, matchCount: tags.length});
|
||||
});
|
||||
}
|
||||
|
||||
function getMainPids(tids, callback) {
|
||||
|
||||
@@ -60,7 +60,7 @@ module.exports = function(User) {
|
||||
|
||||
var currentPage = Math.max(1, Math.ceil((start + 1) / resultsPerPage));
|
||||
pageCount = Math.ceil(matchCount / resultsPerPage);
|
||||
pagination.create(currentPage, pageCount, data);
|
||||
data.pagination = pagination.create(currentPage, pageCount);
|
||||
|
||||
next(null, data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user