SearchForm.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import React from 'react';
  2. import { FormGroup, Button, InputGroup } from 'react-bootstrap';
  3. import { AsyncTypeahead } from 'react-bootstrap-typeahead';
  4. import axios from 'axios'
  5. import UserPicture from '../User/UserPicture';
  6. import PageListMeta from '../PageList/PageListMeta';
  7. import PagePath from '../PageList/PagePath';
  8. // Header.SearchForm
  9. export default class SearchForm extends React.Component {
  10. constructor(props) {
  11. super(props);
  12. this.crowi = window.crowi; // FIXME
  13. this.state = {
  14. input: '',
  15. keyword: '',
  16. searchedKeyword: '',
  17. pages: [],
  18. searchError: null,
  19. };
  20. this.search = this.search.bind(this);
  21. this.clearForm = this.clearForm.bind(this);
  22. this.getFormClearComponent = this.getFormClearComponent.bind(this);
  23. this.renderMenuItemChildren = this.renderMenuItemChildren.bind(this);
  24. this.onInputChange = this.onInputChange.bind(this);
  25. this.onChange = this.onChange.bind(this);
  26. }
  27. componentDidMount() {
  28. }
  29. componentWillUnmount() {
  30. }
  31. search(keyword) {
  32. if (keyword === '') {
  33. this.setState({
  34. keyword: '',
  35. searchedKeyword: '',
  36. });
  37. return;
  38. }
  39. this.crowi.apiGet('/search', {q: keyword})
  40. .then(res => {
  41. this.setState({
  42. keyword: '',
  43. pages: res.data,
  44. });
  45. }).catch(err => {
  46. this.setState({
  47. searchError: err
  48. });
  49. });
  50. }
  51. getFormClearComponent() {
  52. let isHidden = (this.state.input.length === 0);
  53. return isHidden ? <span></span> : (
  54. <a className="btn btn-link search-top-clear" onClick={this.clearForm} hidden={isHidden}>
  55. <i className="fa fa-times-circle" />
  56. </a>
  57. );
  58. }
  59. clearForm() {
  60. this._typeahead.getInstance().clear();
  61. this.setState({keyword: ''});
  62. }
  63. onInputChange(text) {
  64. this.setState({input: text});
  65. }
  66. onChange(options) {
  67. const page = options[0]; // should be single page selected
  68. // navigate to page
  69. window.location = page.path;
  70. }
  71. renderMenuItemChildren(option, props, index) {
  72. const page = option;
  73. return (
  74. <span>
  75. <UserPicture user={page.revision.author} />
  76. <PagePath page={page} />
  77. <PageListMeta page={page} />
  78. </span>
  79. );
  80. }
  81. render() {
  82. const emptyLabel = (this.state.searchError !== null) ? 'Error on searching.' : 'No matches found.';
  83. const formClear = this.getFormClearComponent();
  84. return (
  85. <form
  86. action="/_search"
  87. className="search-form form-group input-group search-top-input-group"
  88. >
  89. <FormGroup>
  90. <InputGroup>
  91. <AsyncTypeahead
  92. ref={ref => this._typeahead = ref}
  93. name="q"
  94. labelKey="path"
  95. minLength={2}
  96. options={this.state.pages}
  97. placeholder="Search ... Page Title (Path) and Content"
  98. submitFormOnEnter={true}
  99. onSearch={this.search}
  100. onInputChange={this.onInputChange}
  101. onChange={this.onChange}
  102. renderMenuItemChildren={this.renderMenuItemChildren}
  103. />
  104. {formClear}
  105. <InputGroup.Button>
  106. <Button type="submit">
  107. <i className="search-top-icon fa fa-search"></i>
  108. </Button >
  109. </InputGroup.Button>
  110. </InputGroup>
  111. </FormGroup>
  112. </form>
  113. );
  114. }
  115. }
  116. SearchForm.propTypes = {
  117. };
  118. SearchForm.defaultProps = {
  119. };