mirror of https://github.com/vector-im/riot-web
Use the KeyBindingsManager in EditMessageComposer
parent
4a138f3b84
commit
12387b4978
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue