mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 03:26:04 +01:00
infinite scrolling for topics in category view, changed how topics are stored in categories, using sorted sets instead of sets now, if you update to this commit run node app --upgrade to upgrade the redis schema, #141
This commit is contained in:
@@ -6,7 +6,8 @@
|
|||||||
googleEl = document.getElementById('google-share'),
|
googleEl = document.getElementById('google-share'),
|
||||||
twitter_url = templates.get('twitter-intent-url'),
|
twitter_url = templates.get('twitter-intent-url'),
|
||||||
facebook_url = templates.get('facebook-share-url'),
|
facebook_url = templates.get('facebook-share-url'),
|
||||||
google_url = templates.get('google-share-url');
|
google_url = templates.get('google-share-url'),
|
||||||
|
loadingMoreTopics = false;
|
||||||
|
|
||||||
app.enter_room(room);
|
app.enter_room(room);
|
||||||
|
|
||||||
@@ -34,7 +35,8 @@
|
|||||||
'event:new_topic'
|
'event:new_topic'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
socket.on('event:new_topic', function(data) {
|
function onNewTopic(data) {
|
||||||
|
|
||||||
var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: [data] }),
|
var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: [data] }),
|
||||||
topic = document.createElement('div'),
|
topic = document.createElement('div'),
|
||||||
container = document.getElementById('topics-container'),
|
container = document.getElementById('topics-container'),
|
||||||
@@ -59,8 +61,9 @@
|
|||||||
container.insertBefore(topic, null);
|
container.insertBefore(topic, null);
|
||||||
$(topic).hide().fadeIn('slow');
|
$(topic).hide().fadeIn('slow');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
socket.on('event:new_topic', onNewTopic);
|
||||||
|
|
||||||
socket.emit('api:categories.getRecentReplies', cid);
|
socket.emit('api:categories.getRecentReplies', cid);
|
||||||
socket.on('api:categories.getRecentReplies', function(posts) {
|
socket.on('api:categories.getRecentReplies', function(posts) {
|
||||||
@@ -92,4 +95,40 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function onTopicsLoaded(topics) {
|
||||||
|
|
||||||
|
var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: topics }),
|
||||||
|
container = $('#topics-container');
|
||||||
|
|
||||||
|
jQuery('#topics-container, .category-sidebar').removeClass('hidden');
|
||||||
|
jQuery('#category-no-topics').remove();
|
||||||
|
|
||||||
|
container.append(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function loadMoreTopics(cid) {
|
||||||
|
loadingMoreTopics = true;
|
||||||
|
socket.emit('api:category.loadMore', {
|
||||||
|
cid: cid,
|
||||||
|
after: $('#topics-container').children().length
|
||||||
|
}, function(data) {
|
||||||
|
if(data.topics.length) {
|
||||||
|
onTopicsLoaded(data.topics);
|
||||||
|
loadingMoreTopics = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).off('scroll').on('scroll', function(ev) {
|
||||||
|
var windowHeight = document.body.offsetHeight - $(window).height(),
|
||||||
|
half = windowHeight / 2;
|
||||||
|
|
||||||
|
if (document.body.scrollTop > half && !loadingMoreTopics) {
|
||||||
|
loadMoreTopics(cid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
@@ -201,8 +201,7 @@
|
|||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
// Infinite scrolling of posts
|
// Infinite scrolling of posts
|
||||||
$(window).off('scroll');
|
$(window).off('scroll').on('scroll', function() {
|
||||||
$(window).on('scroll', function() {
|
|
||||||
var windowHeight = document.body.offsetHeight - $(window).height(),
|
var windowHeight = document.body.offsetHeight - $(window).height(),
|
||||||
half = windowHeight / 2;
|
half = windowHeight / 2;
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ var RDB = require('./redis.js'),
|
|||||||
category_description = categoryData.description;
|
category_description = categoryData.description;
|
||||||
|
|
||||||
function getTopicIds(next) {
|
function getTopicIds(next) {
|
||||||
Categories.getTopicIds(category_id, next);
|
Categories.getTopicIds(category_id, 0, 19, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveUsers(next) {
|
function getActiveUsers(next) {
|
||||||
Categories.getActiveUsers(category_id, next);
|
Categories.getActiveUsers(category_id, next);
|
||||||
}
|
}
|
||||||
@@ -44,15 +45,7 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
function getTopics(next) {
|
function getTopics(next) {
|
||||||
topics.getTopicsByTids(tids, current_user, function(topicsData) {
|
topics.getTopicsByTids(tids, current_user, function(topicsData) {
|
||||||
// Float pinned topics to the top
|
|
||||||
topicsData = topicsData.sort(function(a, b) {
|
|
||||||
if (a.pinned !== b.pinned) return b.pinned - a.pinned;
|
|
||||||
else {
|
|
||||||
return b.lastposttime - a.lastposttime;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
next(null, topicsData);
|
next(null, topicsData);
|
||||||
|
|
||||||
}, category_id);
|
}, category_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,8 +82,16 @@ var RDB = require('./redis.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.getTopicIds = function(cid, callback) {
|
Categories.getCategoryTopics = function(cid, start, stop, uid, callback) {
|
||||||
RDB.smembers('categories:' + cid + ':tid', callback);
|
Categories.getTopicIds(cid, start, stop, function(err, tids) {
|
||||||
|
topics.getTopicsByTids(tids, uid, function(topicsData) {
|
||||||
|
callback(topicsData);
|
||||||
|
}, cid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Categories.getTopicIds = function(cid, start, stop, callback) {
|
||||||
|
RDB.zrevrange('categories:' + cid + ':tid', start, stop, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.getActiveUsers = function(cid, callback) {
|
Categories.getActiveUsers = function(cid, callback) {
|
||||||
@@ -144,7 +145,7 @@ var RDB = require('./redis.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
Categories.isTopicsRead = function(cid, uid, callback) {
|
Categories.isTopicsRead = function(cid, uid, callback) {
|
||||||
RDB.smembers('categories:' + cid + ':tid', function(err, tids) {
|
RDB.zrange('categories:' + cid + ':tid', 0, -1, function(err, tids) {
|
||||||
|
|
||||||
topics.hasReadTopics(tids, uid, function(hasRead) {
|
topics.hasReadTopics(tids, uid, function(hasRead) {
|
||||||
|
|
||||||
|
|||||||
46
src/posts.js
46
src/posts.js
@@ -108,6 +108,20 @@ var RDB = require('./redis.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Posts.getPostField = function(pid, field, callback) {
|
||||||
|
RDB.hget('post:' + pid, field, function(err, data) {
|
||||||
|
if(err === null)
|
||||||
|
callback(data);
|
||||||
|
else
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Posts.setPostField = function(pid, field, value) {
|
||||||
|
RDB.hset('post:' + pid, field, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Posts.getPostsByPids = function(pids, callback) {
|
Posts.getPostsByPids = function(pids, callback) {
|
||||||
var posts = [];
|
var posts = [];
|
||||||
|
|
||||||
@@ -141,35 +155,6 @@ var RDB = require('./redis.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Posts.getPostField = function(pid, field, callback) {
|
|
||||||
RDB.hget('post:' + pid, field, function(err, data) {
|
|
||||||
if(err === null)
|
|
||||||
callback(data);
|
|
||||||
else
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Posts.setPostField = function(pid, field, value) {
|
|
||||||
RDB.hset('post:' + pid, field, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Posts.getPostFields = function(pid, fields, callback) {
|
|
||||||
RDB.hmget('post:' + pid, fields, function(err, data) {
|
|
||||||
if(err === null) {
|
|
||||||
var returnData = {};
|
|
||||||
|
|
||||||
for(var i=0, ii=fields.length; i<ii; ++i) {
|
|
||||||
returnData[fields[i]] = data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(returnData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Posts.get_cid_by_pid = function(pid, callback) {
|
Posts.get_cid_by_pid = function(pid, callback) {
|
||||||
Posts.getPostField(pid, 'tid', function(tid) {
|
Posts.getPostField(pid, 'tid', function(tid) {
|
||||||
if (tid) {
|
if (tid) {
|
||||||
@@ -317,7 +302,8 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
feed.updateTopic(tid, cid);
|
feed.updateTopic(tid, cid);
|
||||||
|
|
||||||
RDB.zadd('categories:recent_posts:cid:' + cid, Date.now(), pid);
|
RDB.zadd('categories:recent_posts:cid:' + cid, timestamp, pid);
|
||||||
|
RDB.zadd('categories:' + cid + ':tid', timestamp, tid);
|
||||||
|
|
||||||
// this is a bit of a naive implementation, defn something to look at post-MVP
|
// this is a bit of a naive implementation, defn something to look at post-MVP
|
||||||
RDB.scard('cid:' + cid + ':active_users', function(amount) {
|
RDB.scard('cid:' + cid + ':active_users', function(amount) {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
(function(RedisDB) {
|
(function(RedisDB) {
|
||||||
var redis = require('redis'),
|
var redis = require('redis'),
|
||||||
|
nconf = require('nconf'),
|
||||||
utils = require('./../public/src/utils.js');
|
utils = require('./../public/src/utils.js');
|
||||||
|
|
||||||
RedisDB.exports = redis.createClient(global.nconf.get('redis:port'), global.nconf.get('redis:host'));
|
RedisDB.exports = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host'));
|
||||||
|
|
||||||
if( global.nconf.get('redis:password') ) {
|
if(nconf.get('redis:password')) {
|
||||||
RedisDB.exports.auth(global.nconf.get('redis:password'));
|
RedisDB.exports.auth(nconf.get('redis:password'));
|
||||||
}
|
}
|
||||||
|
|
||||||
RedisDB.exports.handle = function(error) {
|
RedisDB.exports.handle = function(error) {
|
||||||
|
|||||||
@@ -133,6 +133,9 @@ var RDB = require('./redis.js'),
|
|||||||
if (privileges.editable) {
|
if (privileges.editable) {
|
||||||
|
|
||||||
topics.setTopicField(tid, 'pinned', 1);
|
topics.setTopicField(tid, 'pinned', 1);
|
||||||
|
topics.getTopicField(tid, 'cid', function(cid) {
|
||||||
|
RDB.zadd('categories:' + cid + ':tid', Math.pow(2,53), tid);
|
||||||
|
});
|
||||||
|
|
||||||
if (socket) {
|
if (socket) {
|
||||||
io.sockets.in('topic_' + tid).emit('event:topic_pinned', {
|
io.sockets.in('topic_' + tid).emit('event:topic_pinned', {
|
||||||
@@ -154,7 +157,9 @@ var RDB = require('./redis.js'),
|
|||||||
if (privileges.editable) {
|
if (privileges.editable) {
|
||||||
|
|
||||||
topics.setTopicField(tid, 'pinned', 0);
|
topics.setTopicField(tid, 'pinned', 0);
|
||||||
|
topics.getTopicFields(tid, ['cid', 'lastposttime'], function(topicData) {
|
||||||
|
RDB.zadd('categories:' + topicData.cid + ':tid', topicData.lastposttime, tid);
|
||||||
|
});
|
||||||
if (socket) {
|
if (socket) {
|
||||||
io.sockets.in('topic_' + tid).emit('event:topic_unpinned', {
|
io.sockets.in('topic_' + tid).emit('event:topic_unpinned', {
|
||||||
tid: tid,
|
tid: tid,
|
||||||
@@ -172,9 +177,15 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
ThreadTools.move = function(tid, cid, socket) {
|
ThreadTools.move = function(tid, cid, socket) {
|
||||||
|
|
||||||
topics.getTopicField(tid, 'cid', function(oldCid) {
|
topics.getTopicFields(tid, ['cid', 'lastposttime'], function(topicData) {
|
||||||
|
var oldCid = topicData.cid;
|
||||||
|
var multi = RDB.multi();
|
||||||
|
|
||||||
|
multi.zrem('categories:' + oldCid + ':tid', tid);
|
||||||
|
multi.zadd('categories:' + cid + ':tid', topicData.lastposttime, tid);
|
||||||
|
|
||||||
|
multi.exec(function(err, result) {
|
||||||
|
|
||||||
RDB.smove('categories:' + oldCid + ':tid', 'categories:' + cid + ':tid', tid, function(err, result) {
|
|
||||||
if (!err && result === 1) {
|
if (!err && result === 1) {
|
||||||
|
|
||||||
topics.setTopicField(tid, 'cid', cid);
|
topics.setTopicField(tid, 'cid', cid);
|
||||||
|
|||||||
@@ -628,7 +628,7 @@ marked.setOptions({
|
|||||||
|
|
||||||
|
|
||||||
// in future it may be possible to add topics to several categories, so leaving the door open here.
|
// in future it may be possible to add topics to several categories, so leaving the door open here.
|
||||||
RDB.sadd('categories:' + category_id + ':tid', tid);
|
RDB.zadd('categories:' + category_id + ':tid', timestamp, tid);
|
||||||
RDB.hincrby('category:' + category_id, 'topic_count', 1);
|
RDB.hincrby('category:' + category_id, 'topic_count', 1);
|
||||||
RDB.incr('totaltopiccount');
|
RDB.incr('totaltopiccount');
|
||||||
|
|
||||||
@@ -653,6 +653,17 @@ marked.setOptions({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Topics.getTopicFields = function(tid, fields, callback) {
|
||||||
|
RDB.hmgetObject('topic:' + tid, fields, function(err, data) {
|
||||||
|
if(err === null) {
|
||||||
|
callback(data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Topics.setTopicField = function(tid, field, value) {
|
Topics.setTopicField = function(tid, field, value) {
|
||||||
RDB.hset('topic:' + tid, field, value);
|
RDB.hset('topic:' + tid, field, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,74 @@
|
|||||||
|
var RDB = require('./redis.js'),
|
||||||
|
async = require('async');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function upgradeCategory(cid, callback) {
|
||||||
|
RDB.type('categories:'+ cid +':tid', function(err, type) {
|
||||||
|
if (type === 'set') {
|
||||||
|
RDB.smembers('categories:' + cid + ':tid', function(err, tids) {
|
||||||
|
|
||||||
|
function moveTopic(tid, callback) {
|
||||||
|
RDB.hget('topic:' + tid, 'timestamp', function(err, timestamp) {
|
||||||
|
if(err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
RDB.zadd('temp_categories:'+ cid + ':tid', timestamp, tid);
|
||||||
|
callback(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async.each(tids, moveTopic, function(err) {
|
||||||
|
if(!err) {
|
||||||
|
console.log('renaming ' + cid);
|
||||||
|
RDB.rename('temp_categories:' + cid + ':tid', 'categories:' + cid + ':tid');
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('category already upgraded '+ cid);
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
exports.upgrade = function() {
|
exports.upgrade = function() {
|
||||||
|
|
||||||
console.log('upgrading nodebb now');
|
console.log('upgrading nodebb now');
|
||||||
|
|
||||||
|
var schema = [
|
||||||
|
function upgradeCategories(next) {
|
||||||
|
console.log('upgrading categories');
|
||||||
|
|
||||||
|
RDB.lrange('categories:cid', 0, -1, function(err, cids) {
|
||||||
|
|
||||||
|
async.each(cids, upgradeCategory, function(err) {
|
||||||
|
if(!err)
|
||||||
|
next(null, 'upgraded categories');
|
||||||
|
else
|
||||||
|
next(err, null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function upgradeUsers(next) {
|
||||||
|
console.log('upgrading users');
|
||||||
|
next(null, 'upgraded users');
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
async.series(schema, function(err, results) {
|
||||||
|
if(!err)
|
||||||
|
console.log('upgrade complete');
|
||||||
|
else
|
||||||
|
console.log(err);
|
||||||
|
|
||||||
|
process.exit();
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -554,13 +554,22 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
|
|
||||||
socket.on('api:topic.loadMore', function(data, callback) {
|
socket.on('api:topic.loadMore', function(data, callback) {
|
||||||
var start = data.after,
|
var start = data.after,
|
||||||
end = start + 10;
|
end = start + 9;
|
||||||
|
|
||||||
topics.getTopicPosts(data.tid, start, end, uid, function(posts) {
|
topics.getTopicPosts(data.tid, start, end, uid, function(posts) {
|
||||||
callback({posts:posts});
|
callback({posts:posts});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('api:category.loadMore', function(data, callback) {
|
||||||
|
var start = data.after,
|
||||||
|
end = start + 9;
|
||||||
|
|
||||||
|
categories.getCategoryTopics(data.cid, start, end, uid, function(topics) {
|
||||||
|
callback({topics:topics});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
socket.on('api:admin.topics.getMore', function(data) {
|
socket.on('api:admin.topics.getMore', function(data) {
|
||||||
topics.getAllTopics(data.limit, data.after, function(topics) {
|
topics.getAllTopics(data.limit, data.after, function(topics) {
|
||||||
socket.emit('api:admin.topics.getMore', JSON.stringify(topics));
|
socket.emit('api:admin.topics.getMore', JSON.stringify(topics));
|
||||||
|
|||||||
Reference in New Issue
Block a user