diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js index e43763bb62b8a..45203382d3952 100644 --- a/editor/components/block-list/block.js +++ b/editor/components/block-list/block.js @@ -57,8 +57,8 @@ import { isMultiSelecting, getBlockIndex, getEditedPostAttribute, - getNextBlock, - getPreviousBlock, + getNextBlockUid, + getPreviousBlockUid, isBlockHovered, isBlockMultiSelected, isBlockSelected, @@ -290,20 +290,20 @@ export class BlockListBlock extends Component { } mergeBlocks( forward = false ) { - const { block, previousBlock, nextBlock, onMerge } = this.props; + const { block, previousBlockUid, nextBlockUid, onMerge } = this.props; // Do nothing when it's the first block. if ( - ( ! forward && ! previousBlock ) || - ( forward && ! nextBlock ) + ( ! forward && ! previousBlockUid ) || + ( forward && ! nextBlockUid ) ) { return; } if ( forward ) { - onMerge( block, nextBlock ); + onMerge( block.uid, nextBlockUid ); } else { - onMerge( previousBlock, block ); + onMerge( previousBlockUid, block.uid ); } // Manually trigger typing mode, since merging will remove this block and @@ -612,8 +612,8 @@ export class BlockListBlock extends Component { const mapStateToProps = ( state, { uid, rootUID } ) => { const isSelected = isBlockSelected( state, uid ); return { - previousBlock: getPreviousBlock( state, uid ), - nextBlock: getNextBlock( state, uid ), + previousBlockUid: getPreviousBlockUid( state, uid ), + nextBlockUid: getNextBlockUid( state, uid ), block: getBlock( state, uid ), isMultiSelected: isBlockMultiSelected( state, uid ), isFirstMultiSelected: isFirstMultiSelectedBlock( state, uid ), diff --git a/editor/components/writing-flow/index.js b/editor/components/writing-flow/index.js index 524c4585b39a3..925457ff91dcd 100644 --- a/editor/components/writing-flow/index.js +++ b/editor/components/writing-flow/index.js @@ -24,8 +24,8 @@ import { placeCaretAtVerticalEdge, } from '../../utils/dom'; import { - getPreviousBlock, - getNextBlock, + getPreviousBlockUid, + getNextBlockUid, getMultiSelectedBlocksStartUid, getMultiSelectedBlocks, getSelectedBlock, @@ -155,20 +155,20 @@ class WritingFlow extends Component { } expandSelection( currentStartUid, isReverse ) { - const { previousBlock, nextBlock } = this.props; + const { previousBlockUid, nextBlockUid } = this.props; - const expandedBlock = isReverse ? previousBlock : nextBlock; - if ( expandedBlock ) { - this.props.onMultiSelect( currentStartUid, expandedBlock.uid ); + const expandedBlockUid = isReverse ? previousBlockUid : nextBlockUid; + if ( expandedBlockUid ) { + this.props.onMultiSelect( currentStartUid, expandedBlockUid ); } } moveSelection( isReverse ) { - const { previousBlock, nextBlock } = this.props; + const { previousBlockUid, nextBlockUid } = this.props; - const focusedBlock = isReverse ? previousBlock : nextBlock; - if ( focusedBlock ) { - this.props.onSelectBlock( focusedBlock.uid ); + const focusedBlockUid = isReverse ? previousBlockUid : nextBlockUid; + if ( focusedBlockUid ) { + this.props.onSelectBlock( focusedBlockUid ); } } @@ -299,8 +299,8 @@ class WritingFlow extends Component { export default connect( ( state ) => ( { - previousBlock: getPreviousBlock( state ), - nextBlock: getNextBlock( state ), + previousBlockUid: getPreviousBlockUid( state ), + nextBlockUid: getNextBlockUid( state ), selectionStart: getMultiSelectedBlocksStartUid( state ), hasMultiSelection: getMultiSelectedBlocks( state ).length > 1, selectedBlock: getSelectedBlock( state ), diff --git a/editor/store/actions.js b/editor/store/actions.js index 806ed66f17ffe..4edd407317179 100644 --- a/editor/store/actions.js +++ b/editor/store/actions.js @@ -257,10 +257,18 @@ export function trashPost( postId, postType ) { }; } -export function mergeBlocks( blockA, blockB ) { +/** + * Returns an action object used in signalling that two blocks should be merged + * + * @param {string} blockAUid UID of the first block to merge. + * @param {string} blockBUid UID of the second block to merge. + * + * @return {Object} Action object. + */ +export function mergeBlocks( blockAUid, blockBUid ) { return { type: 'MERGE_BLOCKS', - blocks: [ blockA, blockB ], + blocks: [ blockAUid, blockBUid ], }; } diff --git a/editor/store/effects.js b/editor/store/effects.js index ef21cce9b920b..8807f588bef18 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -218,7 +218,10 @@ export default { }, MERGE_BLOCKS( action, store ) { const { dispatch } = store; - const [ blockA, blockB ] = action.blocks; + const state = store.getState(); + const [ blockAUid, blockBUid ] = action.blocks; + const blockA = getBlock( state, blockAUid ); + const blockB = getBlock( state, blockBUid ); const blockType = getBlockType( blockA.name ); // Only focus the previous block if it's not mergeable diff --git a/editor/store/selectors.js b/editor/store/selectors.js index c09879ad37cde..36cf126ec4daf 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -538,7 +538,7 @@ export function getBlockRootUID( state, uid ) { } /** - * Returns the block adjacent one at the given reference startUID and modifier + * Returns the UID of the block adjacent one at the given reference startUID and modifier * directionality. Defaults start UID to the selected block, and direction as * next block. Returns null if there is no adjacent block. * @@ -546,9 +546,9 @@ export function getBlockRootUID( state, uid ) { * @param {?string} startUID Optional UID of block from which to search. * @param {?number} modifier Directionality multiplier (1 next, -1 previous). * - * @return {?Object} Adjacent block object, or null if none exists. + * @return {?string} Return the UID of the block, or null if none exists. */ -export function getAdjacentBlock( state, startUID, modifier = 1 ) { +export function getAdjacentBlockUid( state, startUID, modifier = 1 ) { // Default to selected block. if ( startUID === undefined ) { startUID = get( getSelectedBlock( state ), 'uid' ); @@ -591,33 +591,33 @@ export function getAdjacentBlock( state, startUID, modifier = 1 ) { } // Assume incremented index is within the set. - return getBlock( state, orderSet[ nextIndex ] ); + return orderSet[ nextIndex ]; } /** - * Returns the previous block from the given reference startUID. Defaults start + * Returns the previous block's UID from the given reference startUID. Defaults start * UID to the selected block. Returns null if there is no previous block. * * @param {Object} state Global application state. * @param {?string} startUID Optional UID of block from which to search. * - * @return {?Object} Adjacent block object, or null if none exists. + * @return {?string} Adjacent block's UID, or null if none exists. */ -export function getPreviousBlock( state, startUID ) { - return getAdjacentBlock( state, startUID, -1 ); +export function getPreviousBlockUid( state, startUID ) { + return getAdjacentBlockUid( state, startUID, -1 ); } /** - * Returns the next block from the given reference startUID. Defaults start UID + * Returns the next block's UID from the given reference startUID. Defaults start UID * to the selected block. Returns null if there is no next block. * * @param {Object} state Global application state. * @param {?string} startUID Optional UID of block from which to search. * - * @return {?Object} Adjacent block object, or null if none exists. + * @return {?string} Adjacent block's UID, or null if none exists. */ -export function getNextBlock( state, startUID ) { - return getAdjacentBlock( state, startUID, 1 ); +export function getNextBlockUid( state, startUID ) { + return getAdjacentBlockUid( state, startUID, 1 ); } /** diff --git a/editor/store/test/actions.js b/editor/store/test/actions.js index f23d23dd8f630..c418d1ccd18fb 100644 --- a/editor/store/test/actions.js +++ b/editor/store/test/actions.js @@ -272,15 +272,11 @@ describe( 'actions', () => { describe( 'mergeBlocks', () => { it( 'should return MERGE_BLOCKS action', () => { - const blockA = { - uid: 'blockA', - }; - const blockB = { - uid: 'blockB', - }; - expect( mergeBlocks( blockA, blockB ) ).toEqual( { + const blockAUid = 'blockA'; + const blockBUid = 'blockB'; + expect( mergeBlocks( blockAUid, blockBUid ) ).toEqual( { type: 'MERGE_BLOCKS', - blocks: [ blockA, blockB ], + blocks: [ blockAUid, blockBUid ], } ); } ); } ); diff --git a/editor/store/test/effects.js b/editor/store/test/effects.js index 2a2538812e8d5..98267d1fc9241 100644 --- a/editor/store/test/effects.js +++ b/editor/store/test/effects.js @@ -48,11 +48,13 @@ describe( 'effects', () => { describe( '.MERGE_BLOCKS', () => { const handler = effects.MERGE_BLOCKS; + const defaultGetBlock = selectors.getBlock; afterEach( () => { getBlockTypes().forEach( ( block ) => { unregisterBlockType( block.name ); } ); + selectors.getBlock = defaultGetBlock; } ); it( 'should only focus the blockA if the blockA has no merge function', () => { @@ -65,8 +67,13 @@ describe( 'effects', () => { uid: 'ribs', name: 'core/test-block', }; + selectors.getBlock = ( state, uid ) => { + return blockA.uid === uid ? blockA : blockB; + }; + const dispatch = jest.fn(); - handler( mergeBlocks( blockA, blockB ), { dispatch } ); + const getState = () => ( {} ); + handler( mergeBlocks( blockA.uid, blockB.uid ), { dispatch, getState } ); expect( dispatch ).toHaveBeenCalledTimes( 1 ); expect( dispatch ).toHaveBeenCalledWith( selectBlock( 'chicken' ) ); @@ -93,8 +100,12 @@ describe( 'effects', () => { name: 'core/test-block', attributes: { content: 'ribs' }, }; + selectors.getBlock = ( state, uid ) => { + return blockA.uid === uid ? blockA : blockB; + }; const dispatch = jest.fn(); - handler( mergeBlocks( blockA, blockB ), { dispatch } ); + const getState = () => ( {} ); + handler( mergeBlocks( blockA.uid, blockB.uid ), { dispatch, getState } ); expect( dispatch ).toHaveBeenCalledTimes( 2 ); expect( dispatch ).toHaveBeenCalledWith( selectBlock( 'chicken', -1 ) ); @@ -127,8 +138,12 @@ describe( 'effects', () => { name: 'core/test-block2', attributes: { content: 'ribs' }, }; + selectors.getBlock = ( state, uid ) => { + return blockA.uid === uid ? blockA : blockB; + }; const dispatch = jest.fn(); - handler( mergeBlocks( blockA, blockB ), { dispatch } ); + const getState = () => ( {} ); + handler( mergeBlocks( blockA.uid, blockB.uid ), { dispatch, getState } ); expect( dispatch ).not.toHaveBeenCalled(); } ); @@ -180,8 +195,12 @@ describe( 'effects', () => { name: 'core/test-block-2', attributes: { content2: 'ribs' }, }; + selectors.getBlock = ( state, uid ) => { + return blockA.uid === uid ? blockA : blockB; + }; const dispatch = jest.fn(); - handler( mergeBlocks( blockA, blockB ), { dispatch } ); + const getState = () => ( {} ); + handler( mergeBlocks( blockA.uid, blockB.uid ), { dispatch, getState } ); expect( dispatch ).toHaveBeenCalledTimes( 2 ); // expect( dispatch ).toHaveBeenCalledWith( focusBlock( 'chicken', { offset: -1 } ) ); diff --git a/editor/store/test/selectors.js b/editor/store/test/selectors.js index c818c498ac26c..d542aed6df969 100644 --- a/editor/store/test/selectors.js +++ b/editor/store/test/selectors.js @@ -47,8 +47,8 @@ const { getMultiSelectedBlocksEndUid, getBlockOrder, getBlockIndex, - getPreviousBlock, - getNextBlock, + getPreviousBlockUid, + getNextBlockUid, isBlockSelected, isBlockWithinSelection, isBlockMultiSelected, @@ -1372,15 +1372,11 @@ describe( 'selectors', () => { } ); } ); - describe( 'getPreviousBlock', () => { + describe( 'getPreviousBlockUid', () => { it( 'should return the previous block', () => { const state = { editor: { present: { - blocksByUid: { - 23: { uid: 23, name: 'core/heading', attributes: {} }, - 123: { uid: 123, name: 'core/paragraph', attributes: {} }, - }, blockOrder: { '': [ 123, 23 ], }, @@ -1388,24 +1384,13 @@ describe( 'selectors', () => { }, }; - expect( getPreviousBlock( state, 23 ) ).toEqual( { - uid: 123, - name: 'core/paragraph', - attributes: {}, - innerBlocks: [], - } ); + expect( getPreviousBlockUid( state, 23 ) ).toEqual( 123 ); } ); it( 'should return the previous block (nested context)', () => { const state = { editor: { present: { - blocksByUid: { - 23: { uid: 23, name: 'core/heading', attributes: {} }, - 123: { uid: 123, name: 'core/paragraph', attributes: {} }, - 56: { uid: 56, name: 'core/heading', attributes: {} }, - 456: { uid: 456, name: 'core/paragraph', attributes: {} }, - }, blockOrder: { '': [ 123, 23 ], 123: [ 456, 56 ], @@ -1414,22 +1399,13 @@ describe( 'selectors', () => { }, }; - expect( getPreviousBlock( state, 56, '123' ) ).toEqual( { - uid: 456, - name: 'core/paragraph', - attributes: {}, - innerBlocks: [], - } ); + expect( getPreviousBlockUid( state, 56, '123' ) ).toEqual( 456 ); } ); it( 'should return null for the first block', () => { const state = { editor: { present: { - blocksByUid: { - 23: { uid: 23, name: 'core/heading', attributes: {} }, - 123: { uid: 123, name: 'core/paragraph', attributes: {} }, - }, blockOrder: { '': [ 123, 23 ], }, @@ -1437,19 +1413,13 @@ describe( 'selectors', () => { }, }; - expect( getPreviousBlock( state, 123 ) ).toBeNull(); + expect( getPreviousBlockUid( state, 123 ) ).toBeNull(); } ); it( 'should return null for the first block (nested context)', () => { const state = { editor: { present: { - blocksByUid: { - 23: { uid: 23, name: 'core/heading', attributes: {} }, - 123: { uid: 123, name: 'core/paragraph', attributes: {} }, - 56: { uid: 56, name: 'core/heading', attributes: {} }, - 456: { uid: 456, name: 'core/paragraph', attributes: {} }, - }, blockOrder: { '': [ 123, 23 ], 123: [ 456, 56 ], @@ -1458,19 +1428,15 @@ describe( 'selectors', () => { }, }; - expect( getPreviousBlock( state, 456, '123' ) ).toBeNull(); + expect( getPreviousBlockUid( state, 456, '123' ) ).toBeNull(); } ); } ); - describe( 'getNextBlock', () => { + describe( 'getNextBlockUid', () => { it( 'should return the following block', () => { const state = { editor: { present: { - blocksByUid: { - 23: { uid: 23, name: 'core/heading', attributes: {} }, - 123: { uid: 123, name: 'core/paragraph', attributes: {} }, - }, blockOrder: { '': [ 123, 23 ], }, @@ -1478,24 +1444,13 @@ describe( 'selectors', () => { }, }; - expect( getNextBlock( state, 123 ) ).toEqual( { - uid: 23, - name: 'core/heading', - attributes: {}, - innerBlocks: [], - } ); + expect( getNextBlockUid( state, 123 ) ).toEqual( 23 ); } ); it( 'should return the following block (nested context)', () => { const state = { editor: { present: { - blocksByUid: { - 23: { uid: 23, name: 'core/heading', attributes: {} }, - 123: { uid: 123, name: 'core/paragraph', attributes: {} }, - 56: { uid: 56, name: 'core/heading', attributes: {} }, - 456: { uid: 456, name: 'core/paragraph', attributes: {} }, - }, blockOrder: { '': [ 123, 23 ], 123: [ 456, 56 ], @@ -1504,22 +1459,13 @@ describe( 'selectors', () => { }, }; - expect( getNextBlock( state, 456, '123' ) ).toEqual( { - uid: 56, - name: 'core/heading', - attributes: {}, - innerBlocks: [], - } ); + expect( getNextBlockUid( state, 456, '123' ) ).toEqual( 56 ); } ); it( 'should return null for the last block', () => { const state = { editor: { present: { - blocksByUid: { - 23: { uid: 23, name: 'core/heading', attributes: {} }, - 123: { uid: 123, name: 'core/paragraph', attributes: {} }, - }, blockOrder: { '': [ 123, 23 ], }, @@ -1527,19 +1473,13 @@ describe( 'selectors', () => { }, }; - expect( getNextBlock( state, 23 ) ).toBeNull(); + expect( getNextBlockUid( state, 23 ) ).toBeNull(); } ); it( 'should return null for the last block (nested context)', () => { const state = { editor: { present: { - blocksByUid: { - 23: { uid: 23, name: 'core/heading', attributes: {} }, - 123: { uid: 123, name: 'core/paragraph', attributes: {} }, - 56: { uid: 56, name: 'core/heading', attributes: {} }, - 456: { uid: 456, name: 'core/paragraph', attributes: {} }, - }, blockOrder: { '': [ 123, 23 ], 123: [ 456, 56 ], @@ -1548,7 +1488,7 @@ describe( 'selectors', () => { }, }; - expect( getNextBlock( state, 56, '123' ) ).toBeNull(); + expect( getNextBlockUid( state, 56, '123' ) ).toBeNull(); } ); } );