160 lines
4.1 KiB
JavaScript
160 lines
4.1 KiB
JavaScript
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;
|