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)

This commit is contained in:
Julian Lam
2013-12-05 13:59:16 -05:00
parent 43b012b32e
commit d9ee9bf5e3
9 changed files with 88 additions and 25 deletions

View File

@@ -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) {
mobileMenu.init();
});

View File

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

View File

@@ -28,7 +28,7 @@
}
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) {
return callback(new Error('topic-invalid'));
}

View File

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

View File

@@ -115,7 +115,7 @@ var path = require('path'),
app.get('/topic/:id/:slug?', function (req, res, next) {
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 (data.deleted === '1' && data.expose_tools === 0) {
return res.json(404, {});

View File

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

View File

@@ -17,7 +17,9 @@ var async = require('async'),
notifications = require('./notifications'),
feed = require('./feed'),
favourites = require('./favourites'),
meta = require('./meta');
meta = require('./meta')
websockets = require('./websockets');
(function(Topics) {
@@ -91,7 +93,6 @@ var async = require('async'),
Topics.markAsRead(tid, uid);
});
// 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.hincrby('category:' + cid, 'topic_count', 1);
@@ -109,6 +110,8 @@ var async = require('async'),
// Auto-subscribe the post creator to the newly created topic
threadTools.toggleFollow(tid, uid);
Topics.pushUnreadCount();
Topics.getTopicForCategoryView(tid, uid, function(topicData) {
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) {
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) {
if (!exists) {
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.pushUnreadCount(current_user);
Topics.increaseViewCount(tid);
}
function getTopicData(next) {
Topics.getTopicData(tid, next);

View File

@@ -465,7 +465,7 @@ var path = require('path'),
async.waterfall([
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.deleted === '1' && topicData.expose_tools === 0) {
return next(new Error('Topic deleted'), null);

View File

@@ -66,7 +66,6 @@ websockets.init = function(io) {
var hs = socket.handshake,
sessionID, uid, lastPostTime = 0;
// Validate the session, if present
socketCookieParser(hs, {}, function(err) {
sessionID = socket.handshake.signedCookies["express.sid"];
@@ -106,8 +105,6 @@ websockets.init = function(io) {
});
});
socket.on('disconnect', function() {
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) {
var start = data.after,
end = start + 9;
@@ -1139,6 +1142,10 @@ websockets.init = function(io) {
websockets.in = function(room) {
return io.sockets.in(room);
};
websockets.getConnectedClients = function() {
return userSockets;
}
}
})(module.exports);