/** * This is the box that pops up if you press ctrl+f. It handles searching through the content on the page and scrolling to matches. */ import React from "react"; import LoggerStore from "../../../stores/LoggerStore"; import { CtrlFSearch } from "../../../stores/CtrlFSearch"; interface IProps { show: boolean; } interface IState { matches: any; activeIndex: number; searchString: string; } export default class LoggerSearchBox extends React.Component { constructor(props: IProps) { super(props); this.state = { matches: new CtrlFSearch().getIterator(), activeIndex: 1, searchString: LoggerStore.getSearchBoxString(), }; LoggerStore.setLogSearchBoxString(this.state.searchString); this.onKeyPress = this.onKeyPress.bind(this); this.scrollToNextMatch = this.scrollToNextMatch.bind(this); this.scrollToPreviousMatch = this.scrollToPreviousMatch.bind(this); this.focus = this.focus.bind(this); this.setSearchString = this.setSearchString.bind(this); this.onSearchUpdate = this.onSearchUpdate.bind(this); } focus() { if (this.refs.SearchBox) { (this.refs.SearchBox as HTMLInputElement).focus(); } } onKeyPress(e: React.KeyboardEvent) { if (e.key === "Enter") { this.scrollToNextMatch(); } } setSearchString(e: React.ChangeEvent) { LoggerStore.setLogSearchBoxString(e.target.value); } onSearchUpdate() { this.setState( { matches: LoggerStore.getSearchMatches(), searchString: LoggerStore.getSearchBoxString(), }, () => { if (this.state.activeIndex === 1) { this.scrollToNextMatch(); } else { this.state.matches.setActiveIndex(this.state.activeIndex); } } ); } scrollToNextMatch() { // SearchResultNumber is X out of N matches. It's X. const { matches } = this.state; const nextMatch = matches.next(); if (nextMatch.value !== undefined) { this.setState({ activeIndex: nextMatch.searchResultNumber, }); LoggerStore.setActiveRowIndex(nextMatch.value); } } scrollToPreviousMatch() { const { matches } = this.state; const nextMatch = matches.previous(); this.setState({ activeIndex: nextMatch.searchResultNumber, }); LoggerStore.setActiveRowIndex(nextMatch.value); } hideSearchBox() { LoggerStore.hideSearchBox(); } componentDidMount() { LoggerStore.addListener("loggerNewMessages", this.searchAgain); LoggerStore.addListener("showSearchBox", this.focus); LoggerStore.addListener("showSearchBoxChange", this.focus); LoggerStore.addListener("searchBoxTextChange", this.onSearchUpdate); } componentWillUnmount() { LoggerStore.removeListener("loggerNewMessages", this.searchAgain); LoggerStore.removeListener("showSearchBox", this.focus); LoggerStore.removeListener("showSearchBoxChange", this.focus); LoggerStore.removeListener("searchBoxTextChange", this.onSearchUpdate); } searchAgain() { LoggerStore.setLogSearchBoxString(LoggerStore.Search.searchString); } render() { const classes = "fsbl-logger-searchbox"; if (!this.props.show) { return null; } const numMatches = this.state.matches && this.state.matches.values ? this.state.matches.values.length : 0; // For when matches < 10. let left = "152px"; if (numMatches >= 10) { left = "142px"; } else if (numMatches >= 100) { left = "128px"; } const matchTextStyle = { left, }; return (
{numMatches > 0 && ( )}
Cancel
); } }