diff --git a/src/components/Widgets/MarkdownControlElements/RawEditor/index.css b/src/components/Widgets/MarkdownControlElements/RawEditor/index.css index 6e91c9f0..f158b7f8 100644 --- a/src/components/Widgets/MarkdownControlElements/RawEditor/index.css +++ b/src/components/Widgets/MarkdownControlElements/RawEditor/index.css @@ -1,3 +1,22 @@ .root { position: relative; } + +.dragging { } + +.shim { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: none; + border: 2px dashed #aaa; + background: rgba(0,0,0,0.2); +} + +.dragging .shim { + z-index: 1000; + display: block; + pointer-events: none; +} diff --git a/src/components/Widgets/MarkdownControlElements/RawEditor/index.js b/src/components/Widgets/MarkdownControlElements/RawEditor/index.js index d921a4c1..ad9c2cf3 100644 --- a/src/components/Widgets/MarkdownControlElements/RawEditor/index.js +++ b/src/components/Widgets/MarkdownControlElements/RawEditor/index.js @@ -24,10 +24,6 @@ function processUrl(url) { return `/${ url }`; } -function preventDefault(e) { - e.preventDefault(); -} - function cleanupPaste(paste) { const content = html.toContent(paste); return markdown.toText(content); @@ -76,11 +72,9 @@ export default class RawEditor extends React.Component { }, }; } + componentDidMount() { this.updateHeight(); - this.element.addEventListener('dragenter', preventDefault, false); - this.element.addEventListener('dragover', preventDefault, false); - this.element.addEventListener('drop', this.handleDrop, false); this.element.addEventListener('paste', this.handlePaste, false); } @@ -93,9 +87,7 @@ export default class RawEditor extends React.Component { } componentWillUnmount() { - this.element.removeEventListener('dragenter', preventDefault); - this.element.removeEventListener('dragover', preventDefault); - this.element.removeEventListener('drop', this.handleDrop); + this.element.removeEventListener('paste', this.handlePaste); } getSelection() { @@ -256,8 +248,25 @@ export default class RawEditor extends React.Component { }; } + handleDragEnter = (e) => { + e.preventDefault(); + this.setState({ dragging: true }); + }; + + handleDragLeave = (e) => { + e.preventDefault(); + this.setState({ dragging: false }); + }; + + handleDragOver = (e) => { + e.preventDefault(); + }; + handleDrop = (e) => { e.preventDefault(); + + this.setState({ dragging: false }); + let data; if (e.dataTransfer.files && e.dataTransfer.files.length) { @@ -296,8 +305,19 @@ export default class RawEditor extends React.Component { render() { const { onAddMedia, onRemoveMedia, getMedia } = this.props; - const { showToolbar, showBlockMenu, plugins, selectionPosition } = this.state; - return (
+ const { showToolbar, showBlockMenu, plugins, selectionPosition, dragging } = this.state; + const classNames = [styles.root]; + if (dragging) { + classNames.push(styles.dragging); + } + + return (
+
); } } diff --git a/src/components/Widgets/MarkdownControlElements/VisualEditor/index.css b/src/components/Widgets/MarkdownControlElements/VisualEditor/index.css index 54764f89..9dc2e9b5 100644 --- a/src/components/Widgets/MarkdownControlElements/VisualEditor/index.css +++ b/src/components/Widgets/MarkdownControlElements/VisualEditor/index.css @@ -20,6 +20,13 @@ & p { margin-bottom: 20px; } + & hr { + border: 1px solid; + margin-bottom: 20px; + } + & li > p { + margin: 0; + } & div[data-plugin] { background: #fff; border: 1px solid #aaa; @@ -28,6 +35,25 @@ } } +.dragging { } + +.shim { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: none; + border: 2px dashed #aaa; + background: rgba(0,0,0,0.2); +} + +.dragging .shim { + z-index: 1000; + display: block; + pointer-events: none; +} + :global { & .ProseMirror { position: relative; diff --git a/src/components/Widgets/MarkdownControlElements/VisualEditor/index.js b/src/components/Widgets/MarkdownControlElements/VisualEditor/index.js index 17718916..216b30fc 100644 --- a/src/components/Widgets/MarkdownControlElements/VisualEditor/index.js +++ b/src/components/Widgets/MarkdownControlElements/VisualEditor/index.js @@ -11,6 +11,7 @@ import { keymap } from 'prosemirror-keymap'; import { schema, defaultMarkdownSerializer } from 'prosemirror-markdown'; import { baseKeymap, setBlockType, toggleMark } from 'prosemirror-commands'; import registry from '../../../../lib/registry'; +import MediaProxy from '../../../../valueObjects/MediaProxy'; import { buildKeymap } from './keymap'; import createMarkdownParser from './parser'; import Toolbar from '../Toolbar'; @@ -213,15 +214,71 @@ export default class Editor extends Component { this.view.props.onAction(this.view.state.tr.replaceSelectionWith(nodeType.create(data.toJS())).action()); }; + handleDragEnter = (e) => { + e.preventDefault(); + this.setState({ dragging: true }); + }; + + handleDragLeave = (e) => { + e.preventDefault(); + this.setState({ dragging: false }); + }; + + handleDragOver = (e) => { + e.preventDefault(); + }; + + handleDrop = (e) => { + e.preventDefault(); + + this.setState({ dragging: false }); + + const { schema } = this.state; + + const nodes = []; + + if (e.dataTransfer.files && e.dataTransfer.files.length) { + Array.from(e.dataTransfer.files).forEach((file) => { + const mediaProxy = new MediaProxy(file.name, file); + this.props.onAddMedia(mediaProxy); + if (file.type.split('/')[0] === 'image') { + nodes.push( + schema.nodes.image.create({ src: mediaProxy.public_path, alt: file.name }) + ); + } else { + nodes.push( + schema.marks.link.create({ href: mediaProxy.public_path, title: file.name }) + ); + } + }); + } else { + nodes.push(schema.nodes.paragraph.create({}, e.dataTransfer.getData('text/plain'))); + } + + nodes.forEach((node) => { + this.view.props.onAction(this.view.state.tr.replaceSelectionWith(node).action()); + }); + }; + handleToggle = () => { this.props.onMode('raw'); }; render() { const { onAddMedia, onRemoveMedia, getMedia } = this.props; - const { plugins, showToolbar, showBlockMenu, selectionPosition } = this.state; + const { plugins, showToolbar, showBlockMenu, selectionPosition, dragging } = this.state; + const classNames = [styles.editor]; + if (dragging) { + classNames.push(styles.dragging); + } - return (
+ return (
+
); } } diff --git a/src/components/Widgets/MarkdownControlElements/VisualEditor/serializer.js b/src/components/Widgets/MarkdownControlElements/VisualEditor/serializer.js deleted file mode 100644 index e69de29b..00000000