Renamed /src to /frontend
This commit is contained in:
159
frontend/components/MarkdownEditor/MarkdownEditor.js
Normal file
159
frontend/components/MarkdownEditor/MarkdownEditor.js
Normal file
@ -0,0 +1,159 @@
|
||||
import React from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import Codemirror from 'react-codemirror';
|
||||
import 'codemirror/mode/gfm/gfm';
|
||||
import 'codemirror/mode/javascript/javascript';
|
||||
import 'codemirror/addon/edit/continuelist';
|
||||
import 'codemirror/addon/display/placeholder.js';
|
||||
import Dropzone from 'react-dropzone';
|
||||
|
||||
import ClickablePadding from './components/ClickablePadding';
|
||||
|
||||
import styles from './MarkdownEditor.scss';
|
||||
import './codemirror.scss';
|
||||
|
||||
import { client } from 'utils/ApiClient';
|
||||
|
||||
@observer
|
||||
class MarkdownEditor extends React.Component {
|
||||
static propTypes = {
|
||||
text: React.PropTypes.string,
|
||||
onChange: React.PropTypes.func.isRequired,
|
||||
replaceText: React.PropTypes.func.isRequired,
|
||||
onSave: React.PropTypes.func.isRequired,
|
||||
|
||||
// This is actually not used but it triggers
|
||||
// re-render to help with CodeMirror focus issues
|
||||
preview: React.PropTypes.bool,
|
||||
}
|
||||
|
||||
getEditorInstance = () => {
|
||||
return this.refs.editor.getCodeMirror();
|
||||
}
|
||||
|
||||
onChange = (newText) => {
|
||||
if (newText !== this.props.text) {
|
||||
this.props.onChange(newText);
|
||||
}
|
||||
}
|
||||
|
||||
onDropAccepted = (files) => {
|
||||
const file = files[0];
|
||||
const editor = this.getEditorInstance();
|
||||
|
||||
const cursorPosition = editor.getCursor();
|
||||
const insertOnNewLine = cursorPosition.ch !== 0;
|
||||
let newCursorPositionLine;
|
||||
|
||||
// Lets set up the upload text
|
||||
const pendingUploadTag = ``;
|
||||
if (insertOnNewLine) {
|
||||
editor.replaceSelection('\n' + pendingUploadTag + '\n');
|
||||
newCursorPositionLine = cursorPosition.line + 3;
|
||||
} else {
|
||||
editor.replaceSelection(pendingUploadTag + '\n');
|
||||
newCursorPositionLine = cursorPosition.line + 2;
|
||||
}
|
||||
editor.setCursor(newCursorPositionLine, 0);
|
||||
|
||||
client.post('/user.s3Upload', {
|
||||
kind: file.type,
|
||||
size: file.size,
|
||||
filename: file.name,
|
||||
})
|
||||
.then(response => {
|
||||
const data = response.data;
|
||||
// Upload using FormData API
|
||||
let formData = new FormData();
|
||||
|
||||
for (let key in data.form) {
|
||||
formData.append(key, data.form[key]);
|
||||
}
|
||||
|
||||
if (file.blob) {
|
||||
formData.append('file', file.file);
|
||||
} else {
|
||||
formData.append('file', file);
|
||||
}
|
||||
|
||||
fetch(data.upload_url, {
|
||||
method: 'post',
|
||||
body: formData
|
||||
})
|
||||
.then(s3Response => {
|
||||
this.props.replaceText({
|
||||
original: pendingUploadTag,
|
||||
new: ``
|
||||
});
|
||||
editor.setCursor(newCursorPositionLine, 0);
|
||||
})
|
||||
.catch(err => {
|
||||
this.props.replaceText({
|
||||
original: pendingUploadTag,
|
||||
new: '',
|
||||
});
|
||||
editor.setCursor(newCursorPositionLine, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onPaddingTopClick = () => {
|
||||
const cm = this.getEditorInstance();
|
||||
cm.setCursor(0, 0);
|
||||
cm.focus();
|
||||
}
|
||||
|
||||
onPaddingBottomClick = () => {
|
||||
const cm = this.getEditorInstance();
|
||||
cm.setCursor(cm.lineCount(), 0);
|
||||
cm.focus();
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const options = {
|
||||
readOnly: false,
|
||||
lineNumbers: false,
|
||||
mode: 'gfm',
|
||||
matchBrackets: true,
|
||||
lineWrapping: true,
|
||||
viewportMargin: Infinity,
|
||||
scrollbarStyle: 'null',
|
||||
theme: 'atlas',
|
||||
extraKeys: {
|
||||
Enter: 'newlineAndIndentContinueMarkdownList',
|
||||
|
||||
"Ctrl-Enter": this.props.onSave,
|
||||
"Cmd-Enter": this.props.onSave,
|
||||
|
||||
"Cmd-Esc": this.props.onCancel,
|
||||
"Ctrl-Esc": this.props.onCancel,
|
||||
|
||||
// "Cmd-Shift-p": this.props.togglePreview,
|
||||
// "Ctrl-Shift-p": this.props.togglePreview,
|
||||
},
|
||||
placeholder: "# Start with a title...",
|
||||
};
|
||||
|
||||
return (
|
||||
<Dropzone
|
||||
onDropAccepted={this.onDropAccepted}
|
||||
disableClick={true}
|
||||
multiple={false}
|
||||
accept={'image/*'}
|
||||
className={styles.container}
|
||||
>
|
||||
<ClickablePadding onClick={ this.onPaddingTopClick } />
|
||||
<Codemirror
|
||||
value={this.props.text}
|
||||
onChange={this.onChange}
|
||||
options={options}
|
||||
ref="editor"
|
||||
className={styles.codeMirrorContainer}
|
||||
/>
|
||||
<ClickablePadding onClick={ this.onPaddingBottomClick } />
|
||||
</Dropzone>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MarkdownEditor;
|
Reference in New Issue
Block a user