Support m.room.tombstone events
For https://github.com/vector-im/riot-web/issues/7164pull/21833/head
parent
c00610cb2c
commit
7f8cd203a8
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
|
Copyright 2018 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -22,6 +23,27 @@ limitations under the License.
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_MessageComposer_replaced_wrapper {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MessageComposer_replaced_valign {
|
||||||
|
height: 60px;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MessageComposer_roomReplaced_icon {
|
||||||
|
float: left;
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_MessageComposer_roomReplaced_header {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_MessageComposer_autocomplete_wrapper {
|
.mx_MessageComposer_autocomplete_wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 0;
|
height: 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
Copyright 2017 New Vector Ltd
|
Copyright 2017, 2018 New Vector Ltd
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -25,6 +25,7 @@ import dis from '../../../dispatcher';
|
||||||
import RoomViewStore from '../../../stores/RoomViewStore';
|
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||||
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||||
import Stickerpicker from './Stickerpicker';
|
import Stickerpicker from './Stickerpicker';
|
||||||
|
import { makeRoomPermalink } from '../../../matrix-to';
|
||||||
|
|
||||||
const formatButtonList = [
|
const formatButtonList = [
|
||||||
_td("bold"),
|
_td("bold"),
|
||||||
|
@ -51,7 +52,9 @@ export default class MessageComposer extends React.Component {
|
||||||
this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this);
|
this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this);
|
||||||
this.onInputStateChanged = this.onInputStateChanged.bind(this);
|
this.onInputStateChanged = this.onInputStateChanged.bind(this);
|
||||||
this.onEvent = this.onEvent.bind(this);
|
this.onEvent = this.onEvent.bind(this);
|
||||||
|
this._onRoomStateEvents = this._onRoomStateEvents.bind(this);
|
||||||
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
|
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
|
||||||
|
this._onTombstoneClick = this._onTombstoneClick.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
inputState: {
|
inputState: {
|
||||||
|
@ -61,6 +64,7 @@ export default class MessageComposer extends React.Component {
|
||||||
},
|
},
|
||||||
showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'),
|
showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'),
|
||||||
isQuoting: Boolean(RoomViewStore.getQuotingEvent()),
|
isQuoting: Boolean(RoomViewStore.getQuotingEvent()),
|
||||||
|
tombstone: this._getRoomTombstone(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,12 +74,14 @@ export default class MessageComposer extends React.Component {
|
||||||
// marked as encrypted.
|
// marked as encrypted.
|
||||||
// XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something.
|
// XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something.
|
||||||
MatrixClientPeg.get().on("event", this.onEvent);
|
MatrixClientPeg.get().on("event", this.onEvent);
|
||||||
|
MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents);
|
||||||
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
|
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (MatrixClientPeg.get()) {
|
if (MatrixClientPeg.get()) {
|
||||||
MatrixClientPeg.get().removeListener("event", this.onEvent);
|
MatrixClientPeg.get().removeListener("event", this.onEvent);
|
||||||
|
MatrixClientPeg.get().removeListener("RoomState.events", this._onRoomStateEvents);
|
||||||
}
|
}
|
||||||
if (this._roomStoreToken) {
|
if (this._roomStoreToken) {
|
||||||
this._roomStoreToken.remove();
|
this._roomStoreToken.remove();
|
||||||
|
@ -88,6 +94,18 @@ export default class MessageComposer extends React.Component {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onRoomStateEvents(ev, state) {
|
||||||
|
if (ev.getRoomId() !== this.props.room.roomId) return;
|
||||||
|
|
||||||
|
if (ev.getType() === 'm.room.tombstone') {
|
||||||
|
this.setState({tombstone: this._getRoomTombstone()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getRoomTombstone() {
|
||||||
|
return this.props.room.currentState.getStateEvents('m.room.tombstone', '');
|
||||||
|
}
|
||||||
|
|
||||||
_onRoomViewStoreUpdate() {
|
_onRoomViewStoreUpdate() {
|
||||||
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
|
const isQuoting = Boolean(RoomViewStore.getQuotingEvent());
|
||||||
if (this.state.isQuoting === isQuoting) return;
|
if (this.state.isQuoting === isQuoting) return;
|
||||||
|
@ -207,6 +225,17 @@ export default class MessageComposer extends React.Component {
|
||||||
this.messageComposerInput.enableRichtext(!this.state.inputState.isRichTextEnabled);
|
this.messageComposerInput.enableRichtext(!this.state.inputState.isRichTextEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onTombstoneClick(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
|
||||||
|
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
highlighted: true,
|
||||||
|
room_id: replacementRoomId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
|
const me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId);
|
||||||
const uploadInputStyle = {display: 'none'};
|
const uploadInputStyle = {display: 'none'};
|
||||||
|
@ -262,7 +291,7 @@ export default class MessageComposer extends React.Component {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canSendMessages = this.props.room.currentState.maySendMessage(
|
const canSendMessages = !this.state.tombstone && this.props.room.currentState.maySendMessage(
|
||||||
MatrixClientPeg.get().credentials.userId);
|
MatrixClientPeg.get().credentials.userId);
|
||||||
|
|
||||||
if (canSendMessages) {
|
if (canSendMessages) {
|
||||||
|
@ -322,6 +351,24 @@ export default class MessageComposer extends React.Component {
|
||||||
callButton,
|
callButton,
|
||||||
videoCallButton,
|
videoCallButton,
|
||||||
);
|
);
|
||||||
|
} else if (this.state.tombstone) {
|
||||||
|
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
|
||||||
|
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
controls.push(<div className="mx_MessageComposer_replaced_wrapper">
|
||||||
|
<div className="mx_MessageComposer_replaced_valign">
|
||||||
|
<img className="mx_MessageComposer_roomReplaced_icon" src="img/room_replaced.svg" />
|
||||||
|
<span className="mx_MessageComposer_roomReplaced_header">
|
||||||
|
{_t("This room has been replaced and is no longer active.")}
|
||||||
|
</span><br />
|
||||||
|
<a href={makeRoomPermalink(replacementRoomId)}
|
||||||
|
className="mx_MessageComposer_roomReplaced_link"
|
||||||
|
onClick={this._onTombstoneClick}
|
||||||
|
>
|
||||||
|
{_t("The conversation continues here.")}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>);
|
||||||
} else {
|
} else {
|
||||||
controls.push(
|
controls.push(
|
||||||
<div key="controls_error" className="mx_MessageComposer_noperm_error">
|
<div key="controls_error" className="mx_MessageComposer_noperm_error">
|
||||||
|
|
|
@ -393,6 +393,8 @@
|
||||||
"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.",
|
"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.",
|
||||||
"Upload Files": "Upload Files",
|
"Upload Files": "Upload Files",
|
||||||
"Are you sure you want to upload the following files?": "Are you sure you want to upload the following files?",
|
"Are you sure you want to upload the following files?": "Are you sure you want to upload the following files?",
|
||||||
|
"This room has been replaced and is no longer active.": "This room has been replaced and is no longer active.",
|
||||||
|
"The conversation continues here.": "The conversation continues here.",
|
||||||
"Encrypted room": "Encrypted room",
|
"Encrypted room": "Encrypted room",
|
||||||
"Unencrypted room": "Unencrypted room",
|
"Unencrypted room": "Unencrypted room",
|
||||||
"Hangup": "Hangup",
|
"Hangup": "Hangup",
|
||||||
|
|
Loading…
Reference in New Issue