move between editable events with arrow keys

pull/21833/head
Bruno Windels 2019-05-24 14:42:33 +02:00
parent 8926fcb3a6
commit 3591eedcfa
2 changed files with 47 additions and 8 deletions

View File

@ -23,6 +23,7 @@ import EditorModel from '../../../editor/model';
import {setCaretPosition} from '../../../editor/caret';
import {getCaretOffsetAndText} from '../../../editor/dom';
import {htmlSerializeIfNeeded, textSerialize} from '../../../editor/serialize';
import {findPreviousEditableEvent, findNextEditableEvent} from '../../../utils/EventUtils';
import {parseEvent} from '../../../editor/deserialize';
import Autocomplete from '../rooms/Autocomplete';
import {PartCreator} from '../../../editor/parts';
@ -42,7 +43,7 @@ export default class MessageEditor extends React.Component {
constructor(props, context) {
super(props, context);
const room = this.context.matrixClient.getRoom(this.props.event.getRoomId());
const room = this._getRoom();
const partCreator = new PartCreator(
() => this._autocompleteRef,
query => this.setState({query}),
@ -61,6 +62,10 @@ export default class MessageEditor extends React.Component {
this._autocompleteRef = null;
}
_getRoom() {
return this.context.matrixClient.getRoom(this.props.event.getRoomId());
}
_updateEditorState = (caret) => {
renderModel(this._editorRef, this.model);
if (caret) {
@ -79,6 +84,16 @@ export default class MessageEditor extends React.Component {
this.model.update(text, event.inputType, caret);
}
_isCaretAtStart() {
const {caret} = getCaretOffsetAndText(this._editorRef, document.getSelection());
return caret.offset === 0;
}
_isCaretAtEnd() {
const {caret, text} = getCaretOffsetAndText(this._editorRef, document.getSelection());
return caret.offset === text.length;
}
_onKeyDown = (event) => {
// insert newline on Shift+Enter
if (event.shiftKey && event.key === "Enter") {
@ -112,6 +127,27 @@ export default class MessageEditor extends React.Component {
event.preventDefault();
} else if (event.key === "Escape") {
this._cancelEdit();
} else if (event.key === "ArrowUp") {
if (!this._isCaretAtStart()) {
return;
}
const previousEvent = findPreviousEditableEvent(this._getRoom(), this.props.event.getId());
if (previousEvent) {
dis.dispatch({action: 'edit_event', event: previousEvent});
event.preventDefault();
}
} else if (event.key === "ArrowDown") {
if (!this._isCaretAtEnd()) {
return;
}
const nextEvent = findNextEditableEvent(this._getRoom(), this.props.event.getId());
if (nextEvent) {
dis.dispatch({action: 'edit_event', event: nextEvent});
} else {
dis.dispatch({action: 'edit_event', event: null});
dis.dispatch({action: 'focus_composer'});
}
event.preventDefault();
}
}

View File

@ -60,6 +60,7 @@ import RoomViewStore from '../../../stores/RoomViewStore';
import ReplyThread from "../elements/ReplyThread";
import {ContentHelpers} from 'matrix-js-sdk';
import AccessibleButton from '../elements/AccessibleButton';
import { findPreviousEditableEvent } from '../../../utils/EventUtils';
const REGEX_EMOTICON_WHITESPACE = new RegExp('(?:^|\\s)(' + EMOTICON_REGEX.source + ')\\s$');
@ -1188,14 +1189,16 @@ export default class MessageComposerInput extends React.Component {
// and we must be at the edge of the document (up=start, down=end)
if (up) {
if (!selection.anchor.isAtStartOfNode(document)) return;
} else {
if (!selection.anchor.isAtEndOfNode(document)) return;
}
const selected = this.selectHistory(up);
if (selected) {
const editEvent = findPreviousEditableEvent(this.props.room);
if (editEvent) {
// We're selecting history, so prevent the key event from doing anything else
e.preventDefault();
dis.dispatch({
action: 'edit_event',
event: editEvent,
});
}
}
} else {
this.moveAutocompleteSelection(up);