SearchForm.js 3.4 KB

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