|
|
|
@ -8,7 +8,89 @@ import LocationLabel from './LocationLabel'; |
|
|
|
|
import ScoreField from './ScoreField'; |
|
|
|
|
import './ResultsList.css'; |
|
|
|
|
import punycode from 'punycode'; |
|
|
|
|
import history from './history'; |
|
|
|
|
|
|
|
|
|
class SearchField extends Component { |
|
|
|
|
constructor(props) { |
|
|
|
|
super(props); |
|
|
|
|
this.state = { |
|
|
|
|
value: '', |
|
|
|
|
lastQuery: '', |
|
|
|
|
hits: 0, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
this.handleChange = this.handleChange.bind(this); |
|
|
|
|
this.handleSubmit = this.handleSubmit.bind(this); |
|
|
|
|
this.doSearch = this.doSearch.bind(this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
componentDidMount() { |
|
|
|
|
// init search from URL
|
|
|
|
|
let params = (new URL(document.location)).searchParams; |
|
|
|
|
if (typeof params === 'object') { |
|
|
|
|
let q = params.get('q'); |
|
|
|
|
if (q !== null && q !== '') { |
|
|
|
|
this.doSearch(q); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
doSearch(q) { |
|
|
|
|
var minTermLength = 1; |
|
|
|
|
|
|
|
|
|
if (q === '') { |
|
|
|
|
history.push(`/`); |
|
|
|
|
} else { |
|
|
|
|
history.push(`/?q=${q}`); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.setState({value: q}); |
|
|
|
|
|
|
|
|
|
if (q.length > minTermLength && q !== this.state.lastQuery) { |
|
|
|
|
var searchResult = this.props.searchIndex.search(q + "*"); |
|
|
|
|
this.setState({ |
|
|
|
|
lastQuery: q, |
|
|
|
|
hits: searchResult.length, |
|
|
|
|
}); |
|
|
|
|
this.props.callback(searchResult); |
|
|
|
|
} else if (q.length <= minTermLength) { |
|
|
|
|
this.setState({ |
|
|
|
|
lastQuery: q, |
|
|
|
|
hits: 0, |
|
|
|
|
}); |
|
|
|
|
this.props.callback(null); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
handleChange(event) { |
|
|
|
|
var q = event.target.value; |
|
|
|
|
this.doSearch(q); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
handleSubmit(event) { |
|
|
|
|
console.log('A name was submitted:', this.state.value); |
|
|
|
|
event.preventDefault(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
render() { |
|
|
|
|
var hitsInfo = <span> </span>; |
|
|
|
|
if (this.state.lastQuery !== '') { |
|
|
|
|
hitsInfo = <span>{this.state.hits} Treffer</span>; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div className='col-12'> |
|
|
|
|
<form onSubmit={this.handleSubmit}> |
|
|
|
|
<div className='form-group'> |
|
|
|
|
<label htmlFor='queryInput'>Finde Deine Site</label> |
|
|
|
|
<input className='form-control' type='search' name='query' placeholder="Finde Deine Site" value={this.state.value} onChange={this.handleChange} id='queryInput' /> |
|
|
|
|
<small className='form-text'>{hitsInfo}</small> |
|
|
|
|
</div> |
|
|
|
|
</form> |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class URLField extends Component { |
|
|
|
|
displayURL(url) { |
|
|
|
@ -27,39 +109,88 @@ class URLField extends Component { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResultsList extends Component { |
|
|
|
|
render() { |
|
|
|
|
// sort results by score (descending)
|
|
|
|
|
this.props.results.sort((a, b) => { |
|
|
|
|
// if score is the same, use response time as tie breaker
|
|
|
|
|
if (a.score === b.score &&
|
|
|
|
|
typeof a.rating.HTTP_RESPONSE_DURATION.value === 'number' && |
|
|
|
|
typeof b.rating.HTTP_RESPONSE_DURATION.value === 'number') { |
|
|
|
|
return a.rating.HTTP_RESPONSE_DURATION.value - b.rating.HTTP_RESPONSE_DURATION.value; |
|
|
|
|
} |
|
|
|
|
return b.score - a.score; |
|
|
|
|
constructor(props) { |
|
|
|
|
super(props); |
|
|
|
|
|
|
|
|
|
var sitesHash = {}; |
|
|
|
|
for (var site of props.results) { |
|
|
|
|
sitesHash[site.input_url] = site; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.state = { |
|
|
|
|
sitesHash: sitesHash, |
|
|
|
|
searchResult: null, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
this.searchResultCallback = this.searchResultCallback.bind(this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
searchResultCallback(result) { |
|
|
|
|
this.setState({ |
|
|
|
|
searchResult: result, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
render() { |
|
|
|
|
var rows = []; |
|
|
|
|
this.props.results.forEach((element, index) => { |
|
|
|
|
|
|
|
|
|
var row = ( |
|
|
|
|
<Link key={element.input_url} to={`/sites/${ encodeURIComponent(element.input_url) }`} className='ResultsList'> |
|
|
|
|
<div className='ResultsList row'> |
|
|
|
|
<div className='col-9 col-sm-10 col-md-10'> |
|
|
|
|
<LocationLabel level={element.meta.level} type={element.meta.type} district={element.meta.district} city={element.meta.city} state={element.meta.state} truncate={true} /> |
|
|
|
|
<URLField inputURL={element.input_url} canonicalURLs={element.resulting_urls} /> |
|
|
|
|
</div> |
|
|
|
|
<div className='col-3 col-sm-2 col-md-2 d-flex'> |
|
|
|
|
<ScoreField score={element.score} maxScore={13} /> |
|
|
|
|
|
|
|
|
|
if (this.state.searchResult) { |
|
|
|
|
for (var site of this.state.searchResult) { |
|
|
|
|
var element = this.state.sitesHash[site.ref]; |
|
|
|
|
|
|
|
|
|
var row = ( |
|
|
|
|
<Link key={element.input_url} to={`/sites/${ encodeURIComponent(element.input_url) }`} className='ResultsList'> |
|
|
|
|
<div className='ResultsList row'> |
|
|
|
|
<div className='col-9 col-sm-10 col-md-10'> |
|
|
|
|
<LocationLabel level={element.meta.level} type={element.meta.type} district={element.meta.district} city={element.meta.city} state={element.meta.state} truncate={true} /> |
|
|
|
|
<URLField inputURL={element.input_url} canonicalURLs={element.resulting_urls} /> |
|
|
|
|
</div> |
|
|
|
|
<div className='col-3 col-sm-2 col-md-2 d-flex'> |
|
|
|
|
<ScoreField score={element.score} maxScore={13} /> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</Link> |
|
|
|
|
); |
|
|
|
|
</Link> |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
rows.push(row); |
|
|
|
|
}); |
|
|
|
|
rows.push(row); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return rows; |
|
|
|
|
var placeholder = ( |
|
|
|
|
<div className='row placeholder' key='placeholder'> |
|
|
|
|
<div className='col-12 text-center'> |
|
|
|
|
Vergleiche Deine GRÜNE Website mit {this.props.results.length} anderen und erfahre, was Du verbessern kannst. |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
var improve = ( |
|
|
|
|
<div className='row improve' key='improve'> |
|
|
|
|
<div className='col-12 text-center'> |
|
|
|
|
GREEN SPIDER ist freie Software. <a href='https://github.com/netzbegruenung/green-spider/'>Hilf mit, sie zu verbessern!</a> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
var noresult = [placeholder, improve]; |
|
|
|
|
var resultFound = ( |
|
|
|
|
<div className='row results'> |
|
|
|
|
<div className='col-12'> |
|
|
|
|
{rows} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div> |
|
|
|
|
<div className='row searchInputRow'> |
|
|
|
|
<div className='col-12'> |
|
|
|
|
<SearchField searchIndex={this.props.searchIndex} callback={this.searchResultCallback} /> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
{ rows.length ? resultFound : noresult } |
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|