implemented morph exceptions

master
Malar Kannan 2017-07-31 17:19:56 +05:30
parent c1952dc8ac
commit c0eedb4555
8 changed files with 324 additions and 182 deletions

View File

@ -3,32 +3,32 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"eslint": "^4.2.0", "eslint": "^4.3.0",
"eslint-config-react-app": "^1.0.5", "eslint-config-react-app": "^1.0.5",
"react": "^15.5.4", "react": "^15.6.1",
"react-addons-css-transition-group": "^15.5.2", "react-addons-css-transition-group": "^15.6.0",
"react-dom": "^15.5.4", "react-dom": "^15.6.1",
"react-redux": "^5.0.5", "react-redux": "^5.0.5",
"react-sortable-hoc": "^0.6.5", "react-sortable-hoc": "^0.6.6",
"react-transition-group": "^1.1.3", "react-transition-group": "^1.1.3",
"reflexbox": "^3.0.0-0", "reflexbox": "^3.0.0-0",
"semantic-ui-css": "^2.2.10", "semantic-ui-css": "^2.2.11",
"semantic-ui-react": "^0.68.5", "semantic-ui-react": "^0.71.3",
"xml2js": "^0.4.17", "xml2js": "^0.4.17",
"xml2js-xpath": "^0.8.0" "xml2js-xpath": "^0.8.0"
}, },
"devDependencies": { "devDependencies": {
"@types/es6-shim": "^0.31.34", "@types/es6-shim": "^0.31.34",
"@types/jest": "^19.2.4", "@types/jest": "^19.2.4",
"@types/lodash": "^4.14.66", "@types/lodash": "^4.14.71",
"@types/node": "^7.0.29", "@types/node": "^7.0.39",
"@types/pure-render-decorator": "^0.2.27", "@types/pure-render-decorator": "^0.2.27",
"@types/react": "^15.0.27", "@types/react": "^15.6.0",
"@types/react-addons-css-transition-group": "^15.0.2", "@types/react-addons-css-transition-group": "^15.0.3",
"@types/react-dom": "^15.5.0", "@types/react-dom": "^15.5.1",
"@types/react-redux": "^4.4.46", "@types/react-redux": "^4.4.47",
"@types/react-sortable-hoc": "^0.6.0", "@types/react-sortable-hoc": "^0.6.0",
"@types/react-transition-group": "^1.1.0", "@types/react-transition-group": "^1.1.2",
"@types/xml2js": "0.0.33", "@types/xml2js": "0.0.33",
"app-root-path": "^2.0.1", "app-root-path": "^2.0.1",
"autoprefixer": "7.1.0", "autoprefixer": "7.1.0",
@ -48,19 +48,19 @@
"postcss-loader": "2.0.5", "postcss-loader": "2.0.5",
"promise": "7.1.1", "promise": "7.1.1",
"react-dev-utils": "^2.0.1", "react-dev-utils": "^2.0.1",
"react-error-overlay": "^1.0.6", "react-error-overlay": "^1.0.9",
"source-map-loader": "^0.2.1", "source-map-loader": "^0.2.1",
"style-loader": "0.17.0", "style-loader": "0.17.0",
"sw-precache-webpack-plugin": "0.9.1", "sw-precache-webpack-plugin": "0.9.1",
"ts-loader": "^2.0.3", "ts-loader": "^2.3.2",
"tslint": "^5.2.0", "tslint": "^5.5.0",
"tslint-loader": "^3.5.3", "tslint-loader": "^3.5.3",
"tslint-react": "^3.0.0", "tslint-react": "^3.1.0",
"typescript": "^2.3.3", "typescript": "^2.4.2",
"url-loader": "0.5.8", "url-loader": "0.5.8",
"webpack": "2.6.0", "webpack": "2.6.0",
"webpack-dev-server": "2.4.5", "webpack-dev-server": "2.4.5",
"webpack-manifest-plugin": "^1.1.0", "webpack-manifest-plugin": "^1.2.1",
"whatwg-fetch": "2.0.3", "whatwg-fetch": "2.0.3",
"write-file-webpack-plugin": "^4.1.0" "write-file-webpack-plugin": "^4.1.0"
}, },

View File

@ -91,13 +91,19 @@ function propListAttrAccessor(attrPred: any) {
set: (li: any, value: any) => { set: (li: any, value: any) => {
let lexItem = _.cloneDeep(li); let lexItem = _.cloneDeep(li);
let allProps = _.get<any>(lexItem, lens, []); let allProps = _.get<any>(lexItem, lens, []);
let setValue = value.map((v: any) => {
let ret = {};
_.set(ret, '$.form', v.key);
_.set(ret, '_', v.value);
return ret;
});
if (allProps.length > 0) { if (allProps.length > 0) {
let keepProps = _.filter<any>(allProps, (m) => { let keepProps = _.filter<any>(allProps, (m) => {
return !pred(m); return !pred(m);
}); });
_.set(lexItem, lens, _.concat(keepProps, value)); _.set(lexItem, lens, _.concat(keepProps, setValue));
} else { } else {
_.set(lexItem, lens, value); _.set(lexItem, lens, setValue);
} }
return lexItem; return lexItem;
} }
@ -190,6 +196,22 @@ const fieldMetaMap = {
}, },
}; };
function getSelectOptions(field: string, entries: any) {
let allOpts = entries.map((q: any) => {
return fieldMetaMap[field].get(q);
});
switch (fieldMetaMap[field].type) {
case 'select':
return _.uniq(allOpts);
case 'list':
return _.uniq(_.flatten(allOpts));
case 'proplist':
return _.uniq(_.map(_.flatten(allOpts), (v) => _.get<any>(v, 'key')));
default:
return [];
}
}
export const xmlToEntries = (xmlData: any) => { export const xmlToEntries = (xmlData: any) => {
let allEntries = _.chain(xmlData) let allEntries = _.chain(xmlData)
.get<any>('document.lexicon[0].item') .get<any>('document.lexicon[0].item')
@ -209,17 +231,18 @@ export const xmlToEntries = (xmlData: any) => {
}); });
let langEntries = _.reduce(allEntries, langReducer, {}); let langEntries = _.reduce(allEntries, langReducer, {});
let langs = _.keys(langEntries); let langs = _.keys(langEntries);
let selectableFields = ['select', 'list', 'proplist'];
let selectFields = _.fromPairs(langs.map((lang) => { let selectFields = _.fromPairs(langs.map((lang) => {
let langOpts = _.fromPairs(_.keys(fieldMetaMap).filter((s) => { let langOpts = _.fromPairs(_.keys(fieldMetaMap).filter((s) => {
return _.includes(['select', 'list'], fieldMetaMap[s].type); return _.includes(selectableFields, fieldMetaMap[s].type);
}).map((s) => { }).map((s) => {
let entries = _.get<any>(langEntries, lang, 'en'); let entries = _.get<any>(langEntries, lang, 'en');
let allOpts = entries.map((q: any) => { // let allOpts = entries.map((q: any) => {
return fieldMetaMap[s].get(q); // return fieldMetaMap[s].get(q);
}); // });
let select = _.isEqual(fieldMetaMap[s].type, 'select'); // let select = _.isEqual(fieldMetaMap[s].type, 'select');
let selectOptions = select ? _.uniq(allOpts) : _.uniq(_.flatten(allOpts)); // let selectOptions = select ? _.uniq(allOpts) : _.uniq(_.flatten(allOpts));
return [s, selectOptions]; return [s, getSelectOptions(s, entries)];
})); }));
return [lang, langOpts]; return [lang, langOpts];
})); }));

View File

@ -1,6 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { componentForType } from './LexSingleInput'; import { componentForType } from './LexInputContainer';
import { import {
Card, Card,
Button Button

View File

@ -77,7 +77,7 @@ function LexMatches(params: any) {
if (props.searchText === '') { if (props.searchText === '') {
return ( return (
<Container> <Container>
<Header size="mini">Empty</Header> <Header size="tiny">Empty</Header>
Type something in the searchbar. Type something in the searchbar.
</Container> </Container>
); );

265
src/LexInputContainer.tsx Normal file
View File

@ -0,0 +1,265 @@
import * as React from 'react';
import * as _ from 'lodash';
import { Label, Form } from 'semantic-ui-react';
const { Flex, Box } = require('reflexbox');
import {
Input,
Dropdown,
Image,
Modal,
Button,
} from 'semantic-ui-react';
class LexInputContainer extends React.Component<any, any> {
public render() {
return (
<div>
<Form>
<Form.Group as={Flex} inline={true} style={{ margin: '0 0 5px 5px' }}>
<Form.Field as={Box} w={2 / 5} style={{ textAlign: 'right' }}>
{this.props.label}
</Form.Field>
<Form.Field as={Box} w={3 / 5} >
{this.props.children}
</Form.Field>
</Form.Group>
</Form>
</div>
);
}
}
function changedLabel(changed: boolean, text: string) {
let labelClass = changed ? 'olive' : '';
return (
<Label
pointing="right"
className={labelClass}
>
{text}
</Label>
);
}
function textInput(params: any) {
let { field, sh, value, changed } = params;
return (
<LexInputContainer
label={changedLabel(changed, field)}
key={field}
>
<Input
onChange={(e, d) => { sh(d.value); }}
value={value}
placeholder={field}
type="text"
dir="auto"
style={{ width: '10em' }}
/>
</LexInputContainer>
);
}
function selectInput(params: any) {
let { field, sh, value, options, langSelOpts, changed } = params;
let staticOpts = options;
let fieldOpts = _.get<any>(langSelOpts, field, []);
let selOpts = staticOpts ? staticOpts : fieldOpts;
let dropOptions = selOpts.map((k: any, i: any, c: any) => {
return { key: i, value: k, text: k };
});
return (
<LexInputContainer key={field} label={changedLabel(changed, field)}>
<Dropdown
options={dropOptions}
onChange={(e, d) => { sh(d.value); }}
value={value}
compact={true}
selection={true}
search={true}
style={{ width: '10em' }}
/>
</LexInputContainer>
);
}
function imagePreview(params: any) {
let { field, value, changed } = params;
let imageSrc = '/png/' + value;
return value !== '' ? (
<LexInputContainer key={field} label={changedLabel(changed, field)}>
<Image src={imageSrc} size="large" bordered={true} />
</LexInputContainer>
) : textInput(params);
}
function listInput(params: any) {
let { field, sh, langSelOpts, value, changed } = params;
let fieldOpts = _.get<any>(langSelOpts, field, []);
let renderLabel = (label: any) => ({
content: `${label.value}`,
});
let dropOptions = fieldOpts.map((k: any, i: any, c: any) => {
return {
key: i,
value: k,
text: k,
};
});
return (
<LexInputContainer key={field} label={changedLabel(changed, field)}>
<Dropdown
options={dropOptions}
onChange={(e, d) => {
sh(d.value);
}}
value={value}
compact={true}
selection={true}
search={true}
multiple={true}
fluid={true}
style={{ width: '10em' }}
renderLabel={renderLabel}
/>
</LexInputContainer>
);
}
function propListInput(params: any) {
let { field, changed } = params;
return (
<LexInputContainer key={field} label={changedLabel(changed, field)}>
<PropListInput params={params} />
</LexInputContainer>
);
}
class PropListInput extends React.Component<any, any> {
constructor(props: any) {
super(props);
let { value } = this.props.params;
let dropOptions = this.dropOptsForVal(value);
this.state = { value, dropOptions, modalOpen: false, exKey: '', exVal: '' };
}
dropOptsForVal(value: any) {
let { field, langSelOpts } = this.props.params;
let fieldOpts = _.get<any>(langSelOpts, field, []);
function valueForKey(key: string) {
let match = _.find(value, (v: any) => _.isEqual(v.key, key));
if (match) {
return match;
} else {
return { key, value: '' };
}
}
return fieldOpts.map((k: any, i: any) => {
return {
key: i,
value: valueForKey(k),
text: k,
};
});
}
public render() {
let { sh } = this.props.params;
let renderLabel = (label: any) => ({
content: `${label.value.key}-${label.value.value}`,
});
let value = _.filter(this.state.dropOptions, (o: any) => {
return _.some(this.state.value, (v: any) => {
return _.isEqual(v.key, o.value.key);
});
}).map((so) => so.value);
let onCloseModal = (e: any) => {
let except = { key: this.state.exKey, value: this.state.exVal };
let ns = _.concat(this.state.value, except);
this.setState({
dropOptions: this.dropOptsForVal(ns),
value: ns,
modalOpen: false,
exKey: '',
exVal: ''
});
sh(ns);
};
let dropDownComp = (
<Dropdown
options={this.state.dropOptions}
onChange={(e, d) => {
let newValue = d.value as any;
let addedValue = _.difference(newValue, this.state.value) as any;
console.log('added: ', addedValue);
let didAdd = _.size(addedValue) > 0;
let newState = didAdd ? {
exKey: addedValue[0].key,
} : {
exKey: '',
value: newValue
} as any;
this.setState({ ...newState, modalOpen: didAdd });
if (!didAdd) {
sh(newValue);
}
}}
value={value}
compact={true}
selection={true}
search={true}
multiple={true}
fluid={true}
style={{ width: '10em' }}
renderLabel={renderLabel}
/>
);
return (
<Modal
open={this.state.modalOpen}
onClose={onCloseModal}
size="mini"
trigger={dropDownComp}
>
<Modal.Content>
Enter the exception for {this.state.exKey}
</Modal.Content>
<Modal.Actions>
<Input
focus={true}
onChange={(e, d: any) => {
this.setState({ exVal: d.value });
}}
/>
<Button onClick={onCloseModal}>
Done
</Button>
</Modal.Actions>
</Modal>
);
}
}
export function componentForType(type: string, params: any) {
switch (type) {
case 'text': {
return textInput(params);
}
case 'select': {
return selectInput(params);
}
case 'preview': {
return imagePreview(params);
}
case 'list': {
return listInput(params);
}
case 'proplist': {
return propListInput(params);
}
default: {
console.log('type discarded :', type);
return null;
}
}
}

View File

@ -63,7 +63,7 @@ export class LexXMLSelect extends React.Component<any, any> {
export class LexSetup extends React.Component<any, any> { export class LexSetup extends React.Component<any, any> {
xmlBuilder = new XML.Builder(); xmlBuilder = new XML.Builder();
xmlFileName = 'new_es.xml'; xmlFileName = 'new_es_orig.xml';
constructor(props: any) { constructor(props: any) {
super(props); super(props);
this.state = { this.state = {
@ -95,7 +95,7 @@ export class LexSetup extends React.Component<any, any> {
let editor = ( let editor = (
<div> <div>
<Segment inverted={true} size="tiny" attached={true}> <Segment inverted={true} size="tiny" attached={true}>
<Header color="teal" size="mini"> <Header color="teal" size="tiny">
{saveButton} {saveButton}
{loadButton} {loadButton}
<LexXMLSelect <LexXMLSelect

View File

@ -1,148 +0,0 @@
import * as React from 'react';
import * as _ from 'lodash';
import { Label, Form } from 'semantic-ui-react';
const { Flex, Box } = require('reflexbox');
import {
Input,
Dropdown,
Image
} from 'semantic-ui-react';
class LexSingleInput extends React.Component<any, any> {
public render() {
return (
<div>
<Form>
<Form.Group as={Flex} inline={true} style={{ margin: '0 0 5px 5px' }}>
<Form.Field as={Box} w={2 / 5} style={{ textAlign: 'right' }}>
{this.props.label}
</Form.Field>
<Form.Field as={Box} w={3 / 5} >
{this.props.children}
</Form.Field>
</Form.Group>
</Form>
</div>
);
}
}
function changedLabel(changed: boolean, text: string) {
let labelClass = changed ? 'olive' : '';
return (
<Label
pointing="right"
className={labelClass}
>
{text}
</Label>
);
}
function textInput(params: any) {
let { field, sh, value, changed } = params;
return (
<LexSingleInput
label={changedLabel(changed, field)}
key={field}
>
<Input
onChange={(e, d) => { sh(d.value); }}
value={value}
placeholder={field}
type="text"
dir="auto"
style={{ width: '10em' }}
/>
</LexSingleInput>
);
}
function selectInput(params: any) {
let { field, sh, value, options, langSelOpts, changed } = params;
let staticOpts = options;
let fieldOpts = _.get<any>(langSelOpts, field, []);
let selOpts = staticOpts ? staticOpts : fieldOpts;
let dropOptions = selOpts.map((k: any, i: any, c: any) => {
return { key: i, value: k, text: k };
});
return (
<LexSingleInput key={field} label={changedLabel(changed, field)}>
<Dropdown
options={dropOptions}
onChange={(e, d) => { sh(d.value); }}
value={value}
compact={true}
selection={true}
search={true}
style={{ width: '10em' }}
/>
</LexSingleInput>
);
}
function imagePreview(params: any) {
let { field, value, changed } = params;
let imageSrc = '/png/' + value;
return value !== '' ? (
<LexSingleInput key={field} label={changedLabel(changed, field)}>
<Image src={imageSrc} size="large" bordered={true} />
</LexSingleInput>
) : textInput(params);
}
function listInput(params: any) {
let { field, sh, langSelOpts, value, changed } = params;
let fieldOpts = _.get<any>(langSelOpts, field, []);
let renderLabel = (label: any) => ({
content: `${label.value}`,
});
let dropOptions = fieldOpts.map((k: any, i: any, c: any) => {
return {
key: i,
value: k,
text: k,
};
});
return (
<LexSingleInput key={field} label={changedLabel(changed, field)}>
<Dropdown
options={dropOptions}
onChange={(e, d) => {
sh(d.value);
}}
value={value}
compact={true}
selection={true}
search={true}
multiple={true}
fluid={true}
style={{ width: '10em' }}
renderLabel={renderLabel}
/>
</LexSingleInput>
);
}
export function componentForType(type: string, params: any) {
switch (type) {
case 'text': {
return textInput(params);
}
case 'select': {
return selectInput(params);
}
case 'preview': {
return imagePreview(params);
}
case 'list': {
// return (<ListInput params={params} />);
return listInput(params);
}
default: {
// console.log('type discarded :', type);
// console.log('values discarded :', fieldMeta.get(li));
return null;
}
}
}

View File

@ -6,7 +6,9 @@ import json
import codecs import codecs
import glob import glob
import os import os
xmlDir = 'public/'
production = True if os.environ.get('NODE_ENV','') == 'production' else False
xmlDir = 'public/' if production else 'build/'
# from flask_cors import CORS, cross_origin # from flask_cors import CORS, cross_origin
# CORS(app) # CORS(app)