diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js
index 75ca902fc3..d105610dd5 100644
--- a/src/components/structures/MessagePanel.js
+++ b/src/components/structures/MessagePanel.js
@@ -129,25 +129,39 @@ module.exports = React.createClass({
this.eventNodes = {};
- // we do two passes over the events list; first of all, we figure out
- // which events we want to show, and where the read markers fit into
- // the list; then we actually create the event tiles. This allows us to
- // behave slightly differently for the last event in the list.
- //
- // (Arguably we could do this when the events are added to this.props,
- // but that would make it trickier to keep in sync with the read marker, given
- // the read marker isn't necessarily on an event which we will show).
- //
- var eventsToShow = [];
+ var i;
- // the index in 'eventsToShow' of the event *before* which we put the
- // read marker or its ghost. (Note that it may be equal to
- // eventsToShow.length, which means it would be at the end of the timeline)
- var ghostIndex, readMarkerIndex;
+ // first figure out which is the last event in the list which we're
+ // actually going to show; this allows us to behave slightly
+ // differently for the last event in the list.
+ for (i = this.props.events.length-1; i >= 0; i--) {
+ var mxEv = this.props.events[i];
+ if (!EventTile.haveTileForEvent(mxEv)) {
+ continue;
+ }
- for (var i = 0; i < this.props.events.length; i++) {
+ if (this.props.isConferenceUser && mxEv.getType() === "m.room.member") {
+ if (this.props.isConferenceUser(mxEv.getSender()) ||
+ this.props.isConferenceUser(mxEv.getStateKey())) {
+ continue; // suppress conf user join/parts
+ }
+ }
+
+ break;
+ }
+ var lastShownEventIndex = i;
+
+ var ret = [];
+
+ var prevEvent = null; // the last event we showed
+
+ // assume there is no read marker until proven otherwise
+ var readMarkerVisible = false;
+
+ for (i = 0; i < this.props.events.length; i++) {
var mxEv = this.props.events[i];
var wantTile = true;
+ var eventId = mxEv.getId();
if (!EventTile.haveTileForEvent(mxEv)) {
wantTile = false;
@@ -160,58 +174,34 @@ module.exports = React.createClass({
}
}
+ var last = (i == lastShownEventIndex);
+
if (wantTile) {
- eventsToShow.push(mxEv);
+ ret.push(this._getTilesForEvent(prevEvent, mxEv, last));
+ } else if (!mxEv.status) {
+ // if we aren't showing the event, put in a dummy scroll token anyway, so
+ // that we can scroll to the right place.
+ ret.push(
);
}
- var eventId = mxEv.getId();
- if (eventId == this.props.readMarkerEventId) {
- readMarkerIndex = eventsToShow.length;
- } else if (eventId == this.currentReadMarkerEventId && !this.currentGhostEventId) {
- // there is currently a read-up-to marker at this point, but no
- // more. Show an animation of it disappearing.
- ghostIndex = eventsToShow.length;
- this.currentGhostEventId = eventId;
- } else if (eventId == this.currentGhostEventId) {
- // if we're showing an animation, continue to show it.
- ghostIndex = eventsToShow.length;
- }
- }
-
- var ret = [];
-
- var prevEvent = null; // the last event we showed
-
- // assume there is no read marker until proven otherwise
- var readMarkerVisible = false;
-
- for (var i = 0; i < eventsToShow.length; i++) {
- var mxEv = eventsToShow[i];
- var wantTile = true;
-
- // insert the read marker if appropriate. Note that doing it here
- // implicitly means that we never put it at the end of the timeline,
- // because i will never reach eventsToShow.length.
- if (i == readMarkerIndex) {
+ if (eventId == this.props.readMarkerEventId && i < lastShownEventIndex) {
// suppress the read marker if the next event is sent by us; this
// is a nonsensical and temporary situation caused by the delay between
// us sending a message and receiving the synthesized receipt.
- if (mxEv.sender && mxEv.sender.userId != this.props.ourUserId) {
+ var nextEvent = this.props.events[i+1];
+ if (nextEvent.sender && nextEvent.sender.userId != this.props.ourUserId) {
ret.push(this._getReadMarkerTile());
readMarkerVisible = true;
}
- } else if (i == ghostIndex) {
+ } else if (eventId == this.currentReadMarkerEventId && !this.currentGhostEventId) {
+ // there is currently a read-up-to marker at this point, but no
+ // more. Show an animation of it disappearing.
+ ret.push(this._getReadMarkerGhostTile());
+ this.currentGhostEventId = eventId;
+ } else if (eventId == this.currentGhostEventId) {
+ // if we're showing an animation, continue to show it.
ret.push(this._getReadMarkerGhostTile());
}
-
- var last = false;
- if (i == eventsToShow.length - 1) {
- last = true;
- }
-
- // add the tiles for this event
- ret.push(this._getTilesForEvent(prevEvent, mxEv, last));
- prevEvent = mxEv;
}
this.currentReadMarkerEventId = readMarkerVisible ? this.props.readMarkerEventId : null;
diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js
index 14da1e9ab8..ae5db3a36a 100644
--- a/src/components/structures/TimelinePanel.js
+++ b/src/components/structures/TimelinePanel.js
@@ -92,6 +92,7 @@ module.exports = React.createClass({
this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt);
+ MatrixClientPeg.get().on("Room.redaction", this.onRoomRedaction);
this._initTimeline(this.props);
},
@@ -121,6 +122,7 @@ module.exports = React.createClass({
if (client) {
client.removeListener("Room.timeline", this.onRoomTimeline);
client.removeListener("Room.receipt", this.onRoomReceipt);
+ client.removeListener("Room.redaction", this.onRoomRedaction);
}
},
@@ -202,6 +204,17 @@ module.exports = React.createClass({
});
},
+ onRoomRedaction: function(ev, room) {
+ if (this.unmounted) return;
+
+ // ignore events for other rooms
+ if (room !== this.props.room) return;
+
+ // we could skip an update if the event isn't in our timeline,
+ // but that's probably an early optimisation.
+ this.forceUpdate();
+ },
+
sendReadReceipt: function() {
if (!this.refs.messagePanel) return;
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index 36ec85e91b..daff377ebd 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -65,6 +65,7 @@ module.exports = React.createClass({
statics: {
haveTileForEvent: function(e) {
+ if (e.isRedacted()) return false;
if (eventTileTypes[e.getType()] == undefined) return false;
if (eventTileTypes[e.getType()] == 'messages.TextualEvent') {
return TextForEvent.textForEvent(e) !== '';