diff options
Diffstat (limited to 'scraper/client/common')
| -rw-r--r-- | scraper/client/common/autocomplete.component.js | 118 | ||||
| -rw-r--r-- | scraper/client/common/autocomplete.css | 39 | ||||
| -rw-r--r-- | scraper/client/common/common.css | 2 | ||||
| -rw-r--r-- | scraper/client/common/index.js | 1 |
4 files changed, 103 insertions, 57 deletions
diff --git a/scraper/client/common/autocomplete.component.js b/scraper/client/common/autocomplete.component.js index 12419cf1..03039b1c 100644 --- a/scraper/client/common/autocomplete.component.js +++ b/scraper/client/common/autocomplete.component.js @@ -47,29 +47,33 @@ class Autocomplete extends Component { this.handleCancel = this.handleCancel.bind(this) } - componentWillMount() { + componentDidMount() { // build index based on what's in the hierarchy - const { nodes } = this.props.hierarchy + const { entities, lookup } = this.props.institutions let index = [] this.index = index - Object.keys(nodes).forEach(key => { - const node = nodes[key] - if (!key || !node || !node.name || !node.parent) return - let { name } = node - let prefixName = name - if (node.is_attribute) { - const parent = nodes[node.parent] - if (parent) { - prefixName = parent.name + " (" + name + ")" - } - } - index.push([sanitizeForAutocomplete(prefixName), name, node.id]) - node.synonyms - .split("\n") - .map(word => word = word.trim()) - .filter(word => !!word) - .forEach(word => index.push([prefixName, name, node.id])) + Object.keys(entities).forEach(name => { + if (!name) return + index.push([sanitizeForAutocomplete(name), name]) + }) + Object.keys(lookup).forEach(name => { + if (!name) return + index.push([sanitizeForAutocomplete(name), lookup[name]]) }) + // console.log(index) + // node.synonyms + // .split("\n") + // .map(word => word = word.trim()) + // .filter(word => !!word) + // .forEach(word => index.push([prefixName, name, node.id])) + } + + componentDidUpdate(oldProps) { + if (this.props.vetting !== oldProps.vetting) { + this.handleChange({ target: { value: this.props.vetting }}) + } else if (this.props.value !== oldProps.value) { + this.handleChange({ target: { value: this.props.value }}) + } } handleKeyDown(e) { @@ -101,6 +105,7 @@ class Autocomplete extends Component { default: break } + return null } handleChange(e) { @@ -115,31 +120,42 @@ class Autocomplete extends Component { }) return } - const re = new RegExp(value) - let matches = [] let seen = {} - this.index.forEach(pair => { - if (seen[pair[2]]) return - if (pair[0].match(re)) { - seen[pair[2]] = true - if (pair[1].indexOf(value) === 0) { - matches.unshift(pair[2]) - } else { - matches.push(pair[2]) + let matches = [] + value.split(' ').forEach(word => { + const re = new RegExp(word) + this.index.forEach(([synonym, term]) => { + if (synonym.match(re)) { + if (synonym.indexOf(value) === 0) { + if (term in seen) { + seen[term] += 4 + } else { + seen[term] = 4 + } + } else if (term in seen) { + seen[term] += 1 + } else { + seen[term] = 1 + } } - } + }) + matches = Object.keys(seen) + .map(term => [seen[term], term]) + .sort((a, b) => { + return b[0] - a[0] + }) + .slice(0, 100) + .map(pair => pair[1]) }) this.setState({ q, selected: 0, - matches: matches.slice(0, 10), + matches, }) } - handleSelect(id) { - const { nodes } = this.props.hierarchy - const node = nodes[id] - if (this.props.onSelect) this.props.onSelect(node) + handleSelect(name) { + if (this.props.onSelect) this.props.onSelect(name) this.setState({ q: "", selected: 0, matches: [] }) } @@ -149,28 +165,14 @@ class Autocomplete extends Component { } render() { - // const suggestions = this.state.suggestions.map((suggestion)) - const { nodes } = this.props.hierarchy const { q, selected } = this.state const matches = this.state.matches.map((match, i) => { - const node = nodes[match] - const parent = nodes[node.parent] - let label - if (node.is_attribute) { - label = ( - <span> - {formatLabel(parent.name, q)} - {' '}<small>{'('}{formatLabel(node.name, q)}{')'}</small> - </span> - ) - } else { - label = formatLabel(node.name, q) - } + const label = formatLabel(match, q) return ( <div key={i} className={selected === i ? 'selected' : ''} - onClick={() => this.handleSelect(node.id)} + onClick={() => this.handleSelect(match)} onMouseEnter={() => this.setState({ selected: i })} > {label} @@ -185,14 +187,17 @@ class Autocomplete extends Component { value={this.state.q} onKeyDown={this.handleKeyDown} onChange={this.handleChange} - autoFocus + autoFocus={this.props.autoFocus} autoCapitalize="off" autoComplete="off" - placeholder="Start typing a name" + placeholder={this.props.placeholder} + ref={ref => this._el = ref} /> - <div className="matches"> - {matches} - </div> + {!!matches.length && + <div className="matches"> + {matches} + </div> + } </div> ) } @@ -200,6 +205,7 @@ class Autocomplete extends Component { const mapStateToProps = (state, ownProps) => ({ onSelect: ownProps.onSelect, + institutions: state.api.institutions, }) const mapDispatchToProps = (dispatch) => ({ diff --git a/scraper/client/common/autocomplete.css b/scraper/client/common/autocomplete.css new file mode 100644 index 00000000..ac90ea72 --- /dev/null +++ b/scraper/client/common/autocomplete.css @@ -0,0 +1,39 @@ +.autocomplete { + position: relative; + margin-bottom: 4px; +} +.autocomplete input[type=text], +.autocomplete .matches { + width: 400px; +} +.autocomplete div { + background: white; + cursor: pointer; +} +.autocomplete .matches { + position: absolute; + top: 100%; + left: 0; + border: 1px solid #888; + max-height: 220px; + overflow-y: auto; + z-index: 1; +} +.autocomplete .matches div { + padding: 3px; +} +.autocomplete .matches div:nth-child(even) { + background: #eee; +} +.autocomplete .matches div:nth-child(odd) { + background: #fff; +} +.autocomplete .matches div:nth-child(even).selected, +.autocomplete .matches div:nth-child(odd).selected { + color: #fff; + background: #000; + cursor: pointer; +} +.autocomplete .selected { + background: rgba(128,128,128,0.2); +}
\ No newline at end of file diff --git a/scraper/client/common/common.css b/scraper/client/common/common.css index b014541a..fb31aefb 100644 --- a/scraper/client/common/common.css +++ b/scraper/client/common/common.css @@ -7,7 +7,7 @@ html,body { } body { font-family: Helvetica, sans-serif; - font-weight: 300; + color: #333; } h1 { diff --git a/scraper/client/common/index.js b/scraper/client/common/index.js index 8ced56b3..8925aae0 100644 --- a/scraper/client/common/index.js +++ b/scraper/client/common/index.js @@ -5,6 +5,7 @@ import Gate from './gate.component' import Autocomplete from './autocomplete.component' import { TableObject, TableArray, TableTuples, TableRow, TableCell } from './table.component' import './common.css' +import './autocomplete.css' export { Header, |
