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 = `![${file.name}](Uploading...)`; 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: `![${file.name}](${data.asset.url})` }); 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 ( ); } } export default MarkdownEditor;