SearchForm.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import React from 'react';
  2. import { FormGroup, Button, InputGroup } from 'react-bootstrap';
  3. import { AsyncTypeahead } from 'react-bootstrap-typeahead';
  4. import UserPicture from '../User/UserPicture';
  5. import PageListMeta from '../PageList/PageListMeta';
  6. import PagePath from '../PageList/PagePath';
  7. import PropTypes from 'prop-types';
  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. isLoading: false,
  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.setState({isLoading: true});
  41. this.crowi.apiGet('/search', {q: keyword})
  42. .then(res => {
  43. this.setState({
  44. isLoading: false,
  45. keyword: '',
  46. pages: res.data,
  47. });
  48. })
  49. .catch(err => {
  50. this.setState({
  51. isLoading: false,
  52. searchError: err,
  53. });
  54. });
  55. }
  56. getFormClearComponent() {
  57. let isHidden = (this.state.input.length === 0);
  58. return isHidden ? <span></span> : (
  59. <a className="btn btn-link search-top-clear" onClick={this.clearForm} hidden={isHidden}>
  60. <i className="fa fa-times-circle" />
  61. </a>
  62. );
  63. }
  64. clearForm() {
  65. this._typeahead.getInstance().clear();
  66. this.setState({keyword: ''});
  67. }
  68. onInputChange(text) {
  69. this.setState({input: text});
  70. }
  71. onChange(selected) {
  72. const page = selected[0]; // should be single page selected
  73. // navigate to page
  74. if (page != null) {
  75. window.location = page.path;
  76. }
  77. }
  78. renderMenuItemChildren(option, props, index) {
  79. const page = option;
  80. return (
  81. <span>
  82. <UserPicture user={page.revision.author} />
  83. <PagePath page={page} />
  84. <PageListMeta page={page} />
  85. </span>
  86. );
  87. }
  88. render() {
  89. const emptyLabel = (this.state.searchError !== null)
  90. ? 'Error on searching.'
  91. : 'No matches found on title... Hit [Enter] key so that search on contents.';
  92. const formClear = this.getFormClearComponent();
  93. return (
  94. <form
  95. action="/_search"
  96. className="search-form form-group input-group search-top-input-group"
  97. >
  98. <FormGroup>
  99. <InputGroup>
  100. <AsyncTypeahead
  101. ref={ref => this._typeahead = ref}
  102. isLoading={this.state.isLoading}
  103. labelKey="path"
  104. minLength={2}
  105. options={this.state.pages}
  106. placeholder="Search ..."
  107. emptyLabel={emptyLabel}
  108. align='left'
  109. submitFormOnEnter={true}
  110. onSearch={this.search}
  111. onInputChange={this.onInputChange}
  112. onChange={this.onChange}
  113. renderMenuItemChildren={this.renderMenuItemChildren}
  114. />
  115. {formClear}
  116. <InputGroup.Button>
  117. <Button type="submit">
  118. <i className="search-top-icon fa fa-search"></i>
  119. </Button >
  120. </InputGroup.Button>
  121. </InputGroup>
  122. </FormGroup>
  123. </form>
  124. );
  125. }
  126. }
  127. SearchForm.propTypes = {
  128. };
  129. SearchForm.defaultProps = {
  130. };