Commit 57cdcb37 authored by hh1966's avatar hh1966
Browse files

Move richtext and ketcher to seperate componentes in research plan detail

parent d120f1b0
......@@ -58,6 +58,9 @@
/public/images/research_plans/*
!/public/images/research_plans/.keep
/public/images/thumbnail/*
!/public/images/thumbnail/.keep
/public/images/*
!/public/images/wild_card/
!/public/images/ghs/
......
......@@ -115,9 +115,7 @@ module Chemotion
params do
requires :id, type: Integer, desc: "Research plan id"
optional :name, type: String, desc: "Research plan name"
optional :description, type: Hash, desc: "Research plan description"
optional :svg_file, type: String, desc: "Research plan SVG file"
optional :sdf_file, type: String, desc: "Research plan SDF file"
optional :body, type: Array, desc: "Research plan body"
end
route_param :id do
before do
......
......@@ -8,7 +8,6 @@ import {
import SVG from 'react-inlinesvg';
import { includes, last, findKey, values } from 'lodash';
import ElementCollectionLabels from './ElementCollectionLabels';
import StructureEditorModal from './structure_editor/StructureEditorModal';
import UIStore from './stores/UIStore';
import UIActions from './actions/UIActions';
......@@ -24,6 +23,10 @@ import SpinnerPencilIcon from './common/SpinnerPencilIcon';
import ImageModal from './common/ImageModal';
import LoadingActions from './actions/LoadingActions';
import RichTextField from './research_plan/RichTextField';
import KetcherField from './research_plan/KetcherField';
const editorTooltip = exts => <Tooltip id="editor_tooltip">Available extensions: {exts}</Tooltip>;
const downloadTooltip = <Tooltip id="download_tooltip">Download attachment</Tooltip>;
......@@ -78,100 +81,16 @@ export default class ResearchPlanDetails extends Component {
});
}
svgOrLoading(research_plan) {
let svgPath = '';
if (this.state.loadingMolecule) {
svgPath = '/images/wild_card/loading-bubbles.svg';
} else {
svgPath = research_plan.svgPath;
}
const className = svgPath ? 'svg-container' : 'svg-container-empty';
const imageDefault = !includes(svgPath, 'no_image_180.svg');
return (
<div>
<Panel defaultExpanded={imageDefault} style={{ border: '0px', backgroundColor: 'white' }}>
<Panel.Heading style={{ border: '0px', backgroundColor: 'white' }}>
<Panel.Title toggle>
<OverlayTrigger
placement="bottom"
overlay={<Tooltip id="closeresearch_plan">Expand/Collapse Image</Tooltip>}
>
<Button
bsSize="xsmall"
className="button-right"
>
<i className="fa fa-picture-o" />
</Button>
</OverlayTrigger>
</Panel.Title>
</Panel.Heading>
<Panel.Collapse style={{ border: '0px', backgroundColor: 'white' }}>
<Panel.Body>
<div
className={className}
onClick={this.showStructureEditor.bind(this)}
>
<Glyphicon className="pull-right" glyph="pencil" />
<SVG key={svgPath} src={svgPath} className="molecule-mid" />
</div>
</Panel.Body>
</Panel.Collapse>
</Panel>
</div>
);
}
handleStructureEditorSave(sdf_file, svg_file, config = null) {
let {research_plan} = this.state;
research_plan.changed = true;
research_plan.sdf_file = sdf_file;
const smiles = config ? config.smiles : null;
this.setState({loadingMolecule: true});
const isChemdraw = smiles ? true : false
ResearchPlansFetcher.updateSVGFile(svg_file, isChemdraw).then((json) => {
research_plan.svg_file = json.svg_path;
this.setState({research_plan: research_plan, loadingMolecule: false});
this.hideStructureEditor();
});
}
handleStructureEditorCancel() {
this.hideStructureEditor()
}
structureEditorButton(isDisabled) {
return (
<Button onClick={this.showStructureEditor.bind(this)} disabled={isDisabled}>
<Glyphicon glyph='pencil'/>
</Button>
)
}
structureEditorModal(research_plan) {
const molfile = research_plan.sdf_file;
return(
<StructureEditorModal
key={research_plan.id}
showModal={this.state.showStructureEditor}
onSave={this.handleStructureEditorSave.bind(this)}
onCancel={this.handleStructureEditorCancel.bind(this)}
molfile={molfile} />
)
}
handleSubmit() {
const { research_plan } = this.state;
LoadingActions.start();
if (research_plan.isNew) {
ElementActions.createResearchPlan(research_plan);
} else {
ElementActions.updateResearchPlan(research_plan);
}
if (research_plan.is_new) {
const force = true;
DetailActions.close(research_plan, force);
......@@ -196,27 +115,15 @@ export default class ResearchPlanDetails extends Component {
case 'name':
research_plan.name = value;
break;
case 'description':
research_plan.description = value;
break;
// case 'description':
// research_plan.description = value;
// break;
}
this.setState({
research_plan: research_plan
});
}
showStructureEditor() {
this.setState({
showStructureEditor: true
});
}
hideStructureEditor() {
this.setState({
showStructureEditor: false
});
}
researchPlanHeader(research_plan) {
let saveBtnDisplay = research_plan.changed ? '' : 'none';
......@@ -258,9 +165,6 @@ export default class ResearchPlanDetails extends Component {
<Col md={2}>
<h4>{research_plan.name}</h4>
</Col>
<Col md={10}>
{this.svgOrLoading(research_plan)}
</Col>
</Row>
)
}
......@@ -459,10 +363,37 @@ export default class ResearchPlanDetails extends Component {
Utils.downloadFile({contents: `/api/v1/attachments/${attachment.id}`, name: attachment.filename});
}
handleChange(value, index) {
let {research_plan} = this.state
research_plan.changed = true
research_plan.body[index].value = value
this.setState({
research_plan: research_plan
});
}
propertiesTab(research_plan) {
const { name, description } = research_plan;
const submitLabel = research_plan.isNew ? "Create" : "Save";
const disabled = research_plan.isMethodDisabled('body')
let bodyFields = research_plan.body.map((field, index) => {
switch (field.type) {
case 'richtext':
return <RichTextField key={field.id}
field={field} index={index} disabled={disabled}
onChange={this.handleChange.bind(this)} />
break;
case 'ketcher':
return <KetcherField key={field.id}
field={field} index={index} disabled={disabled}
onChange={this.handleChange.bind(this)} />
break;
}
})
return (
<ListGroup fill="true">
<ListGroupItem>
......@@ -479,16 +410,8 @@ export default class ResearchPlanDetails extends Component {
</FormGroup>
</Col>
</Row>
{bodyFields}
<Row>
<Col md={12}>
<FormGroup>
<ControlLabel>Description</ControlLabel>
<QuillEditor value={research_plan.description}
onChange={event => this.handleInputChange('description', {target: {value: event}})}
disabled={research_plan.isMethodDisabled('description')}
/>
</FormGroup>
</Col>
<Col md={12}>
<FormGroup>
<ControlLabel>Files</ControlLabel>
......@@ -502,24 +425,23 @@ export default class ResearchPlanDetails extends Component {
);
}
literatureTab(research_plan){
const { name, description } = research_plan;
const submitLabel = research_plan.isNew ? "Create" : "Save";
literatureTab(research_plan){
const { name, description } = research_plan;
const submitLabel = research_plan.isNew ? "Create" : "Save";
return (
<ResearchPlansLiteratures
element={research_plan}
/>
);
}
return (
<ResearchPlansLiteratures
element={research_plan}
/>
);
}
handleSelect(eventKey) {
UIActions.selectTab({tabKey: eventKey, type: 'screen'});
this.setState({
activeTab: eventKey
})
}
handleSelect(eventKey) {
UIActions.selectTab({tabKey: eventKey, type: 'screen'});
this.setState({
activeTab: eventKey
})
}
render() {
const { research_plan } = this.state;
......@@ -542,7 +464,6 @@ export default class ResearchPlanDetails extends Component {
{this.literatureTab(research_plan)}
</Tab>
</Tabs>
{this.structureEditorModal(research_plan)}
<ButtonToolbar>
<Button bsStyle="primary" onClick={() => DetailActions.close(research_plan)}>Close</Button>
<Button bsStyle="warning" onClick={() => this.handleSubmit()}>{submitLabel}</Button>
......
import Element from './Element';
import { isEmpty } from 'lodash';
const uuidv4 = require('uuid/v4');
export default class ResearchPlan extends Element {
/*isMethodRestricted(m) {
return false;
}*/
static buildEmpty(collection_id) {
let description_default = {
"ops": [{ "insert": "" }]
}
return new ResearchPlan({
collection_id: collection_id,
type: 'research_plan',
name: 'New Research Plan',
description: description_default,
svg_file: '',
sdf_file: '',
attachments: [],
body: [
{
id: uuidv4(),
type: 'ketcher',
value: {
svg_file: null,
svg_file: null,
thumb_svg: null
}
},
{
id: uuidv4(),
type: 'richtext',
value: null
}
]
});
}
serialize() {
return super.serialize({
name: this.name,
description: this.description,
svg_file: this.svg_file,
sdf_file: this.sdf_file,
body: this.body,
attachments: this.attachments
});
}
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormGroup, Row, Col, Glyphicon } from 'react-bootstrap';
import SVG from 'react-inlinesvg';
import { includes, last, findKey, values } from 'lodash';
import ResearchPlansFetcher from '../fetchers/ResearchPlansFetcher';
import StructureEditorModal from '../structure_editor/StructureEditorModal';
import QuillEditor from '../QuillEditor';
export default class KetcherField extends Component {
constructor(props) {
super(props)
const { field, index, disabled, onChange } = props
this.state = {
field,
index,
disabled,
onChange,
showStructureEditor: false,
loadingMolecule: false
}
}
showStructureEditor() {
this.setState({
showStructureEditor: true
});
}
hideStructureEditor() {
this.setState({
showStructureEditor: false
});
}
handleStructureEditorSave(sdf_file, svg_file, config = null) {
let { field, index, onChange } = this.state
field.value = {
sdf_file: sdf_file,
svg_file: svg_file
}
const smiles = config ? config.smiles : null;
this.setState({loadingMolecule: true});
const isChemdraw = smiles ? true : false
ResearchPlansFetcher.updateSVGFile(svg_file, isChemdraw).then((json) => {
field.value.svg_file = json.svg_path;
this.setState({
field: field,
loadingMolecule: false
});
onChange(field.value, index)
this.hideStructureEditor();
});
}
handleStructureEditorCancel() {
this.hideStructureEditor()
}
renderStructureEditorModal(field) {
const molfile = field.value.sdf_file;
return(
<StructureEditorModal key={field.id}
showModal={this.state.showStructureEditor}
onSave={this.handleStructureEditorSave.bind(this)}
onCancel={this.handleStructureEditorCancel.bind(this)}
molfile={molfile} />
)
}
render() {
let { field, disabled } = this.state
let className, svgPath
if (field.value.svg_file) {
className = 'svg-container'
svgPath = '/images/research_plans/' + field.value.svg_file
} else {
className = 'svg-container-empty'
svgPath = '/images/wild_card/loading-bubbles.svg'
}
console.log(svgPath);
const imageDefault = !includes(svgPath, 'no_image_180.svg');
return (
<Row>
<Col md={12}>
<FormGroup>
<div className={className}
onClick={this.showStructureEditor.bind(this)} >
<Glyphicon className="pull-right" glyph="pencil" />
<SVG key={svgPath} src={svgPath} className="molecule-mid" />
</div>
</FormGroup>
</Col>
{this.renderStructureEditorModal(field)}
</Row>
)
}
}
KetcherField.propTypes = {
field: PropTypes.object,
index: PropTypes.number,
disabled: PropTypes.bool,
onChange: PropTypes.func,
}
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormGroup, Row, Col } from 'react-bootstrap';
import QuillEditor from '../QuillEditor';
export default class RichTextField extends Component {
constructor(props) {
super(props)
const { field, index, disabled, onChange } = props
this.state = {
field,
index,
disabled,
onChange
}
}
handleChange(event) {
let { field, index, onChange } = this.state
field.value = event
this.setState({
field: field
});
onChange(field.value, index)
}
render() {
let { field, disabled } = this.state
return (
<Row>
<Col md={12}>
<FormGroup>
<QuillEditor value={field.value}
onChange={this.handleChange.bind(this)}
disabled={disabled}
/>
</FormGroup>
</Col>
</Row>
)
}
}
RichTextField.propTypes = {
field: PropTypes.object,
index: PropTypes.number,
disabled: PropTypes.bool,
onChange: PropTypes.func,
}
......@@ -9528,9 +9528,9 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
"integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
},
"validate-npm-package-license": {
"version": "3.0.4",
......
......@@ -76,7 +76,7 @@
"sha.js": "^2.4.11",
"sha256": "^0.2.0",
"uglifyify": "~5.0.1",
"uuid": "^2.0.2",
"uuid": "^3.3.2",
"whatwg-fetch": "2.0.3",
"xlsx": "^0.12.9"
},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment