1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-21 14:41:23 +02:00

Drop dragged nodes into the correct place (#3001)

When drag-and-dropping nodes within the same editor, the removal of
the dragged nodes can cause paths and offsets to change. This is
really hard to compensate for.

Instead of compensating for it, rearranging the order things happen
mean we are always working with a document in a reasonable state.

Now, we:

1. Fire a MouseUp event on `event.target` (because we haven't done
   anything, it's guaranteed to exist)
2. Save the range we're dragging (for later)
3. Select the target range (because we haven't deleted anything, this
   is still valid)
4. Delete the range we're dragging (this will automatically adjust the
   editor's selection)
5. Insert the dragged fragment at the current range

No matter where we're dragging from or to, these should all be
pointing at places that both exist, and haven't changed.
This commit is contained in:
Justin Weiss
2019-09-08 10:06:20 -07:00
committed by Ian Storm Taylor
parent 8d0899fee9
commit 6269fcaa71

View File

@@ -299,7 +299,7 @@ function AfterPlugin(options = {}) {
const { value } = editor
const { document, selection } = value
const window = getWindow(event.target)
let target = editor.findEventRange(event)
const target = editor.findEventRange(event)
if (!target) {
return next()
@@ -312,26 +312,30 @@ function AfterPlugin(options = {}) {
editor.focus()
// If the drag is internal and the target is after the selection, it
// needs to account for the selection's content being deleted.
if (
isDraggingInternally &&
selection.end.offset < target.end.offset &&
selection.end.path.equals(target.end.path)
) {
target = target.moveForward(
selection.start.path.equals(selection.end.path)
? 0 - selection.end.offset + selection.start.offset
: 0 - selection.end.offset
// COMPAT: React's onSelect event breaks after an onDrop event
// has fired in a node: https://github.com/facebook/react/issues/11379.
// Until this is fixed in React, we dispatch a mouseup event on that
// DOM node, since that will make it go back to normal.
const el = editor.findDOMNode(target.focus.path)
if (el) {
el.dispatchEvent(
new MouseEvent('mouseup', {
view: window,
bubbles: true,
cancelable: true,
})
)
}
if (isDraggingInternally) {
editor.delete()
}
const draggedRange = selection
editor.select(target)
if (isDraggingInternally) {
editor.deleteAtRange(draggedRange)
}
if (type === 'text' || type === 'html') {
const { anchor } = target
let hasVoidParent = document.hasVoidParent(anchor.path, editor)
@@ -366,22 +370,6 @@ function AfterPlugin(options = {}) {
editor.insertFragment(fragment)
}
// COMPAT: React's onSelect event breaks after an onDrop event
// has fired in a node: https://github.com/facebook/react/issues/11379.
// Until this is fixed in React, we dispatch a mouseup event on that
// DOM node, since that will make it go back to normal.
const el = editor.findDOMNode(target.focus.path)
if (el) {
el.dispatchEvent(
new MouseEvent('mouseup', {
view: window,
bubbles: true,
cancelable: true,
})
)
}
next()
}