Add support for MD / HTML in room topics (#8215)
* Add support for MD / HTML in room topics Setting MD / HTML supported: - /topic command - Room settings overlay - Space settings overlay Display of MD / HTML supported: - /topic command - Room header - Space home Based on extensible events as defined in [MSC1767] Fixes: vector-im/element-web#5180 Signed-off-by: Johannes Marbach <johannesm@element.io> [MSC1767]: matrix-org/matrix-spec-proposals#1767 * Fix build error * Add comment to explain origin of styles Co-authored-by: Travis Ralston <travpc@gmail.com> * Empty commit to retrigger build * Fix import grouping * Fix useTopic test * Add tests for HtmlUtils * Add slash command test * Add further serialize test * Fix ternary formatting Co-authored-by: Travis Ralston <travpc@gmail.com> * Add blank line Co-authored-by: Travis Ralston <travpc@gmail.com> * Properly mock SettingsStore access * Remove trailing space * Assert on HTML content and add test for plain text in HTML parameter * Appease the linter * Fix JSDoc comment * Fix toEqual call formatting * Repurpose test for literal HTML case * Empty commit to fix CI Co-authored-by: Travis Ralston <travpc@gmail.com> Co-authored-by: Travis Ralston <travisr@matrix.org>
This commit is contained in:
parent
8036985204
commit
abd39c61b1
16 changed files with 298 additions and 19 deletions
|
@ -25,6 +25,7 @@ import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers';
|
|||
import { Element as ChildElement, parseFragment as parseHtml } from "parse5";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { IContent } from 'matrix-js-sdk/src/models/event';
|
||||
import { MRoomTopicEventContent } from 'matrix-js-sdk/src/@types/topic';
|
||||
import { SlashCommand as SlashCommandEvent } from "@matrix-org/analytics-events/types/typescript/SlashCommand";
|
||||
|
||||
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||
|
@ -32,7 +33,7 @@ import dis from './dispatcher/dispatcher';
|
|||
import { _t, _td, ITranslatableError, newTranslatableError } from './languageHandler';
|
||||
import Modal from './Modal';
|
||||
import MultiInviter from './utils/MultiInviter';
|
||||
import { linkifyAndSanitizeHtml } from './HtmlUtils';
|
||||
import { linkifyElement, topicToHtml } from './HtmlUtils';
|
||||
import QuestionDialog from "./components/views/dialogs/QuestionDialog";
|
||||
import WidgetUtils from "./utils/WidgetUtils";
|
||||
import { textToHtmlRainbow } from "./utils/colour";
|
||||
|
@ -66,6 +67,7 @@ import { XOR } from "./@types/common";
|
|||
import { PosthogAnalytics } from "./PosthogAnalytics";
|
||||
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
|
||||
import VoipUserMapper from './VoipUserMapper';
|
||||
import { htmlSerializeFromMdIfNeeded } from './editor/serialize';
|
||||
import { leaveRoomBehaviour } from "./utils/leave-behaviour";
|
||||
|
||||
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
|
||||
|
@ -463,7 +465,8 @@ export const Commands = [
|
|||
runFn: function(roomId, args) {
|
||||
const cli = MatrixClientPeg.get();
|
||||
if (args) {
|
||||
return success(cli.setRoomTopic(roomId, args));
|
||||
const html = htmlSerializeFromMdIfNeeded(args, { forceHTML: false });
|
||||
return success(cli.setRoomTopic(roomId, args, html));
|
||||
}
|
||||
const room = cli.getRoom(roomId);
|
||||
if (!room) {
|
||||
|
@ -472,14 +475,19 @@ export const Commands = [
|
|||
);
|
||||
}
|
||||
|
||||
const topicEvents = room.currentState.getStateEvents('m.room.topic', '');
|
||||
const topic = topicEvents && topicEvents.getContent().topic;
|
||||
const topicHtml = topic ? linkifyAndSanitizeHtml(topic) : _t('This room has no topic.');
|
||||
const content: MRoomTopicEventContent = room.currentState.getStateEvents('m.room.topic', '')?.getContent();
|
||||
const topic = !!content
|
||||
? ContentHelpers.parseTopicContent(content)
|
||||
: { text: _t('This room has no topic.') };
|
||||
|
||||
const ref = e => e && linkifyElement(e);
|
||||
const body = topicToHtml(topic.text, topic.html, ref, true);
|
||||
|
||||
Modal.createTrackedDialog('Slash Commands', 'Topic', InfoDialog, {
|
||||
title: room.name,
|
||||
description: <div dangerouslySetInnerHTML={{ __html: topicHtml }} />,
|
||||
description: <div ref={ref}>{ body }</div>,
|
||||
hasCloseButton: true,
|
||||
className: "markdown-body",
|
||||
});
|
||||
return success();
|
||||
},
|
||||
|
@ -1333,11 +1341,10 @@ interface ICmd {
|
|||
}
|
||||
|
||||
/**
|
||||
* Process the given text for /commands and return a bound method to perform them.
|
||||
* Process the given text for /commands and returns a parsed command that can be used for running the operation.
|
||||
* @param {string} input The raw text input by the user.
|
||||
* @return {null|function(): Object} Function returning an object with the property 'error' if there was an error
|
||||
* processing the command, or 'promise' if a request was sent out.
|
||||
* Returns null if the input didn't match a command.
|
||||
* @return {ICmd} The parsed command object.
|
||||
* Returns an empty object if the input didn't match a command.
|
||||
*/
|
||||
export function getCommand(input: string): ICmd {
|
||||
const { cmd, args } = parseCommandString(input);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue