mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-20 02:48:51 +00:00
keyboard can scroll search container (#5684)
This commit is contained in:
@@ -7,10 +7,15 @@ const propTypes = {
|
|||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
onItemClickHandler: PropTypes.func.isRequired,
|
onItemClickHandler: PropTypes.func.isRequired,
|
||||||
isHighlight: PropTypes.bool,
|
isHighlight: PropTypes.bool,
|
||||||
|
setRef: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SearchResultItem extends React.Component {
|
class SearchResultItem extends React.Component {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
setRef: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
onClickHandler = () => {
|
onClickHandler = () => {
|
||||||
var item = this.props.item;
|
var item = this.props.item;
|
||||||
this.props.onItemClickHandler(item);
|
this.props.onItemClickHandler(item);
|
||||||
@@ -29,6 +34,7 @@ class SearchResultItem extends React.Component {
|
|||||||
<li
|
<li
|
||||||
className={classnames('search-result-item', {'search-result-item-highlight': this.props.isHighlight })}
|
className={classnames('search-result-item', {'search-result-item-highlight': this.props.isHighlight })}
|
||||||
onClick={this.onClickHandler}
|
onClick={this.onClickHandler}
|
||||||
|
ref={ref => this.props.setRef(ref)}
|
||||||
>
|
>
|
||||||
<img className={item.link_content ? 'item-img' : 'lib-item-img'} src={fileIconUrl} alt="" />
|
<img className={item.link_content ? 'item-img' : 'lib-item-img'} src={fileIconUrl} alt="" />
|
||||||
<div className="item-content">
|
<div className="item-content">
|
||||||
|
@@ -40,8 +40,10 @@ class Search extends Component {
|
|||||||
searchPageUrl: this.baseSearchPageURL
|
searchPageUrl: this.baseSearchPageURL
|
||||||
};
|
};
|
||||||
this.inputValue = '';
|
this.inputValue = '';
|
||||||
|
this.highlightRef = null;
|
||||||
this.source = null; // used to cancel request;
|
this.source = null; // used to cancel request;
|
||||||
this.inputRef = React.createRef();
|
this.inputRef = React.createRef();
|
||||||
|
this.searchContainer = React.createRef();
|
||||||
this.searchResultListRef = React.createRef();
|
this.searchResultListRef = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,26 +66,12 @@ class Search extends Component {
|
|||||||
else if (isHotkey('esc', e)) {
|
else if (isHotkey('esc', e)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.resetToDefault();
|
this.resetToDefault();
|
||||||
}
|
} else if (isHotkey('enter', e)) {
|
||||||
else if (isHotkey('enter', e)) {
|
this.onEnter(e);
|
||||||
e.preventDefault();
|
} else if (isHotkey('up', e)) {
|
||||||
let item = this.state.resultItems[this.state.highlightIndex];
|
this.onUp(e);
|
||||||
if (item) {
|
} else if (isHotkey('down', e)) {
|
||||||
if (document.activeElement) {
|
this.onDown(e);
|
||||||
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),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,6 +87,50 @@ class Search extends Component {
|
|||||||
this.resetToDefault();
|
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) => {
|
onItemClickHandler = (item) => {
|
||||||
this.resetToDefault();
|
this.resetToDefault();
|
||||||
this.props.onSearchedClick(item);
|
this.props.onSearchedClick(item);
|
||||||
@@ -159,7 +191,6 @@ class Search extends Component {
|
|||||||
this.source = null;
|
this.source = null;
|
||||||
if (res.data.total > 0) {
|
if (res.data.total > 0) {
|
||||||
this.setState({
|
this.setState({
|
||||||
highlightIndex: 0,
|
|
||||||
resultItems: [...this.state.resultItems, this.formatResultItems(res.data.results)],
|
resultItems: [...this.state.resultItems, this.formatResultItems(res.data.results)],
|
||||||
isResultGetted: true,
|
isResultGetted: true,
|
||||||
page: page + 1,
|
page: page + 1,
|
||||||
@@ -188,7 +219,6 @@ class Search extends Component {
|
|||||||
this.source = null;
|
this.source = null;
|
||||||
if (res.data.total > 0) {
|
if (res.data.total > 0) {
|
||||||
this.setState({
|
this.setState({
|
||||||
highlightIndex: 0,
|
|
||||||
resultItems: [...this.state.resultItems, ...this.formatResultItems(res.data.results)],
|
resultItems: [...this.state.resultItems, ...this.formatResultItems(res.data.results)],
|
||||||
isResultGetted: true,
|
isResultGetted: true,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@@ -302,12 +332,14 @@ class Search extends Component {
|
|||||||
return (
|
return (
|
||||||
<ul className="search-result-list" ref={this.searchResultListRef}>
|
<ul className="search-result-list" ref={this.searchResultListRef}>
|
||||||
{resultItems.map((item, index) => {
|
{resultItems.map((item, index) => {
|
||||||
|
const isHighlight = index === highlightIndex;
|
||||||
return (
|
return (
|
||||||
<SearchResultItem
|
<SearchResultItem
|
||||||
key={index}
|
key={index}
|
||||||
item={item}
|
item={item}
|
||||||
onItemClickHandler={this.onItemClickHandler}
|
onItemClickHandler={this.onItemClickHandler}
|
||||||
isHighlight={index === highlightIndex}
|
isHighlight={isHighlight}
|
||||||
|
setRef={isHighlight ? (ref) => {this.highlightRef = ref;} : () => {}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -354,7 +386,11 @@ class Search extends Component {
|
|||||||
<button type="button" className="search-icon-right input-icon-addon fas fa-times border-0 bg-transparent mr-4" onClick={this.onCloseHandler} aria-label={gettext('Close')}></button>
|
<button type="button" className="search-icon-right input-icon-addon fas fa-times border-0 bg-transparent mr-4" onClick={this.onCloseHandler} aria-label={gettext('Close')}></button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="search-result-container dropdown-search-result-container" onScroll={this.onResultListScroll}>
|
<div
|
||||||
|
className="search-result-container dropdown-search-result-container"
|
||||||
|
onScroll={this.onResultListScroll}
|
||||||
|
ref={this.searchContainer}
|
||||||
|
>
|
||||||
{this.renderSearchResult()}
|
{this.renderSearchResult()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user