-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix calculation of new block index on drop #10201
Changes from all commits
cc965d0
d1c54ae
a9af190
e846a28
b7d69ba
b53d8c6
bc1501e
bebfdbd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,12 @@ | |
import { Draggable } from '@wordpress/components'; | ||
import { withSelect } from '@wordpress/data'; | ||
|
||
const BlockDraggable = ( { children, clientId, rootClientId, blockElementId, index, layout, onDragStart, onDragEnd } ) => { | ||
const BlockDraggable = ( { children, clientId, rootClientId, blockElementId, index, onDragStart, onDragEnd } ) => { | ||
const transferData = { | ||
type: 'block', | ||
fromIndex: index, | ||
rootClientId, | ||
clientId, | ||
layout, | ||
srcIndex: index, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improve nomenclature, as it was inconsistent ( |
||
srcRootClientId: rootClientId, | ||
srcClientId: clientId, | ||
}; | ||
|
||
return ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,27 @@ import { Component } from '@wordpress/element'; | |
import { withDispatch, withSelect } from '@wordpress/data'; | ||
import { compose } from '@wordpress/compose'; | ||
|
||
const parseDropEvent = ( event ) => { | ||
let result = { | ||
srcRootClientId: null, | ||
srcClientId: null, | ||
srcIndex: null, | ||
type: null, | ||
}; | ||
|
||
if ( ! event.dataTransfer ) { | ||
return result; | ||
} | ||
|
||
try { | ||
result = Object.assign( result, JSON.parse( event.dataTransfer.getData( 'text' ) ) ); | ||
} catch ( err ) { | ||
return result; | ||
} | ||
|
||
return result; | ||
}; | ||
|
||
class BlockDropZone extends Component { | ||
constructor() { | ||
super( ...arguments ); | ||
|
@@ -56,28 +77,29 @@ class BlockDropZone extends Component { | |
} | ||
|
||
onDrop( event, position ) { | ||
if ( ! event.dataTransfer ) { | ||
return; | ||
} | ||
|
||
let clientId, type, rootClientId, fromIndex; | ||
const { rootClientId: dstRootClientId, clientId: dstClientId, index: dstIndex, getDescendants } = this.props; | ||
const { srcRootClientId, srcClientId, srcIndex, type } = parseDropEvent( event ); | ||
|
||
const isBlockDropType = ( dropType ) => dropType === 'block'; | ||
const isSameLevel = ( srcRoot, dstRoot ) => { | ||
// Note that rootClientId of top-level blocks will be undefined OR a void string, | ||
// so we also need to account for that case separately. | ||
return ( srcRoot === dstRoot ) || ( ! srcRoot === true && ! dstRoot === true ); | ||
}; | ||
const isSameBlock = ( src, dst ) => src === dst; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: I feel extracting this to a separate function doesn't provide anything "useful" as it's just a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it seems straightforward code, but I like how having the function helps document the intent for the reader. |
||
const isSrcBlockAnAncestorOfDstBlock = ( src, dst ) => getDescendants( [ src ] ).some( ( id ) => id === dst ); | ||
|
||
try { | ||
( { clientId, type, rootClientId, fromIndex } = JSON.parse( event.dataTransfer.getData( 'text' ) ) ); | ||
} catch ( err ) { | ||
if ( ! isBlockDropType( type ) || | ||
isSameBlock( srcClientId, dstClientId ) || | ||
isSrcBlockAnAncestorOfDstBlock( srcClientId, dstClientId ) ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: Could it be useful to extract the behavior of this function to something like |
||
return; | ||
} | ||
|
||
if ( type !== 'block' ) { | ||
return; | ||
} | ||
const { index } = this.props; | ||
const positionIndex = this.getInsertIndex( position ); | ||
|
||
// If the block is kept at the same level and moved downwards, subtract | ||
// to account for blocks shifting upward to occupy its old position. | ||
const insertIndex = index && fromIndex < index && rootClientId === this.props.rootClientId ? positionIndex - 1 : positionIndex; | ||
this.props.moveBlockToPosition( clientId, rootClientId, insertIndex ); | ||
// If the block is kept at the same level and moved downwards, | ||
// subtract to account for blocks shifting upward to occupy its old position. | ||
const insertIndex = dstIndex && srcIndex < dstIndex && isSameLevel( srcRootClientId, dstRootClientId ) ? positionIndex - 1 : positionIndex; | ||
this.props.moveBlockToPosition( srcClientId, srcRootClientId, insertIndex ); | ||
} | ||
|
||
render() { | ||
|
@@ -109,7 +131,7 @@ export default compose( | |
} = dispatch( 'core/editor' ); | ||
|
||
return { | ||
insertBlocks( blocks, insertIndex ) { | ||
insertBlocks( blocks, index ) { | ||
const { rootClientId, layout } = ownProps; | ||
|
||
if ( layout ) { | ||
|
@@ -122,21 +144,22 @@ export default compose( | |
) ); | ||
} | ||
|
||
insertBlocks( blocks, insertIndex, rootClientId ); | ||
insertBlocks( blocks, index, rootClientId ); | ||
}, | ||
updateBlockAttributes( ...args ) { | ||
updateBlockAttributes( ...args ); | ||
}, | ||
moveBlockToPosition( clientId, fromRootClientId, index ) { | ||
const { rootClientId, layout } = ownProps; | ||
moveBlockToPosition( clientId, fromRootClientId, rootClientId, layout, index ); | ||
moveBlockToPosition( srcClientId, srcRootClientId, dstIndex ) { | ||
const { rootClientId: dstRootClientId, layout } = ownProps; | ||
moveBlockToPosition( srcClientId, srcRootClientId, dstRootClientId, layout, dstIndex ); | ||
}, | ||
}; | ||
} ), | ||
withSelect( ( select, { rootClientId } ) => { | ||
const { getTemplateLock } = select( 'core/editor' ); | ||
const { getDescendants, getTemplateLock } = select( 'core/editor' ); | ||
return { | ||
isLocked: !! getTemplateLock( rootClientId ), | ||
getDescendants, | ||
}; | ||
} ) | ||
)( BlockDropZone ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
layout
was unnecessary so I took advantage of this PR to clean that as well in c7af125