Do debouncing for autocomplete in a sane way

- Fixes https://github.com/vector-im/riot-web/issues/4419
 - Fixes https://github.com/matrix-org/matrix-react-sdk/pull/518#issuecomment-285901871
 - Fixes https://github.com/matrix-org/matrix-react-sdk/pull/518#issuecomment-285910503
 - Fixes bug where the setting being used was the `autocompleteDelay` "syncedSetting" when it should have been the "localSetting" (so the setting being used was always the default)
This commit is contained in:
Luke Barnard 2017-06-28 17:27:21 +01:00
parent b3eee0c007
commit de81188b13

View file

@ -40,25 +40,51 @@ export default class Autocomplete extends React.Component {
}; };
} }
async componentWillReceiveProps(props, state) { componentWillReceiveProps(newProps, state) {
if (props.query === this.props.query) { // Query hasn't changed so don't try to complete it
return null; if (newProps.query === this.props.query) {
}
return await this.complete(props.query, props.selection);
}
async complete(query, selection) {
let forceComplete = this.state.forceComplete;
const completionPromise = getCompletions(query, selection, forceComplete);
this.completionPromise = completionPromise;
const completions = await this.completionPromise;
// There's a newer completion request, so ignore results.
if (completionPromise !== this.completionPromise) {
return; return;
} }
this.complete(newProps.query, newProps.selection);
}
complete(query, selection) {
if (this.debounceCompletionsRequest) {
clearTimeout(this.debounceCompletionsRequest);
}
if (query === "") {
this.setState({
// Clear displayed completions
completions: [],
completionList: [],
// Reset selected completion
selectionOffset: COMPOSER_SELECTED,
// Hide the autocomplete box
hide: true,
});
return Q(null);
}
let autocompleteDelay = UserSettingsStore.getLocalSetting('autocompleteDelay', 200);
// Don't debounce if we are already showing completions
if (this.state.completions.length > 0) {
autocompleteDelay = 0;
}
const deferred = Q.defer();
this.debounceCompletionsRequest = setTimeout(() => {
getCompletions(
query, selection, this.state.forceComplete,
).then((completions) => {
this.processCompletions(completions);
deferred.resolve();
});
}, autocompleteDelay);
return deferred.promise;
}
processCompletions(completions) {
const completionList = flatMap(completions, (provider) => provider.completions); const completionList = flatMap(completions, (provider) => provider.completions);
// Reset selection when completion list becomes empty. // Reset selection when completion list becomes empty.
@ -88,23 +114,13 @@ export default class Autocomplete extends React.Component {
hide = false; hide = false;
} }
const autocompleteDelay = UserSettingsStore.getSyncedSetting('autocompleteDelay', 200);
// We had no completions before, but do now, so we should apply our display delay here
if (this.state.completionList.length === 0 && completionList.length > 0 &&
!forceComplete && autocompleteDelay > 0) {
await Q.delay(autocompleteDelay);
}
// Force complete is turned off each time since we can't edit the query in that case
forceComplete = false;
this.setState({ this.setState({
completions, completions,
completionList, completionList,
selectionOffset, selectionOffset,
hide, hide,
forceComplete, // Force complete is turned off each time since we can't edit the query in that case
forceComplete: false,
}); });
} }