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

Commit 2b66cfc

Browse files
authored
Open message in editing mode when keyboard up is pressed (RTE) (#10079)
Move to previous message when arrow up is pressed in the main composer (RTE)
1 parent f1a08cd commit 2b66cfc

File tree

11 files changed

+487
-365
lines changed

11 files changed

+487
-365
lines changed

src/components/views/rooms/MessageComposer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
489489
e2eStatus={this.props.e2eStatus}
490490
menuPosition={menuPosition}
491491
placeholder={this.renderPlaceholderText()}
492+
eventRelation={this.props.relation}
492493
/>
493494
);
494495
} else {

src/components/views/rooms/wysiwyg_composer/ComposerContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ limitations under the License.
1515
*/
1616

1717
import { createContext, useContext } from "react";
18+
import { IEventRelation } from "matrix-js-sdk/src/matrix";
1819

1920
import { SubSelection } from "./types";
2021
import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
@@ -29,6 +30,7 @@ export function getDefaultContextValue(defaultValue?: Partial<ComposerContextSta
2930
export interface ComposerContextState {
3031
selection: SubSelection;
3132
editorStateTransfer?: EditorStateTransfer;
33+
eventRelation?: IEventRelation;
3234
}
3335

3436
export const ComposerContext = createContext<ComposerContextState>(getDefaultContextValue());

src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ limitations under the License.
1515
*/
1616

1717
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react";
18+
import { IEventRelation } from "matrix-js-sdk/src/models/event";
1819

1920
import { useWysiwygSendActionHandler } from "./hooks/useWysiwygSendActionHandler";
2021
import { WysiwygComposer } from "./components/WysiwygComposer";
@@ -48,17 +49,19 @@ interface SendWysiwygComposerProps {
4849
onChange: (content: string) => void;
4950
onSend: () => void;
5051
menuPosition: MenuProps;
52+
eventRelation?: IEventRelation;
5153
}
5254

5355
// Default needed for React.lazy
5456
export default function SendWysiwygComposer({
5557
isRichTextEnabled,
5658
e2eStatus,
5759
menuPosition,
60+
eventRelation,
5861
...props
5962
}: SendWysiwygComposerProps): JSX.Element {
6063
const Composer = isRichTextEnabled ? WysiwygComposer : PlainTextComposer;
61-
const defaultContextValue = useRef(getDefaultContextValue());
64+
const defaultContextValue = useRef(getDefaultContextValue({ eventRelation }));
6265

6366
return (
6467
<ComposerContext.Provider value={defaultContextValue.current}>

src/components/views/rooms/wysiwyg_composer/hooks/useInitialContent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function getFormattedContent(editorStateTransfer: EditorStateTransfer): string {
3333
);
3434
}
3535

36-
function parseEditorStateTransfer(
36+
export function parseEditorStateTransfer(
3737
editorStateTransfer: EditorStateTransfer,
3838
room: Room,
3939
mxClient: MatrixClient,
@@ -64,7 +64,7 @@ function parseEditorStateTransfer(
6464
// this.saveStoredEditorState();
6565
}
6666

67-
export function useInitialContent(editorStateTransfer: EditorStateTransfer): string {
67+
export function useInitialContent(editorStateTransfer: EditorStateTransfer): string | undefined {
6868
const roomContext = useRoomContext();
6969
const mxClient = useMatrixClientContext();
7070

src/components/views/rooms/wysiwyg_composer/hooks/useInputEventProcessor.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { ComposerContextState, useComposerContext } from "../ComposerContext";
3030
import EditorStateTransfer from "../../../../../utils/EditorStateTransfer";
3131
import { useMatrixClientContext } from "../../../../../contexts/MatrixClientContext";
3232
import { isCaretAtEnd, isCaretAtStart } from "../utils/selection";
33-
import { getEventsFromEditorStateTransfer } from "../utils/event";
33+
import { getEventsFromEditorStateTransfer, getEventsFromRoom } from "../utils/event";
3434
import { endEditing } from "../utils/editing";
3535

3636
export function useInputEventProcessor(
@@ -87,22 +87,30 @@ function handleKeyboardEvent(
8787
mxClient: MatrixClient,
8888
): KeyboardEvent | null {
8989
const { editorStateTransfer } = composerContext;
90-
const isEditorModified = initialContent !== composer.content();
90+
const isEditing = Boolean(editorStateTransfer);
91+
const isEditorModified = isEditing ? initialContent !== composer.content() : composer.content().length !== 0;
9192
const action = getKeyBindingsManager().getMessageComposerAction(event);
9293

9394
switch (action) {
9495
case KeyBindingAction.SendMessage:
9596
send();
9697
return null;
9798
case KeyBindingAction.EditPrevMessage: {
98-
// If not in edition
9999
// Or if the caret is not at the beginning of the editor
100100
// Or the editor is modified
101-
if (!editorStateTransfer || !isCaretAtStart(editor) || isEditorModified) {
101+
if (!isCaretAtStart(editor) || isEditorModified) {
102102
break;
103103
}
104104

105-
const isDispatched = dispatchEditEvent(event, false, editorStateTransfer, roomContext, mxClient);
105+
const isDispatched = dispatchEditEvent(
106+
event,
107+
false,
108+
editorStateTransfer,
109+
composerContext,
110+
roomContext,
111+
mxClient,
112+
);
113+
106114
if (isDispatched) {
107115
return null;
108116
}
@@ -117,7 +125,14 @@ function handleKeyboardEvent(
117125
break;
118126
}
119127

120-
const isDispatched = dispatchEditEvent(event, true, editorStateTransfer, roomContext, mxClient);
128+
const isDispatched = dispatchEditEvent(
129+
event,
130+
true,
131+
editorStateTransfer,
132+
composerContext,
133+
roomContext,
134+
mxClient,
135+
);
121136
if (!isDispatched) {
122137
endEditing(roomContext);
123138
event.preventDefault();
@@ -134,19 +149,22 @@ function handleKeyboardEvent(
134149
function dispatchEditEvent(
135150
event: KeyboardEvent,
136151
isForward: boolean,
137-
editorStateTransfer: EditorStateTransfer,
152+
editorStateTransfer: EditorStateTransfer | undefined,
153+
composerContext: ComposerContextState,
138154
roomContext: IRoomState,
139155
mxClient: MatrixClient,
140156
): boolean {
141-
const foundEvents = getEventsFromEditorStateTransfer(editorStateTransfer, roomContext, mxClient);
157+
const foundEvents = editorStateTransfer
158+
? getEventsFromEditorStateTransfer(editorStateTransfer, roomContext, mxClient)
159+
: getEventsFromRoom(composerContext, roomContext);
142160
if (!foundEvents) {
143161
return false;
144162
}
145163

146164
const newEvent = findEditableEvent({
147165
events: foundEvents,
148166
isForward,
149-
fromEventId: editorStateTransfer.getEvent().getId(),
167+
fromEventId: editorStateTransfer?.getEvent().getId(),
150168
});
151169
if (newEvent) {
152170
dis.dispatch({

src/components/views/rooms/wysiwyg_composer/utils/event.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ limitations under the License.
1515
*/
1616

1717
import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
18+
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
1819

1920
import EditorStateTransfer from "../../../../../utils/EditorStateTransfer";
2021
import { IRoomState } from "../../../../structures/RoomView";
22+
import { ComposerContextState } from "../ComposerContext";
2123

2224
// From EditMessageComposer private get events(): MatrixEvent[]
2325
export function getEventsFromEditorStateTransfer(
@@ -44,3 +46,14 @@ export function getEventsFromEditorStateTransfer(
4446
const isInThread = Boolean(editorStateTransfer.getEvent().getThread());
4547
return liveTimelineEvents.concat(isInThread ? [] : pendingEvents);
4648
}
49+
50+
// From SendMessageComposer private onKeyDown = (event: KeyboardEvent): void
51+
export function getEventsFromRoom(
52+
composerContext: ComposerContextState,
53+
roomContext: IRoomState,
54+
): MatrixEvent[] | undefined {
55+
const isReplyingToThread = composerContext.eventRelation?.key === THREAD_RELATION_TYPE.name;
56+
return roomContext.liveTimeline
57+
?.getEvents()
58+
.concat(isReplyingToThread ? [] : roomContext.room?.getPendingEvents() || []);
59+
}

src/components/views/rooms/wysiwyg_composer/utils/selection.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,21 @@ export function isCaretAtStart(editor: HTMLElement): boolean {
4444
const selection = document.getSelection();
4545

4646
// No selection or the caret is not at the beginning of the selected element
47-
if (!selection || selection.anchorOffset !== 0) {
47+
if (!selection) {
4848
return false;
4949
}
5050

51+
// When we are pressing keyboard up in an empty main composer, the selection is on the editor with an anchorOffset at O or 1 (yes, this is strange)
52+
const isOnFirstElement = selection.anchorNode === editor && selection.anchorOffset <= 1;
53+
if (isOnFirstElement) {
54+
return true;
55+
}
56+
5157
// In case of nested html elements (list, code blocks), we are going through all the first child
5258
let child = editor.firstChild;
5359
do {
5460
if (child === selection.anchorNode) {
55-
return true;
61+
return selection.anchorOffset === 0;
5662
}
5763
} while ((child = child?.firstChild || null));
5864

0 commit comments

Comments
 (0)