diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 657b01c663..5e2414f37a 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -325,6 +325,11 @@ module.exports = React.createClass({ this.currentGhostEventId = null; } + this._readReceiptsByEvent = {}; + if (this.props.showReadReceipts) { + this._readReceiptsByEvent = this._getReadReceiptsByShownEvent(); + } + const isMembershipChange = (e) => e.getType() === 'm.room.member'; for (i = 0; i < this.props.events.length; i++) { @@ -525,10 +530,8 @@ module.exports = React.createClass({ // Local echos have a send "status". const scrollToken = mxEv.status ? undefined : eventId; - let readReceipts; - if (this.props.showReadReceipts) { - readReceipts = this._getReadReceiptsForEvent(mxEv); - } + const readReceipts = this._readReceiptsByEvent[eventId]; + ret.push(
  • { - return r2.ts - r1.ts; - }); + // Get an object that maps from event ID to a list of read receipts that + // should be shown next to that event. If a hidden event has read receipts, + // they are folded into the receipts of the last shown event. + _getReadReceiptsByShownEvent: function() { + const receiptsByEvent = {}; + + let lastShownEventId; + for (const event of this.props.events) { + if (this._shouldShowEvent(event)) { + lastShownEventId = event.getId(); + } + if (!lastShownEventId) { + continue; + } + const existingReceipts = receiptsByEvent[lastShownEventId] || []; + const newReceipts = this._getReadReceiptsForEvent(event); + receiptsByEvent[lastShownEventId] = existingReceipts.concat(newReceipts); + } + + // After grouping receipts by shown events, do another pass to sort each + // receipt list. + for (const eventId in receiptsByEvent) { + receiptsByEvent[eventId].sort((r1, r2) => { + return r2.ts - r1.ts; + }); + } + + return receiptsByEvent; }, _getReadMarkerTile: function(visible) {