autocomplete polishing
* suppress autocomplete when navigating through history * only search for slashcommands if in the first block of the editor * handle suffix returns from providers correctly * fix bugs when pressing ctrl-a, typing and then tab to complete a replacement by collapsing selection to anchor when inserting a completion in the editorpull/21833/head
parent
c967ecc4e5
commit
5605439e76
|
@ -114,7 +114,7 @@ export default class Autocomplete extends React.Component {
|
|||
|
||||
processQuery(query, selection) {
|
||||
return this.autocompleter.getCompletions(
|
||||
query, selection, this.state.forceComplete,
|
||||
query, selection, this.state.forceComplete
|
||||
).then((completions) => {
|
||||
// Only ever process the completions for the most recent query being processed
|
||||
if (query !== this.queryRequested) {
|
||||
|
|
|
@ -178,6 +178,7 @@ export default class MessageComposerInput extends React.Component {
|
|||
this.plainWithIdPills = new PlainWithPillsSerializer({ pillFormat: 'id' });
|
||||
this.plainWithPlainPills = new PlainWithPillsSerializer({ pillFormat: 'plain' });
|
||||
|
||||
this.suppressAutoComplete = false;
|
||||
this.direction = '';
|
||||
}
|
||||
|
||||
|
@ -535,6 +536,8 @@ export default class MessageComposerInput extends React.Component {
|
|||
|
||||
onKeyDown = (ev: Event, change: Change, editor: Editor) => {
|
||||
|
||||
this.suppressAutoComplete = false;
|
||||
|
||||
// skip void nodes - see
|
||||
// https://github.com/ianstormtaylor/slate/issues/762#issuecomment-304855095
|
||||
if (ev.keyCode === KeyCode.LEFT) {
|
||||
|
@ -978,6 +981,8 @@ export default class MessageComposerInput extends React.Component {
|
|||
// we skip it for now given we know we're about to setState anyway
|
||||
editorState = change.value;
|
||||
|
||||
this.suppressAutoComplete = true;
|
||||
|
||||
this.setState({ editorState }, ()=>{
|
||||
this.refs.editor.focus();
|
||||
});
|
||||
|
@ -1061,13 +1066,15 @@ export default class MessageComposerInput extends React.Component {
|
|||
let editorState = activeEditorState;
|
||||
|
||||
if (range) {
|
||||
const change = editorState.change().moveOffsetsTo(range.start, range.end);
|
||||
const change = editorState.change()
|
||||
.collapseToAnchor()
|
||||
.moveOffsetsTo(range.start, range.end);
|
||||
editorState = change.value;
|
||||
}
|
||||
|
||||
const change = editorState.change().insertInlineAtRange(
|
||||
editorState.selection, inline
|
||||
);
|
||||
const change = editorState.change()
|
||||
.insertInlineAtRange(editorState.selection, inline)
|
||||
.insertText(suffix);
|
||||
editorState = change.value;
|
||||
|
||||
this.setState({ editorState, originalEditorState: activeEditorState }, ()=>{
|
||||
|
@ -1185,13 +1192,12 @@ export default class MessageComposerInput extends React.Component {
|
|||
}
|
||||
|
||||
getAutocompleteQuery(editorState: Value) {
|
||||
// FIXME: do we really want to regenerate this every time the control is rerendered?
|
||||
|
||||
// We can just return the current block where the selection begins, which
|
||||
// should be enough to capture any autocompletion input, given autocompletion
|
||||
// providers only search for the first match which intersects with the current selection.
|
||||
// This avoids us having to serialize the whole thing to plaintext and convert
|
||||
// selection offsets in & out of the plaintext domain.
|
||||
|
||||
return editorState.document.getDescendant(editorState.selection.anchorKey).text;
|
||||
|
||||
// Don't send markdown links to the autocompleter
|
||||
|
@ -1199,10 +1205,19 @@ export default class MessageComposerInput extends React.Component {
|
|||
}
|
||||
|
||||
getSelectionRange(editorState: Value) {
|
||||
let beginning = false;
|
||||
const query = this.getAutocompleteQuery(editorState);
|
||||
const firstChild = editorState.document.nodes.get(0);
|
||||
const firstGrandChild = firstChild && firstChild.nodes.get(0);
|
||||
beginning = (firstChild && firstGrandChild &&
|
||||
firstChild.object === 'block' && firstGrandChild.object === 'text' &&
|
||||
editorState.selection.anchorKey === firstGrandChild.key);
|
||||
|
||||
// return a character range suitable for handing to an autocomplete provider.
|
||||
// the range is relative to the anchor of the current editor selection.
|
||||
// if the selection spans multiple blocks, then we collapse it for the calculation.
|
||||
const range = {
|
||||
beginning, // whether the selection is in the first block of the editor or not
|
||||
start: editorState.selection.anchorOffset,
|
||||
end: (editorState.selection.anchorKey == editorState.selection.focusKey) ?
|
||||
editorState.selection.focusOffset : editorState.selection.anchorOffset,
|
||||
|
@ -1273,7 +1288,7 @@ export default class MessageComposerInput extends React.Component {
|
|||
room={this.props.room}
|
||||
onConfirm={this.setDisplayedCompletion}
|
||||
onSelectionChange={this.setDisplayedCompletion}
|
||||
query={this.getAutocompleteQuery(activeEditorState)}
|
||||
query={ this.suppressAutoComplete ? '' : this.getAutocompleteQuery(activeEditorState) }
|
||||
selection={this.getSelectionRange(activeEditorState)}
|
||||
/>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue