revamped handling of unread messages, so that a socket call is made to all socket clients whenever a new unread message is available. Prior behaviour had the unread count updated via ajax call on ajaxify (which was clumsy at best and didn't update automagically)

v1.18.x
Julian Lam 11 years ago
parent 43b012b32e
commit d9ee9bf5e3

@ -196,6 +196,24 @@
}); });
}); });
function updateUnreadCount(count) {
var badge = $('#numUnreadBadge');
badge.html(count > 20 ? '20+' : count);
if (count > 0) {
badge
.removeClass('badge-inverse')
.addClass('badge-important');
} else {
badge
.removeClass('badge-important')
.addClass('badge-inverse');
}
}
socket.on('event:unread.updateCount', updateUnreadCount);
socket.emit('api:unread.count', updateUnreadCount);
require(['mobileMenu'], function(mobileMenu) { require(['mobileMenu'], function(mobileMenu) {
mobileMenu.init(); mobileMenu.init();
}); });

@ -185,20 +185,20 @@
} }
}); });
jQuery.getJSON(RELATIVE_PATH + '/api/unread/total', function(data) { // jQuery.getJSON(RELATIVE_PATH + '/api/unread/total', function(data) {
var badge = jQuery('#numUnreadBadge'); // var badge = jQuery('#numUnreadBadge');
badge.html(data.count > 20 ? '20+' : data.count); // badge.html(data.count > 20 ? '20+' : data.count);
if (data.count > 0) { // if (data.count > 0) {
badge // badge
.removeClass('badge-inverse') // .removeClass('badge-inverse')
.addClass('badge-important'); // .addClass('badge-important');
} else { // } else {
badge // badge
.removeClass('badge-important') // .removeClass('badge-important')
.addClass('badge-inverse'); // .addClass('badge-inverse');
} // }
}); // });
}, },
isRelativeUrl: function(url) { isRelativeUrl: function(url) {

@ -28,7 +28,7 @@
} }
Feed.updateTopic = function (tid, callback) { Feed.updateTopic = function (tid, callback) {
topics.getTopicWithPosts(tid, 0, 0, -1, function (err, topicData) { topics.getTopicWithPosts(tid, 0, 0, -1, true, function (err, topicData) {
if (err) { if (err) {
return callback(new Error('topic-invalid')); return callback(new Error('topic-invalid'));
} }

@ -149,6 +149,9 @@ var RDB = require('./redis'),
next(); next();
}); });
}, },
function(next) {
topics.pushUnreadCount(null, next);
},
function(next) { function(next) {
Posts.getCidByPid(postData.pid, function(err, cid) { Posts.getCidByPid(postData.pid, function(err, cid) {
if(err) { if(err) {

@ -115,7 +115,7 @@ var path = require('path'),
app.get('/topic/:id/:slug?', function (req, res, next) { app.get('/topic/:id/:slug?', function (req, res, next) {
var uid = (req.user) ? req.user.uid : 0; var uid = (req.user) ? req.user.uid : 0;
topics.getTopicWithPosts(req.params.id, uid, 0, 10, function (err, data) { topics.getTopicWithPosts(req.params.id, uid, 0, 10, false, function (err, data) {
if (!err) { if (!err) {
if (data.deleted === '1' && data.expose_tools === 0) { if (data.deleted === '1' && data.expose_tools === 0) {
return res.json(404, {}); return res.json(404, {});

@ -78,6 +78,11 @@ var DebugRoute = function(app) {
}); });
}); });
}); });
app.get('/test', function(req, res) {
topics.pushUnreadCount();
res.send();
});
}); });
}; };

@ -17,7 +17,9 @@ var async = require('async'),
notifications = require('./notifications'), notifications = require('./notifications'),
feed = require('./feed'), feed = require('./feed'),
favourites = require('./favourites'), favourites = require('./favourites'),
meta = require('./meta'); meta = require('./meta')
websockets = require('./websockets');
(function(Topics) { (function(Topics) {
@ -91,7 +93,6 @@ var async = require('async'),
Topics.markAsRead(tid, uid); Topics.markAsRead(tid, uid);
}); });
// 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.zadd('categories:' + cid + ':tid', timestamp, tid); RDB.zadd('categories:' + cid + ':tid', timestamp, tid);
RDB.hincrby('category:' + cid, 'topic_count', 1); RDB.hincrby('category:' + cid, 'topic_count', 1);
@ -109,6 +110,8 @@ var async = require('async'),
// Auto-subscribe the post creator to the newly created topic // Auto-subscribe the post creator to the newly created topic
threadTools.toggleFollow(tid, uid); threadTools.toggleFollow(tid, uid);
Topics.pushUnreadCount();
Topics.getTopicForCategoryView(tid, uid, function(topicData) { Topics.getTopicForCategoryView(tid, uid, function(topicData) {
topicData.unreplied = 1; topicData.unreplied = 1;
@ -394,6 +397,29 @@ var async = require('async'),
}); });
}; };
Topics.pushUnreadCount = function(uids, callback) {
console.log('uids', uids);
if (uids == 0) throw new Error();
if (!uids) {
clients = websockets.getConnectedClients();
uids = Object.keys(clients);
} else if (!Array.isArray(uids)) {
uids = [uids];
}
async.each(uids, function(uid, next) {
Topics.getUnreadTids(uid, 0, 19, function(err, tids) {
websockets.in('uid_' + uid).emit('event:unread.updateCount', tids.length);
});
}, function(err) {
winston.error(err);
if (callback) {
callback();
}
});
};
Topics.getTopicsByTids = function(tids, current_user, callback, category_id) { Topics.getTopicsByTids = function(tids, current_user, callback, category_id) {
var retrieved_topics = []; var retrieved_topics = [];
@ -497,14 +523,18 @@ var async = require('async'),
} }
Topics.getTopicWithPosts = function(tid, current_user, start, end, callback) { Topics.getTopicWithPosts = function(tid, current_user, start, end, quiet, callback) {
threadTools.exists(tid, function(exists) { threadTools.exists(tid, function(exists) {
if (!exists) { if (!exists) {
return callback(new Error('Topic tid \'' + tid + '\' not found')); return callback(new Error('Topic tid \'' + tid + '\' not found'));
} }
// "quiet" is used for things like RSS feed updating, HTML parsing for non-js users, etc
if (!quiet) {
Topics.markAsRead(tid, current_user); Topics.markAsRead(tid, current_user);
Topics.pushUnreadCount(current_user);
Topics.increaseViewCount(tid); Topics.increaseViewCount(tid);
}
function getTopicData(next) { function getTopicData(next) {
Topics.getTopicData(tid, next); Topics.getTopicData(tid, next);

@ -465,7 +465,7 @@ var path = require('path'),
async.waterfall([ async.waterfall([
function (next) { function (next) {
topics.getTopicWithPosts(tid, ((req.user) ? req.user.uid : 0), 0, -1, function (err, topicData) { topics.getTopicWithPosts(tid, ((req.user) ? req.user.uid : 0), 0, -1, true, function (err, topicData) {
if (topicData) { if (topicData) {
if (topicData.deleted === '1' && topicData.expose_tools === 0) { if (topicData.deleted === '1' && topicData.expose_tools === 0) {
return next(new Error('Topic deleted'), null); return next(new Error('Topic deleted'), null);

@ -66,7 +66,6 @@ websockets.init = function(io) {
var hs = socket.handshake, var hs = socket.handshake,
sessionID, uid, lastPostTime = 0; sessionID, uid, lastPostTime = 0;
// Validate the session, if present // Validate the session, if present
socketCookieParser(hs, {}, function(err) { socketCookieParser(hs, {}, function(err) {
sessionID = socket.handshake.signedCookies["express.sid"]; sessionID = socket.handshake.signedCookies["express.sid"];
@ -106,8 +105,6 @@ websockets.init = function(io) {
}); });
}); });
socket.on('disconnect', function() { socket.on('disconnect', function() {
var index = userSockets[uid].indexOf(socket); var index = userSockets[uid].indexOf(socket);
@ -870,6 +867,12 @@ websockets.init = function(io) {
}); });
}); });
socket.on('api:unread.count', function(callback) {
topics.getUnreadTids(uid, 0, 19, function(err, tids) {
socket.emit('event:unread.updateCount', tids.length);
});
});
socket.on('api:category.loadMore', function(data, callback) { socket.on('api:category.loadMore', function(data, callback) {
var start = data.after, var start = data.after,
end = start + 9; end = start + 9;
@ -1139,6 +1142,10 @@ websockets.init = function(io) {
websockets.in = function(room) { websockets.in = function(room) {
return io.sockets.in(room); return io.sockets.in(room);
}; };
websockets.getConnectedClients = function() {
return userSockets;
}
} }
})(module.exports); })(module.exports);

Loading…
Cancel
Save