From 6d36be531131299512bfe41286540c7fff06dfb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 12 Oct 2015 17:10:04 +0200 Subject: [PATCH] Add documentation for SearchBar and put threshold into AppConstants --- .../piece_list_toolbar.js | 4 +- js/components/search_bar.js | 58 ++++++++++++++++--- js/constants/application_constants.js | 3 +- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index 8f65fb31..b7db7ce6 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -6,6 +6,8 @@ import PieceListToolbarFilterWidget from './piece_list_toolbar_filter_widget'; import PieceListToolbarOrderWidget from './piece_list_toolbar_order_widget'; import SearchBar from '../search_bar'; +import AppConstants from '../../constants/application_constants'; + let PieceListToolbar = React.createClass({ propTypes: { @@ -76,7 +78,7 @@ let PieceListToolbar = React.createClass({ className="pull-right search-bar ascribe-input-glyph" searchFor={searchFor} searchQuery={searchQuery} - threshold={500}/> + threshold={AppConstants.searchThreshold}/> {this.getOrderWidget()} {this.getFilterWidget()} diff --git a/js/components/search_bar.js b/js/components/search_bar.js index 642094b3..365d6485 100644 --- a/js/components/search_bar.js +++ b/js/components/search_bar.js @@ -12,12 +12,16 @@ const { update } = React.addons; const SearchBar = React.createClass({ propTypes: { + // a function that accepts a string as a search query and updates the + // propagated `searchQuery` after successfully retrieving the + // request from the server searchFor: func.isRequired, searchQuery: string.isRequired, className: string, - // in milliseconds + // the number of milliseconds the component + // should wait before requesting search results from the server threshold: number.isRequired }, @@ -25,7 +29,7 @@ const SearchBar = React.createClass({ return { timers: [], searchQuery: '', - searching: false + loading: false }; }, @@ -33,16 +37,44 @@ const SearchBar = React.createClass({ const searchQueryProps = this.props.searchQuery; const searchQueryPrevProps = prevProps.searchQuery; const searchQueryState = this.state.searchQuery; - const { searching } = this.state; + const { loading } = this.state; - if(searching && (searchQueryProps && searchQueryState && searchQueryProps === searchQueryState || !searchQueryPrevProps && searchQueryProps === searchQueryState)) { - this.setState({ searching: false }); + /** + * 1. Condition: `loading` must be true, which implies that `evaluateTimer`, + * has already been called + * + * AND + * + * 2. Condition: `searchQueryProps` and `searchQueryState` are true and equal + * (which means that the search query has been propagated to the inner + * fetch method of `fetchPieceList`, which in turn means that a fetch + * has completed) + * + * OR + * + * 3. Condition: `searchQueryProps` and `searchQueryState` can be any value (`true` or + * `false`, as long as they're equal). This case only occurs when the user + * has entered a `searchQuery` and deletes the query in one go, reseting + * `searchQueryProps` to empty string ('' === false) again. + */ + + const firstCondition = !!loading; + const secondCondition = searchQueryProps && searchQueryState && searchQueryProps === searchQueryState; + const thirdCondition = !searchQueryPrevProps && searchQueryProps === searchQueryState; + + if(firstCondition && (secondCondition || thirdCondition)) { + this.setState({ loading: false }); } }, startTimers(searchQuery) { const { timers } = this.state; const { threshold } = this.props; + + // the timer waits for the specified threshold time in milliseconds + // and then calls `evaluateTimer`, that checks if another letter + // has been added to the query (by checking if there are newer + // timers on the stack aka. `this.state.timers`) const timer = { searchQuery, cb: setTimeout(this.evaluateTimer(timers.length, searchQuery), threshold) @@ -56,9 +88,14 @@ const SearchBar = React.createClass({ return () => { const { timers } = this.state; + // If there have been no timers added to `this.state.timers`, + // while the `threshold` was passed, we start loading + // by querying the server. if(timers.length <= timerIndex + 1) { - // clean the timers array - this.setState({ timers: [], searching: true }, () => { + // However, we're doing that only after setting `this.state.loading` + // to `true`, as we want to display a little spinner while loading. + // We also clean the now worthless `timers` array. + this.setState({ timers: [], loading: true }, () => { // search for the query this.props.searchFor(searchQuery); }); @@ -67,6 +104,9 @@ const SearchBar = React.createClass({ }, handleChange({ target: { value }}) { + // On each letter entry we're updating the state of the component + // and start a timer, which we're also pushing to the state + // of the component this.startTimers(value); this.setState({ searchQuery: value }); }, @@ -74,9 +114,9 @@ const SearchBar = React.createClass({ render() { let searchIcon = ; const { className } = this.props; - const { searching } = this.state; + const { loading } = this.state; - if(searching) { + if(loading) { searchIcon = ; } diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index c74fdce9..0271dda7 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -78,7 +78,8 @@ let constants = { 'copyrightAssociations': ['ARS', 'DACS', 'Bildkunst', 'Pictoright', 'SODRAC', 'Copyright Agency/Viscopy', 'SAVA', 'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART', 'IVARO', 'SIAE', 'JASPAR-SPDA', 'AKKA/LAA', 'LATGA-A', 'SOMAAP', 'ARTEGESTION', 'CARIER', 'BONO', 'APSAV', - 'SPA', 'GESTOR', 'VISaRTA', 'RAO', 'LITA', 'DALRO', 'VeGaP', 'BUS', 'ProLitteris', 'AGADU', 'AUTORARTE', 'BUBEDRA', 'BBDA', 'BCDA', 'BURIDA', 'ADAVIS', 'BSDA'] + 'SPA', 'GESTOR', 'VISaRTA', 'RAO', 'LITA', 'DALRO', 'VeGaP', 'BUS', 'ProLitteris', 'AGADU', 'AUTORARTE', 'BUBEDRA', 'BBDA', 'BCDA', 'BURIDA', 'ADAVIS', 'BSDA'], + 'searchThreshold': 500 }; export default constants;