1
0
mirror of https://github.com/ascribe/onion.git synced 2024-11-15 01:25:17 +01:00

Add documentation for SearchBar and put threshold into AppConstants

This commit is contained in:
Tim Daubenschütz 2015-10-12 17:10:04 +02:00
parent c59f5267ce
commit 6d36be5311
3 changed files with 54 additions and 11 deletions

View File

@ -6,6 +6,8 @@ import PieceListToolbarFilterWidget from './piece_list_toolbar_filter_widget';
import PieceListToolbarOrderWidget from './piece_list_toolbar_order_widget'; import PieceListToolbarOrderWidget from './piece_list_toolbar_order_widget';
import SearchBar from '../search_bar'; import SearchBar from '../search_bar';
import AppConstants from '../../constants/application_constants';
let PieceListToolbar = React.createClass({ let PieceListToolbar = React.createClass({
propTypes: { propTypes: {
@ -76,7 +78,7 @@ let PieceListToolbar = React.createClass({
className="pull-right search-bar ascribe-input-glyph" className="pull-right search-bar ascribe-input-glyph"
searchFor={searchFor} searchFor={searchFor}
searchQuery={searchQuery} searchQuery={searchQuery}
threshold={500}/> threshold={AppConstants.searchThreshold}/>
<span className="pull-right"> <span className="pull-right">
{this.getOrderWidget()} {this.getOrderWidget()}
{this.getFilterWidget()} {this.getFilterWidget()}

View File

@ -12,12 +12,16 @@ const { update } = React.addons;
const SearchBar = React.createClass({ const SearchBar = React.createClass({
propTypes: { 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, searchFor: func.isRequired,
searchQuery: string.isRequired, searchQuery: string.isRequired,
className: string, className: string,
// in milliseconds // the number of milliseconds the component
// should wait before requesting search results from the server
threshold: number.isRequired threshold: number.isRequired
}, },
@ -25,7 +29,7 @@ const SearchBar = React.createClass({
return { return {
timers: [], timers: [],
searchQuery: '', searchQuery: '',
searching: false loading: false
}; };
}, },
@ -33,16 +37,44 @@ const SearchBar = React.createClass({
const searchQueryProps = this.props.searchQuery; const searchQueryProps = this.props.searchQuery;
const searchQueryPrevProps = prevProps.searchQuery; const searchQueryPrevProps = prevProps.searchQuery;
const searchQueryState = this.state.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) { startTimers(searchQuery) {
const { timers } = this.state; const { timers } = this.state;
const { threshold } = this.props; 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 = { const timer = {
searchQuery, searchQuery,
cb: setTimeout(this.evaluateTimer(timers.length, searchQuery), threshold) cb: setTimeout(this.evaluateTimer(timers.length, searchQuery), threshold)
@ -56,9 +88,14 @@ const SearchBar = React.createClass({
return () => { return () => {
const { timers } = this.state; 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) { if(timers.length <= timerIndex + 1) {
// clean the timers array // However, we're doing that only after setting `this.state.loading`
this.setState({ timers: [], searching: true }, () => { // 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 // search for the query
this.props.searchFor(searchQuery); this.props.searchFor(searchQuery);
}); });
@ -67,6 +104,9 @@ const SearchBar = React.createClass({
}, },
handleChange({ target: { value }}) { 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.startTimers(value);
this.setState({ searchQuery: value }); this.setState({ searchQuery: value });
}, },
@ -74,9 +114,9 @@ const SearchBar = React.createClass({
render() { render() {
let searchIcon = <Glyphicon glyph='search' className="filter-glyph"/>; let searchIcon = <Glyphicon glyph='search' className="filter-glyph"/>;
const { className } = this.props; const { className } = this.props;
const { searching } = this.state; const { loading } = this.state;
if(searching) { if(loading) {
searchIcon = <span className="glyph-ascribe-spool-chunked ascribe-color spin"/>; searchIcon = <span className="glyph-ascribe-spool-chunked ascribe-color spin"/>;
} }

View File

@ -78,7 +78,8 @@ let constants = {
'copyrightAssociations': ['ARS', 'DACS', 'Bildkunst', 'Pictoright', 'SODRAC', 'Copyright Agency/Viscopy', 'SAVA', 'copyrightAssociations': ['ARS', 'DACS', 'Bildkunst', 'Pictoright', 'SODRAC', 'Copyright Agency/Viscopy', 'SAVA',
'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART', 'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART',
'IVARO', 'SIAE', 'JASPAR-SPDA', 'AKKA/LAA', 'LATGA-A', 'SOMAAP', 'ARTEGESTION', 'CARIER', 'BONO', 'APSAV', '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; export default constants;