diff --git a/frontend/src/components/search/search-result-item.js b/frontend/src/components/search/search-result-item.js index 844d279247..793a7d1a60 100644 --- a/frontend/src/components/search/search-result-item.js +++ b/frontend/src/components/search/search-result-item.js @@ -7,10 +7,15 @@ const propTypes = { item: PropTypes.object.isRequired, onItemClickHandler: PropTypes.func.isRequired, isHighlight: PropTypes.bool, + setRef: PropTypes.func, }; class SearchResultItem extends React.Component { + static defaultProps = { + setRef: () => {}, + }; + onClickHandler = () => { var item = this.props.item; this.props.onItemClickHandler(item); @@ -29,6 +34,7 @@ class SearchResultItem extends React.Component {
  • this.props.setRef(ref)} >
    diff --git a/frontend/src/components/search/search.js b/frontend/src/components/search/search.js index 438519d38f..31c8a7c60b 100644 --- a/frontend/src/components/search/search.js +++ b/frontend/src/components/search/search.js @@ -40,8 +40,10 @@ class Search extends Component { searchPageUrl: this.baseSearchPageURL }; this.inputValue = ''; + this.highlightRef = null; this.source = null; // used to cancel request; this.inputRef = React.createRef(); + this.searchContainer = React.createRef(); this.searchResultListRef = React.createRef(); } @@ -64,26 +66,12 @@ class Search extends Component { else if (isHotkey('esc', e)) { e.preventDefault(); this.resetToDefault(); - } - else if (isHotkey('enter', e)) { - e.preventDefault(); - let item = this.state.resultItems[this.state.highlightIndex]; - if (item) { - if (document.activeElement) { - document.activeElement.blur(); - } - this.onItemClickHandler(item); - } - } - else if (isHotkey('up', e)) { - this.setState({ - highlightIndex: Math.max(this.state.highlightIndex - 1, 0), - }); - } - else if (isHotkey('down', e)) { - this.setState({ - highlightIndex: Math.min(this.state.highlightIndex + 1, this.state.resultItems.length - 1), - }); + } else if (isHotkey('enter', e)) { + this.onEnter(e); + } else if (isHotkey('up', e)) { + this.onUp(e); + } else if (isHotkey('down', e)) { + this.onDown(e); } }; @@ -99,6 +87,50 @@ class Search extends Component { this.resetToDefault(); }; + onUp = (e) => { + e.preventDefault(); + e.stopPropagation(); + const { highlightIndex } = this.state; + if (highlightIndex > 0) { + this.setState({ highlightIndex: highlightIndex - 1 }, () => { + if (this.highlightRef) { + const { top, height } = this.highlightRef.getBoundingClientRect(); + if (top - height < 0) { + this.searchContainer.current.scrollTop -= height; + } + } + }); + } + }; + + onDown = (e) => { + e.preventDefault(); + e.stopPropagation(); + const { highlightIndex, resultItems } = this.state; + if (highlightIndex < resultItems.length - 1) { + this.setState({ highlightIndex: highlightIndex + 1 }, () => { + if (this.highlightRef) { + const { top, height } = this.highlightRef.getBoundingClientRect(); + const outerHeight = 300; + if (top > outerHeight) { + this.searchContainer.current.scrollTop += height; + } + } + }); + } + }; + + onEnter = (e) => { + e.preventDefault(); + let item = this.state.resultItems[this.state.highlightIndex]; + if (item) { + if (document.activeElement) { + document.activeElement.blur(); + } + this.onItemClickHandler(item); + } + }; + onItemClickHandler = (item) => { this.resetToDefault(); this.props.onSearchedClick(item); @@ -159,7 +191,6 @@ class Search extends Component { this.source = null; if (res.data.total > 0) { this.setState({ - highlightIndex: 0, resultItems: [...this.state.resultItems, this.formatResultItems(res.data.results)], isResultGetted: true, page: page + 1, @@ -188,7 +219,6 @@ class Search extends Component { this.source = null; if (res.data.total > 0) { this.setState({ - highlightIndex: 0, resultItems: [...this.state.resultItems, ...this.formatResultItems(res.data.results)], isResultGetted: true, isLoading: false, @@ -302,12 +332,14 @@ class Search extends Component { return (
    -
    +
    {this.renderSearchResult()}