GlobalSearch.jsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import { withUnstatedContainers } from '../UnstatedUtils';
  5. import AppContainer from '~/client/services/AppContainer';
  6. import SearchForm from '../SearchForm';
  7. class GlobalSearch extends React.Component {
  8. constructor(props) {
  9. super(props);
  10. const isSearchScopeChildrenAsDefault = this.props.appContainer.getConfig().isSearchScopeChildrenAsDefault;
  11. this.state = {
  12. text: '',
  13. isScopeChildren: isSearchScopeChildrenAsDefault,
  14. };
  15. this.onInputChange = this.onInputChange.bind(this);
  16. this.onClickAllPages = this.onClickAllPages.bind(this);
  17. this.onClickChildren = this.onClickChildren.bind(this);
  18. this.search = this.search.bind(this);
  19. }
  20. onInputChange(text) {
  21. this.setState({ text });
  22. }
  23. onClickAllPages() {
  24. this.setState({ isScopeChildren: false });
  25. }
  26. onClickChildren() {
  27. this.setState({ isScopeChildren: true });
  28. }
  29. search() {
  30. const url = new URL(window.location.href);
  31. url.pathname = '/_search';
  32. // construct search query
  33. let q = this.state.text;
  34. if (this.state.isScopeChildren) {
  35. q += ` prefix:${window.location.pathname}`;
  36. }
  37. url.searchParams.append('q', q);
  38. window.location.href = url.href;
  39. }
  40. render() {
  41. const { t, appContainer, dropup } = this.props;
  42. const scopeLabel = this.state.isScopeChildren
  43. ? t('header_search_box.label.This tree')
  44. : t('header_search_box.label.All pages');
  45. const config = appContainer.getConfig();
  46. const isReachable = config.isSearchServiceReachable;
  47. return (
  48. <div className={`form-group mb-0 d-print-none ${isReachable ? '' : 'has-error'}`}>
  49. <div className="input-group flex-nowrap">
  50. <div className={`input-group-prepend ${dropup ? 'dropup' : ''}`}>
  51. <button className="btn btn-secondary dropdown-toggle py-0" type="button" data-toggle="dropdown" aria-haspopup="true">
  52. {scopeLabel}
  53. </button>
  54. <div className="dropdown-menu">
  55. <button className="dropdown-item" type="button" onClick={this.onClickAllPages}>{ t('header_search_box.item_label.All pages') }</button>
  56. <button className="dropdown-item" type="button" onClick={this.onClickChildren}>{ t('header_search_box.item_label.This tree') }</button>
  57. </div>
  58. </div>
  59. <SearchForm
  60. t={this.props.t}
  61. crowi={this.props.appContainer}
  62. onInputChange={this.onInputChange}
  63. onSubmit={this.search}
  64. placeholder="Search ..."
  65. dropup={dropup}
  66. />
  67. <div className="btn-group-submit-search">
  68. <span role="button" className="btn-link text-decoration-none" onClick={this.search}>
  69. <i className="icon-magnifier"></i>
  70. </span>
  71. </div>
  72. </div>
  73. </div>
  74. );
  75. }
  76. }
  77. GlobalSearch.propTypes = {
  78. t: PropTypes.func.isRequired, // i18next
  79. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  80. dropup: PropTypes.bool,
  81. };
  82. /**
  83. * Wrapper component for using unstated
  84. */
  85. const GlobalSearchWrapper = withUnstatedContainers(GlobalSearch, [AppContainer]);
  86. export default withTranslation()(GlobalSearchWrapper);