import React, { PropTypes } from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './FolderSelect.styl' import _ from 'lodash' class FolderSelect extends React.Component { constructor (props) { super(props) this.state = { status: 'IDLE', search: '', optionIndex: -1 } } componentDidMount () { this.value = this.props.value } componentDidUpdate () { this.value = this.props.value } handleClick (e) { this.setState({ status: 'SEARCH', optionIndex: -1 }, () => { this.refs.search.focus() }) } handleFocus (e) { if (this.state.status === 'IDLE') { this.setState({ status: 'FOCUS' }) } } handleBlur (e) { if (this.state.status === 'FOCUS') { this.setState({ status: 'IDLE' }) } } handleKeyDown (e) { switch (e.keyCode) { case 13: if (this.state.status === 'FOCUS') { this.setState({ status: 'SEARCH', optionIndex: -1 }, () => { this.refs.search.focus() }) } break case 40: case 38: if (this.state.status === 'FOCUS') { this.setState({ status: 'SEARCH', optionIndex: 0 }, () => { this.refs.search.focus() }) } break case 9: if (e.shiftKey) { e.preventDefault() let tabbable = document.querySelectorAll('a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])') let previousEl = tabbable[Array.prototype.indexOf.call(tabbable, this.refs.root) - 1] if (previousEl != null) previousEl.focus() } } } handleSearchInputBlur (e) { if (e.relatedTarget !== this.refs.root) { this.setState({ status: 'IDLE' }) } } handleSearchInputChange (e) { let { folders } = this.props let search = this.refs.search.value let optionIndex = search.length > 0 ? _.findIndex(folders, (folder) => { return folder.name.match(new RegExp('^' + _.escapeRegExp(search), 'i')) }) : -1 this.setState({ search: this.refs.search.value, optionIndex: optionIndex }) } handleSearchInputKeyDown (e) { switch (e.keyCode) { case 40: e.stopPropagation() this.nextOption() break case 38: e.stopPropagation() this.previousOption() break case 13: e.stopPropagation() this.selectOption() break case 27: e.stopPropagation() this.setState({ status: 'FOCUS' }, () => { this.refs.root.focus() }) } } nextOption () { let { storages } = this.props let { optionIndex } = this.state optionIndex++ if (optionIndex >= folders.length) optionIndex = 0 this.setState({ optionIndex }) } previousOption () { let { folders } = this.props let { optionIndex } = this.state optionIndex-- if (optionIndex < 0) optionIndex = folders.length - 1 this.setState({ optionIndex }) } selectOption () { let { folders } = this.props let optionIndex = this.state.optionIndex let folder = folders[optionIndex] if (folder != null) { this.setState({ status: 'FOCUS' }, () => { this.setValue(folder.key) this.refs.root.focus() }) } } handleOptionClick (storageKey, folderKey) { return (e) => { e.stopPropagation() this.setState({ status: 'FOCUS' }, () => { this.setValue(storageKey + '-' + folderKey) this.refs.root.focus() }) } } setValue (value) { this.value = value this.props.onChange() } render () { let { className, data, value } = this.props let splitted = value.split('-') let storageKey = splitted.shift() let folderKey = splitted.shift() let options = [] data.storageMap.forEach((storage, index) => { storage.folders.forEach((folder) => { options.push({ storage: storage, folder: folder }) }) }) let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0] if (this.state.search.trim().length > 0) { let filter = new RegExp('^' + _.escapeRegExp(this.state.search), 'i') options = options.filter((option) => filter.test(option.folder.name)) } let optionList = options .map((option, index) => { return (