From 6cb59f7071dc39de76fd0fb232937ccf3acd27f2 Mon Sep 17 00:00:00 2001 From: Pierre Boyer Date: Tue, 14 May 2019 08:54:00 +0200 Subject: [PATCH 1/7] Allow left/right arrow keys to navigate through the autocompletion list --- .../views/rooms/MessageComposerInput.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index a525fcb874f..e569c5bb3b1 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -670,6 +670,31 @@ export default class MessageComposerInput extends React.Component { onKeyDown = (ev: KeyboardEvent, change: Change, editor: Editor) => { this.suppressAutoComplete = false; + this.direction = ''; + + // Navigate autocomplete list with arrow keys + if (this.autocomplete.state.completionList.length > 0) { + if (!(ev.ctrlKey || ev.shiftKey || ev.altKey || ev.metaKey)) { + switch (ev.keyCode) { + case KeyCode.LEFT: + this.moveAutocompleteSelection(true); + ev.preventDefault(); + return true; + case KeyCode.RIGHT: + this.moveAutocompleteSelection(false); + ev.preventDefault(); + return true; + case KeyCode.UP: + this.moveAutocompleteSelection(true); + ev.preventDefault(); + return true; + case KeyCode.DOWN: + this.moveAutocompleteSelection(false); + ev.preventDefault(); + return true; + } + } + } // skip void nodes - see // https://github.com/ianstormtaylor/slate/issues/762#issuecomment-304855095 From 6e4c3bfe5680bb6685d828913dd9f706e205e874 Mon Sep 17 00:00:00 2001 From: Pierre Boyer Date: Tue, 14 May 2019 09:27:20 +0200 Subject: [PATCH 2/7] Remove now unused code --- .../views/rooms/MessageComposerInput.js | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index e569c5bb3b1..8b54a2d8bba 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -702,8 +702,6 @@ export default class MessageComposerInput extends React.Component { this.direction = 'Previous'; } else if (ev.keyCode === KeyCode.RIGHT) { this.direction = 'Next'; - } else { - this.direction = ''; } switch (ev.keyCode) { @@ -1197,35 +1195,28 @@ export default class MessageComposerInput extends React.Component { }; onVerticalArrow = (e, up) => { - if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) { - return; - } - - // Select history only if we are not currently auto-completing - if (this.autocomplete.state.completionList.length === 0) { - const selection = this.state.editorState.selection; - - // selection must be collapsed - if (!selection.isCollapsed) return; - const document = this.state.editorState.document; - - // and we must be at the edge of the document (up=start, down=end) - if (up) { - if (!selection.anchor.isAtStartOfNode(document)) return; - - const editEvent = findEditableEvent(this.props.room, false); - if (editEvent) { - // We're selecting history, so prevent the key event from doing anything else - e.preventDefault(); - dis.dispatch({ - action: 'edit_event', - event: editEvent, - }); - } + if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) return; + + // Select history + const selection = this.state.editorState.selection; + + // selection must be collapsed + if (!selection.isCollapsed) return; + const document = this.state.editorState.document; + + // and we must be at the edge of the document (up=start, down=end) + if (up) { + if (!selection.anchor.isAtStartOfNode(document)) return; + + const editEvent = findEditableEvent(this.props.room, false); + 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); - e.preventDefault(); } }; From bb133c1ebcb291c62c3f6f02d202f180f3d2ced4 Mon Sep 17 00:00:00 2001 From: Pierre Boyer Date: Tue, 14 May 2019 10:13:04 +0200 Subject: [PATCH 3/7] Merge onUpArrow and onDownArrow into more general moveSelection --- src/components/views/rooms/Autocomplete.js | 23 +++++----------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/components/views/rooms/Autocomplete.js b/src/components/views/rooms/Autocomplete.js index 9aef5433c3e..243cfe2f753 100644 --- a/src/components/views/rooms/Autocomplete.js +++ b/src/components/views/rooms/Autocomplete.js @@ -171,26 +171,13 @@ export default class Autocomplete extends React.Component { } // called from MessageComposerInput - onUpArrow(): ?Completion { + moveSelection(delta): ?Completion { const completionCount = this.countCompletions(); - // completionCount + 1, since 0 means composer is selected - const selectionOffset = (completionCount + 1 + this.state.selectionOffset - 1) - % (completionCount + 1); - if (!completionCount) { - return null; - } - this.setSelection(selectionOffset); - } + if (completionCount === 0) return; // there are no items to move the selection through - // called from MessageComposerInput - onDownArrow(): ?Completion { - const completionCount = this.countCompletions(); - // completionCount + 1, since 0 means composer is selected - const selectionOffset = (this.state.selectionOffset + 1) % (completionCount + 1); - if (!completionCount) { - return null; - } - this.setSelection(selectionOffset); + // Note: selectionOffset 0 represents the unsubstituted text, while 1 means first pill selected + const index = (this.state.selectionOffset + delta + completionCount + 1) % (completionCount + 1); + this.setSelection(index); } onEscape(e): boolean { From 97d4d1b73a3d21289c882ec37043aae8b5c28f8c Mon Sep 17 00:00:00 2001 From: Pierre Boyer Date: Tue, 14 May 2019 10:16:10 +0200 Subject: [PATCH 4/7] Update composer to correctly call countCompletions and moveSelection --- .../views/rooms/MessageComposerInput.js | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 8b54a2d8bba..74f358c1612 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -673,23 +673,23 @@ export default class MessageComposerInput extends React.Component { this.direction = ''; // Navigate autocomplete list with arrow keys - if (this.autocomplete.state.completionList.length > 0) { + if (this.autocomplete.countCompletions() > 0) { if (!(ev.ctrlKey || ev.shiftKey || ev.altKey || ev.metaKey)) { switch (ev.keyCode) { case KeyCode.LEFT: - this.moveAutocompleteSelection(true); + this.autocomplete.moveSelection(-1); ev.preventDefault(); return true; case KeyCode.RIGHT: - this.moveAutocompleteSelection(false); + this.autocomplete.moveSelection(+1); ev.preventDefault(); return true; case KeyCode.UP: - this.moveAutocompleteSelection(true); + this.autocomplete.moveSelection(-1); ev.preventDefault(); return true; case KeyCode.DOWN: - this.moveAutocompleteSelection(false); + this.autocomplete.moveSelection(+1); ev.preventDefault(); return true; } @@ -1225,23 +1225,19 @@ export default class MessageComposerInput extends React.Component { someCompletions: null, }); e.preventDefault(); - if (this.autocomplete.state.completionList.length === 0) { + if (this.autocomplete.countCompletions() === 0) { // Force completions to show for the text currently entered const completionCount = await this.autocomplete.forceComplete(); this.setState({ someCompletions: completionCount > 0, }); // Select the first item by moving "down" - await this.moveAutocompleteSelection(false); + await this.autocomplete.moveSelection(+1); } else { - await this.moveAutocompleteSelection(e.shiftKey); + await this.autocomplete.moveSelection(e.shiftKey ? -1 : +1); } }; - moveAutocompleteSelection = (up) => { - up ? this.autocomplete.onUpArrow() : this.autocomplete.onDownArrow(); - }; - onEscape = async (e) => { e.preventDefault(); if (this.autocomplete) { From ed6427571e724c53f75d8fd41807df5c7b4950eb Mon Sep 17 00:00:00 2001 From: Pierre Boyer Date: Tue, 4 Jun 2019 13:21:39 +0200 Subject: [PATCH 5/7] Update src/editor/autocomplete to correctly call countCompletions and moveSelection --- src/editor/autocomplete.js | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/editor/autocomplete.js b/src/editor/autocomplete.js index ceaf18c4446..ba18207de1d 100644 --- a/src/editor/autocomplete.js +++ b/src/editor/autocomplete.js @@ -42,31 +42,19 @@ export default class AutocompleteWrapperModel { async onTab(e) { const acComponent = this._getAutocompleterComponent(); - if (acComponent.state.completionList.length === 0) { + if (acComponent.countCompletions() === 0) { // Force completions to show for the text currently entered await acComponent.forceComplete(); // Select the first item by moving "down" - await acComponent.onDownArrow(); + await acComponent.moveSelection(+1); } else { - if (e.shiftKey) { - await acComponent.onUpArrow(); - } else { - await acComponent.onDownArrow(); - } + await acComponent.moveSelection(e.shiftKey ? -1 : +1); } this._updateCallback({ close: true, }); } - onUpArrow() { - this._getAutocompleterComponent().onUpArrow(); - } - - onDownArrow() { - this._getAutocompleterComponent().onDownArrow(); - } - onPartUpdate(part, offset) { // cache the typed value and caret here // so we can restore it in onComponentSelectionChange when the value is undefined (meaning it should be the typed text) From a4dec88c651a731fd40175b0c3260dc85169176b Mon Sep 17 00:00:00 2001 From: Pierre Boyer Date: Tue, 4 Jun 2019 13:57:15 +0200 Subject: [PATCH 6/7] Add back on..Arrow functions. Add left/right key navigation in MessageEditor --- src/components/views/elements/MessageEditor.js | 4 ++++ src/editor/autocomplete.js | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/components/views/elements/MessageEditor.js b/src/components/views/elements/MessageEditor.js index ed86bcb0a35..98569023cb8 100644 --- a/src/components/views/elements/MessageEditor.js +++ b/src/components/views/elements/MessageEditor.js @@ -116,6 +116,10 @@ export default class MessageEditor extends React.Component { autoComplete.onUpArrow(event); break; case "ArrowDown": autoComplete.onDownArrow(event); break; + case "ArrowLeft": + autoComplete.onLeftArrow(event); break; + case "ArrowRight": + autoComplete.onRightArrow(event); break; case "Tab": autoComplete.onTab(event); break; case "Escape": diff --git a/src/editor/autocomplete.js b/src/editor/autocomplete.js index ba18207de1d..c0dc0208970 100644 --- a/src/editor/autocomplete.js +++ b/src/editor/autocomplete.js @@ -55,6 +55,22 @@ export default class AutocompleteWrapperModel { }); } + onUpArrow() { + this._getAutocompleterComponent().moveSelection(-1); + } + + onDownArrow() { + this._getAutocompleterComponent().moveSelection(+1); + } + + onLeftArrow() { + this._getAutocompleterComponent().moveSelection(-1); + } + + onRightArrow() { + this._getAutocompleterComponent().moveSelection(+1); + } + onPartUpdate(part, offset) { // cache the typed value and caret here // so we can restore it in onComponentSelectionChange when the value is undefined (meaning it should be the typed text) From 81585676407bfe603691b7ec49431e0ba9591ed2 Mon Sep 17 00:00:00 2001 From: Pierre Boyer Date: Wed, 5 Jun 2019 10:49:49 +0200 Subject: [PATCH 7/7] Remove left/right autocomplete navigation for MessageEditor --- src/components/views/elements/MessageEditor.js | 4 ---- src/editor/autocomplete.js | 8 -------- 2 files changed, 12 deletions(-) diff --git a/src/components/views/elements/MessageEditor.js b/src/components/views/elements/MessageEditor.js index 98569023cb8..ed86bcb0a35 100644 --- a/src/components/views/elements/MessageEditor.js +++ b/src/components/views/elements/MessageEditor.js @@ -116,10 +116,6 @@ export default class MessageEditor extends React.Component { autoComplete.onUpArrow(event); break; case "ArrowDown": autoComplete.onDownArrow(event); break; - case "ArrowLeft": - autoComplete.onLeftArrow(event); break; - case "ArrowRight": - autoComplete.onRightArrow(event); break; case "Tab": autoComplete.onTab(event); break; case "Escape": diff --git a/src/editor/autocomplete.js b/src/editor/autocomplete.js index c0dc0208970..ce0550d88ec 100644 --- a/src/editor/autocomplete.js +++ b/src/editor/autocomplete.js @@ -63,14 +63,6 @@ export default class AutocompleteWrapperModel { this._getAutocompleterComponent().moveSelection(+1); } - onLeftArrow() { - this._getAutocompleterComponent().moveSelection(-1); - } - - onRightArrow() { - this._getAutocompleterComponent().moveSelection(+1); - } - onPartUpdate(part, offset) { // cache the typed value and caret here // so we can restore it in onComponentSelectionChange when the value is undefined (meaning it should be the typed text)