From 5c176ce457f195dfad15d0c7d01d36fc2f9fdbdd Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 13 Feb 2019 19:19:10 +0100 Subject: possible PDF embed --- client/geocode/autocomplete.component.js | 208 ------------------------ client/geocode/geocode.component.js | 25 --- client/geocode/index.js | 10 -- scraper/client/common/activeLink.component.js | 16 -- scraper/client/common/autocomplete.component.js | 208 ++++++++++++++++++++++++ scraper/client/common/index.js | 4 +- scraper/client/paper/paper.address.js | 85 +++++++++- scraper/client/paper/paper.citations.js | 3 +- scraper/client/paper/paper.css | 12 +- scraper/client/paper/paper.manager.js | 4 +- scraper/client/paper/paper.unknown.js | 4 +- 11 files changed, 305 insertions(+), 274 deletions(-) delete mode 100644 client/geocode/autocomplete.component.js delete mode 100644 client/geocode/geocode.component.js delete mode 100644 client/geocode/index.js delete mode 100644 scraper/client/common/activeLink.component.js create mode 100644 scraper/client/common/autocomplete.component.js diff --git a/client/geocode/autocomplete.component.js b/client/geocode/autocomplete.component.js deleted file mode 100644 index 12419cf1..00000000 --- a/client/geocode/autocomplete.component.js +++ /dev/null @@ -1,208 +0,0 @@ -import React, { Component } from 'react' -// import PropTypes from 'prop-types' -import { bindActionCreators } from 'redux' -import { connect } from 'react-redux' - -function formatLabel(label, value) { - if (!value) { - return label - } - let len = 0 - return ( - - { - label.split(new RegExp(value.replace(/[-\[\]\(\)\+\*\\\^\$\{\}\.\?\&\|\<\>]/g, ''), "i")) // eslint-disable-line - .reduce((prev, current, i) => { - if (!i) { - len += current.length - return [current] - } - const ret = prev.concat({label.substr(len, value.length)}, current) - len += value.length + current.length - return ret - }, []) - } - - ) -} - -function sanitizeForAutocomplete(s) { - return (s || "") - .toLowerCase() - .replace(/[^a-zA-Z0-9 ]/g, '') - .trim() - .replace(/\\/g, '') -} - -class Autocomplete extends Component { - constructor(props) { - super() - this.state = { - q: props.q || "", - selected: 0, - matches: [] - } - this.handleKeyDown = this.handleKeyDown.bind(this) - this.handleChange = this.handleChange.bind(this) - this.handleCancel = this.handleCancel.bind(this) - } - - componentWillMount() { - // build index based on what's in the hierarchy - const { nodes } = this.props.hierarchy - 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])) - }) - } - - handleKeyDown(e) { - let id - switch (e.keyCode) { - case 27: // escape - e.preventDefault() - this.handleCancel() - break - case 37: // left - case 38: // up - e.preventDefault() - this.setState({ - selected: (this.state.matches.length + this.state.selected - 1) % this.state.matches.length - }) - return false - case 39: // right - case 40: // down - e.preventDefault() - this.setState({ - selected: (this.state.selected + 1) % this.state.matches.length - }) - return false - case 13: // enter - id = this.state.matches[this.state.selected] - e.preventDefault() - this.handleSelect(id) - return false - default: - break - } - } - - handleChange(e) { - // search for the given string in our index - const q = e.target.value - let value = sanitizeForAutocomplete(q) - if (!value.length) { - this.setState({ - q, - selected: 0, - matches: [], - }) - 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]) - } - } - }) - this.setState({ - q, - selected: 0, - matches: matches.slice(0, 10), - }) - } - - handleSelect(id) { - const { nodes } = this.props.hierarchy - const node = nodes[id] - if (this.props.onSelect) this.props.onSelect(node) - this.setState({ q: "", selected: 0, matches: [] }) - } - - handleCancel() { - if (this.props.onCancel) this.props.onCancel() - this.setState({ q: "", selected: 0, matches: [] }) - } - - 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 = ( - - {formatLabel(parent.name, q)} - {' '}{'('}{formatLabel(node.name, q)}{')'} - - ) - } else { - label = formatLabel(node.name, q) - } - return ( -
this.handleSelect(node.id)} - onMouseEnter={() => this.setState({ selected: i })} - > - {label} -
- ) - }) - return ( -
- -
- {matches} -
-
- ) - } -} - -const mapStateToProps = (state, ownProps) => ({ - onSelect: ownProps.onSelect, -}) - -const mapDispatchToProps = (dispatch) => ({ -}) - -export default connect(mapStateToProps, mapDispatchToProps)(Autocomplete) diff --git a/client/geocode/geocode.component.js b/client/geocode/geocode.component.js deleted file mode 100644 index e57d238d..00000000 --- a/client/geocode/geocode.component.js +++ /dev/null @@ -1,25 +0,0 @@ -import React, { Component } from 'react' - -import Autocomplete from './autocomplete.component' - -class GeocodeContainer extends Component { - // constructor() { - // super() - // } - render() { - // const { } = this.props - return ( -
- -
- -
-
- ) - } -} - - -export default GeocodeContainer diff --git a/client/geocode/index.js b/client/geocode/index.js deleted file mode 100644 index 4f0da3f6..00000000 --- a/client/geocode/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom' - -// import { toArray } from '../util' - -import GeocodeContainer from './autocomplete.component' - -ReactDOM.render( - , document.querySelector('#container') -) diff --git a/scraper/client/common/activeLink.component.js b/scraper/client/common/activeLink.component.js deleted file mode 100644 index 59f63881..00000000 --- a/scraper/client/common/activeLink.component.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react' -import { NavLink } from 'react-router-dom' - -export default function ActiveLink({ - to, - className = 'navlink', - children -}) { - return ( - - - {children} - - - ) -} diff --git a/scraper/client/common/autocomplete.component.js b/scraper/client/common/autocomplete.component.js new file mode 100644 index 00000000..12419cf1 --- /dev/null +++ b/scraper/client/common/autocomplete.component.js @@ -0,0 +1,208 @@ +import React, { Component } from 'react' +// import PropTypes from 'prop-types' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +function formatLabel(label, value) { + if (!value) { + return label + } + let len = 0 + return ( + + { + label.split(new RegExp(value.replace(/[-\[\]\(\)\+\*\\\^\$\{\}\.\?\&\|\<\>]/g, ''), "i")) // eslint-disable-line + .reduce((prev, current, i) => { + if (!i) { + len += current.length + return [current] + } + const ret = prev.concat({label.substr(len, value.length)}, current) + len += value.length + current.length + return ret + }, []) + } + + ) +} + +function sanitizeForAutocomplete(s) { + return (s || "") + .toLowerCase() + .replace(/[^a-zA-Z0-9 ]/g, '') + .trim() + .replace(/\\/g, '') +} + +class Autocomplete extends Component { + constructor(props) { + super() + this.state = { + q: props.q || "", + selected: 0, + matches: [] + } + this.handleKeyDown = this.handleKeyDown.bind(this) + this.handleChange = this.handleChange.bind(this) + this.handleCancel = this.handleCancel.bind(this) + } + + componentWillMount() { + // build index based on what's in the hierarchy + const { nodes } = this.props.hierarchy + 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])) + }) + } + + handleKeyDown(e) { + let id + switch (e.keyCode) { + case 27: // escape + e.preventDefault() + this.handleCancel() + break + case 37: // left + case 38: // up + e.preventDefault() + this.setState({ + selected: (this.state.matches.length + this.state.selected - 1) % this.state.matches.length + }) + return false + case 39: // right + case 40: // down + e.preventDefault() + this.setState({ + selected: (this.state.selected + 1) % this.state.matches.length + }) + return false + case 13: // enter + id = this.state.matches[this.state.selected] + e.preventDefault() + this.handleSelect(id) + return false + default: + break + } + } + + handleChange(e) { + // search for the given string in our index + const q = e.target.value + let value = sanitizeForAutocomplete(q) + if (!value.length) { + this.setState({ + q, + selected: 0, + matches: [], + }) + 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]) + } + } + }) + this.setState({ + q, + selected: 0, + matches: matches.slice(0, 10), + }) + } + + handleSelect(id) { + const { nodes } = this.props.hierarchy + const node = nodes[id] + if (this.props.onSelect) this.props.onSelect(node) + this.setState({ q: "", selected: 0, matches: [] }) + } + + handleCancel() { + if (this.props.onCancel) this.props.onCancel() + this.setState({ q: "", selected: 0, matches: [] }) + } + + 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 = ( + + {formatLabel(parent.name, q)} + {' '}{'('}{formatLabel(node.name, q)}{')'} + + ) + } else { + label = formatLabel(node.name, q) + } + return ( +
this.handleSelect(node.id)} + onMouseEnter={() => this.setState({ selected: i })} + > + {label} +
+ ) + }) + return ( +
+ +
+ {matches} +
+
+ ) + } +} + +const mapStateToProps = (state, ownProps) => ({ + onSelect: ownProps.onSelect, +}) + +const mapDispatchToProps = (dispatch) => ({ +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Autocomplete) diff --git a/scraper/client/common/index.js b/scraper/client/common/index.js index c5b4af5b..8ced56b3 100644 --- a/scraper/client/common/index.js +++ b/scraper/client/common/index.js @@ -1,8 +1,8 @@ -import ActiveLink from './activeLink.component' import Header from './header.component' import Footer from './footer.component' import Loader from './loader.component' import Gate from './gate.component' +import Autocomplete from './autocomplete.component' import { TableObject, TableArray, TableTuples, TableRow, TableCell } from './table.component' import './common.css' @@ -16,5 +16,5 @@ export { TableTuples, TableRow, TableCell, - ActiveLink, + Autocomplete, } diff --git a/scraper/client/paper/paper.address.js b/scraper/client/paper/paper.address.js index 2240388f..6d02c3db 100644 --- a/scraper/client/paper/paper.address.js +++ b/scraper/client/paper/paper.address.js @@ -4,27 +4,98 @@ import { connect } from 'react-redux' import * as actions from '../actions' -// import { Loader } from '../common' +import { Loader, Autocomplete } from '../common' +const initialState = { + citation: null, + institution_1: '', + institution_2: '', + institution_3: '', + institution_4: '', +} class PaperAddress extends Component { + state = { + ...initialState + } + componentDidMount() { const { sha256 } = this.props.match.params this.props.actions.getAddress(sha256) + const citation = this.getCitation(sha256) + this.setState({ citation }) } - componentDidUpdate(newProps) { - const { sha256: oldSha256 } = this.props.match.params - const { sha256 } = newProps.match.params - if (sha256 !== oldSha256) { - this.props.actions.getPaperInfo(this.props.match.params.key) + componentDidUpdate(oldProps) { + const { sha256 } = this.props.match.params + const { address } = this.props.api + const { sha256: oldSha256 } = oldProps.match.params + const { address: oldAddress } = oldProps.api + const oldPaper = oldAddress ? oldAddress.paper : null + const paper = address ? address.paper : null + + if (oldSha256 && sha256 !== oldSha256) { + console.log('update address') + this.props.actions.getAddress(sha256) + const citation = this.getCitation(sha256) + this.setState({ + ...initialState, + citation + }) + } else if (address && !address.loading && address.paper && (!oldPaper || oldPaper !== address.paper)) { + if (paper.error) { + const citation = this.getCitation(sha256) + this.setState({ + ...initialState, + citation, + }) + } else { + console.log(paper) + const citation = this.getCitation(sha256) + this.setState({ + citation, + institution_1: paper['Institution #1'], + institution_2: paper['Institution #2'], + institution_3: paper['Institution #3'], + institution_4: paper['Institution #4'], + }) + } + } else if (oldProps.api.unknownCitations !== this.props.api.unknownCitations) { + const citation = this.getCitation(sha256) + this.setState({ citation }) } } + getCitation(sha256) { + const { paperInfo, unknownCitations } = this.props.api + let citation = (unknownCitations.citations || []).find(f => f.id === sha256) + if (!citation) { + citation = (paperInfo.citations || []).find(f => f.id === sha256) + } + console.log(sha256, citation) + return citation + } + render() { // if (!this.props.match.params.key) return null // if (this.props.api.address.loading) return // if (!this.props.api.paperInfo.dataset) return
Metadata not found
- return null + let { paperInfo, unknownCitations } = this.props.api + if (paperInfo.loading || unknownCitations.loading) return + console.log(this.state) + const { citation } = this.state + if (!citation) { + return
Citation not found in this paper
+ } + return ( +
+

{citation.title}

+
{citation.id}
+ {this.state.institution_1} + {/* +