SearchForm.js 3.8 KB

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