From c7dbb5947fbf491f1bbb3676a8521d33dae35a94 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Tue, 25 Oct 2022 18:33:25 +0200 Subject: [PATCH] Keep content when switching between rich text and plain text mode --- .../views/rooms/MessageComposer.tsx | 8 ++++++++ .../wysiwyg_composer/SendWysiwygComposer.tsx | 1 + .../components/PlainTextComposer.tsx | 20 +++++++++++++------ ...rFunctions.tsx => useComposerFunctions.ts} | 0 ...Listeners.tsx => usePlainTextListeners.ts} | 0 .../utils/createMessageContent.ts | 5 +---- src/utils/room/htmlToPlaintext.ts | 19 ++++++++++++++++++ 7 files changed, 43 insertions(+), 10 deletions(-) rename src/components/views/rooms/wysiwyg_composer/hooks/{useComposerFunctions.tsx => useComposerFunctions.ts} (100%) rename src/components/views/rooms/wysiwyg_composer/hooks/{usePlainTextListeners.tsx => usePlainTextListeners.ts} (100%) create mode 100644 src/utils/room/htmlToPlaintext.ts diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index f663f57e9c..787b4e2e5b 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -60,6 +60,7 @@ import { } from '../../../voice-broadcast'; import { SendWysiwygComposer, sendMessage } from './wysiwyg_composer/'; import { MatrixClientProps, withMatrixClientHOC } from '../../../contexts/MatrixClientContext'; +import { htmlToPlainText } from '../../../utils/room/htmlToPlaintext'; let instanceCount = 0; @@ -102,6 +103,7 @@ interface IState { showVoiceBroadcastButton: boolean; isWysiwygLabEnabled: boolean; isRichTextEnabled: boolean; + initialComposerContent: string; } export class MessageComposer extends React.Component { @@ -138,6 +140,7 @@ export class MessageComposer extends React.Component { showVoiceBroadcastButton: SettingsStore.getValue(Features.VoiceBroadcast), isWysiwygLabEnabled: SettingsStore.getValue("feature_wysiwyg_composer"), isRichTextEnabled: true, + initialComposerContent: '', }; this.instanceId = instanceCount++; @@ -355,6 +358,10 @@ export class MessageComposer extends React.Component { private onRichTextToggle = () => { this.setState(state => ({ isRichTextEnabled: !state.isRichTextEnabled, + initialComposerContent: !state.isRichTextEnabled ? + state.composerContent : + // TODO when available use rust model plain text + htmlToPlainText(state.composerContent), })); }; @@ -434,6 +441,7 @@ export class MessageComposer extends React.Component { onChange={this.onWysiwygChange} onSend={this.sendMessage} isRichTextEnabled={this.state.isRichTextEnabled} + initialContent={this.state.initialComposerContent} />, ); } else { diff --git a/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx index 9208e79ac4..a612cef433 100644 --- a/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx +++ b/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx @@ -34,6 +34,7 @@ const Content = forwardRef( ); interface SendWysiwygComposerProps { + initialContent: string; isRichTextEnabled: boolean; disabled?: boolean; onChange: (content: string) => void; diff --git a/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx b/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx index cf25175755..d873c3549c 100644 --- a/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx +++ b/src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer.tsx @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { MutableRefObject, ReactNode } from 'react'; +import React, { MutableRefObject, ReactNode, useEffect } from 'react'; + import { useComposerFunctions } from '../hooks/useComposerFunctions'; import { usePlainTextListeners } from '../hooks/usePlainTextListeners'; import { ComposerFunctions } from '../types'; - import { Editor } from "./Editor"; interface PlainTextComposerProps { @@ -33,12 +33,20 @@ interface PlainTextComposerProps { ) => ReactNode; } -export function PlainTextComposer({ className, disabled, onSend, onChange, children }: PlainTextComposerProps) { - const {ref, onInput, onPaste, onKeyDown} = usePlainTextListeners(onChange, onSend) - const composerFunctions = useComposerFunctions(ref) +export function PlainTextComposer({ + className, disabled, onSend, onChange, children, initialContent }: PlainTextComposerProps, +) { + const { ref, onInput, onPaste, onKeyDown } = usePlainTextListeners(onChange, onSend); + const composerFunctions = useComposerFunctions(ref); + + useEffect(() => { + if (ref.current) { + ref.current.innerText = initialContent; + } + }, [ref, initialContent]); return
- {children?.(ref, composerFunctions)} + { children?.(ref, composerFunctions) }
; } diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.tsx b/src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.ts similarity index 100% rename from src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.tsx rename to src/components/views/rooms/wysiwyg_composer/hooks/useComposerFunctions.ts diff --git a/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.tsx b/src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts similarity index 100% rename from src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.tsx rename to src/components/views/rooms/wysiwyg_composer/hooks/usePlainTextListeners.ts diff --git a/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts b/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts index df42b0062b..0b4c983acf 100644 --- a/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts +++ b/src/components/views/rooms/wysiwyg_composer/utils/createMessageContent.ts @@ -20,6 +20,7 @@ import { htmlSerializeFromMdIfNeeded } from "../../../../../editor/serialize"; import SettingsStore from "../../../../../settings/SettingsStore"; import { RoomPermalinkCreator } from "../../../../../utils/permalinks/Permalinks"; import { addReplyToMessageContent } from "../../../../../utils/Reply"; +import { htmlToPlainText } from "../../../../../utils/room/htmlToPlaintext"; // Merges favouring the given relation function attachRelation(content: IContent, relation?: IEventRelation): void { @@ -50,10 +51,6 @@ function getTextReplyFallback(mxEvent: MatrixEvent): string { return ""; } -function htmlToPlainText(html: string) { - return new DOMParser().parseFromString(html, 'text/html').documentElement.textContent; -} - interface CreateMessageContentParams { relation?: IEventRelation; replyToEvent?: MatrixEvent; diff --git a/src/utils/room/htmlToPlaintext.ts b/src/utils/room/htmlToPlaintext.ts new file mode 100644 index 0000000000..883db8d360 --- /dev/null +++ b/src/utils/room/htmlToPlaintext.ts @@ -0,0 +1,19 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +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. +*/ + +export function htmlToPlainText(html: string) { + return new DOMParser().parseFromString(html, 'text/html').documentElement.textContent; +}