diff --git a/frontend/components/Editor/Editor.js b/frontend/components/Editor/Editor.js index 51051ce2..26f2d167 100644 --- a/frontend/components/Editor/Editor.js +++ b/frontend/components/Editor/Editor.js @@ -6,6 +6,8 @@ import { Editor, Plain } from 'slate'; import keydown from 'react-keydown'; import classnames from 'classnames/bind'; import type { Document, State, Editor as EditorType } from './types'; +import getDataTransferFiles from 'utils/getDataTransferFiles'; +import uploadFile from 'utils/uploadFile'; import Flex from 'components/Flex'; import ClickablePadding from './components/ClickablePadding'; import Toolbar from './components/Toolbar'; @@ -78,6 +80,39 @@ type Props = { this.props.onChange(Markdown.serialize(state)); }; + handleDrop = async (ev: SyntheticEvent) => { + // check if this event was already handled by the Editor + if (ev.isDefaultPrevented()) return; + + // otherwise we'll handle this + ev.preventDefault(); + ev.stopPropagation(); + + const files = getDataTransferFiles(ev); + for (const file of files) { + await this.insertFile(file); + } + }; + + insertFile = async (file: Object) => { + this.props.onImageUploadStart(); + const asset = await uploadFile(file); + const state = this.editor.getState(); + const transform = state.transform(); + transform.collapseToEndOf(state.document); + transform.insertBlock({ + type: 'image', + isVoid: true, + data: { src: asset.url, alt: file.name }, + }); + this.props.onImageUploadStop(); + this.setState({ state: transform.apply() }); + }; + + cancelEvent = (ev: SyntheticEvent) => { + ev.preventDefault(); + }; + @keydown('meta+s') onSaveAndContinue(ev: SyntheticKeyboardEvent) { ev.preventDefault(); @@ -115,7 +150,14 @@ type Props = { render = () => { return ( - + {!this.props.readOnly && } - + ); }; } @@ -147,10 +189,6 @@ MarkdownEditor.childContextTypes = { starred: PropTypes.bool, }; -const Container = styled(Flex)` - height: 100%; -`; - const HeaderContainer = styled(Flex).attrs({ align: 'flex-end', })` diff --git a/frontend/components/Editor/Editor.scss b/frontend/components/Editor/Editor.scss index 9cb57c6d..d9dd7269 100644 --- a/frontend/components/Editor/Editor.scss +++ b/frontend/components/Editor/Editor.scss @@ -1,6 +1,10 @@ .editor { + font-weight: 400; + font-size: 1em; + line-height: 1.5em; + padding: 0 3em; + width: 50em; color: #1b2631; - width: 100%; h1, h2, diff --git a/frontend/scenes/Document/Document.js b/frontend/scenes/Document/Document.js index 9b11fc14..c6eab2c0 100644 --- a/frontend/scenes/Document/Document.js +++ b/frontend/scenes/Document/Document.js @@ -197,22 +197,20 @@ type Props = { when={this.document.hasPendingChanges} message={DISCARD_CHANGES} /> - - - + @@ -270,11 +268,7 @@ const LoadingState = styled(PreviewLoading)` `; const DocumentContainer = styled.div` - font-weight: 400; - font-size: 1em; - line-height: 1.5em; - padding: 0 3em; - width: 50em; + `; const StyledDropToImport = styled(DropToImport)` diff --git a/frontend/utils/getDataTransferFiles.js b/frontend/utils/getDataTransferFiles.js new file mode 100644 index 00000000..5811090b --- /dev/null +++ b/frontend/utils/getDataTransferFiles.js @@ -0,0 +1,18 @@ +// @flow +export default function getDataTransferFiles(event: SyntheticEvent) { + let dataTransferItemsList = []; + if (event.dataTransfer) { + const dt = event.dataTransfer; + if (dt.files && dt.files.length) { + dataTransferItemsList = dt.files; + } else if (dt.items && dt.items.length) { + // During the drag even the dataTransfer.files is null + // but Chrome implements some drag store, which is accesible via dataTransfer.items + dataTransferItemsList = dt.items; + } + } else if (event.target && event.target.files) { + dataTransferItemsList = event.target.files; + } + // Convert from DataTransferItemsList to the native Array + return Array.prototype.slice.call(dataTransferItemsList); +}