added more search/display fields and made more robust

master
Malar Kannan 2017-06-20 18:50:54 +05:30
parent 6159f53137
commit 2c62605deb
5 changed files with 210 additions and 93 deletions

10
package-lock.json generated
View File

@ -28,6 +28,11 @@
"version": "https://registry.npmjs.org/@types/jest/-/jest-19.2.4.tgz",
"integrity": "sha1-VDZRcSU1lit9xhXhjko4H8JodEI="
},
"@types/lodash": {
"version": "4.14.66",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.66.tgz",
"integrity": "sha512-LpGSiIy5/utq8AT2bSXGnENnS1kCZJ1m84L1yqKst2UehSZe6VWROmiysYg/lLJR6zu2ooeVoQtkUHToA+mEtQ=="
},
"@types/node": {
"version": "https://registry.npmjs.org/@types/node/-/node-7.0.31.tgz",
"integrity": "sha1-gOpNF1WZsqABScKaEKTrLf9ZLoY="
@ -4370,6 +4375,11 @@
"integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=",
"dev": true
},
"reflexbox": {
"version": "3.0.0-0",
"resolved": "https://registry.npmjs.org/reflexbox/-/reflexbox-3.0.0-0.tgz",
"integrity": "sha512-r+7vdyy+kscKFyk2083MLemiT/x3nwzCSif/UwCCoobmwq+cNmJ+hrL7Bu1tJjFOAYjVbIk/GyL5svTRiD0wzg=="
},
"regenerate": {
"version": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz",
"integrity": "sha1-0ZQcZ7rUN+G+dkM63Vs4X5WxkmA=",

View File

@ -7,6 +7,7 @@
"@blueprintjs/table": "^1.16.0",
"@types/es6-shim": "^0.31.34",
"@types/jest": "^19.2.4",
"@types/lodash": "^4.14.66",
"@types/node": "^7.0.29",
"@types/pure-render-decorator": "^0.2.27",
"@types/react": "^15.0.27",
@ -18,6 +19,7 @@
"react-addons-css-transition-group": "^15.5.2",
"react-dom": "^15.5.4",
"react-transition-group": "^1.1.3",
"reflexbox": "^3.0.0-0",
"semantic-ui-css": "^2.2.10",
"semantic-ui-react": "^0.68.5",
"xml2js": "^0.4.17",

View File

@ -26,15 +26,5 @@
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -1,13 +1,11 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "192x192",
"type": "image/png"
}
],
"short_name": "LexEditor",
"name": "Freespeech LexEditor App",
"icons": [{
"src": "favicon.ico",
"sizes": "192x192",
"type": "image/png"
}],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",

View File

@ -1,34 +1,38 @@
import * as React from 'react';
import * as _ from 'lodash';
import {
// Button,
// Classes,
// InputGroup,
// Intent,
// Menu,
// MenuItem,
// Popover,
// Position,
// Spinner,
// Switch,
// Tag,
// Tooltip,
FocusStyleManager,
} from '@blueprintjs/core';
import * as XML from 'xml2js';
import * as XPath from 'xml2js-xpath';
const { Flex, Box } = require('reflexbox');
FocusStyleManager.onlyShowFocusOnTabs();
type ReactEvent = React.ChangeEvent<HTMLInputElement>;
enum EditorMode {
Empty = 1, Edit, Add
}
interface LexEditorProps {
fileName: RequestInfo;
}
const searchLensMap = {
'label': 'label[0]',
'unl': 'unl[0]',
'synset': 'lexprops[0].wnsynset[0]',
'guid': 'guid[0]',
'pos': 'pos[0]',
'image': 'image[0]',
'relations': 'relations[0]',
'frame': 'syntacticprops[0].property[0]._',
'morphclass': 'lexprops[0].morphology[0].morph[0]._',
'stats': 'stats[0].property[0]._',
'lang': '$.id',
};
class LexEditor extends React.Component<LexEditorProps, any> {
constructor(props: LexEditorProps) {
super(props);
this.handleOnSearch = this.handleOnSearch.bind(this);
this.state = { lexData: {}, matchedEntries: [] };
}
@ -39,91 +43,204 @@ class LexEditor extends React.Component<LexEditorProps, any> {
XML.parseString(xmlString, (err, lexData) => {
this.setState({ ...this.state, lexData });
});
})
.catch((e) => {
console.log('errored :', e);
});
// .catch((error) => {
// console.error(error);
// });
}
public render() {
return (
<div>
<LexSearch handleOnSearch={this.handleOnSearch} />
<LexMatches matchedEntries={this.state.matchedEntries} />
</div>
);
}
private handleOnSearch(event: ReactEvent): void {
let searchText = event.target.value;
// this.setState({ ...this.state, searchText });
let pathQ = './/lang';
let words = XPath.find(this.state.lexData.document, pathQ);
let matchedEntries = words.filter((obj) => {
if (obj.label[0] === searchText) {
return true;
}
return false;
});
this.setState({ ...this.state, matchedEntries });
}
}
interface LexSearchProps {
handleOnSearch: (e: ReactEvent) => void;
}
class LexSearch extends React.Component<LexSearchProps, null> {
public render() {
return (
<div className="pt-input-group" style={{ width: '300px' }}>
<span className="pt-icon pt-icon-search" />
<input
className="pt-input"
type="search"
placeholder="Search input"
dir="auto"
onChange={e => this.props.handleOnSearch(e)}
<LexSearch handleOnSearch={(e: any) => this.handleOnSearch(e)} />
<LexMatches
matchedEntries={this.state.matchedEntries}
mode={this.state.mode}
searchText={this.state.searchText}
searchType={this.state.searchType}
/>
</div>
);
}
}
class LexMatches extends React.Component<any, any> {
public render() {
return (
<div>
{this.props.matchedEntries.map((mObj: any) => {
console.log('Matched ObjectEntry' + mObj);
return (<LexEntry key={mObj.unl} lexItem={mObj} />);
})}
</div>
);
private handleOnSearch(searchEvent: any): void {
let searchText = searchEvent.searchValue;
let searchType = searchLensMap[searchEvent.searchType];
let matchedEntries = _.chain(this.state.lexData)
.get<any>('document.lexicon[0].item')
.flatMap((o: any) => _.chain(o)
.get<any>('entry')
.map((p: any) => _.chain(p)
.get<any>('lang[0]')
.set('guid[0]', o.$.guid)
.value())
.value()
)
.filter((q: any) => _.get<any>(q, searchType, '') === searchText)
.value();
let emptyOrAdd = searchText === '' ? EditorMode.Empty : EditorMode.Add;
let mode = matchedEntries.length > 0 ? EditorMode.Edit : emptyOrAdd;
this.setState({ ...this.state, matchedEntries, mode, searchText, searchType });
}
}
class LexEntry extends React.Component<any, any> {
class LexSearch extends React.Component<any, any> {
searchType: String = 'label';
searchValue: String = '';
public render() {
return (
<div className="pt-form-group">
<label className="pt-label" htmlFor="example-form-group-input-a">
UNL
<Flex p={1} align="center" className="pt-control-group">
<div
className="pt-select"
onChange={e => this.handleTypeChange(e)}
>
<select>
{_.keys(searchLensMap).map(k => {
return <option value={k}> {_.capitalize(k)}</option>;
})}
</select>
</div>
<div className="pt-input-group" style={{ width: '120px' }}>
<span className="pt-icon pt-icon-search" />
<input
type="text"
className="pt-input"
placeholder="Search input"
dir="auto"
onChange={e => this.handleLookup(e)}
/>
</div>
</Flex>
);
}
private handleLookup(e: any) {
this.searchValue = e.target.value;
this.props.handleOnSearch({ searchType: this.searchType, searchValue: this.searchValue });
}
private handleTypeChange(e: any) {
this.searchType = e.target.value;
this.props.handleOnSearch({ searchType: this.searchType, searchValue: this.searchValue });
}
}
function selectMode(props: any) {
let editEntries = props.matchedEntries.map((mObj: any) => {
let uniqueKey = mObj.guid[0] + '#' + mObj.$.id;
return (<LexEdit key={uniqueKey} lexItem={mObj} />);
});
switch (props.mode) {
case EditorMode.Edit:
return editEntries;
case EditorMode.Add:
let addProps = {};
_.set(addProps, props.searchType, props.searchText);
return <LexEdit lexItem={addProps} />;
default:
return (
<div className="pt-non-ideal-state">
<div className="pt-non-ideal-state-visual pt-non-ideal-state-icon">
<span className="pt-icon pt-icon-folder-open" />
</div>
<h4 className="pt-non-ideal-state-title">Empty</h4>
<div className="pt-non-ideal-state-description">
Type something in the searchbar.
</div>
</div>
);
}
}
function LexMatches(props: any) {
return (
<Flex m={10} align="center" wrap={true}>
{selectMode(props)}
</Flex>
);
}
class LexEdit extends React.Component<any, any> {
public render() {
let li = this.props.lexItem;
let lexFields = _.keys(searchLensMap).map(e => {
return this.getLabelField(e, searchLensMap[e], li);
});
return (
<Box wx={240} mx={10} my={20} className="pt-card pt-elevation-2 pt-interactive">
<label className="pt-label">
GUID {_.get<any>(li, 'guid', '')}
</label>
<div className="pt-form-content">
<label className="pt-label">
Language: {_.get<any>(li, '$.id', '')}
</label>
<Box column={true} m={1}>
{lexFields}
</Box>
</Box>
);
}
private getLabelField(text: string, labelLens: string, li: any) {
return (
<LexField
key={text}
labelText={_.capitalize(text)}
fieldType={text}
fieldText={_.get<any>(li, labelLens, '')}
fieldHandler={(e: any) => this.handleOnChange(e)}
/>
);
}
private handleOnChange(event: any) {
this.setState(event);
}
}
class LexField extends React.Component<any, any> {
constructor(props: any) {
super(props);
this.state = { fieldText: this.props.fieldText };
}
public render() {
return (
<div className="pt-form-group pt-inline">
<Box w={2 / 5}>
<label style={{ textAlign: 'right' }} className="pt-label" htmlFor="example-form-group-input-a">
{this.props.labelText}
</label>
</Box>
<Box w={3 / 5}>
<input
id="example-form-group-input-a"
className="pt-input"
style={{ width: '300px' }}
placeholder="UNL Value"
value={this.props.lexItem.unl}
style={{ width: '110px' }}
placeholder={this.props.fieldType}
value={this.state.fieldText}
type="text"
dir="auto"
onChange={(e: any) => this.onFieldChange(e)}
/>
</div>
</Box>
</div>
);
}
public componentWillReceiveProps(nextProps: any) {
if (this.props.fieldText !== nextProps.fieldText) {
let fieldText = nextProps.fieldText;
this.setState({ ...this.state, fieldText });
}
}
private onFieldChange(e: any) {
let fieldText = e.target.value;
let eventData = {};
eventData[this.props.fieldType] = fieldText;
this.setState({ ...this.state, fieldText });
this.props.fieldHandler(eventData);
}
}
export default LexEditor;