From 87e2cb8a27c0c1eea99f99a434a4e9ab9065361e Mon Sep 17 00:00:00 2001 From: Sebastien Hut Date: Mon, 9 Feb 2015 00:21:00 +0100 Subject: [PATCH] MUC: Querying an archive fragment --- clientapp/models/contact.js | 37 +++++++++------ clientapp/models/muc.js | 59 ++++++++++++++++++++++-- clientapp/pages/chat.js | 88 +++++++++++++++++++++++++++--------- clientapp/pages/groupchat.js | 82 +++++++++++++++++++++++++-------- 4 files changed, 208 insertions(+), 58 deletions(-) diff --git a/clientapp/models/contact.js b/clientapp/models/contact.js index 47017b2..0e5df66 100644 --- a/clientapp/models/contact.js +++ b/clientapp/models/contact.js @@ -281,30 +281,37 @@ module.exports = HumanModel.define({ this.lastInteraction = newInteraction; } }, - fetchHistory: function () { + fetchHistory: function (old) { var self = this; app.whenConnected(function () { var filter = { 'with': self.jid, rsm: { - count: 20, + max: old ? 40 : 50, before: true } }; - var lastMessage = self.messages.last(); - if (lastMessage && lastMessage.archivedId) { - filter.rsm.after = lastMessage.archivedId; - } - - if (self.lastHistoryFetch && !isNaN(self.lastHistoryFetch.valueOf())) { - if (self.lastInteraction > self.lastHistoryFetch) { - filter.start = self.lastInteraction; - } else { - filter.start = self.lastHistoryFetch; - } + if (old) { + var firstMessage = self.messages.first(); + if (firstMessage && firstMessage.archivedId) { + filter.rsm.before = firstMessage.archivedId; + } } else { - filter.end = new Date(Date.now()); + var lastMessage = self.messages.last(); + if (lastMessage && lastMessage.archivedId) { + filter.rsm.after = lastMessage.archivedId; + } + + if (self.lastHistoryFetch && !isNaN(self.lastHistoryFetch.valueOf())) { + if (self.lastInteraction > self.lastHistoryFetch) { + filter.start = self.lastInteraction; + } else { + filter.start = self.lastHistoryFetch; + } + } else { + filter.end = new Date(Date.now()); + } } client.getHistory(filter, function (err, res) { @@ -313,7 +320,7 @@ module.exports = HumanModel.define({ self.lastHistoryFetch = new Date(Date.now()); var results = res.mamQuery.results || []; - results.reverse(); + if (!old) results.reverse(); results.forEach(function (result) { var msg = result.mam.forwarded.message; diff --git a/clientapp/models/muc.js b/clientapp/models/muc.js index 17f9b66..f9035db 100644 --- a/clientapp/models/muc.js +++ b/clientapp/models/muc.js @@ -10,7 +10,6 @@ var Resources = require('./resources'); var Messages = require('./messages'); var Message = require('./message'); - module.exports = HumanModel.define({ initialize: function (attrs) { if (attrs.jid) { @@ -138,12 +137,64 @@ module.exports = HumanModel.define({ this.resources.reset(); client.joinRoom(this.jid, this.nick, { - history: { - maxstanzas: 50 - //since: this.lastInteraction + joinMuc: { + history: { + maxstanzas: 50 + } } }); }, + fetchHistory: function() { + var self = this; + app.whenConnected(function () { + var filter = { + 'to': self.jid, + rsm: { + max: 40, + before: true + } + }; + + var firstMessage = self.messages.first(); + if (firstMessage && firstMessage.created) { + var end = new Date(firstMessage.created - 1); + filter.end = end.toISOString(); + } + + client.getHistory(filter, function (err, res) { + if (err) return; + + self.lastHistoryFetch = new Date(Date.now()); + + var results = res.mamQuery.results || []; + + results.forEach(function (result) { + var msg = result.mam.forwarded.message; + + msg.mid = msg.id; + delete msg.id; + + if (!msg.delay) { + msg.delay = result.mam.forwarded.delay; + } + + if (msg.replace) { + var original = Message.idLookup(msg.from[msg.type == 'groupchat' ? 'full' : 'bare'], msg.replace); + // Drop the message if editing a previous, but + // keep it if it didn't actually change an + // existing message. + if (original && original.correct(msg)) return; + } + + var message = new Message(msg); + message.archivedId = result.mam.id; + message.acked = true; + + self.addMessage(message, false); + }); + }); + }); + }, leave: function () { this.resources.reset(); client.leaveRoom(this.jid, this.nick); diff --git a/clientapp/pages/chat.js b/clientapp/pages/chat.js index 86a69e4..3860374 100644 --- a/clientapp/pages/chat.js +++ b/clientapp/pages/chat.js @@ -22,7 +22,7 @@ module.exports = BasePage.extend({ this.listenTo(this, 'pageunloaded', this.handlePageUnloaded); this.listenTo(this.model.messages, 'change', this.refreshModel); - this.listenTo(this.model.messages, 'sort', this.renderCollection); + //this.listenTo(this.model.messages, 'sort', this.renderCollection); this.render(); }, @@ -52,6 +52,16 @@ module.exports = BasePage.extend({ show: function (animation) { BasePage.prototype.show.apply(this, [animation]); this.sendChatState('active'); + + this.firstChanged = true; + var self = this; + $('.messages').scroll(function() { + if (self.firstChanged && $(".messages li:first-child").offset().top > 0) { + self.firstChanged = false; + self.model.fetchHistory(true); + } + }); + this.$chatInput.focus(); }, hide: function () { @@ -209,35 +219,71 @@ module.exports = BasePage.extend({ refreshModel: function (model) { var existing = this.$('#chat' + model.cid); existing.replaceWith(model.partialTemplateHtml); + existing = this.$('#chat' + model.cid); + embedIt(existing); }, handleJingleResourcesChanged: function (model, val) { var resources = val || this.model.jingleResources; this.$('button.call').prop('disabled', !resources.length); }, appendModel: function (model, preload) { - var newEl, first, last, newDay = false; + var newEl, first, last; + var msgDate = Date.create(model.timestamp); + var messageDay = msgDate.format('{month} {ord}, {yyyy}'); - var messageDay = Date.create(model.timestamp).format('{month} {ord}, {yyyy}'); - if (messageDay !== this.lastDate) { - var dayDivider = $(templates.includes.dayDivider({day_name: messageDay})); - this.staydown.append(dayDivider[0]); - this.lastDate = messageDay; - newDay = true; - } + if (this.firstModel === undefined || msgDate > Date.create(this.firstModel.timestamp)) { + if (this.firstModel === undefined) { + this.firstModel = model; + this.firstDate = messageDay; + } - var isGrouped = !newDay && model.shouldGroupWith(this.lastModel); - if (isGrouped) { - newEl = $(model.partialTemplateHtml); - last = this.$messageList.find('li').last(); - last.find('.messageWrapper').append(newEl); - last.addClass('chatGroup'); - this.staydown.checkdown(); - } else { - newEl = $(model.templateHtml); - this.staydown.append(newEl[0]); - this.lastModel = model; + if (messageDay !== this.lastDate) { + var dayDivider = $(templates.includes.dayDivider({day_name: messageDay})); + this.staydown.append(dayDivider[0]); + this.lastDate = messageDay; + } + + var isGrouped = model.shouldGroupWith(this.lastModel); + if (isGrouped) { + newEl = $(model.partialTemplateHtml); + last = this.$messageList.find('li').last(); + last.find('.messageWrapper').append(newEl); + last.addClass('chatGroup'); + this.staydown.checkdown(); + } else { + newEl = $(model.templateHtml); + this.staydown.append(newEl[0]); + this.lastModel = model; + } + if (!model.pending) embedIt(newEl); + } + else { + var scrollDown = this.$messageList.prop('scrollHeight') - this.$messageList.scrollTop(); + var firstEl = this.$messageList.find('li').first(); + + if (messageDay !== this.firstDate) { + var dayDivider = $(templates.includes.dayDivider({day_name: messageDay})); + firstEl.before(dayDivider[0]); + var firstEl = this.$messageList.find('li').first(); + this.firstDate = messageDay; + } + + var isGrouped = model.shouldGroupWith(this.firstModel); + if (isGrouped) { + newEl = $(model.partialTemplateHtml); + first = this.$messageList.find('li').first().next(); + first.find('.messageWrapper div:first').after(newEl); + first.addClass('chatGroup'); + } else { + newEl = $(model.templateHtml); + firstEl.after(newEl[0]); + this.firstModel = model; + } + if (!model.pending) embedIt(newEl); + + this.$messageList.scrollTop(this.$messageList.prop('scrollHeight') - scrollDown); + this.firstChanged = true; } - embedIt(newEl); }, handleAcceptClick: function (e) { e.preventDefault(); diff --git a/clientapp/pages/groupchat.js b/clientapp/pages/groupchat.js index 2faad15..ea0825a 100644 --- a/clientapp/pages/groupchat.js +++ b/clientapp/pages/groupchat.js @@ -48,6 +48,16 @@ module.exports = BasePage.extend({ to: this.model.jid, chatState: 'active' }); + + this.firstChanged = true; + var self = this; + $('.messages').scroll(function() { + if (self.firstChanged && $(".messages li:first-child").offset().top > 0) { + self.firstChanged = false; + self.model.fetchHistory(); + } + }); + this.$chatInput.focus(); }, hide: function () { @@ -83,6 +93,7 @@ module.exports = BasePage.extend({ }, renderMessages: function () { var self = this; + this.firstDate = ''; this.lastDate = ''; this.model.messages.each(function (model, i) { self.appendModel(model); @@ -238,27 +249,62 @@ module.exports = BasePage.extend({ }, appendModel: function (model, preload) { var newEl, first, last; + var msgDate = Date.create(model.timestamp); + var messageDay = msgDate.format('{month} {ord}, {yyyy}'); - var messageDay = Date.create(model.timestamp).format('{month} {ord}, {yyyy}'); - if (messageDay !== this.lastDate) { - var dayDivider = $(templates.includes.dayDivider({day_name: messageDay})); - this.staydown.append(dayDivider[0]); - this.lastDate = messageDay; - } + if (this.firstModel === undefined || msgDate > Date.create(this.firstModel.timestamp)) { + if (this.firstModel === undefined) { + this.firstModel = model; + this.firstDate = messageDay; + } - var isGrouped = model.shouldGroupWith(this.lastModel); - if (isGrouped) { - newEl = $(model.partialTemplateHtml); - last = this.$messageList.find('li').last(); - last.find('.messageWrapper').append(newEl); - last.addClass('chatGroup'); - this.staydown.checkdown(); - } else { - newEl = $(model.templateHtml); - this.staydown.append(newEl[0]); - this.lastModel = model; + if (messageDay !== this.lastDate) { + var dayDivider = $(templates.includes.dayDivider({day_name: messageDay})); + this.staydown.append(dayDivider[0]); + this.lastDate = messageDay; + } + + var isGrouped = model.shouldGroupWith(this.lastModel); + if (isGrouped) { + newEl = $(model.partialTemplateHtml); + last = this.$messageList.find('li').last(); + last.find('.messageWrapper').append(newEl); + last.addClass('chatGroup'); + this.staydown.checkdown(); + } else { + newEl = $(model.templateHtml); + this.staydown.append(newEl[0]); + this.lastModel = model; + } + if (!model.pending) embedIt(newEl); + } + else { + var scrollDown = this.$messageList.prop('scrollHeight') - this.$messageList.scrollTop(); + var firstEl = this.$messageList.find('li').first(); + + if (messageDay !== this.firstDate) { + var dayDivider = $(templates.includes.dayDivider({day_name: messageDay})); + firstEl.before(dayDivider[0]); + var firstEl = this.$messageList.find('li').first(); + this.firstDate = messageDay; + } + + var isGrouped = model.shouldGroupWith(this.firstModel); + if (isGrouped) { + newEl = $(model.partialTemplateHtml); + first = this.$messageList.find('li').first().next(); + first.find('.messageWrapper div:first').after(newEl); + first.addClass('chatGroup'); + } else { + newEl = $(model.templateHtml); + firstEl.after(newEl[0]); + this.firstModel = model; + } + if (!model.pending) embedIt(newEl); + + this.$messageList.scrollTop(this.$messageList.prop('scrollHeight') - scrollDown); + this.firstChanged = true; } - embedIt(newEl); }, refreshModel: function (model) { var existing = this.$('#chat' + model.cid);