From 0b17812b9cfc412a7a2cde11bcffab6722d1c414 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 14 Jun 2019 11:01:34 +0200 Subject: [PATCH 1/3] allow editing emotes --- src/utils/EventUtils.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/utils/EventUtils.js b/src/utils/EventUtils.js index 219b53bc5e..ffc47e2277 100644 --- a/src/utils/EventUtils.js +++ b/src/utils/EventUtils.js @@ -46,9 +46,12 @@ export function isContentActionable(mxEvent) { } export function canEditContent(mxEvent) { - return mxEvent.status !== EventStatus.CANCELLED && - mxEvent.getType() === 'm.room.message' && - mxEvent.getOriginalContent().msgtype === "m.text" && + if (mxEvent.status === EventStatus.CANCELLED || mxEvent.getType() !== "m.room.message") { + return false; + } + const content = mxEvent.getOriginalContent(); + const {msgtype} = content; + return (msgtype === "m.text" || msgtype === "m.emote") && mxEvent.getSender() === MatrixClientPeg.get().getUserId(); } From aecfbce55cb70fd6acad41847c95e75b97c04afb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 14 Jun 2019 11:01:52 +0200 Subject: [PATCH 2/3] prepend "/me " to emotes when parsing them to edit --- src/editor/deserialize.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/editor/deserialize.js b/src/editor/deserialize.js index 48625cba5f..2d98bbc41a 100644 --- a/src/editor/deserialize.js +++ b/src/editor/deserialize.js @@ -207,12 +207,13 @@ function parseHtmlMessage(html, room, client) { export function parseEvent(event, room, client) { const content = event.getContent(); + let parts; if (content.format === "org.matrix.custom.html") { - return parseHtmlMessage(content.formatted_body || "", room, client); + parts = parseHtmlMessage(content.formatted_body || "", room, client); } else { const body = content.body || ""; const lines = body.split("\n"); - const parts = lines.reduce((parts, line, i) => { + parts = lines.reduce((parts, line, i) => { const isLast = i === lines.length - 1; const text = new PlainPart(line); const newLine = !isLast && new NewlinePart("\n"); @@ -222,6 +223,9 @@ export function parseEvent(event, room, client) { return parts.concat(text); } }, []); - return parts; } + if (content.msgtype === "m.emote") { + parts.unshift(new PlainPart("/me ")); + } + return parts; } From 3cfdd518ee51598d6fdbf3a359d86c08cfb88cd1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 14 Jun 2019 11:02:20 +0200 Subject: [PATCH 3/3] detect emote when sending (and trim "/me " for content) --- src/components/views/elements/MessageEditor.js | 18 +++++++++++++++--- src/editor/model.js | 8 ++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/components/views/elements/MessageEditor.js b/src/components/views/elements/MessageEditor.js index 0aff6781ee..9faae4588b 100644 --- a/src/components/views/elements/MessageEditor.js +++ b/src/components/views/elements/MessageEditor.js @@ -150,16 +150,28 @@ export default class MessageEditor extends React.Component { dis.dispatch({action: 'focus_composer'}); } + _isEmote() { + const firstPart = this.model.parts[0]; + return firstPart && firstPart.type === "plain" && firstPart.text.startsWith("/me "); + } + _sendEdit = () => { + const isEmote = this._isEmote(); + let model = this.model; + if (isEmote) { + // trim "/me " + model = model.clone(); + model.removeText({index: 0, offset: 0}, 4); + } const newContent = { - "msgtype": "m.text", - "body": textSerialize(this.model), + "msgtype": isEmote ? "m.emote" : "m.text", + "body": textSerialize(model), }; const contentBody = { msgtype: newContent.msgtype, body: ` * ${newContent.body}`, }; - const formattedBody = htmlSerializeIfNeeded(this.model); + const formattedBody = htmlSerializeIfNeeded(model); if (formattedBody) { newContent.format = "org.matrix.custom.html"; newContent.formatted_body = formattedBody; diff --git a/src/editor/model.js b/src/editor/model.js index 04a56ab65b..7cc6041044 100644 --- a/src/editor/model.js +++ b/src/editor/model.js @@ -27,6 +27,10 @@ export default class EditorModel { this._updateCallback = updateCallback; } + clone() { + return new EditorModel(this._parts, this._partCreator, this._updateCallback); + } + _insertPart(index, part) { this._parts.splice(index, 0, part); if (this._activePartIdx >= index) { @@ -91,7 +95,7 @@ export default class EditorModel { const position = this.positionForOffset(diff.at, caret.atNodeEnd); let removedOffsetDecrease = 0; if (diff.removed) { - removedOffsetDecrease = this._removeText(position, diff.removed.length); + removedOffsetDecrease = this.removeText(position, diff.removed.length); } let addedLen = 0; if (diff.added) { @@ -177,7 +181,7 @@ export default class EditorModel { * @return {Number} how many characters before pos were also removed, * usually because of non-editable parts that can only be removed in their entirety. */ - _removeText(pos, len) { + removeText(pos, len) { let {index, offset} = pos; let removedOffsetDecrease = 0; while (len > 0) {