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

Commit 15d286e

Browse files
authored
Merge pull request #3144 from matrix-org/bwindels/edit-history
Edit history dialog
2 parents 31b2592 + c9c8401 commit 15d286e

File tree

10 files changed

+342
-112
lines changed

10 files changed

+342
-112
lines changed

res/css/_components.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
@import "./views/dialogs/_EncryptedEventDialog.scss";
6262
@import "./views/dialogs/_GroupAddressPicker.scss";
6363
@import "./views/dialogs/_IncomingSasDialog.scss";
64+
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
6465
@import "./views/dialogs/_RestoreKeyBackupDialog.scss";
6566
@import "./views/dialogs/_RoomSettingsDialog.scss";
6667
@import "./views/dialogs/_RoomUpgradeDialog.scss";

res/css/structures/_RoomDirectory.scss

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,6 @@ limitations under the License.
3535
flex: 1;
3636
}
3737

38-
.mx_RoomDirectory .gm-scroll-view {
39-
// little hack because gemini doesn't seem to detect
40-
// the scrollbar width well in this instance
41-
// when using css scrollbars
42-
scrollbar-width: thin;
43-
}
44-
4538
.mx_RoomDirectory_createRoom {
4639
background-color: $button-bg-color;
4740
border-radius: 4px;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright 2019 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
.mx_MessageEditHistoryDialog .mx_Dialog_header > .mx_Dialog_title {
18+
text-align: center;
19+
}
20+
21+
.mx_MessageEditHistoryDialog {
22+
display: flex;
23+
flex-direction: column;
24+
max-height: 60vh;
25+
}
26+
27+
.mx_MessageEditHistoryDialog_scrollPanel {
28+
flex: 1 1 auto;
29+
}
30+
31+
.mx_MessageEditHistoryDialog_edits {
32+
list-style-type: none;
33+
font-size: 14px;
34+
padding: 0;
35+
color: $primary-fg-color;
36+
37+
.mx_EventTile_line, .mx_EventTile_content {
38+
margin-right: 0px;
39+
}
40+
}
41+

res/css/views/messages/_MessageTimestamp.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ limitations under the License.
1515
*/
1616

1717
.mx_MessageTimestamp {
18+
color: $event-timestamp-color;
19+
font-size: 10px;
1820
}

res/css/views/rooms/_EventTile.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ limitations under the License.
9393
display: block;
9494
visibility: hidden;
9595
white-space: nowrap;
96-
color: $event-timestamp-color;
97-
font-size: 10px;
9896
left: 0px;
9997
width: 46px; /* 8 + 30 (avatar) + 8 */
10098
text-align: center;
@@ -403,6 +401,7 @@ limitations under the License.
403401
color: $roomtopic-color;
404402
display: inline-block;
405403
margin-left: 9px;
404+
cursor: pointer;
406405
}
407406

408407
/* Various markdown overrides */
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright 2019 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
import PropTypes from 'prop-types';
19+
import MatrixClientPeg from "../../../MatrixClientPeg";
20+
import { _t } from '../../../languageHandler';
21+
import sdk from "../../../index";
22+
import {wantsDateSeparator} from '../../../DateUtils';
23+
import SettingsStore from '../../../settings/SettingsStore';
24+
25+
export default class MessageEditHistoryDialog extends React.PureComponent {
26+
static propTypes = {
27+
mxEvent: PropTypes.object.isRequired,
28+
};
29+
30+
constructor(props) {
31+
super(props);
32+
this.state = {
33+
events: [],
34+
nextBatch: null,
35+
isLoading: true,
36+
isTwelveHour: SettingsStore.getValue("showTwelveHourTimestamps"),
37+
};
38+
}
39+
40+
loadMoreEdits = async (backwards) => {
41+
if (backwards || (!this.state.nextBatch && !this.state.isLoading)) {
42+
// bail out on backwards as we only paginate in one direction
43+
return false;
44+
}
45+
const opts = {from: this.state.nextBatch};
46+
const roomId = this.props.mxEvent.getRoomId();
47+
const eventId = this.props.mxEvent.getId();
48+
const result = await MatrixClientPeg.get().relations(
49+
roomId, eventId, "m.replace", "m.room.message", opts);
50+
let resolve;
51+
const promise = new Promise(r => resolve = r);
52+
this.setState({
53+
events: this.state.events.concat(result.events),
54+
nextBatch: result.nextBatch,
55+
isLoading: false,
56+
}, () => {
57+
const hasMoreResults = !!this.state.nextBatch;
58+
resolve(hasMoreResults);
59+
});
60+
return promise;
61+
}
62+
63+
componentDidMount() {
64+
this.loadMoreEdits();
65+
}
66+
67+
_renderEdits() {
68+
const EditHistoryMessage = sdk.getComponent('messages.EditHistoryMessage');
69+
const DateSeparator = sdk.getComponent('messages.DateSeparator');
70+
const nodes = [];
71+
let lastEvent;
72+
this.state.events.forEach(e => {
73+
if (!lastEvent || wantsDateSeparator(lastEvent.getDate(), e.getDate())) {
74+
nodes.push(<li key={e.getTs() + "~"}><DateSeparator ts={e.getTs()} /></li>);
75+
}
76+
nodes.push(<EditHistoryMessage key={e.getId()} mxEvent={e} isTwelveHour={this.state.isTwelveHour} />);
77+
lastEvent = e;
78+
});
79+
return nodes;
80+
}
81+
82+
render() {
83+
let content;
84+
if (this.state.error) {
85+
content = this.state.error;
86+
} else if (this.state.isLoading) {
87+
const Spinner = sdk.getComponent("elements.Spinner");
88+
content = <Spinner />;
89+
} else {
90+
const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
91+
content = (<ScrollPanel
92+
className="mx_MessageEditHistoryDialog_scrollPanel"
93+
onFillRequest={ this.loadMoreEdits }
94+
stickyBottom={false}
95+
startAtBottom={false}
96+
>
97+
<ul className="mx_MessageEditHistoryDialog_edits mx_MessagePanel_alwaysShowTimestamps">{this._renderEdits()}</ul>
98+
</ScrollPanel>);
99+
}
100+
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
101+
return (
102+
<BaseDialog className='mx_MessageEditHistoryDialog' hasCancel={true}
103+
onFinished={this.props.onFinished} title={_t("Message edits")}>
104+
{content}
105+
</BaseDialog>
106+
);
107+
}
108+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
Copyright 2019 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
import PropTypes from 'prop-types';
19+
import * as HtmlUtils from '../../../HtmlUtils';
20+
import {formatTime} from '../../../DateUtils';
21+
import {MatrixEvent} from 'matrix-js-sdk';
22+
import {pillifyLinks} from '../../../utils/pillify';
23+
24+
export default class EditHistoryMessage extends React.PureComponent {
25+
static propTypes = {
26+
// the message event being edited
27+
mxEvent: PropTypes.instanceOf(MatrixEvent).isRequired,
28+
};
29+
30+
componentDidMount() {
31+
pillifyLinks(this.refs.content.children, this.props.mxEvent);
32+
}
33+
34+
componentDidUpdate() {
35+
pillifyLinks(this.refs.content.children, this.props.mxEvent);
36+
}
37+
38+
render() {
39+
const {mxEvent} = this.props;
40+
const content = mxEvent.event.content["m.new_content"] || mxEvent.event.content;
41+
const contentElements = HtmlUtils.bodyToHtml(content);
42+
let contentContainer;
43+
if (mxEvent.getContent().msgtype === "m.emote") {
44+
const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
45+
contentContainer = (<div className="mx_EventTile_content" ref="content">*&nbsp;
46+
<span className="mx_MEmoteBody_sender">{ name }</span>
47+
&nbsp;{contentElements}
48+
</div>);
49+
} else {
50+
contentContainer = (<div className="mx_EventTile_content" ref="content">{contentElements}</div>);
51+
}
52+
const timestamp = formatTime(new Date(mxEvent.getTs()), this.props.isTwelveHour);
53+
return <li className="mx_EventTile">
54+
<div className="mx_EventTile_line">
55+
<span className="mx_MessageTimestamp">{timestamp}</span>
56+
{ contentContainer }
57+
</div>
58+
</li>;
59+
}
60+
}

0 commit comments

Comments
 (0)