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

Handle /me in rte #10558

Merged
merged 10 commits into from
Apr 11, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import SettingsStore from "../../../../../settings/SettingsStore";
import { RoomPermalinkCreator } from "../../../../../utils/permalinks/Permalinks";
import { addReplyToMessageContent } from "../../../../../utils/Reply";

export const EMOTE_PREFIX = "/me ";

// Merges favouring the given relation
function attachRelation(content: IContent, relation?: IEventRelation): void {
if (relation) {
Expand Down Expand Up @@ -61,6 +63,8 @@ interface CreateMessageContentParams {
editedEvent?: MatrixEvent;
}

const isMatrixEvent = (e: MatrixEvent | undefined): e is MatrixEvent => e instanceof MatrixEvent;

export async function createMessageContent(
message: string,
isHTML: boolean,
Expand All @@ -72,22 +76,22 @@ export async function createMessageContent(
editedEvent,
}: CreateMessageContentParams,
): Promise<IContent> {
// TODO emote ?

const isEditing = Boolean(editedEvent);
const isReply = isEditing ? Boolean(editedEvent?.replyEventId) : Boolean(replyToEvent);
const isEditing = isMatrixEvent(editedEvent);
const isReply = isEditing ? Boolean(editedEvent.replyEventId) : isMatrixEvent(replyToEvent);
Comment on lines +79 to +80
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change allows TS to help us a bit more in the body of this big function, and saves us having to keep checking whether the event is undefined or not.

const isReplyAndEditing = isEditing && isReply;

/*const isEmote = containsEmote(model);
const isEmote = message.startsWith(EMOTE_PREFIX);
if (isEmote) {
model = stripEmoteCommand(model);
// if we are dealing with an emote we want to remove the prefix so that `/me` does not
// appear after the `* <userName>` text in the timeline
message = message.slice(EMOTE_PREFIX.length);
}
if (startsWith(model, "//")) {
model = stripPrefix(model, "/");
if (message.startsWith("//")) {
// if user wants to enter a single slash at the start of a message, this
// is how they have to do it (due to it clashing with commands), so here we
// remove the first character to make sure //word displays as /word
message = message.slice(1);
}
model = unescapeMessage(model);*/

// const body = textSerialize(model);

// if we're editing rich text, the message content is pure html
// BUT if we're not, the message content will be plain text
Expand All @@ -96,8 +100,7 @@ export async function createMessageContent(
const formattedBodyPrefix = (isReplyAndEditing && getHtmlReplyFallback(editedEvent)) || "";

const content: IContent = {
// TODO emote
msgtype: MsgType.Text,
msgtype: isEmote ? MsgType.Emote : MsgType.Text,
body: isEditing ? `${bodyPrefix} * ${body}` : body,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import dis from "../../../../../dispatcher/dispatcher";
import { createRedactEventDialog } from "../../../dialogs/ConfirmRedactDialog";
import { endEditing, cancelPreviousPendingEdit } from "./editing";
import EditorStateTransfer from "../../../../../utils/EditorStateTransfer";
import { createMessageContent } from "./createMessageContent";
import { createMessageContent, EMOTE_PREFIX } from "./createMessageContent";
import { isContentModified } from "./isContentModified";
import { CommandCategories, getCommand } from "../../../../../SlashCommands";
import { runSlashCommand, shouldSendAnyway } from "../../../../../editor/commands";
Expand Down Expand Up @@ -78,11 +78,11 @@ export async function sendMessage(

let content: IContent | null = null;

// Functionality here approximates what can be found in SendMessageComposer.sendMessage()
if (message.startsWith("/") && !message.startsWith("//")) {
// Slash command handling here approximates what can be found in SendMessageComposer.sendMessage()
// but note that the /me and // special cases are handled by the call to createMessageContent
if (message.startsWith("/") && !message.startsWith("//") && !message.startsWith(EMOTE_PREFIX)) {
const { cmd, args } = getCommand(message);
if (cmd) {
// TODO handle /me special case separately, see end of SlashCommands.Commands
const threadId = relation?.rel_type === THREAD_RELATION_TYPE.name ? relation?.event_id : null;
let commandSuccessful: boolean;
[content, commandSuccessful] = await runSlashCommand(cmd, args, roomId, threadId ?? null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ 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.
*/
import { MsgType } from "matrix-js-sdk/src/matrix";

import { mkEvent } from "../../../../../test-utils";
import { RoomPermalinkCreator } from "../../../../../../src/utils/permalinks/Permalinks";
import { createMessageContent } from "../../../../../../src/components/views/rooms/wysiwyg_composer/utils/createMessageContent";
import {
createMessageContent,
EMOTE_PREFIX,
} from "../../../../../../src/components/views/rooms/wysiwyg_composer/utils/createMessageContent";

describe("createMessageContent", () => {
const permalinkCreator = {
Expand Down Expand Up @@ -130,4 +134,24 @@ describe("createMessageContent", () => {
},
});
});

it("Should strip the /me prefix from a message", async () => {
const textBody = "some body text";
const content = await createMessageContent(EMOTE_PREFIX + textBody, true, { permalinkCreator });

expect(content).toMatchObject({ body: textBody, formatted_body: textBody });
});

it("Should strip single / from message prefixed with //", async () => {
const content = await createMessageContent("//twoSlashes", true, { permalinkCreator });

expect(content).toMatchObject({ body: "/twoSlashes", formatted_body: "/twoSlashes" });
});

it("Should set the content type to MsgType.Emote when /me prefix is used", async () => {
const textBody = "some body text";
const content = await createMessageContent(EMOTE_PREFIX + textBody, true, { permalinkCreator });

expect(content).toMatchObject({ msgtype: MsgType.Emote });
});
});