SearchTop.jsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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 '../../services/AppContainer';
  6. import NavigationContainer from '../../services/NavigationContainer';
  7. import SearchForm from '../SearchForm';
  8. class SearchTop extends React.Component {
  9. constructor(props) {
  10. super(props);
  11. this.state = {
  12. text: '',
  13. isScopeChildren: false,
  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. Root = ({ children }) => {
  41. const { isDeviceSmallerThanMd: isCollapsed } = this.props.navigationContainer.state;
  42. return isCollapsed
  43. ? (
  44. <div id="grw-search-top-collapse" className="collapse bg-dark p-3">
  45. {children}
  46. </div>
  47. )
  48. : (
  49. <div className="grw-search-top-absolute position-absolute">
  50. {children}
  51. </div>
  52. );
  53. };
  54. SearchTopForm = () => {
  55. const { t, appContainer } = this.props;
  56. const scopeLabel = this.state.isScopeChildren
  57. ? t('header_search_box.label.This tree')
  58. : t('header_search_box.label.All pages');
  59. const config = appContainer.getConfig();
  60. const isReachable = config.isSearchServiceReachable;
  61. return (
  62. <div className={`form-group mb-0 d-print-none ${isReachable ? '' : 'has-error'}`}>
  63. <div className="input-group flex-nowrap">
  64. <div className="input-group-prepend">
  65. <button className="btn btn-secondary dropdown-toggle py-0" type="button" data-toggle="dropdown" aria-haspopup="true">
  66. {scopeLabel}
  67. </button>
  68. <div className="dropdown-menu">
  69. <button className="dropdown-item" type="button" onClick={this.onClickAllPages}>{ t('header_search_box.item_label.All pages') }</button>
  70. <button className="dropdown-item" type="button" onClick={this.onClickChildren}>{ t('header_search_box.item_label.This tree') }</button>
  71. </div>
  72. </div>
  73. <SearchForm
  74. t={this.props.t}
  75. crowi={this.props.appContainer}
  76. onInputChange={this.onInputChange}
  77. onSubmit={this.search}
  78. placeholder="Search ..."
  79. />
  80. <div className="btn-group-submit-search">
  81. <span className="btn-link text-decoration-none" onClick={this.search}>
  82. <i className="icon-magnifier"></i>
  83. </span>
  84. </div>
  85. </div>
  86. </div>
  87. );
  88. }
  89. render() {
  90. const { Root, SearchTopForm } = this;
  91. return (
  92. <Root><SearchTopForm /></Root>
  93. );
  94. }
  95. }
  96. SearchTop.propTypes = {
  97. t: PropTypes.func.isRequired, // i18next
  98. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  99. navigationContainer: PropTypes.instanceOf(NavigationContainer).isRequired,
  100. };
  101. /**
  102. * Wrapper component for using unstated
  103. */
  104. const SearchTopWrapper = withUnstatedContainers(SearchTop, [AppContainer, NavigationContainer]);
  105. export default withTranslation()(SearchTopWrapper);