|
|
@@ -1,5 +1,6 @@
|
|
|
import React from 'react';
|
|
|
import PropTypes from 'prop-types';
|
|
|
+import SearchTypeahead from '../SearchTypeahead';
|
|
|
|
|
|
// Search.SearchForm
|
|
|
export default class SearchForm extends React.Component {
|
|
|
@@ -10,39 +11,75 @@ export default class SearchForm extends React.Component {
|
|
|
this.state = {
|
|
|
keyword: this.props.keyword,
|
|
|
searchedKeyword: this.props.keyword,
|
|
|
+ searchError: null,
|
|
|
};
|
|
|
|
|
|
- this.handleSubmit = this.handleSubmit.bind(this);
|
|
|
+ this.onSearchError = this.onSearchError.bind(this);
|
|
|
this.handleChange = this.handleChange.bind(this);
|
|
|
+ this.onSubmit = this.onSubmit.bind(this);
|
|
|
}
|
|
|
|
|
|
- search() {
|
|
|
- if (this.state.searchedKeyword != this.state.keyword) {
|
|
|
- this.props.onSearchFormChanged({keyword: this.state.keyword});
|
|
|
- this.setState({searchedKeyword: this.state.keyword});
|
|
|
+ onSearchError(err) {
|
|
|
+ this.setState({
|
|
|
+ searchError: err,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ handleChange(selected) {
|
|
|
+ const page = selected[0]; // should be single page selected
|
|
|
+ // navigate to page
|
|
|
+ if (page != null) {
|
|
|
+ window.location = page.path;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- handleSubmit(event) {
|
|
|
- event.preventDefault();
|
|
|
- this.search({keyword: this.state.keyword});
|
|
|
+ onSubmit(query) {
|
|
|
+ // get the closest form element
|
|
|
+ const elem = this.refs.form;
|
|
|
+ const form = elem.closest('form');
|
|
|
+ // submit with jQuery
|
|
|
+ $(form).submit();
|
|
|
}
|
|
|
|
|
|
- handleChange(event) {
|
|
|
- const keyword = event.target.value;
|
|
|
- this.setState({keyword});
|
|
|
+ getHelpElement() {
|
|
|
+ return (
|
|
|
+ <table className="table m-1 search-help">
|
|
|
+ <caption className="text-left text-primary p-2 mb-2">
|
|
|
+ <h5 className="m-1"><i className="icon-magnifier pr-2 mb-2"/>Search Help</h5>
|
|
|
+ </caption>
|
|
|
+ <tbody>
|
|
|
+ <tr>
|
|
|
+ <td className="text-right mt-0 pr-2 p-1"><code>keyword</code></td>
|
|
|
+ <th className="mr-2"><h6 className="pr-2 m-0 pt-1">記事名 or 本文に<samp>"keyword"</samp>を含む</h6></th>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td className="text-right mt-0 pr-2 p-1"><code>a b</code></td>
|
|
|
+ <th><h6 className="m-0 pt-1">文字列<samp>"a"</samp>と<samp>"b"</samp>を含む (スペース区切り)</h6></th>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td className="text-right mt-0 pr-2 p-1"><code>-keyword</code></td>
|
|
|
+ <th><h6 className="m-0 pt-1">文字列<samp>"keyword"</samp>を含まない</h6></th>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
render() {
|
|
|
+ const emptyLabel = (this.state.searchError !== null)
|
|
|
+ ? 'Error on searching.'
|
|
|
+ : 'No matches found on title... Hit [Enter] key so that search on contents.';
|
|
|
+
|
|
|
return (
|
|
|
- <form className="form form-group input-group" onSubmit={this.handleSubmit}>
|
|
|
- <input
|
|
|
- type="text"
|
|
|
- name="q"
|
|
|
- value={this.state.keyword}
|
|
|
+ <form ref='form' className="form form-group input-group" onSubmit={this.onSubmit}>
|
|
|
+ <SearchTypeahead
|
|
|
+ crowi={this.props.crowi}
|
|
|
onChange={this.handleChange}
|
|
|
- className="form-control"
|
|
|
- />
|
|
|
+ onSubmit={this.onSubmit}
|
|
|
+ onSearchError={this.onSearchError}
|
|
|
+ emptyLabel={emptyLabel}
|
|
|
+ keywordOnInit={this.state.keyword}
|
|
|
+ />
|
|
|
<span className="input-group-btn">
|
|
|
<button type="submit" className="btn btn-default">
|
|
|
<i className="search-top-icon icon-magnifier"></i>
|
|
|
@@ -54,6 +91,7 @@ export default class SearchForm extends React.Component {
|
|
|
}
|
|
|
|
|
|
SearchForm.propTypes = {
|
|
|
+ crowi: PropTypes.object.isRequired,
|
|
|
keyword: PropTypes.string,
|
|
|
onSearchFormChanged: PropTypes.func.isRequired,
|
|
|
};
|