import React from 'react'; import classNames from 'classnames'; import LazyScroller, {Themes} from './common/LazyScroller'; import i18n from '../i18n'; import RegexUtils from '../utils/RegexUtils'; import '../styles/autocomplete_popout.styl'; const INPUT_REF = 'input'; const AutocompletePopout = React.createClass({ getDefaultProps() { return { sections: [null], }; }, getInitialState() { return this.createState(); }, componentWillReceiveProps() { this.setState(this.createState(this.state.prefix)); }, createState(prefix = '') { const regex = new RegExp(`^${RegexUtils.escape(prefix.trim())}`, 'i'); const filter = v => regex.test(v); const rows = this.props.sections.map((_, i) => this.props.onFilterResults(filter, i)); let selectedSection = 0; for (; selectedSection < rows.length; selectedSection++) { if (rows[selectedSection].length > 0) { break; } } return { prefix, selectedSection, selectedRow: 0, rows, }; }, componentDidMount() { process.nextTick(this.focus); }, handleChange(e) { const prefix = e.target.value; this.props.onQueryChange && this.props.onQueryChange(prefix); this.setState(this.createState(prefix)); }, handleMouseEnter(section, row) { this.setState({ selectedSection: section, selectedRow: row, }); }, handleClick(section, row) { this.props.onSelect(this.state.rows[section][row], section); this.props.onClose(); }, handleKeyDown(e) { let {selectedSection, selectedRow} = this.state; switch (e.keyCode) { case 9: // TAB case 40: // DOWN e.preventDefault(); if (this.props.sections.length > selectedSection && ++selectedRow >= this.state.rows[selectedSection].length) { if (++selectedSection >= this.props.sections.length) { selectedSection = 0; } selectedRow = 0; } this.setState({selectedSection, selectedRow}); break; case 38: // UP e.preventDefault(); if (--selectedRow < 0) { if (--selectedSection < 0) { selectedSection = this.props.sections.length - 1; } selectedRow = this.state.rows[selectedSection].length - 1; } this.setState({selectedSection, selectedRow}); break; case 13: // ENTER e.preventDefault(); if (this.props.sections.length > selectedSection && this.state.rows[selectedSection].length > selectedRow) { this.props.onSelect(this.state.rows[selectedSection][selectedRow], selectedSection); this.props.onClose(); } break; case 27: // ESCAPE e.preventDefault(); this.props.onSelect(null, null); this.props.onClose(); break; } }, render() { const results = []; if (this.state.rows.reduce((acc, rows) => acc + rows.length, 0) === 0) { results.push(

{i18n.Messages.AUTOCOMPLETE_NO_RESULTS_HEADER}

{i18n.Messages.AUTOCOMPLETE_NO_RESULTS_BODY}

); } else { const {selectedSection, selectedRow} = this.state; this.props.sections.forEach((section, i) => { const rows = this.state.rows[i]; if (rows.length === 0) return; results.push(
{section}
); rows.forEach((result, j) => { results.push(
{this.props.onRenderResult(result, i)}
); }); }); } return (

{this.props.label}

{results}
); }, focus() { if (this.isMounted()) { this.refs[INPUT_REF].focus(); } }, }); export default AutocompletePopout; // WEBPACK FOOTER // // ./discord_app/components/AutocompletePopout.js