diff --git a/public/src/forum/chats.js b/public/src/forum/chats.js index 2d2123b5d3..110afa4473 100644 --- a/public/src/forum/chats.js +++ b/public/src/forum/chats.js @@ -2,7 +2,7 @@ /* globals define, app, ajaxify, utils, socket, templates */ -define('forum/chats', ['string', 'sounds'], function(S, sounds) { +define('forum/chats', ['string', 'sounds', 'forum/infinitescroll'], function(S, sounds, infinitescroll) { var Chats = { initialised: false }; @@ -70,6 +70,14 @@ define('forum/chats', ['string', 'sounds'], function(S, sounds) { app.openChat(username, uid); }, true); }); + + $('.recent-chats').on('scroll', function() { + var $this = $(this); + var bottom = ($this[0].scrollHeight - $this.height()) * 0.9; + if ($this.scrollTop() > bottom) { + loadMoreRecentChats(); + } + }); }; Chats.addGlobalEventListeners = function() { @@ -197,5 +205,44 @@ define('forum/chats', ['string', 'sounds'], function(S, sounds) { }, callback); }; + function loadMoreRecentChats() { + var recentChats = $('.recent-chats'); + if (recentChats.attr('loading')) { + return; + } + recentChats.attr('loading', 1); + socket.emit('modules.chats.getRecentChats', { + after: recentChats.attr('data-nextstart') + }, function(err, data) { + if (err) { + return app.alertError(err.message); + } + + if (data && data.users.length) { + onRecentChatsLoaded(data.users, function() { + recentChats.removeAttr('loading'); + recentChats.attr('data-nextstart', data.nextStart); + }); + } else { + recentChats.removeAttr('loading'); + } + }); + } + + function onRecentChatsLoaded(users, callback) { + users = users.filter(function(user) { + return !$('.recent-chats li[data-uid=' + user.uid + ']').length; + }); + + if (!users.length) { + return callback(); + } + + infinitescroll.parseAndTranslate('chats', 'chats', {chats: users}, function(html) { + $('.recent-chats').append(html); + callback(); + }); + } + return Chats; }); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index b4234bd488..24bc182716 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -15,11 +15,11 @@ define('chat', ['taskbar', 'string', 'sounds', 'forum/chats'], function(taskbar, return; } - socket.emit('modules.chats.list', function(err, chats) { + socket.emit('modules.chats.getRecentChats', {after: 0}, function(err, chats) { if (err) { return app.alertError(err.message); } - + chats = chats.users; var userObj; chatsListEl.empty(); diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index fe40a3ea9a..1e21ecc62a 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -500,20 +500,21 @@ accountsController.getChats = function(req, res, next) { return next(err); } - // Remove entries if they were already present as a followed contact + //Remove entries if they were already present as a followed contact if (results.contacts && results.contacts.length) { var contactUids = results.contacts.map(function(contact) { return parseInt(contact.uid, 10); }); - results.recentChats = results.recentChats.filter(function(chatObj) { + results.recentChats.users = results.recentChats.users.filter(function(chatObj) { return contactUids.indexOf(parseInt(chatObj.uid, 10)) === -1; }); } if (!req.params.userslug) { return res.render('chats', { - chats: results.recentChats, + chats: results.recentChats.users, + nextStart: results.recentChats.nextStart, contacts: results.contacts }); } @@ -532,7 +533,8 @@ accountsController.getChats = function(req, res, next) { } res.render('chats', { - chats: results.recentChats, + chats: results.recentChats.users, + nextStart: results.recentChats.nextStart, contacts: results.contacts, meta: data.toUser, messages: data.messages diff --git a/src/messaging.js b/src/messaging.js index 8c9c902c5c..16a56dd23e 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -222,26 +222,39 @@ var db = require('./database'), return callback(err); } - db.isSortedSetMembers('uid:' + uid + ':chats:unread', uids, function(err, unreadUids) { + async.parallel({ + unread: function(next) { + db.isSortedSetMembers('uid:' + uid + ':chats:unread', uids, next); + }, + users: function(next) { + user.getMultipleUserFields(uids, ['uid', 'username', 'picture', 'status'] , next); + } + }, function(err, results) { if (err) { return callback(err); } - user.getMultipleUserFields(uids, ['uid', 'username', 'picture', 'status'] , function(err, users) { + results.users = results.users.filter(function(user) { + return user && parseInt(user.uid, 10); + }); + + if (!results.users.length) { + return callback(null, {users: [], nextStart: end + 1}); + } + + results.users.forEach(function(user, index) { + if (user) { + user.unread = results.unread[index]; + user.status = websockets.isUserOnline(user.uid) ? user.status : 'offline'; + } + }); + + db.sortedSetRevRank('uid:' + uid + ':chats', results.users[results.users.length - 1].uid, function(err, rank) { if (err) { return callback(err); } - users = users.filter(function(user) { - return user && parseInt(user.uid, 10); - }); - users.forEach(function(user, index) { - if (user) { - user.unread = unreadUids[index]; - user.status = websockets.isUserOnline(user.uid) ? user.status : 'offline'; - } - }); - callback(null, users); + callback(null, {users: results.users, nextStart: rank + 1}); }); }); }); diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 54e6b4585d..724407fe34 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -266,8 +266,14 @@ function sendTypingNotification(event, socket, data, callback) { server.in('uid_' + data.touid).emit(event, data.fromUid); } -SocketModules.chats.list = function(socket, data, callback) { - Messaging.getRecentChats(socket.uid, 0, 9, callback); +SocketModules.chats.getRecentChats = function(socket, data, callback) { + if (!data || !utils.isNumber(data.after)) { + return callback(new Error('[[error:invalid-data]]')); + } + var start = parseInt(data.after, 10), + end = start + 9; + + Messaging.getRecentChats(socket.uid, start, end, callback); }; /* Notifications */