HeaderSearchBox.jsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import FormGroup from 'react-bootstrap/es/FormGroup';
  5. import Button from 'react-bootstrap/es/Button';
  6. import DropdownButton from 'react-bootstrap/es/DropdownButton';
  7. import MenuItem from 'react-bootstrap/es/MenuItem';
  8. import InputGroup from 'react-bootstrap/es/InputGroup';
  9. import { createSubscribedElement } from './UnstatedUtils';
  10. import AppContainer from '../services/AppContainer';
  11. import SearchForm from './SearchForm';
  12. class HeaderSearchBox extends React.Component {
  13. constructor(props) {
  14. super(props);
  15. this.state = {
  16. text: '',
  17. isScopeChildren: false,
  18. };
  19. this.onInputChange = this.onInputChange.bind(this);
  20. this.onClickAllPages = this.onClickAllPages.bind(this);
  21. this.onClickChildren = this.onClickChildren.bind(this);
  22. this.search = this.search.bind(this);
  23. }
  24. componentDidMount() {
  25. }
  26. componentWillUnmount() {
  27. }
  28. onInputChange(text) {
  29. this.setState({ text });
  30. }
  31. onClickAllPages() {
  32. this.setState({ isScopeChildren: false });
  33. }
  34. onClickChildren() {
  35. this.setState({ isScopeChildren: true });
  36. }
  37. search() {
  38. const url = new URL(window.location.href);
  39. url.pathname = '/_search';
  40. // construct search query
  41. let q = this.state.text;
  42. if (this.state.isScopeChildren) {
  43. q += ` prefix:${window.location.pathname}`;
  44. }
  45. url.searchParams.append('q', q);
  46. window.location.href = url.href;
  47. }
  48. render() {
  49. const { t, appContainer } = this.props;
  50. const scopeLabel = this.state.isScopeChildren
  51. ? t('header_search_box.label.This tree')
  52. : t('header_search_box.label.All pages');
  53. const config = appContainer.getConfig();
  54. const isReachable = config.isSearchServiceReachable;
  55. return (
  56. <FormGroup className={isReachable ? '' : 'has-error'}>
  57. <InputGroup>
  58. <InputGroup.Button className="btn-group-dropdown-scope">
  59. <DropdownButton id="dbScope" title={scopeLabel}>
  60. <MenuItem onClick={this.onClickAllPages}>{ t('header_search_box.item_label.All pages') }</MenuItem>
  61. <MenuItem onClick={this.onClickChildren}>{ t('header_search_box.item_label.This tree') }</MenuItem>
  62. </DropdownButton>
  63. </InputGroup.Button>
  64. <SearchForm
  65. t={this.props.t}
  66. crowi={this.props.appContainer}
  67. onInputChange={this.onInputChange}
  68. onSubmit={this.search}
  69. placeholder="Search ..."
  70. />
  71. <InputGroup.Button className="btn-group-submit-search">
  72. <Button bsStyle="link" onClick={this.search}>
  73. <i className="icon-magnifier"></i>
  74. </Button>
  75. </InputGroup.Button>
  76. </InputGroup>
  77. </FormGroup>
  78. );
  79. }
  80. }
  81. /**
  82. * Wrapper component for using unstated
  83. */
  84. const HeaderSearchBoxWrapper = (props) => {
  85. return createSubscribedElement(HeaderSearchBox, props, [AppContainer]);
  86. };
  87. HeaderSearchBox.propTypes = {
  88. t: PropTypes.func.isRequired, // i18next
  89. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  90. };
  91. export default withTranslation()(HeaderSearchBoxWrapper);