SearchForm.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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. 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)
  83. ? 'Error on searching.'
  84. : 'No matches found on title... Hit [Enter] key so that search on contents.';
  85. const formClear = this.getFormClearComponent();
  86. return (
  87. <form
  88. action="/_search"
  89. className="search-form form-group input-group search-top-input-group"
  90. >
  91. <FormGroup>
  92. <InputGroup>
  93. <AsyncTypeahead
  94. ref={ref => this._typeahead = ref}
  95. name="q"
  96. labelKey="path"
  97. minLength={2}
  98. options={this.state.pages}
  99. placeholder="Search ..."
  100. emptyLabel={emptyLabel}
  101. align='left'
  102. submitFormOnEnter={true}
  103. onSearch={this.search}
  104. onInputChange={this.onInputChange}
  105. onChange={this.onChange}
  106. renderMenuItemChildren={this.renderMenuItemChildren}
  107. />
  108. {formClear}
  109. <InputGroup.Button>
  110. <Button type="submit">
  111. <i className="search-top-icon fa fa-search"></i>
  112. </Button >
  113. </InputGroup.Button>
  114. </InputGroup>
  115. </FormGroup>
  116. </form>
  117. );
  118. }
  119. }
  120. SearchForm.propTypes = {
  121. };
  122. SearchForm.defaultProps = {
  123. };