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:
committed by
Ian Storm Taylor
parent
8d0899fee9
commit
6269fcaa71
@@ -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()
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user