diff --git a/public/src/forum/footer.js b/public/src/forum/footer.js index 1fe343d929..9de817550c 100644 --- a/public/src/forum/footer.js +++ b/public/src/forum/footer.js @@ -183,7 +183,7 @@ if (chat.modalExists(data.fromuid)) { modal = chat.getModal(data.fromuid); chat.appendChatMessage(modal, data.message, data.timestamp); - + if (modal.is(":visible")) { chat.load(modal.attr('UUID')); } else { @@ -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(); }); diff --git a/public/src/utils.js b/public/src/utils.js index 3e890b3f73..d82fe9cd14 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -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) { diff --git a/src/feed.js b/src/feed.js index 522edab086..85ffa63130 100644 --- a/src/feed.js +++ b/src/feed.js @@ -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')); } diff --git a/src/posts.js b/src/posts.js index 66c79350e2..ac4cf01400 100644 --- a/src/posts.js +++ b/src/posts.js @@ -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) { diff --git a/src/routes/api.js b/src/routes/api.js index 389763bac5..9ee9fb14c3 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -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, {}); diff --git a/src/routes/debug.js b/src/routes/debug.js index d089a48b2c..104e48bd08 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -78,6 +78,11 @@ var DebugRoute = function(app) { }); }); }); + + app.get('/test', function(req, res) { + topics.pushUnreadCount(); + res.send(); + }); }); }; diff --git a/src/topics.js b/src/topics.js index 9182f374c7..72073bf18a 100644 --- a/src/topics.js +++ b/src/topics.js @@ -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')); } - Topics.markAsRead(tid, current_user); - Topics.increaseViewCount(tid); + // "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); diff --git a/src/webserver.js b/src/webserver.js index 013ae4b8f4..389255a0a7 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -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); diff --git a/src/websockets.js b/src/websockets.js index ca85bd216c..6fea81be45 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -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);