Remove two possible sources for the "AutoComplete stays visible bug

which is now https://github.com/vector-im/riot-web/issues/4537 <- there.

This does two things:
 - Track which query was the most recent one requesting completion and only process completions for that one. (In this case the empty string "" doesn't have any completions but we still track it so that previous calls with non-empty queries would not race and cause completions to be shown when we actuall don't want any.)
 - Make the "do we want to show the AutoComplete box?" logic a bit more sane
This commit is contained in:
Luke Barnard 2017-07-07 15:30:31 +01:00
parent e970b68859
commit 7a8f524f4a
2 changed files with 18 additions and 14 deletions

View file

@ -50,6 +50,7 @@ export default class Autocomplete extends React.Component {
} }
complete(query, selection) { complete(query, selection) {
this.queryRequested = query;
if (this.debounceCompletionsRequest) { if (this.debounceCompletionsRequest) {
clearTimeout(this.debounceCompletionsRequest); clearTimeout(this.debounceCompletionsRequest);
} }
@ -74,16 +75,25 @@ export default class Autocomplete extends React.Component {
const deferred = Q.defer(); const deferred = Q.defer();
this.debounceCompletionsRequest = setTimeout(() => { this.debounceCompletionsRequest = setTimeout(() => {
getCompletions( this.processQuery(query, selection).then(() => {
query, selection, this.state.forceComplete,
).then((completions) => {
this.processCompletions(completions);
deferred.resolve(); deferred.resolve();
}); });
}, autocompleteDelay); }, autocompleteDelay);
return deferred.promise; return deferred.promise;
} }
processQuery(query, selection) {
return getCompletions(
query, selection, this.state.forceComplete,
).then((completions) => {
// Only ever process the completions for the most recent query being processed
if (query !== this.queryRequested) {
return;
}
this.processCompletions(completions);
});
}
processCompletions(completions) { processCompletions(completions) {
const completionList = flatMap(completions, (provider) => provider.completions); const completionList = flatMap(completions, (provider) => provider.completions);
@ -105,14 +115,9 @@ export default class Autocomplete extends React.Component {
} }
let hide = this.state.hide; let hide = this.state.hide;
// These are lists of booleans that indicate whether whether the corresponding provider had a matching pattern // If `completion.command.command` is truthy, then a provider has matched with the query
const oldMatches = this.state.completions.map((completion) => !!completion.command.command), const anyMatches = completions.some((completion) => !!completion.command.command);
newMatches = completions.map((completion) => !!completion.command.command); hide = !anyMatches;
// So, essentially, we re-show autocomplete if any provider finds a new pattern or stops finding an old one
if (!isEqual(oldMatches, newMatches)) {
hide = false;
}
this.setState({ this.setState({
completions, completions,

View file

@ -514,6 +514,7 @@ export default class MessageComposerInput extends React.Component {
const currentBlockType = RichUtils.getCurrentBlockType(this.state.editorState); const currentBlockType = RichUtils.getCurrentBlockType(this.state.editorState);
// If we're in any of these three types of blocks, shift enter should insert soft newlines // If we're in any of these three types of blocks, shift enter should insert soft newlines
// And just enter should end the block // And just enter should end the block
// XXX: Empirically enter does not end these blocks
if(['blockquote', 'unordered-list-item', 'ordered-list-item'].includes(currentBlockType)) { if(['blockquote', 'unordered-list-item', 'ordered-list-item'].includes(currentBlockType)) {
return false; return false;
} }
@ -629,8 +630,6 @@ export default class MessageComposerInput extends React.Component {
editorState: this.createEditorState(), editorState: this.createEditorState(),
}); });
this.autocomplete.hide();
return true; return true;
} }