1
0
Fork 0
mirror of https://github.com/Alamantus/Lexiconga.git synced 2025-05-09 11:41:47 +02:00

Improve SearchBox functionality

This commit is contained in:
Robbie Antenesse 2017-06-25 15:49:23 -06:00
parent b5d57393c2
commit 08428f51ac
5 changed files with 307 additions and 250 deletions

View file

@ -1,230 +0,0 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import Helper from '../../Helper';
import dictionary from '../../managers/DictionaryData';
export class SearchBox extends Component {
constructor (props) {
super(props);
this.state = {
searchingIn: 'name'
, searchTerm: ''
, filteredPartsOfSpeech: []
, showHeader: false
, showAdvanced: false
};
}
componentDidUpdate(prevProps, prevState) {
if (this.state.showHeader && this.searchBox) {
this.searchBox.focus();
}
}
search () {
const {searchingIn, searchTerm, filteredPartsOfSpeech} = this.state;
const searchConfig = {
searchingIn
, searchTerm
, filteredPartsOfSpeech
};
this.props.search(searchConfig);
}
displaySearchHeader () {
if (this.state.showHeader) {
return (
<header className='search-bar is-small'>
<div className='search-body'>
<div className='search-background'
onClick={() => this.hideHeader()} />
<div className='container'>
<div className='box'>
<div className='columns is-mobile'>
<div className='column'>
<div className='field has-addons'>
<p className='control'>
<span className='select'>
<select value={this.state.searchingIn}
onChange={event => {
this.setState({ searchingIn: event.target.value });
}}>
<option value='name'>Word</option>
<option value='definition'>Definition</option>
<option value='details'>Details</option>
</select>
</span>
</p>
<p className='control is-expanded'>
<input className='input' type='text' placeholder='Search Term'
ref={input => {
this.searchBox = input;
}}
value={this.state.searchTerm}
onChange={event => {
console.log(event);
this.setState({ searchTerm: event.target.value });
}} />
</p>
</div>
{this.showFilterOptions()}
</div>
<div className='column is-narrow'>
<div className='field has-addons'>
<a className='delete'
onClick={() => this.hideHeader()} />
</div>
</div>
</div>
</div>
</div>
</div>
</header>
);
}
}
showFilterOptions () {
if (dictionary.partsOfSpeech.length > 0) {
const searchMethodSectionJSX = this.state.searchingIn !== 'details'
? (
<div className='field is-horizontal'>
<div className='field-label is-normal'>
<label className='label'>Search Method</label>
</div>
<div className='field-body'>
<div className='field'>
<p className='control'>
<label className='radio'>
<input type='radio' name='searchmethod' checked={true} />
Contains
</label>
<label className='radio'>
<input type='radio' name='searchmethod' />
Starts With
</label>
<label className='radio'>
<input type='radio' name='searchmethod' />
Exact
</label>
</p>
</div>
<div className='field'>
<p className='control'>
<span className='help'>
<strong>Contains:</strong>&nbsp;
Search term is anywhere within the {this.state.searchingIn.capitalize()}
</span>
<span className='help'>
<strong>Starts With:</strong>&nbsp;
The {this.state.searchingIn.capitalize()} begins with the search term
</span>
<span className='help'>
<strong>Exact:</strong>&nbsp;
Search term matches the {this.state.searchingIn.capitalize()} exactly
</span>
</p>
</div>
</div>
</div>
)
: null;
const filterSectionJSX = (
<div className='field is-horizontal'>
<div className='field-label is-normal'>
<label className='label'>Filter</label>
</div>
<div className='field-body'>
<div className='field is-grouped'>
{dictionary.partsOfSpeech.map((partOfSpeech) => {
return (
<p className='control'>
<label key={'filterPartOfSpeech' + Date.now()}
className='checkbox'>
<input type='checkbox' checked={true} />
{partOfSpeech}
</label>
</p>
);
})}
</div>
</div>
</div>
);
const advancedSectionJSX = (
<div className='column'>
<div className='box'>
{searchMethodSectionJSX}
{filterSectionJSX}
</div>
</div>
);
return (
<div class='columns'>
<div class='column is-narrow'>
<div className='field'>
<p className='control'>
<a className={`button is-link is-small${this.state.showAdvanced ? ' is-active' : ''}`}
onClick={() => this.setState({showAdvanced: !this.state.showAdvanced})}>
Advanced
</a>
</p>
</div>
</div>
{this.state.showAdvanced ? advancedSectionJSX : null}
</div>
);
}
}
showHeader () {
this.setState({
showHeader: true
});
}
hideHeader () {
this.setState({
showHeader: false
});
}
render () {
return (
<div>
<div className='field has-addons is-hidden-touch'>
<p className='control'>
<input className='input' type='text' readonly={true}
value={this.state.searchTerm}
onClick={() => this.showHeader()} />
</p>
<p className='control'>
<a className='button is-link'
onClick={() => this.showHeader()}>
Search
</a>
</p>
</div>
<a className='button is-hidden-desktop'
onClick={() => this.showHeader()}>
S
</a>
{this.displaySearchHeader()}
</div>
);
}
}

View file

@ -0,0 +1,6 @@
export default {
contains: 'contains',
startsWith: 'start',
endsWith: 'end',
isExactly: 'exact',
};

View file

@ -0,0 +1,273 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import Helper from '../../../Helper';
import dictionary from '../../../managers/DictionaryData';
import METHOD from './SearchMethod.js';
export class SearchBox extends Component {
constructor (props) {
super(props);
this.state = {
searchingIn: 'name',
searchMethod: METHOD.contains,
searchTerm: '',
filteredPartsOfSpeech: [],
showHeader: false,
showAdvanced: false,
};
}
componentDidUpdate(prevProps, prevState) {
if (this.state.showHeader && this.searchBox) {
this.searchBox.focus();
}
}
search () {
const {searchingIn, searchMethod, searchTerm, filteredPartsOfSpeech} = this.state;
const searchConfig = {
searchingIn,
searchMethod,
searchTerm,
filteredPartsOfSpeech,
};
this.props.search(searchConfig);
}
displaySearchHeader () {
if (this.state.showHeader) {
return (
<header className='search-bar is-small'>
<div className='search-body'>
<div className='search-background'
onClick={ this.hideHeader.bind(this) } />
<div className='container'>
<div className='box'>
<div className='columns is-mobile'>
<div className='column'>
<div className='field has-addons'>
<p className='control'>
<span className='select'>
<select value={ this.state.searchingIn }
onChange={event => {
this.setState({ searchingIn: event.target.value });
}}>
<option value='name'>Word</option>
<option value='definition'>Definition</option>
<option value='details'>Details</option>
</select>
</span>
</p>
<p className='control is-expanded'>
<input className='input' type='text' placeholder='Search Term'
ref={input => {
this.searchBox = input;
}}
value={ this.state.searchTerm }
onChange={event => {
console.log(event);
this.setState({ searchTerm: event.target.value });
}} />
</p>
</div>
{ this.showFilterOptions() }
</div>
<div className='column is-narrow'>
<div className='field has-addons'>
<a className='delete'
onClick={ this.hideHeader.bind(this) }
/>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
);
}
}
showFilterOptions () {
if (this.props.partsOfSpeech.length > 0) {
const searchMethodSectionJSX = this.state.searchingIn !== 'details'
? (
<div className='field is-horizontal'>
<div className='field-label is-normal'>
<label className='label'>Search Method</label>
</div>
<div className='field-body'>
<div className='field'>
<p className='control'>
<label className='radio'
title={ `Search term is anywhere within the ${ this.state.searchingIn.capitalize() }` }
>
<input type='radio' name='searchmethod'
value={ METHOD.contains }
checked={ this.state.searchMethod === METHOD.contains }
onClick={event => {
if (event.currentTarget.checked) {
this.setState({
searchMethod: event.currentTarget.value,
});
}
}}
/>
Contains
</label>
<label className='radio'
title={ `The ${ this.state.searchingIn.capitalize() } begins with the search term` }
>
<input type='radio' name='searchmethod'
value={ METHOD.startsWith }
checked={ this.state.searchMethod === METHOD.startsWith }
onClick={event => {
if (event.currentTarget.checked) {
this.setState({
searchMethod: event.currentTarget.value,
});
}
}}
/>
Starts With
</label>
<label className='radio'
title={ `The ${ this.state.searchingIn.capitalize() } ends with the search term` }
>
<input type='radio' name='searchmethod'
value={ METHOD.endsWith }
checked={ this.state.searchMethod === METHOD.endsWith }
onClick={event => {
if (event.currentTarget.checked) {
this.setState({
searchMethod: event.currentTarget.value,
});
}
}}
/>
Ends With
</label>
<label className='radio'
title={ `Search term matches the ${ this.state.searchingIn.capitalize() } exactly` }
>
<input type='radio' name='searchmethod'
value={ METHOD.isExactly }
checked={ this.state.searchMethod === METHOD.isExactly }
onClick={event => {
if (event.currentTarget.checked) {
this.setState({
searchMethod: event.currentTarget.value,
});
}
}}
/>
Exact
</label>
</p>
</div>
</div>
</div>
)
: null;
const filterSectionJSX = (
<div className='field is-horizontal'>
<div className='field-label is-normal'>
<label className='label'>Filter</label>
</div>
<div className='field-body'>
<div className='field is-grouped'>
{
this.props.partsOfSpeech.map(partOfSpeech => {
return (
<p className='control'>
<label key={ 'filterPartOfSpeech' + Date.now() }
className='checkbox'>
<input type='checkbox' checked={ true } />
{ partOfSpeech }
</label>
</p>
);
})
}
</div>
</div>
</div>
);
const advancedSectionJSX = (
<div className='column'>
<div className='box'>
{ searchMethodSectionJSX }
{ filterSectionJSX }
</div>
</div>
);
return (
<div class='columns'>
<div class='column is-narrow'>
<div className='field'>
<p className='control'>
<a className={ `button is-link is-small${ this.state.showAdvanced ? ' is-active' : '' }` }
onClick={ () => this.setState({ showAdvanced: !this.state.showAdvanced }) }>
Advanced
</a>
</p>
</div>
</div>
{ this.state.showAdvanced ? advancedSectionJSX : null }
</div>
);
}
}
showHeader () {
this.setState({
showHeader: true
});
}
hideHeader () {
this.setState({
showHeader: false
});
}
render () {
return (
<div>
<div className='field has-addons is-hidden-touch'>
<p className='control'>
<input className='input' type='text' readonly={ true }
value={ this.state.searchTerm }
onClick={ this.showHeader.bind(this) } />
</p>
<p className='control'>
<a className='button is-link'
onClick={ this.showHeader.bind(this) }>
Search
</a>
</p>
</div>
<a className='button is-hidden-desktop'
onClick={ this.showHeader.bind(this) }>
S
</a>
{ this.displaySearchHeader() }
</div>
);
}
}

View file

@ -8,7 +8,7 @@ export class Header extends Component {
super(props);
this.state = {
displayNavMenu: false
displayNavMenu: false,
}
}
@ -17,14 +17,15 @@ export class Header extends Component {
<nav className='nav'>
<div className='nav-left'>
<a href='/' className='nav-item image'>
<img src={`./logo.${(typeof SVGRect !== 'undefined') ? 'svg' : 'png'}`} alt='Lexiconga Logo' />
<img src={ `./logo.${ (typeof SVGRect !== 'undefined') ? 'svg' : 'png' }` } alt='Lexiconga Logo' />
</a>
</div>
<div className='nav-center'>
<div className='nav-item'>
<SearchBox
search={searchConfig => this.props.search(searchConfig)} />
partsOfSpeech={ this.props.partsOfSpeech }
search={ searchConfig => this.props.search(searchConfig) } />
</div>
</div>
@ -35,7 +36,7 @@ export class Header extends Component {
<span></span>
</span>
<div className={`nav-right nav-menu${this.state.displayNavMenu ? ' is-active' : ''}`}>
<div className={ `nav-right nav-menu${ this.state.displayNavMenu ? ' is-active' : '' }` }>
<span className='nav-item'>
<a className='button'>
Login

View file

@ -19,41 +19,47 @@ class App extends Component {
super(props);
this.state = {
name: dictionary.name
, specification: dictionary.specification
, description: dictionary.description
, partsOfSpeech: dictionary.partsOfSpeech
, displayedWords: []
, searchConfig: null
name: dictionary.name,
specification: dictionary.specification,
description: dictionary.description,
partsOfSpeech: dictionary.partsOfSpeech,
displayedWords: [],
searchConfig: null,
}
}
get dictionaryInfo () {
const {name, specification, description, partsOfSpeech} = this.state;
const info = {
name
, specification
, description
, partsOfSpeech
name,
specification,
description,
partsOfSpeech,
};
return info;
}
updatePartsOfSpeech () {
this.setState({
partsOfSpeech: dictionary.partsOfSpeech,
});
}
updateDisplayedWords () {
// const {searchIn, searchTerm, filteredPartsOfSpeech} = this.state.searchConfig;
// TODO: Sort out searching to remove this temporary solution.
dictionary.wordsPromise.then(words => {
this.setState({
displayedWords: words
displayedWords: words,
})
});
}
search (searchConfig) {
this.setState({
searchConfig: searchConfig
searchConfig: searchConfig,
});
}
@ -61,12 +67,13 @@ class App extends Component {
return (
<div>
<Header
search={searchConfig => this.search(searchConfig)} />
partsOfSpeech={ this.state.partsOfSpeech }
search={ searchConfig => this.search(searchConfig) } />
<MainDisplay
dictionaryInfo={this.dictionaryInfo}
wordsToDisplay={this.state.displayedWords}
updateDisplay={() => this.updateDisplayedWords()} />
dictionaryInfo={ this.dictionaryInfo }
wordsToDisplay={ this.state.displayedWords }
updateDisplay={ this.updateDisplayedWords.bind(this) } />
<Footer />
</div>