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

Commit

Permalink
Open message in editing mode when keyboard up is pressed (RTE) (#10079)
Browse files Browse the repository at this point in the history
Move to previous message when arrow up is pressed in the main composer (RTE)
  • Loading branch information
florianduros authored Feb 3, 2023
1 parent f1a08cd commit 2b66cfc
Show file tree
Hide file tree
Showing 11 changed files with 487 additions and 365 deletions.
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

0 comments on commit 2b66cfc

Please sign in to comment.