diff --git a/src/components/views/rooms/SendMessageComposer.js b/src/components/views/rooms/SendMessageComposer.js index c11d940331..c4ae2929af 100644 --- a/src/components/views/rooms/SendMessageComposer.js +++ b/src/components/views/rooms/SendMessageComposer.js @@ -24,6 +24,8 @@ import { containsEmote, stripEmoteCommand, unescapeMessage, + startsWith, + stripPrefix, } from '../../../editor/serialize'; import {CommandPartCreator} from '../../../editor/parts'; import BasicMessageComposer from "./BasicMessageComposer"; @@ -61,6 +63,9 @@ function createMessageContent(model, permalinkCreator) { if (isEmote) { model = stripEmoteCommand(model); } + if (startsWith(model, "//")) { + model = stripPrefix(model, "/"); + } model = unescapeMessage(model); const repliedToEvent = RoomViewStore.getQuotingEvent(); @@ -175,13 +180,13 @@ export default class SendMessageComposer extends React.Component { const parts = this.model.parts; const firstPart = parts[0]; if (firstPart) { - if (firstPart.type === "command") { + if (firstPart.type === "command" && !firstPart.text.startsWith("//")) { return true; } // be extra resilient when somehow the AutocompleteWrapperModel or // CommandPartCreator fails to insert a command part, so we don't send // a command as a message - if (firstPart.text.startsWith("/") && (firstPart.type === "plain" || firstPart.type === "pill-candidate")) { + if (firstPart.text.startsWith("/") && !firstPart.text.startsWith("//") && (firstPart.type === "plain" || firstPart.type === "pill-candidate")) { return true; } } diff --git a/src/editor/serialize.js b/src/editor/serialize.js index a55eed97da..ba380f2809 100644 --- a/src/editor/serialize.js +++ b/src/editor/serialize.js @@ -61,18 +61,26 @@ export function textSerialize(model) { } export function containsEmote(model) { + return startsWith(model, "/me "); +} + +export function startsWith(model, prefix) { const firstPart = model.parts[0]; // part type will be "plain" while editing, // and "command" while composing a message. return firstPart && (firstPart.type === "plain" || firstPart.type === "command") && - firstPart.text.startsWith("/me "); + firstPart.text.startsWith(prefix); } export function stripEmoteCommand(model) { // trim "/me " + return stripPrefix(model, "/me "); +} + +export function stripPrefix(model, prefix) { model = model.clone(); - model.removeText({index: 0, offset: 0}, 4); + model.removeText({index: 0, offset: 0}, prefix.length); return model; }