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

Initial support for editing messages #2952

Merged
merged 49 commits into from
May 15, 2019
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
6599d60
wire up editor component (somewhat hacky)
bwindels May 6, 2019
9f98a6c
add converted prototype code
bwindels May 6, 2019
76bb56a
initial hookup editor code with react component
bwindels May 7, 2019
6be6492
initial parsing of pills for editor
bwindels May 7, 2019
8f0074f
ignore react comment nodes when locating/setting caret
bwindels May 8, 2019
ebdb9fc
don't collapse whitespace in editor
bwindels May 8, 2019
0f38753
some comments
bwindels May 8, 2019
85adc89
remove logging
bwindels May 8, 2019
a2f1f49
update the DOM manually as opposed through react rendering
bwindels May 8, 2019
a765fdf
run autocomplete after mounting
bwindels May 9, 2019
7507d0d
complete proptypes
bwindels May 9, 2019
1330b43
initial support for auto complete in model and parts
bwindels May 9, 2019
317e88b
initial hacky hookup of Autocomplete menu in MessageEditor
bwindels May 9, 2019
bb73521
prefer textContent over innerText as it's faster
bwindels May 9, 2019
4bb8b79
initial auto complete wrapper, make existing autocompleter work w/ model
bwindels May 9, 2019
fc87a27
make editor nicer
bwindels May 9, 2019
5e6367a
basic support for non-editable parts
bwindels May 9, 2019
aa1b4bb
keep auto complete code close to each other
bwindels May 9, 2019
64b1711
rerender through callback instead of after modifying model
bwindels May 9, 2019
ffff66a
handle Escape properly
bwindels May 9, 2019
22587da
close autocomplete on enter
bwindels May 9, 2019
bc14d4f
comment
bwindels May 9, 2019
580a898
fix autocompl. not always appearing/being updated when there is no part
bwindels May 9, 2019
8d97c00
catch this for now as caret behaviour is still a bit flaky
bwindels May 9, 2019
1a577ee
take non-editable parts into account for new caret position
bwindels May 9, 2019
2c3453d
put caret after replaced part if no caretOffset is given by autocomplete
bwindels May 9, 2019
7a85dd4
after completion, set caret in next part at start
bwindels May 10, 2019
9f597c7
no comment nodes without react,so can bring this back to simpler version
bwindels May 10, 2019
7ebb6ce
WIP commit, newlines sort of working
bwindels May 13, 2019
9e0816c
find caret offset and calculate editor text in same tree-walking algo
bwindels May 13, 2019
4ff37ca
don't show model for now
bwindels May 13, 2019
a3b02cf
make logging quiet
bwindels May 13, 2019
c44fed4
even less logging
bwindels May 13, 2019
c98e716
some pill styling
bwindels May 13, 2019
eaf43d7
correctly parse BRs
bwindels May 13, 2019
2fbe73e
draft of formatting
bwindels May 13, 2019
3abdf6b
also serialize to text and method to tell us if we need html for model
bwindels May 14, 2019
34dbe5f
add newline parts for text messages as well
bwindels May 14, 2019
759a4a5
send the actual m.replace event from composer content
bwindels May 14, 2019
036cb02
add feature flag
bwindels May 14, 2019
e2388af
consistent naming between serialize and deserialize modules
bwindels May 14, 2019
15df72e
reload events when event gets replaced in the timeline
bwindels May 14, 2019
45991bc
replace original event if there have been previous edits
bwindels May 14, 2019
0b18ff5
pass feature flag to js-sdk
bwindels May 14, 2019
fd31e79
fix lint
bwindels May 14, 2019
dc21faa
send edit also in n.new_content field
bwindels May 14, 2019
d83e278
PR feedback, cleanup
bwindels May 15, 2019
6b932d5
remove cruft from edit icon
bwindels May 15, 2019
22533ba
use theme var for bg color
bwindels May 15, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions res/css/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
@import "./views/elements/_InlineSpinner.scss";
@import "./views/elements/_ManageIntegsButton.scss";
@import "./views/elements/_MemberEventListSummary.scss";
@import "./views/elements/_MessageEditor.scss";
@import "./views/elements/_PowerSelector.scss";
@import "./views/elements/_ProgressBar.scss";
@import "./views/elements/_ReplyThread.scss";
Expand Down
72 changes: 72 additions & 0 deletions res/css/views/elements/_MessageEditor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright 2019 Vector Creations Ltd
bwindels marked this conversation as resolved.
Show resolved Hide resolved

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

.mx_MessageEditor {
border-radius: 4px;
background-color: #f3f8fd;
bwindels marked this conversation as resolved.
Show resolved Hide resolved
padding: 11px 13px 7px 56px;

.editor {
border-radius: 4px;
border: solid 1px #e9edf1;
background-color: #ffffff;
padding: 10px;
white-space: pre-wrap;
word-wrap: break-word;
outline: none;

span {
display: inline-block;
padding: 0 5px;
border-radius: 4px;
color: white;
}

span.user-pill, span.room-pill {
border-radius: 16px;
display: inline-block;
color: $primary-fg-color;
background-color: $other-user-pill-bg-color;
padding-left: 5px;
padding-right: 5px;
}
}

.buttons {
display: flex;
flex-direction: row;
justify-content: end;
padding: 5px 0;

.mx_AccessibleButton {
margin-left: 5px;
padding: 5px 40px;
}
}

.model {
background: lightgrey;
padding: 5px;
display: none;
white-space: pre;
font-size: 12px;
}

.mx_MessageEditor_AutoCompleteWrapper {
position: relative;
height: 0;
}
}
4 changes: 4 additions & 0 deletions res/css/views/messages/_MessageActionBar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ limitations under the License.
mask-image: url('$(res)/img/reply.svg');
}

.mx_MessageActionBar_editButton::after {
mask-image: url('$(res)/img/edit.svg');
}

.mx_MessageActionBar_optionsButton::after {
mask-image: url('$(res)/img/icon_context.svg');
}
97 changes: 97 additions & 0 deletions res/img/edit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/MatrixClientPeg.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class MatrixClientPeg {

_createClient(creds: MatrixClientCreds) {
const aggregateRelations = SettingsStore.isFeatureEnabled("feature_reactions");
const enableEdits = SettingsStore.isFeatureEnabled("feature_message_editing");

const opts = {
baseUrl: creds.homeserverUrl,
Expand All @@ -187,6 +188,7 @@ class MatrixClientPeg {
forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer', false),
verificationMethods: [verificationMethods.SAS],
unstableClientRelationAggregation: aggregateRelations,
unstableClientRelationReplacements: enableEdits,
};

this.matrixClient = createMatrixClient(opts);
Expand Down
5 changes: 5 additions & 0 deletions src/components/structures/MessagePanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,14 @@ module.exports = React.createClass({

_getTilesForEvent: function(prevEvent, mxEv, last) {
const EventTile = sdk.getComponent('rooms.EventTile');
const MessageEditor = sdk.getComponent('elements.MessageEditor');
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const ret = [];

if (this.props.editEvent && this.props.editEvent.getId() === mxEv.getId()) {
return [<MessageEditor key={mxEv.getId()} event={mxEv} />];
}

// is this a continuation of the previous message?
let continuation = false;

Expand Down
17 changes: 17 additions & 0 deletions src/components/structures/TimelinePanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ const TimelinePanel = React.createClass({
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().on("Room.timelineReset", this.onRoomTimelineReset);
MatrixClientPeg.get().on("Room.redaction", this.onRoomRedaction);
MatrixClientPeg.get().on("Room.replaceEvent", this.onRoomReplaceEvent);
MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt);
MatrixClientPeg.get().on("Room.localEchoUpdated", this.onLocalEchoUpdated);
MatrixClientPeg.get().on("Room.accountData", this.onAccountData);
Expand Down Expand Up @@ -282,6 +283,7 @@ const TimelinePanel = React.createClass({
client.removeListener("Room.timeline", this.onRoomTimeline);
client.removeListener("Room.timelineReset", this.onRoomTimelineReset);
client.removeListener("Room.redaction", this.onRoomRedaction);
client.removeListener("Room.replaceEvent", this.onRoomReplaceEvent);
client.removeListener("Room.receipt", this.onRoomReceipt);
client.removeListener("Room.localEchoUpdated", this.onLocalEchoUpdated);
client.removeListener("Room.accountData", this.onAccountData);
Expand Down Expand Up @@ -402,6 +404,9 @@ const TimelinePanel = React.createClass({
if (payload.action === 'ignore_state_changed') {
this.forceUpdate();
}
if (payload.action === "edit_event") {
this.setState({editEvent: payload.event});
}
},

onRoomTimeline: function(ev, room, toStartOfTimeline, removed, data) {
Expand Down Expand Up @@ -502,6 +507,17 @@ const TimelinePanel = React.createClass({
this.forceUpdate();
},

onRoomReplaceEvent: function(replacedEvent, newEvent, room) {
if (this.unmounted) return;

// ignore events for other rooms
if (room !== this.props.timelineSet.room) return;

// we could skip an update if the event isn't in our timeline,
// but that's probably an early optimisation.
this._reloadEvents();
},

onRoomReceipt: function(ev, room) {
if (this.unmounted) return;

Expand Down Expand Up @@ -1244,6 +1260,7 @@ const TimelinePanel = React.createClass({
tileShape={this.props.tileShape}
resizeNotifier={this.props.resizeNotifier}
getRelationsForEvent={this.getRelationsForEvent}
editEvent={this.state.editEvent}
/>
);
},
Expand Down
Loading