Commit 583ac862 authored by Maxime Chaillet's avatar Maxime Chaillet

clean the code. It fixes #3

parent 25dbec94
......@@ -8,15 +8,12 @@ import DatasetFooter from "./DatasetFooter/DatasetFooter.js"
import DatasetSummary from "./DatasetSummary/DatasetSummary.js"
import DatasetMetadataTab from "./DatasetMetadataTab/DatasetMetadataTab.js"
import DatasetTechniqueTab from "./DatasetTechniqueTab/DatasetTechniqueTab.js"
import NewEvent from '../Event/newEvent.jsx';
import {Route} from 'react-router-dom'
class DatasetTable extends React.Component {
render() {
var techniques = ["PTYCHO", "TOMO", "FLUO", "KMAP", "MX", "BIOSAXS", "MRT"]
if (this.props.fetching){
if (this.props.fetching) {
return <Loading></Loading>
}
......@@ -46,10 +43,10 @@ class DatasetTable extends React.Component {
<Tab eventKey={1} title="Summary">
<DatasetSummary dataset={dataset} ></DatasetSummary>
</Tab>
{techniques.map(function(technique, i){
{techniques.map(function (technique, i) {
var params = Object.keys(dataset).filter(parameter => parameter.startsWith(technique));
if (params.length > 0){
return <Tab eventKey={i+2} title={technique}>
if (params.length > 0) {
return <Tab eventKey={i + 2} title={technique}>
<DatasetTechniqueTab dataset={dataset} params={params}></DatasetTechniqueTab>
</Tab>
}
......@@ -74,8 +71,6 @@ class DatasetTable extends React.Component {
))
}
</Grid>
<Route path="/investigation/:id/wallelog/new" component={NewEvent} />
</div>
);
......@@ -83,7 +78,7 @@ class DatasetTable extends React.Component {
}
DatasetTable.propTypes = {
datasets : PropTypes.array
datasets: PropTypes.array
};
export default DatasetTable;
import React from 'react';
//bootstrap
import { DropdownButton, MenuItem } from 'react-bootstrap';
import { Editor, getEventRange, getEventTransfer } from 'slate-react'
import { Block, Value } from 'slate'
import EditTable from 'slate-edit-table'
import Plain from 'slate-plain-serializer'
import imageExtensions from 'image-extensions'
import { LAST_CHILD_TYPE_INVALID } from 'slate-schema-violations'
import isUrl from 'is-url'
import { initialValue } from './initialValue'
import { tablePlugin } from './Plugins/table.jsx';
import { imagePlugin } from './Plugins/image.jsx';
import { marksHelper } from './marks';
//import Html from 'slate-html-serializer';
//import { rules } from './htmlSerializerRules'
// Create a new serializer instance with our `rules` from above.
//const html = new Html({ rules })
const tablePluginInstance = EditTable({
typeTable: 'table',
typeRow: 'table_row',
typeCell: 'table_cell',
typeContent: 'paragraph',
})
const plugins = [
tablePluginInstance,
tablePlugin(),
imagePlugin(),
marksHelper(),
]
/**
* A change function to standardize inserting images.
*
* @param {Change} change
* @param {String} src
* @param {Range} target
*/
function insertImage(change, src, target) {
if (target) {
change.select(target)
}
change.insertBlock({
type: 'image',
isVoid: true,
data: { src },
})
}
function isImage(url) {
return !!imageExtensions.find(url.endsWith)
}
/**
* A schema to enforce that there's always a paragraph as the last block.
*
* @type {Object}
*/
const schema = {
document: {
last: { types: ['paragraph'] },
normalize: (change, reason, { node, child }) => {
switch (reason) {
case LAST_CHILD_TYPE_INVALID: {
const paragraph = Block.create('paragraph')
return change.insertNodeByKey(node.key, node.nodes.size, paragraph)
}
}
},
},
}
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
value: Value.fromJSON(initialValue),
}
this.renderEditor = this.renderEditor.bind(this);
this.renderToolbar = this.renderToolbar.bind(this);
}
renderToolbar = () => {
return (
<div className="menu toolbar-menu" style={{ height: '30px', backgroundColor: '#EEEEEE' }}>
<span onMouseDown={this.onClickBoldText}>
<span className="glyphicon glyphicon-bold" ></span>
</span>
<span> &nbsp; </span>
<span onMouseDown={this.onClickItalicText}>
<span className="glyphicon glyphicon-italic" ></span>
</span>
<span> &nbsp; | &nbsp; </span>
<span onMouseDown={this.onClickImage}>
<span className="glyphicon glyphicon-picture" ></span>
</span>
<span> &nbsp; | &nbsp; </span>
<DropdownButton
bsStyle={'default'}
bsSize="xsmall"
title={'Table'}
key={1}
id={`dropdown-basic-${1}`}
>
<MenuItem eventKey="1" onMouseDown={this.onClickNewTable}>New</MenuItem>
<MenuItem eventKey="2" onMouseDown={this.onClickDeleteTable} >Delete</MenuItem>
</DropdownButton>
</div >
)
}
renderEditor = () => {
return (
<div style={{ height: '80%' }}>
<Editor
plugins={plugins}
placeholder="Enter some text..."
value={this.state.value}
schema={schema}
onChange={this.onChange}
onDrop={this.onDropOrPaste}
onPaste={this.onDropOrPaste}
style={{ overflow: 'auto', height: '100%' }}
/>
</div>
)
}
onChange = ({ value }) => {
//localStorage.setItem("content", JSON.stringify(value));
// When the document changes, save the serialized HTML to Local Storage.
//if (value.document != this.state.value.document) {
// desactivate serialization because table support not written yet
// const htmlContent = html.serialize(value)
// localStorage.setItem('formattedHTML', htmlContent)
const plainContent = Plain.serialize(value)
localStorage.setItem('plainText', plainContent)
//}
this.setState({ value })
}
onClickImage = event => {
event.preventDefault()
const src = window.prompt('Enter the URL of the image:')
if (!src) return
const change = this.state.value.change().call(insertImage, src)
this.onChange(change)
}
onClickNewTable = event => {
event.preventDefault()
const change = this.state.value.change().call(tablePluginInstance.changes.insertTable, 2, 2)
this.onChange(change);
}
onClickDeleteTable = event => {
event.preventDefault()
const change = this.state.value.change().call(tablePluginInstance.changes.removeTable)
this.onChange(change);
}
onClickBoldText = event => {
debugger
const change = this.state.value.change().toggleMark('bold');
this.onChange(change);
}
onClickItalicText = event => {
debugger
const change = this.state.value.change().toggleMark('italic');
this.onChange(change);
}
/**
* On drop, insert the image wherever it is dropped.
*
* @param {Event} event
* @param {Change} change
* @param {Editor} editor
*/
onDropOrPaste = (event, change, editor) => {
const target = getEventRange(event, change.value)
if (!target && event.type === 'drop') return
const transfer = getEventTransfer(event)
const { type, text, files } = transfer
if (type === 'files') {
for (const file of files) {
const reader = new FileReader()
const [mime] = file.type.split('/')
if (mime != 'image') continue
reader.addEventListener('load', () => {
editor.change(c => {
c.call(insertImage, reader.result, target)
})
})
reader.readAsDataURL(file)
}
}
if (type === 'text') {
if (!isUrl(text)) return
if (!isImage(text)) return
change.call(insertImage, text, target)
}
}
render() {
debugger
return (
<div style={{ height: '100%', border: "1px solid", borderColor: "#EEEEEE" }}>
{this.renderToolbar()}
{this.renderEditor()}
</div>
)
}
}
export default MyEditor;
......@@ -14,6 +14,9 @@ export function imagePlugin() {
<Image src={src} className={className} style={style} {...attributes} />
)
}
default: {
return (<p> There is no viever for this image. </p>)
}
}
}
}
......@@ -22,6 +25,6 @@ export function imagePlugin() {
class Image extends React.Component {
render() {
const { attributes } = this.props;
return (<img src={this.props.src} className={this.props.className} style={this.props.style} {...attributes} />)
return (<img src={this.props.src} className={this.props.className} style={this.props.style} alt={this.props.filename} {...attributes} />)
}
}
\ No newline at end of file
import React from "react";
import PropTypes from 'prop-types';
export function tablePlugin() {
return {
......
......@@ -10,6 +10,9 @@ export function marksHelper() {
return <strong>{props.children}</strong>
case 'italic':
return <i>{props.children}</i>
default: {
return (<p> {props.children} </p>)
}
}
}
}
......
......@@ -3,9 +3,7 @@ import React from 'react';
import Moment from 'react-moment';
import { Table } from 'react-bootstrap';
import EventHistoryItem from './eventHistoryItem';
import EventHistory from './eventHistory';
import EventHistoryItem from './EventHistoryItem.jsx';
/**
......
......@@ -8,14 +8,14 @@ import { getFileByEventIdHTTPRequest } from '../../api/icat/icatPlus'
class EventFileViewer extends React.Component {
render() {
if (this.props.event.contentType.search("image") != -1 ) {
if (this.props.event.contentType.search("image") !== -1 ) {
return (
<div>
<a href={getFileByEventIdHTTPRequest(this.props.event.investigationId, this.props.event._id)} target='_blank'> <img width={100} src={getFileByEventIdHTTPRequest(this.props.event.investigationId, this.props.event._id)} alt={this.props.event.filename} /> </a> <span> {this.props.event.text} </span>
</div>)
}
if (this.props.event.contentType.search("pdf") != -1 ) {
if (this.props.event.contentType.search("pdf") !== -1 ) {
return (
<div>
<a href={getFileByEventIdHTTPRequest(this.props.event.investigationId, this.props.event._id)} target='_blank'> <img width={100} src="/pdfLogo.png" alt={this.props.event.filename}/> </a> <span> {this.props.event.text} </span>
......
import React from 'react'
import { Row, Col, Button, Panel } from 'react-bootstrap'
import EventHistoryItem from './eventHistoryItem';
import Moment from 'moment';
import EventHistoryItem from './EventHistoryItem.jsx';
/*
* This class manage the complete history of a given event
*/
......
import React from 'react';
import { Panel, Button } from 'react-bootstrap';
import { Grid, Col, Row, Table } from 'react-bootstrap';
import EventFileViewer from './eventFileViewer'
import { Col, Row } from 'react-bootstrap';
import EventFileViewer from './EventFileViewer.jsx'
/**
* This class displays a event history item. As such it does not have any knowledge of history.
......@@ -21,7 +22,6 @@ class EventHistoryItem extends React.Component {
}
render() {
let htmlContent = { __html: this.props.item.formattedHTML };
return (
<div style={{ 'padding-left': this.visuals.paddingLeft }}>
<Panel id="collapsible-panel-example-1" expanded={this.state.expanded}>
......@@ -58,7 +58,7 @@ class EventHistoryItem extends React.Component {
{/*<p> {this.props.item.content} </p> */}
{(this.props.item.category === "commandLine" || this.props.item.category === 'error') ? this.props.item.text : ""}
{this.props.item.category === "comment" ? (<div> {this.props.item.text} </div>) : ""}
{this.props.item.category === "file" ? <EventFileViewer event={this.props.item}/> : ""}
{this.props.item.category === "file" ? <EventFileViewer event={this.props.item} /> : ""}
</Col>
</Row>
......
//React components
import React from 'react'
import { connect } from 'react-redux';
import { Grid, Row, Col, Button } from "react-bootstrap";
import { Link } from 'react-router-dom';
import NewEventUpload from './newEventUpload';
import NewEventText from './newEventText';
import NewEventUpload from './NewEventUpload.jsx';
import NewEventText from './NewEventText.jsx';
class NewEvent extends React.Component {
......
......@@ -2,18 +2,15 @@
import React from 'react'
import { Grid, Row, Col, Button } from "react-bootstrap";
import { Link } from 'react-router-dom';
import MyEditor from './editor/myEditor.jsx';
import { postEvents } from '../../actions/walleLog/index'
import MyEditor from './Editor/MyEditor.jsx';
import { postEvents } from '../../actions/Event/index.js'
/*
* a new event which is some text, comment, error, commandLine,
*/
class NewEventText extends React.Component {
constructor(props) {
super(props);
}
onSubmit() {
this.postEvents();
......
import React from 'react';
//bootstrap
import { DropdownButton, MenuItem } from 'react-bootstrap';
// for slate editor
import { initialValue } from './initialValue'
import { Editor, getEventRange, getEventTransfer } from 'slate-react'
import { Block, Value } from 'slate'
import { LAST_CHILD_TYPE_INVALID } from 'slate-schema-violations'
import imageExtensions from 'image-extensions'
import isUrl from 'is-url'
import Html from 'slate-html-serializer';
import Plain from 'slate-plain-serializer'
import EditTable from 'slate-edit-table'
import { tablePlugin } from './editorPlugins/table.jsx';
import { imagePlugin } from './editorPlugins/image.jsx';
import { marksHelper } from './marks';
import { rules } from './htmlSerializerRules'
// Create a new serializer instance with our `rules` from above.
const html = new Html({ rules })
const tablePluginInstance = EditTable({
typeTable: 'table',
typeRow: 'table_row',
typeCell: 'table_cell',
typeContent: 'paragraph',
})
const plugins = [
tablePluginInstance,
tablePlugin(),
imagePlugin(),
marksHelper(),
]
/**
* A change function to standardize inserting images.
*
* @param {Change} change
* @param {String} src
* @param {Range} target
*/
function insertImage(change, src, target) {
if (target) {
change.select(target)
}
change.insertBlock({
type: 'image',
isVoid: true,
data: { src },
})
}
function isImage(url) {
return !!imageExtensions.find(url.endsWith)
}
/**
* A schema to enforce that there's always a paragraph as the last block.
*
* @type {Object}
*/
const schema = {
document: {
last: { types: ['paragraph'] },
normalize: (change, reason, { node, child }) => {
switch (reason) {
case LAST_CHILD_TYPE_INVALID: {
const paragraph = Block.create('paragraph')
return change.insertNodeByKey(node.key, node.nodes.size, paragraph)
}
}
},
},
}
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
value: Value.fromJSON(initialValue),
}
this.renderEditor = this.renderEditor.bind(this);
this.renderToolbar = this.renderToolbar.bind(this);
}
renderToolbar = () => {
return (
<div className="menu toolbar-menu" style={{height: '30px', backgroundColor:'#EEEEEE'}}>
<span onMouseDown={this.onClickBoldText}>
<span className="glyphicon glyphicon-bold" ></span>
</span>
<span> &nbsp; </span>
<span onMouseDown={this.onClickItalicText}>
<span className="glyphicon glyphicon-italic" ></span>
</span>
<span> &nbsp; | &nbsp; </span>
<span onMouseDown={this.onClickImage}>
<span className="glyphicon glyphicon-picture" ></span>
</span>
<span> &nbsp; | &nbsp; </span>
<DropdownButton
bsStyle={'default'}
bsSize="xsmall"
title={'Table'}
key={1}
id={`dropdown-basic-${1}`}
>
<MenuItem eventKey="1" onMouseDown={this.onClickNewTable}>New</MenuItem>
<MenuItem eventKey="2" onMouseDown={this.onClickDeleteTable} >Delete</MenuItem>
</DropdownButton>
</div >
)
}
renderEditor = () => {
return (
<div style={{ height: '80%' }}>
<Editor
plugins={plugins}
placeholder="Enter some text..."
value={this.state.value}
schema={schema}
onChange={this.onChange}
onDrop={this.onDropOrPaste}
onPaste={this.onDropOrPaste}
style={{ overflow: 'auto', height: '100%' }}
/>
</div>
)
}
onChange = ({ value }) => {
//localStorage.setItem("content", JSON.stringify(value));
// When the document changes, save the serialized HTML to Local Storage.
//if (value.document != this.state.value.document) {
// desactivate serialization because table support not written yet
// const htmlContent = html.serialize(value)
// localStorage.setItem('formattedHTML', htmlContent)
const plainContent = Plain.serialize(value)
localStorage.setItem('plainText', plainContent)
//}
this.setState({ value })
}
onClickImage = event => {
event.preventDefault()
const src = window.prompt('Enter the URL of the image:')
if (!src) return
const change = this.state.value.change().call(insertImage, src)
this.onChange(change)
}
onClickNewTable = event => {
event.preventDefault()
const change = this.state.value.change().call(tablePluginInstance.changes.insertTable, 2, 2)
this.onChange(change);
}
onClickDeleteTable = event => {
event.preventDefault()
const change = this.state.value.change().call(tablePluginInstance.changes.removeTable)
this.onChange(change);
}
onClickBoldText = event => {
debugger
const change = this.state.value.change().toggleMark('bold');
this.onChange(change);
}
onClickItalicText = event => {
debugger
const change = this.state.value.change().toggleMark('italic');
this.onChange(change);
}
/**
* On drop, insert the image wherever it is dropped.
*
* @param {Event} event
* @param {Change} change
* @param {Editor} editor
*/
onDropOrPaste = (event, change, editor) => {
const target = getEventRange(event, change.value)
if (!target && event.type == 'drop') return
const transfer = getEventTransfer(event)
const { type, text, files } = transfer
if (type == 'files') {
for (const file of files) {
const reader = new FileReader()
const [mime] = file.type.split('/')
if (mime != 'image') continue
reader.addEventListener('load', () => {
editor.change(c => {
c.call(insertImage, reader.result, target)
})
})
reader.readAsDataURL(file)
}
}
if (type == 'text') {
if (!isUrl(text)) return
if (!isImage(text)) return
change.call(insertImage, text, target)
}
}
render() {
debugger
return (