Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 2c1ba6f

Browse files
authored
Merge pull request #2124 from matrix-org/dbkr/tombstone
Support m.room.tombstone events
2 parents 7f2599c + 42bb8e4 commit 2c1ba6f

File tree

4 files changed

+88
-2
lines changed

4 files changed

+88
-2
lines changed

res/css/views/rooms/_MessageComposer.scss

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
Copyright 2015, 2016 OpenMarket Ltd
3+
Copyright 2018 New Vector Ltd
34
45
Licensed under the Apache License, Version 2.0 (the "License");
56
you may not use this file except in compliance with the License.
@@ -22,6 +23,29 @@ limitations under the License.
2223
position: relative;
2324
}
2425

26+
.mx_MessageComposer_replaced_wrapper {
27+
margin-left: auto;
28+
margin-right: auto;
29+
}
30+
31+
.mx_MessageComposer_replaced_valign {
32+
height: 60px;
33+
display: table-cell;
34+
vertical-align: middle;
35+
}
36+
37+
.mx_MessageComposer_roomReplaced_icon {
38+
float: left;
39+
margin-right: 20px;
40+
margin-top: 5px;
41+
width: 31px;
42+
height: 31px;
43+
}
44+
45+
.mx_MessageComposer_roomReplaced_header {
46+
font-weight: bold;
47+
}
48+
2549
.mx_MessageComposer_autocomplete_wrapper {
2650
position: relative;
2751
height: 0;

res/img/room_replaced.svg

Lines changed: 13 additions & 0 deletions
Loading

src/components/views/rooms/MessageComposer.js

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
Copyright 2015, 2016 OpenMarket Ltd
3-
Copyright 2017 New Vector Ltd
3+
Copyright 2017, 2018 New Vector Ltd
44
55
Licensed under the Apache License, Version 2.0 (the "License");
66
you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import dis from '../../../dispatcher';
2525
import RoomViewStore from '../../../stores/RoomViewStore';
2626
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
2727
import Stickerpicker from './Stickerpicker';
28+
import { makeRoomPermalink } from '../../../matrix-to';
2829

2930
const formatButtonList = [
3031
_td("bold"),
@@ -51,7 +52,9 @@ export default class MessageComposer extends React.Component {
5152
this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this);
5253
this.onInputStateChanged = this.onInputStateChanged.bind(this);
5354
this.onEvent = this.onEvent.bind(this);
55+
this._onRoomStateEvents = this._onRoomStateEvents.bind(this);
5456
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
57+
this._onTombstoneClick = this._onTombstoneClick.bind(this);
5558

5659
this.state = {
5760
inputState: {
@@ -61,6 +64,7 @@ export default class MessageComposer extends React.Component {
6164
},
6265
showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'),
6366
isQuoting: Boolean(RoomViewStore.getQuotingEvent()),
67+
tombstone: this._getRoomTombstone(),
6468
};
6569
}
6670

@@ -70,6 +74,7 @@ export default class MessageComposer extends React.Component {
7074
// marked as encrypted.
7175
// XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something.
7276
MatrixClientPeg.get().on("event", this.onEvent);
77+
MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents);
7378
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
7479
this._waitForOwnMember();
7580
}
@@ -93,6 +98,7 @@ export default class MessageComposer extends React.Component {
9398
componentWillUnmount() {
9499
if (MatrixClientPeg.get()) {
95100
MatrixClientPeg.get().removeListener("event", this.onEvent);
101+
MatrixClientPeg.get().removeListener("RoomState.events", this._onRoomStateEvents);
96102
}
97103
if (this._roomStoreToken) {
98104
this._roomStoreToken.remove();
@@ -105,6 +111,18 @@ export default class MessageComposer extends React.Component {
105111
this.forceUpdate();
106112
}
107113

114+
_onRoomStateEvents(ev, state) {
115+
if (ev.getRoomId() !== this.props.room.roomId) return;
116+
117+
if (ev.getType() === 'm.room.tombstone') {
118+
this.setState({tombstone: this._getRoomTombstone()});
119+
}
120+
}
121+
122+
_getRoomTombstone() {
123+
return this.props.room.currentState.getStateEvents('m.room.tombstone', '');
124+
}
125+
108126
_onRoomViewStoreUpdate() {
109127
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
110128
if (this.state.isQuoting === isQuoting) return;
@@ -224,6 +242,17 @@ export default class MessageComposer extends React.Component {
224242
this.messageComposerInput.enableRichtext(!this.state.inputState.isRichTextEnabled);
225243
}
226244

245+
_onTombstoneClick(ev) {
246+
ev.preventDefault();
247+
248+
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
249+
dis.dispatch({
250+
action: 'view_room',
251+
highlighted: true,
252+
room_id: replacementRoomId,
253+
});
254+
}
255+
227256
render() {
228257
const uploadInputStyle = {display: 'none'};
229258
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
@@ -280,7 +309,7 @@ export default class MessageComposer extends React.Component {
280309
</div>;
281310
}
282311

283-
const canSendMessages = this.props.room.currentState.maySendMessage(
312+
const canSendMessages = !this.state.tombstone && this.props.room.currentState.maySendMessage(
284313
MatrixClientPeg.get().credentials.userId);
285314

286315
if (canSendMessages) {
@@ -340,6 +369,24 @@ export default class MessageComposer extends React.Component {
340369
callButton,
341370
videoCallButton,
342371
);
372+
} else if (this.state.tombstone) {
373+
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
374+
375+
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
376+
controls.push(<div className="mx_MessageComposer_replaced_wrapper">
377+
<div className="mx_MessageComposer_replaced_valign">
378+
<img className="mx_MessageComposer_roomReplaced_icon" src="img/room_replaced.svg" />
379+
<span className="mx_MessageComposer_roomReplaced_header">
380+
{_t("This room has been replaced and is no longer active.")}
381+
</span><br />
382+
<a href={makeRoomPermalink(replacementRoomId)}
383+
className="mx_MessageComposer_roomReplaced_link"
384+
onClick={this._onTombstoneClick}
385+
>
386+
{_t("The conversation continues here.")}
387+
</a>
388+
</div>
389+
</div>);
343390
} else {
344391
controls.push(
345392
<div key="controls_error" className="mx_MessageComposer_noperm_error">

src/i18n/strings/en_EN.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,8 @@
396396
"At this time it is not possible to reply with a file so this will be sent without being a reply.": "At this time it is not possible to reply with a file so this will be sent without being a reply.",
397397
"Upload Files": "Upload Files",
398398
"Are you sure you want to upload the following files?": "Are you sure you want to upload the following files?",
399+
"This room has been replaced and is no longer active.": "This room has been replaced and is no longer active.",
400+
"The conversation continues here.": "The conversation continues here.",
399401
"Encrypted room": "Encrypted room",
400402
"Unencrypted room": "Unencrypted room",
401403
"Hangup": "Hangup",

0 commit comments

Comments
 (0)