Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"dependencies": {
"@babel/runtime": "^7.12.5",
"@matrix-org/analytics-events": "^0.5.0",
"@matrix-org/matrix-wysiwyg": "^2.3.0",
"@matrix-org/matrix-wysiwyg": "^2.3.1",
"@matrix-org/react-sdk-module-api": "^1.0.0",
"@sentry/browser": "^7.0.0",
"@sentry/tracing": "^7.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/rooms/MessageComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
const { isRichTextEnabled, composerContent } = this.state;
const convertedContent = isRichTextEnabled
? await richToPlain(composerContent)
: await plainToRich(composerContent);
: await plainToRich(composerContent, false);

this.setState({
isRichTextEnabled: !isRichTextEnabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,27 @@ export const dynamicImportSendMessage = async (
};

export const dynamicImportConversionFunctions = async (): Promise<{
/**
* Creates a rust model from rich text input (html) and uses it to generate the plain text equivalent (which may
* contain markdown). The return value must be used to set `.innerHTML` (rather than `.innerText`) to
* ensure that HTML entities are correctly interpreted, and to prevent newline characters being turned into `<br>`.
*
* @param rich - html to convert
* @returns a string of plain text that may contain markdown
*/
richToPlain(rich: string): Promise<string>;
plainToRich(plain: string): Promise<string>;

/**
* Creates a rust model from plain text input (interpreted as markdown) and uses it to generate the rich text
* equivalent. Output can be formatted for display in the composer or for sending in a Matrix message.
*
* @param plain - plain text to convert. Note: when reading the plain text from the editor element, be sure to
* use `.innerHTML` (rather than `.innerText`) to ensure that punctuation characters are correctly HTML-encoded.
* @param inMessageFormat - `true` to format the return value for use as a message `formatted_body`.
* `false` to format it for writing to an editor element.
* @returns a string of html
*/
plainToRich(plain: string, inMessageFormat: boolean): Promise<string>;
}> => {
const { richToPlain, plainToRich } = await retry(() => import("@matrix-org/matrix-wysiwyg"), RETRY_COUNT);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import { RefObject, useEffect } from "react";

export function usePlainTextInitialization(initialContent = "", ref: RefObject<HTMLElement>): void {
useEffect(() => {
// always read and write the ref.current using .innerHTML for consistency in linebreak and HTML entity handling
if (ref.current) {
ref.current.innerText = initialContent;
ref.current.innerHTML = initialContent;
}
}, [ref, initialContent]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@ function isDivElement(target: EventTarget): target is HTMLDivElement {
return target instanceof HTMLDivElement;
}

// Hitting enter inside the editor inserts an editable div, initially containing a <br />
// For correct display, first replace this pattern with a newline character and then remove divs
// noting that they are used to delimit paragraphs
function amendInnerHtml(text: string): string {
return text
.replace(/<div><br><\/div>/g, "\n") // this is pressing enter then not typing
.replace(/<div>/g, "\n") // this is from pressing enter, then typing inside the div
.replace(/<\/div>/g, "");
}

/**
* React hook which generates all of the listeners and the ref to be attached to the editor.
*
Expand Down Expand Up @@ -100,9 +90,8 @@ export function usePlainTextListeners(
} else if (isNotNull(ref) && isNotNull(ref.current)) {
// if called with no argument, read the current innerHTML from the ref and amend it as per `onInput`
const currentRefContent = ref.current.innerHTML;
const amendedContent = amendInnerHtml(currentRefContent);
setContent(amendedContent);
onChange?.(amendedContent);
setContent(currentRefContent);
onChange?.(currentRefContent);
}
},
[onChange, ref],
Expand All @@ -113,16 +102,13 @@ export function usePlainTextListeners(
// when a user selects a suggestion from the autocomplete menu
const { suggestion, onSelect, handleCommand, handleMention, handleAtRoomMention } = useSuggestion(ref, setText);

const enterShouldSend = !useSettingValue<boolean>("MessageComposerInput.ctrlEnterToSend");
const onInput = useCallback(
(event: SyntheticEvent<HTMLDivElement, InputEvent | ClipboardEvent>) => {
if (isDivElement(event.target)) {
// if enterShouldSend, we do not need to amend the html before setting text
const newInnerHTML = enterShouldSend ? event.target.innerHTML : amendInnerHtml(event.target.innerHTML);
setText(newInnerHTML);
setText(event.target.innerHTML);
}
},
[setText, enterShouldSend],
[setText],
);

const onPaste = useCallback(
Expand All @@ -146,6 +132,7 @@ export function usePlainTextListeners(
[eventRelation, mxClient, onInput, roomContext],
);

const enterShouldSend = !useSettingValue<boolean>("MessageComposerInput.ctrlEnterToSend");
const onKeyDown = useCallback(
(event: KeyboardEvent<HTMLDivElement>) => {
// we need autocomplete to take priority when it is open for using enter to select
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export async function createMessageContent(
// TODO markdown support

const isMarkdownEnabled = SettingsStore.getValue<boolean>("MessageComposerInput.useMarkdown");
const formattedBody = isHTML ? message : isMarkdownEnabled ? await plainToRich(message) : null;
const formattedBody = isHTML ? message : isMarkdownEnabled ? await plainToRich(message, true) : null;

if (formattedBody) {
content.format = "org.matrix.custom.html";
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1610,10 +1610,10 @@
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0.tgz#766580036d4df12120ded223e13b5640e77db136"
integrity sha512-ra/bcFdleC1iRNms2I96UXA0NvQYWpMsHrV5EfJRS7qV1PtnQNvgsvMfjMbkx8QT2ErEmIhsvB5fPCpfp8BSuw==

"@matrix-org/matrix-wysiwyg@^2.3.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-2.3.0.tgz#7a815fb90600342cc74c03a3cc7c9908a1d15dd1"
integrity sha512-VtA+Bti2IdqpnpCNaTFHMjbpKXe4xHR+OWWJl/gjuYgn4NJO9lfeeEIv34ftC6dBh7R280JEiMxQ9mDcH0J54g==
"@matrix-org/matrix-wysiwyg@^2.3.1":
version "2.3.1"
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-2.3.1.tgz#4b607323f3ffd8c332abeba7226010ecc031ed12"
integrity sha512-OxJvA+pSGdP2f55foZGEDmU2qvILFLLjV53MOgPw1F6zDAp8nDL1rPPIzFv1qgDj5W7d4Rzq7FnN25vINnAu+A==

"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz":
version "3.2.14"
Expand Down