Use the KeyBindingsManager in EditMessageComposer

pull/21833/head
Clemens Zeidler 2021-02-16 19:05:39 +13:00
parent 4a138f3b84
commit 12387b4978
2 changed files with 65 additions and 39 deletions

View File

@ -2,21 +2,33 @@ import { isMac, Key } from './Keyboard';
import SettingsStore from './settings/SettingsStore'; import SettingsStore from './settings/SettingsStore';
export enum KeyBindingContext { export enum KeyBindingContext {
SendMessageComposer = 'SendMessageComposer', /** Key bindings for the chat message composer component */
MessageComposer = 'MessageComposer',
} }
export enum KeyAction { export enum KeyAction {
None = 'None', None = 'None',
// SendMessageComposer actions: // SendMessageComposer actions:
/** Send a message */
Send = 'Send', Send = 'Send',
/** Go backwards through the send history and use the message in composer view */
SelectPrevSendHistory = 'SelectPrevSendHistory', SelectPrevSendHistory = 'SelectPrevSendHistory',
/** Go forwards through the send history */
SelectNextSendHistory = 'SelectNextSendHistory', SelectNextSendHistory = 'SelectNextSendHistory',
EditLastMessage = 'EditLastMessage', /** Start editing the user's last sent message */
EditPrevMessage = 'EditPrevMessage',
/** Start editing the user's next sent message */
EditNextMessage = 'EditNextMessage',
/** Cancel editing a message */
CancelEditing = 'CancelEditing',
} }
/** /**
* Represent a key combination. * Represent a key combination.
* *
* The combo is evaluated strictly, i.e. the KeyboardEvent must match exactly what is specified in the KeyCombo. * The combo is evaluated strictly, i.e. the KeyboardEvent must match exactly what is specified in the KeyCombo.
*/ */
export type KeyCombo = { export type KeyCombo = {
@ -55,10 +67,22 @@ const messageComposerBindings = (): KeyBinding[] => {
}, },
}, },
{ {
action: KeyAction.EditLastMessage, action: KeyAction.EditPrevMessage,
keyCombo: { keyCombo: {
key: Key.ARROW_UP, key: Key.ARROW_UP,
} },
},
{
action: KeyAction.EditNextMessage,
keyCombo: {
key: Key.ARROW_DOWN,
},
},
{
action: KeyAction.CancelEditing,
keyCombo: {
key: Key.ESCAPE,
},
}, },
]; ];
if (SettingsStore.getValue('MessageComposerInput.ctrlEnterToSend')) { if (SettingsStore.getValue('MessageComposerInput.ctrlEnterToSend')) {
@ -83,7 +107,7 @@ const messageComposerBindings = (): KeyBinding[] => {
/** /**
* Helper method to check if a KeyboardEvent matches a KeyCombo * Helper method to check if a KeyboardEvent matches a KeyCombo
* *
* Note, this method is only exported for testing. * Note, this method is only exported for testing.
*/ */
export function isKeyComboMatch(ev: KeyboardEvent, combo: KeyCombo, onMac: boolean): boolean { export function isKeyComboMatch(ev: KeyboardEvent, combo: KeyCombo, onMac: boolean): boolean {
@ -130,12 +154,12 @@ export type KeyBindingsGetter = () => KeyBinding[];
export class KeyBindingsManager { export class KeyBindingsManager {
/** /**
* Map of KeyBindingContext to a KeyBinding getter arrow function. * Map of KeyBindingContext to a KeyBinding getter arrow function.
* *
* Returning a getter function allowed to have dynamic bindings, e.g. when settings change the bindings can be * Returning a getter function allowed to have dynamic bindings, e.g. when settings change the bindings can be
* recalculated. * recalculated.
*/ */
contextBindings: Record<KeyBindingContext, KeyBindingsGetter> = { contextBindings: Record<KeyBindingContext, KeyBindingsGetter> = {
[KeyBindingContext.SendMessageComposer]: messageComposerBindings, [KeyBindingContext.MessageComposer]: messageComposerBindings,
}; };
/** /**

View File

@ -29,11 +29,10 @@ import EditorStateTransfer from '../../../utils/EditorStateTransfer';
import classNames from 'classnames'; import classNames from 'classnames';
import {EventStatus} from 'matrix-js-sdk'; import {EventStatus} from 'matrix-js-sdk';
import BasicMessageComposer from "./BasicMessageComposer"; import BasicMessageComposer from "./BasicMessageComposer";
import {Key, isOnlyCtrlOrCmdKeyEvent} from "../../../Keyboard";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {Action} from "../../../dispatcher/actions"; import {Action} from "../../../dispatcher/actions";
import SettingsStore from "../../../settings/SettingsStore";
import CountlyAnalytics from "../../../CountlyAnalytics"; import CountlyAnalytics from "../../../CountlyAnalytics";
import {getKeyBindingsManager, KeyAction, KeyBindingContext} from '../../../KeyBindingsManager';
function _isReply(mxEvent) { function _isReply(mxEvent) {
const relatesTo = mxEvent.getContent()["m.relates_to"]; const relatesTo = mxEvent.getContent()["m.relates_to"];
@ -134,38 +133,41 @@ export default class EditMessageComposer extends React.Component {
if (this._editorRef.isComposing(event)) { if (this._editorRef.isComposing(event)) {
return; return;
} }
if (event.metaKey || event.altKey || event.shiftKey) { const action = getKeyBindingsManager().getAction(KeyBindingContext.MessageComposer, event);
return; switch (action) {
} case KeyAction.Send:
const ctrlEnterToSend = !!SettingsStore.getValue('MessageComposerInput.ctrlEnterToSend'); this._sendEdit();
const send = ctrlEnterToSend ? event.key === Key.ENTER && isOnlyCtrlOrCmdKeyEvent(event)
: event.key === Key.ENTER;
if (send) {
this._sendEdit();
event.preventDefault();
} else if (event.key === Key.ESCAPE) {
this._cancelEdit();
} else if (event.key === Key.ARROW_UP) {
if (this._editorRef.isModified() || !this._editorRef.isCaretAtStart()) {
return;
}
const previousEvent = findEditableEvent(this._getRoom(), false, this.props.editState.getEvent().getId());
if (previousEvent) {
dis.dispatch({action: 'edit_event', event: previousEvent});
event.preventDefault(); event.preventDefault();
break;
case KeyAction.CancelEditing:
this._cancelEdit();
break;
case KeyAction.EditPrevMessage: {
if (this._editorRef.isModified() || !this._editorRef.isCaretAtStart()) {
return;
}
const previousEvent = findEditableEvent(this._getRoom(), false,
this.props.editState.getEvent().getId());
if (previousEvent) {
dis.dispatch({action: 'edit_event', event: previousEvent});
event.preventDefault();
}
break;
} }
} else if (event.key === Key.ARROW_DOWN) { case KeyAction.EditNextMessage: {
if (this._editorRef.isModified() || !this._editorRef.isCaretAtEnd()) { if (this._editorRef.isModified() || !this._editorRef.isCaretAtEnd()) {
return; return;
}
const nextEvent = findEditableEvent(this._getRoom(), true, this.props.editState.getEvent().getId());
if (nextEvent) {
dis.dispatch({action: 'edit_event', event: nextEvent});
} else {
dis.dispatch({action: 'edit_event', event: null});
dis.fire(Action.FocusComposer);
}
event.preventDefault();
break;
} }
const nextEvent = findEditableEvent(this._getRoom(), true, this.props.editState.getEvent().getId());
if (nextEvent) {
dis.dispatch({action: 'edit_event', event: nextEvent});
} else {
dis.dispatch({action: 'edit_event', event: null});
dis.fire(Action.FocusComposer);
}
event.preventDefault();
} }
} }