MUC: Querying an archive fragment

This commit is contained in:
Sebastien Hut 2015-02-09 00:21:00 +01:00
parent 3edfe3da21
commit 87e2cb8a27
4 changed files with 208 additions and 58 deletions

View File

@ -281,30 +281,37 @@ module.exports = HumanModel.define({
this.lastInteraction = newInteraction; this.lastInteraction = newInteraction;
} }
}, },
fetchHistory: function () { fetchHistory: function (old) {
var self = this; var self = this;
app.whenConnected(function () { app.whenConnected(function () {
var filter = { var filter = {
'with': self.jid, 'with': self.jid,
rsm: { rsm: {
count: 20, max: old ? 40 : 50,
before: true before: true
} }
}; };
var lastMessage = self.messages.last(); if (old) {
if (lastMessage && lastMessage.archivedId) { var firstMessage = self.messages.first();
filter.rsm.after = lastMessage.archivedId; if (firstMessage && firstMessage.archivedId) {
} filter.rsm.before = firstMessage.archivedId;
}
if (self.lastHistoryFetch && !isNaN(self.lastHistoryFetch.valueOf())) {
if (self.lastInteraction > self.lastHistoryFetch) {
filter.start = self.lastInteraction;
} else {
filter.start = self.lastHistoryFetch;
}
} else { } 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) { client.getHistory(filter, function (err, res) {
@ -313,7 +320,7 @@ module.exports = HumanModel.define({
self.lastHistoryFetch = new Date(Date.now()); self.lastHistoryFetch = new Date(Date.now());
var results = res.mamQuery.results || []; var results = res.mamQuery.results || [];
results.reverse(); if (!old) results.reverse();
results.forEach(function (result) { results.forEach(function (result) {
var msg = result.mam.forwarded.message; var msg = result.mam.forwarded.message;

View File

@ -10,7 +10,6 @@ var Resources = require('./resources');
var Messages = require('./messages'); var Messages = require('./messages');
var Message = require('./message'); var Message = require('./message');
module.exports = HumanModel.define({ module.exports = HumanModel.define({
initialize: function (attrs) { initialize: function (attrs) {
if (attrs.jid) { if (attrs.jid) {
@ -138,12 +137,64 @@ module.exports = HumanModel.define({
this.resources.reset(); this.resources.reset();
client.joinRoom(this.jid, this.nick, { client.joinRoom(this.jid, this.nick, {
history: { joinMuc: {
maxstanzas: 50 history: {
//since: this.lastInteraction 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 () { leave: function () {
this.resources.reset(); this.resources.reset();
client.leaveRoom(this.jid, this.nick); client.leaveRoom(this.jid, this.nick);

View File

@ -22,7 +22,7 @@ module.exports = BasePage.extend({
this.listenTo(this, 'pageunloaded', this.handlePageUnloaded); this.listenTo(this, 'pageunloaded', this.handlePageUnloaded);
this.listenTo(this.model.messages, 'change', this.refreshModel); 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(); this.render();
}, },
@ -52,6 +52,16 @@ module.exports = BasePage.extend({
show: function (animation) { show: function (animation) {
BasePage.prototype.show.apply(this, [animation]); BasePage.prototype.show.apply(this, [animation]);
this.sendChatState('active'); 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(); this.$chatInput.focus();
}, },
hide: function () { hide: function () {
@ -209,35 +219,71 @@ module.exports = BasePage.extend({
refreshModel: function (model) { refreshModel: function (model) {
var existing = this.$('#chat' + model.cid); var existing = this.$('#chat' + model.cid);
existing.replaceWith(model.partialTemplateHtml); existing.replaceWith(model.partialTemplateHtml);
existing = this.$('#chat' + model.cid);
embedIt(existing);
}, },
handleJingleResourcesChanged: function (model, val) { handleJingleResourcesChanged: function (model, val) {
var resources = val || this.model.jingleResources; var resources = val || this.model.jingleResources;
this.$('button.call').prop('disabled', !resources.length); this.$('button.call').prop('disabled', !resources.length);
}, },
appendModel: function (model, preload) { 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 (this.firstModel === undefined || msgDate > Date.create(this.firstModel.timestamp)) {
if (messageDay !== this.lastDate) { if (this.firstModel === undefined) {
var dayDivider = $(templates.includes.dayDivider({day_name: messageDay})); this.firstModel = model;
this.staydown.append(dayDivider[0]); this.firstDate = messageDay;
this.lastDate = messageDay; }
newDay = true;
}
var isGrouped = !newDay && model.shouldGroupWith(this.lastModel); if (messageDay !== this.lastDate) {
if (isGrouped) { var dayDivider = $(templates.includes.dayDivider({day_name: messageDay}));
newEl = $(model.partialTemplateHtml); this.staydown.append(dayDivider[0]);
last = this.$messageList.find('li').last(); this.lastDate = messageDay;
last.find('.messageWrapper').append(newEl); }
last.addClass('chatGroup');
this.staydown.checkdown(); var isGrouped = model.shouldGroupWith(this.lastModel);
} else { if (isGrouped) {
newEl = $(model.templateHtml); newEl = $(model.partialTemplateHtml);
this.staydown.append(newEl[0]); last = this.$messageList.find('li').last();
this.lastModel = model; 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) { handleAcceptClick: function (e) {
e.preventDefault(); e.preventDefault();

View File

@ -48,6 +48,16 @@ module.exports = BasePage.extend({
to: this.model.jid, to: this.model.jid,
chatState: 'active' 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(); this.$chatInput.focus();
}, },
hide: function () { hide: function () {
@ -83,6 +93,7 @@ module.exports = BasePage.extend({
}, },
renderMessages: function () { renderMessages: function () {
var self = this; var self = this;
this.firstDate = '';
this.lastDate = ''; this.lastDate = '';
this.model.messages.each(function (model, i) { this.model.messages.each(function (model, i) {
self.appendModel(model); self.appendModel(model);
@ -238,27 +249,62 @@ module.exports = BasePage.extend({
}, },
appendModel: function (model, preload) { appendModel: function (model, preload) {
var newEl, first, last; 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 (this.firstModel === undefined || msgDate > Date.create(this.firstModel.timestamp)) {
if (messageDay !== this.lastDate) { if (this.firstModel === undefined) {
var dayDivider = $(templates.includes.dayDivider({day_name: messageDay})); this.firstModel = model;
this.staydown.append(dayDivider[0]); this.firstDate = messageDay;
this.lastDate = messageDay; }
}
var isGrouped = model.shouldGroupWith(this.lastModel); if (messageDay !== this.lastDate) {
if (isGrouped) { var dayDivider = $(templates.includes.dayDivider({day_name: messageDay}));
newEl = $(model.partialTemplateHtml); this.staydown.append(dayDivider[0]);
last = this.$messageList.find('li').last(); this.lastDate = messageDay;
last.find('.messageWrapper').append(newEl); }
last.addClass('chatGroup');
this.staydown.checkdown(); var isGrouped = model.shouldGroupWith(this.lastModel);
} else { if (isGrouped) {
newEl = $(model.templateHtml); newEl = $(model.partialTemplateHtml);
this.staydown.append(newEl[0]); last = this.$messageList.find('li').last();
this.lastModel = model; 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) { refreshModel: function (model) {
var existing = this.$('#chat' + model.cid); var existing = this.$('#chat' + model.cid);