diff --git a/frontend/src/Components/Page/Header/MovieSearchInput.css b/frontend/src/Components/Page/Header/MovieSearchInput.css index 153dd750f..fb1b876e2 100644 --- a/frontend/src/Components/Page/Header/MovieSearchInput.css +++ b/frontend/src/Components/Page/Header/MovieSearchInput.css @@ -4,15 +4,15 @@ } .loading { - margin-top: 18px; - margin-bottom: 18px; - text-align: center; + position: absolute; + display: inline-block; + margin-left: 5px; } .ripple { composes: ripple from '~Components/Loading/LoadingIndicator.css'; - border: 2px solid $toolbarColor; + border: 1px solid $toolbarColor; } .input { diff --git a/frontend/src/Components/Page/Header/MovieSearchInput.js b/frontend/src/Components/Page/Header/MovieSearchInput.js index 783f28acd..cf69e3a3a 100644 --- a/frontend/src/Components/Page/Header/MovieSearchInput.js +++ b/frontend/src/Components/Page/Header/MovieSearchInput.js @@ -11,9 +11,7 @@ import FuseWorker from './fuse.worker'; import MovieSearchResult from './MovieSearchResult'; import styles from './MovieSearchInput.css'; -const LOADING_TYPE = 'suggestionsLoading'; const ADD_NEW_TYPE = 'addNew'; -const workerInstance = new FuseWorker(); class MovieSearchInput extends Component { @@ -24,6 +22,7 @@ class MovieSearchInput extends Component { super(props, context); this._autosuggest = null; + this._worker = null; this.state = { value: '', @@ -33,7 +32,23 @@ class MovieSearchInput extends Component { componentDidMount() { this.props.bindShortcut(shortcuts.MOVIE_SEARCH_INPUT.key, this.focusInput); - workerInstance.addEventListener('message', this.onSuggestionsReceived, false); + } + + componentWillUnmount() { + if (this._worker) { + this._worker.removeEventListener('message', this.onSuggestionsReceived, false); + this._worker.terminate(); + this._worker = null; + } + } + + getWorker() { + if (!this._worker) { + this._worker = new FuseWorker(); + this._worker.addEventListener('message', this.onSuggestionsReceived, false); + } + + return this._worker; } // @@ -56,6 +71,15 @@ class MovieSearchInput extends Component { return (
{section.title} + + { + section.loading && + + }
); } @@ -73,16 +97,6 @@ class MovieSearchInput extends Component { ); } - if (item.type === LOADING_TYPE) { - return ( - - ); - } - return ( { + if (event.shiftKey || event.altKey || event.ctrlKey) { + return; + } + + if (event.key === 'Escape') { + this.reset(); + return; + } + if (event.key !== 'Tab' && event.key !== 'Enter') { return; } @@ -155,35 +179,74 @@ class MovieSearchInput extends Component { } onSuggestionsFetchRequested = ({ value }) => { - this.setState({ - suggestions: [ - { - type: LOADING_TYPE, - title: value - } - ] - }); + if (!this.state.loading) { + this.setState({ + loading: true + }); + } + this.requestSuggestions(value); }; requestSuggestions = _.debounce((value) => { - const payload = { - value, - movies: this.props.movies - }; + if (!this.state.loading) { + return; + } - workerInstance.postMessage(payload); + const requestLoading = this.state.requestLoading; + + this.setState({ + requestValue: value, + requestLoading: true + }); + + if (!requestLoading) { + const payload = { + value, + movies: this.props.movies + }; + + this.getWorker().postMessage(payload); + } }, 250); onSuggestionsReceived = (message) => { - this.setState({ - suggestions: message.data - }); + const { + value, + suggestions + } = message.data; + + if (!this.state.loading) { + this.setState({ + requestValue: null, + requestLoading: false + }); + } else if (value === this.state.requestValue) { + this.setState({ + suggestions, + requestValue: null, + requestLoading: false, + loading: false + }); + } else { + this.setState({ + suggestions, + requestLoading: true + }); + + const payload = { + value: this.state.requestValue, + movies: this.props.movies + }; + + this.getWorker().postMessage(payload); + } } onSuggestionsClearRequested = () => { this.setState({ - suggestions: [] + suggestions: [], + loading: false }); } @@ -201,14 +264,16 @@ class MovieSearchInput extends Component { render() { const { value, + loading, suggestions } = this.state; const suggestionGroups = []; - if (suggestions.length) { + if (suggestions.length || loading) { suggestionGroups.push({ - title: 'Existing Movie', + title: 'Existing Movie(s)', + loading, suggestions }); } diff --git a/frontend/src/Components/Page/Header/fuse.worker.js b/frontend/src/Components/Page/Header/fuse.worker.js index 5b27e37ed..59d5e6ede 100644 --- a/frontend/src/Components/Page/Header/fuse.worker.js +++ b/frontend/src/Components/Page/Header/fuse.worker.js @@ -47,7 +47,7 @@ function getSuggestions(movies, value) { return suggestions; } -self.addEventListener('message', (e) => { +onmessage = function(e) { if (!e) { return; } @@ -57,5 +57,12 @@ self.addEventListener('message', (e) => { value } = e.data; - self.postMessage(getSuggestions(movies, value)); -}); + const suggestions = getSuggestions(movies, value); + + const results = { + value, + suggestions + }; + + self.postMessage(results); +};