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

Open message in editing mode when keyboard up is pressed (RTE) #10079

Merged
merged 3 commits into from
Feb 3, 2023
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
1 change: 1 addition & 0 deletions src/components/views/rooms/MessageComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
e2eStatus={this.props.e2eStatus}
menuPosition={menuPosition}
placeholder={this.renderPlaceholderText()}
eventRelation={this.props.relation}
/>
);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ limitations under the License.
*/

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

import { SubSelection } from "./types";
import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
Expand All @@ -29,6 +30,7 @@ export function getDefaultContextValue(defaultValue?: Partial<ComposerContextSta
export interface ComposerContextState {
selection: SubSelection;
editorStateTransfer?: EditorStateTransfer;
eventRelation?: IEventRelation;
}

export const ComposerContext = createContext<ComposerContextState>(getDefaultContextValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ limitations under the License.
*/

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

import { useWysiwygSendActionHandler } from "./hooks/useWysiwygSendActionHandler";
import { WysiwygComposer } from "./components/WysiwygComposer";
Expand Down Expand Up @@ -48,17 +49,19 @@ interface SendWysiwygComposerProps {
onChange: (content: string) => void;
onSend: () => void;
menuPosition: MenuProps;
eventRelation?: IEventRelation;
}

// Default needed for React.lazy
export default function SendWysiwygComposer({
isRichTextEnabled,
e2eStatus,
menuPosition,
eventRelation,
...props
}: SendWysiwygComposerProps): JSX.Element {
const Composer = isRichTextEnabled ? WysiwygComposer : PlainTextComposer;
const defaultContextValue = useRef(getDefaultContextValue());
const defaultContextValue = useRef(getDefaultContextValue({ eventRelation }));

return (
<ComposerContext.Provider value={defaultContextValue.current}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function getFormattedContent(editorStateTransfer: EditorStateTransfer): string {
);
}

function parseEditorStateTransfer(
export function parseEditorStateTransfer(
editorStateTransfer: EditorStateTransfer,
room: Room,
mxClient: MatrixClient,
Expand Down Expand Up @@ -64,7 +64,7 @@ function parseEditorStateTransfer(
// this.saveStoredEditorState();
}

export function useInitialContent(editorStateTransfer: EditorStateTransfer): string {
export function useInitialContent(editorStateTransfer: EditorStateTransfer): string | undefined {
const roomContext = useRoomContext();
const mxClient = useMatrixClientContext();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { ComposerContextState, useComposerContext } from "../ComposerContext";
import EditorStateTransfer from "../../../../../utils/EditorStateTransfer";
import { useMatrixClientContext } from "../../../../../contexts/MatrixClientContext";
import { isCaretAtEnd, isCaretAtStart } from "../utils/selection";
import { getEventsFromEditorStateTransfer } from "../utils/event";
import { getEventsFromEditorStateTransfer, getEventsFromRoom } from "../utils/event";
import { endEditing } from "../utils/editing";

export function useInputEventProcessor(
Expand Down Expand Up @@ -87,22 +87,30 @@ function handleKeyboardEvent(
mxClient: MatrixClient,
): KeyboardEvent | null {
const { editorStateTransfer } = composerContext;
const isEditorModified = initialContent !== composer.content();
const isEditing = Boolean(editorStateTransfer);
const isEditorModified = isEditing ? initialContent !== composer.content() : composer.content().length !== 0;
const action = getKeyBindingsManager().getMessageComposerAction(event);

switch (action) {
case KeyBindingAction.SendMessage:
send();
return null;
case KeyBindingAction.EditPrevMessage: {
// If not in edition
// Or if the caret is not at the beginning of the editor
// Or the editor is modified
if (!editorStateTransfer || !isCaretAtStart(editor) || isEditorModified) {
if (!isCaretAtStart(editor) || isEditorModified) {
break;
}

const isDispatched = dispatchEditEvent(event, false, editorStateTransfer, roomContext, mxClient);
const isDispatched = dispatchEditEvent(
event,
false,
editorStateTransfer,
composerContext,
roomContext,
mxClient,
);

if (isDispatched) {
return null;
}
Expand All @@ -117,7 +125,14 @@ function handleKeyboardEvent(
break;
}

const isDispatched = dispatchEditEvent(event, true, editorStateTransfer, roomContext, mxClient);
const isDispatched = dispatchEditEvent(
event,
true,
editorStateTransfer,
composerContext,
roomContext,
mxClient,
);
if (!isDispatched) {
endEditing(roomContext);
event.preventDefault();
Expand All @@ -134,19 +149,22 @@ function handleKeyboardEvent(
function dispatchEditEvent(
event: KeyboardEvent,
isForward: boolean,
editorStateTransfer: EditorStateTransfer,
editorStateTransfer: EditorStateTransfer | undefined,
composerContext: ComposerContextState,
roomContext: IRoomState,
mxClient: MatrixClient,
): boolean {
const foundEvents = getEventsFromEditorStateTransfer(editorStateTransfer, roomContext, mxClient);
const foundEvents = editorStateTransfer
? getEventsFromEditorStateTransfer(editorStateTransfer, roomContext, mxClient)
: getEventsFromRoom(composerContext, roomContext);
if (!foundEvents) {
return false;
}

const newEvent = findEditableEvent({
events: foundEvents,
isForward,
fromEventId: editorStateTransfer.getEvent().getId(),
fromEventId: editorStateTransfer?.getEvent().getId(),
});
if (newEvent) {
dis.dispatch({
Expand Down
13 changes: 13 additions & 0 deletions src/components/views/rooms/wysiwyg_composer/utils/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ limitations under the License.
*/

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

import EditorStateTransfer from "../../../../../utils/EditorStateTransfer";
import { IRoomState } from "../../../../structures/RoomView";
import { ComposerContextState } from "../ComposerContext";

// From EditMessageComposer private get events(): MatrixEvent[]
export function getEventsFromEditorStateTransfer(
Expand All @@ -44,3 +46,14 @@ export function getEventsFromEditorStateTransfer(
const isInThread = Boolean(editorStateTransfer.getEvent().getThread());
return liveTimelineEvents.concat(isInThread ? [] : pendingEvents);
}

// From SendMessageComposer private onKeyDown = (event: KeyboardEvent): void
export function getEventsFromRoom(
composerContext: ComposerContextState,
roomContext: IRoomState,
): MatrixEvent[] | undefined {
const isReplyingToThread = composerContext.eventRelation?.key === THREAD_RELATION_TYPE.name;
return roomContext.liveTimeline
?.getEvents()
.concat(isReplyingToThread ? [] : roomContext.room?.getPendingEvents() || []);
}
10 changes: 8 additions & 2 deletions src/components/views/rooms/wysiwyg_composer/utils/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,21 @@ export function isCaretAtStart(editor: HTMLElement): boolean {
const selection = document.getSelection();

// No selection or the caret is not at the beginning of the selected element
if (!selection || selection.anchorOffset !== 0) {
if (!selection) {
return false;
}

// 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)
const isOnFirstElement = selection.anchorNode === editor && selection.anchorOffset <= 1;
if (isOnFirstElement) {
return true;
}

// In case of nested html elements (list, code blocks), we are going through all the first child
let child = editor.firstChild;
do {
if (child === selection.anchorNode) {
return true;
return selection.anchorOffset === 0;
}
} while ((child = child?.firstChild || null));

Expand Down
Loading