Skip to content

Commit

Permalink
Added ensure default block logic to replaceBlocks action; refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed Mar 4, 2019
1 parent 0b1fd6b commit 73cb181
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ with one or more replacement blocks.

### moveBlockToPosition

Returns an action object signalling that an indexed block should be moved
Yields an action object signalling that an indexed block should be moved
to a new index.

*Parameters*
Expand Down
138 changes: 81 additions & 57 deletions packages/block-editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,24 @@ import { getDefaultBlockName, createBlock } from '@wordpress/blocks';
*/
import { select } from './controls';

const buildSelectors = ( store ) => ( ...selectors ) => {
const buildSelector = ( selector ) => {
return ( ...args ) => (
select(
store,
selector,
...args,
)
);
};
if ( selectors.length > 1 ) {
return selectors.map( buildSelector );
}
if ( selectors.length === 1 ) {
return buildSelector( selectors[ 0 ] );
}
};
/**
* Generator which will yield a default block insertion action if there
* are no other blocks at the root of the editor. This is expected to be used
* in actions which may result in no blocks remaining in the editor (removal,
* replacement, etc).
*/
function* ensureDefaultBlock() {
const count = yield select(
'core/block-editor',
'getBlockCount',
);

const buildCoreEditorSelectors = buildSelectors( 'core/editor' );
// To avoid a focus loss when removing the last block, assure there is
// always a default block if the last of the blocks have been removed.
if ( count === 0 ) {
yield insertDefaultBlock();
}
}

/**
* Returns an action object used in signalling that blocks state should be
Expand Down Expand Up @@ -224,35 +223,45 @@ export function toggleSelection( isSelectionEnabled = true ) {
* @param {?boolean} ignoreAllowedBlocksValidation If true the blocks will replaced even if the replacement was not allowed e.g: because of allowed blocks restrictions.
*/
export function* replaceBlocks( clientIds, blocks, ignoreAllowedBlocksValidation = false ) {
clientIds = castArray( clientIds );
blocks = castArray( blocks );
const createAction = () => ( {
type: 'REPLACE_BLOCKS',
clientIds: castArray( clientIds ),
blocks: castArray( blocks ),
clientIds,
blocks,
time: Date.now(),
} );
if ( ignoreAllowedBlocksValidation ) {
yield createAction();
yield* ensureDefaultBlock();
return;
}
const [
canInsertBlockType,
getBlockName,
getBlockRootClientId,
] = buildCoreEditorSelectors( 'canInsertBlockType', 'getBlockName', 'getBlockRootClientId' );
const rootClientId = getBlockRootClientId( first( clientIds ) );
const rootClientId = yield select(
'core/block-editor',
'getBlockRootClientId',
first( clientIds )
);
// Replace is valid if the new blocks can be inserted in the root block
// or if we had a block of the same type in the position of the block being replaced.
for ( let index = 0; index < blocks.length; index++ ) {
const block = blocks[ index ];
if ( ! ( yield canInsertBlockType( block.name, rootClientId ) ) ) {
const canInsertBlock = yield select(
'core/block-editor',
'canInsertBlockType',
block.name,
rootClientId
);
if ( ! canInsertBlock ) {
const clientIdToReplace = clientIds[ index ];
const nameOfBlockToReplace = clientIdToReplace && ( yield getBlockName( clientIdToReplace ) );
const nameOfBlockToReplace = clientIdToReplace &&
( yield select( 'core/block-editor', 'getBlockName', 'clientIdToReplace' ) );
if ( ! nameOfBlockToReplace || nameOfBlockToReplace !== block.name ) {
return;
}
}
}
yield createAction();
yield* ensureDefaultBlock();
}

/**
Expand Down Expand Up @@ -291,7 +300,7 @@ export const moveBlocksDown = createOnMove( 'MOVE_BLOCKS_DOWN' );
export const moveBlocksUp = createOnMove( 'MOVE_BLOCKS_UP' );

/**
* Returns an action object signalling that an indexed block should be moved
* Yields an action object signalling that an indexed block should be moved
* to a new index.
*
* @param {?string} clientId The client ID of the block.
Expand All @@ -300,7 +309,6 @@ export const moveBlocksUp = createOnMove( 'MOVE_BLOCKS_UP' );
* @param {number} index The index to move the block into.
* @param {?boolean} ignoreAllowedBlocksValidation If true the block will be moved even if the move was not allowed e.g: because of allowed blocks restrictions.
*
* @return {Object} Action object.
*/
export function* moveBlockToPosition( clientId, fromRootClientId, toRootClientId, index, ignoreAllowedBlocksValidation = false ) {
const createAction = () => ( {
Expand All @@ -311,23 +319,41 @@ export function* moveBlockToPosition( clientId, fromRootClientId, toRootClientId
index,
} );
if ( ignoreAllowedBlocksValidation ) {
return createAction();
yield createAction();
return;
}
const [
canInsertBlockType,
getBlockName,
getTemplateLock,
] = buildCoreEditorSelectors( 'canInsertBlockType', 'getBlockName', 'getTemplateLock' );

const blockName = yield getBlockName( clientId );

// If locking is equal to all on the original clientId (fromRootClientId) it is not possible to move the block to any other position.
// In the other cases (locking !== all ), if moving inside the same block the move is always possible
// if moving to other parent block, the move is possible if we can insert a block of the same type inside the new parent block.
if (
( yield getTemplateLock( fromRootClientId ) ) !== 'all' &&
( fromRootClientId === toRootClientId || ( yield canInsertBlockType( blockName, toRootClientId ) ) )
) {

const templateLock = yield select(
'core/block-editor',
'getTemplateLock',
fromRootClientId
);

// If locking is equal to all on the original clientId (fromRootClientId),
// it is not possible to move the block to any other position.
if ( templateLock === 'all' ) {
return;
}
// If moving inside the same root block the move is always possible.
if ( fromRootClientId === toRootClientId ) {
yield createAction();
}

const blockName = yield select(
'core/block-editor',
'getBlockName',
clientId
);

const canInsertBlock = yield select(
'core/block-editor',
'canInsertBlockType',
blockName,
toRootClientId
);

// If moving to other parent block, the move is possible if we can insert a block of the same type inside the new parent block.
if ( canInsertBlock ) {
yield createAction();
}
}
Expand Down Expand Up @@ -377,15 +403,20 @@ export function* insertBlocks(
updateSelection = true,
ignoreAllowedBlocksValidation = false
) {
blocks = castArray( blocks );
let allowedBlocks;
if ( ignoreAllowedBlocksValidation ) {
allowedBlocks = blocks;
} else {
allowedBlocks = [];
const canInsertBlockType = buildCoreEditorSelectors( 'canInsertBlockType' );
for ( const block of castArray( blocks ) ) {
for ( const block of blocks ) {
if ( block ) {
const isValid = yield canInsertBlockType( block.name, rootClientId );
const isValid = yield select(
'core/block-editor',
'canInsertBlockType',
block.name,
rootClientId
);
if ( isValid ) {
allowedBlocks.push( block );
}
Expand Down Expand Up @@ -493,16 +524,9 @@ export function* removeBlocks( clientIds, selectPrevious = true ) {
clientIds,
};

const count = yield select(
'core/block-editor',
'getBlockCount',
);

// To avoid a focus loss when removing the last block, assure there is
// always a default block if the last of the blocks have been removed.
if ( count === 0 ) {
yield insertDefaultBlock();
}
yield* ensureDefaultBlock();
}

/**
Expand Down
22 changes: 0 additions & 22 deletions packages/block-editor/src/store/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ import {
replaceBlocks,
selectBlock,
setTemplateValidity,
insertDefaultBlock,
resetBlocks,
} from './actions';
import {
getBlock,
getBlocks,
getSelectedBlockCount,
getBlockCount,
getTemplateLock,
getTemplate,
isValidTemplate,
Expand Down Expand Up @@ -60,23 +58,6 @@ export function validateBlocksToTemplate( action, store ) {
}
}

/**
* Effect handler which will return a default block insertion action if there
* are no other blocks at the root of the editor. This is expected to be used
* in actions which may result in no blocks remaining in the editor (removal,
* replacement, etc).
*
* @param {Object} action Action which had initiated the effect handler.
* @param {Object} store Store instance.
*
* @return {?Object} Default block insert action, if no other blocks exist.
*/
export function ensureDefaultBlock( action, store ) {
if ( ! getBlockCount( store.getState() ) ) {
return insertDefaultBlock();
}
}

export default {
MERGE_BLOCKS( action, store ) {
const { dispatch } = store;
Expand Down Expand Up @@ -127,9 +108,6 @@ export default {
RESET_BLOCKS: [
validateBlocksToTemplate,
],
REPLACE_BLOCKS: [
ensureDefaultBlock,
],
MULTI_SELECT: ( action, { getState } ) => {
const blockCount = getSelectedBlockCount( getState() );

Expand Down
40 changes: 26 additions & 14 deletions packages/block-editor/src/store/test/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,36 +116,48 @@ describe( 'actions', () => {
} );

describe( 'replaceBlock', () => {
it( 'should return the REPLACE_BLOCKS action', () => {
it( 'should yield the REPLACE_BLOCKS action', () => {
const block = {
clientId: 'ribs',
};

expect(
Array.from( replaceBlock( [ 'chicken' ], block, true ) )
).toEqual( [ {
type: 'REPLACE_BLOCKS',
clientIds: [ 'chicken' ],
blocks: [ block ],
time: expect.any( Number ),
} ] );
).toEqual( [
{
type: 'REPLACE_BLOCKS',
clientIds: [ 'chicken' ],
blocks: [ block ],
time: expect.any( Number ),
},
select(
'core/block-editor',
'getBlockCount'
),
] );
} );
} );

describe( 'replaceBlocks', () => {
it( 'should return the REPLACE_BLOCKS action', () => {
it( 'should yield the REPLACE_BLOCKS action', () => {
const blocks = [ {
clientId: 'ribs',
} ];

expect(
Array.from( replaceBlocks( [ 'chicken' ], blocks, true ) )
).toEqual( [ {
type: 'REPLACE_BLOCKS',
clientIds: [ 'chicken' ],
blocks,
time: expect.any( Number ),
} ] );
).toEqual( [
{
type: 'REPLACE_BLOCKS',
clientIds: [ 'chicken' ],
blocks,
time: expect.any( Number ),
},
select(
'core/block-editor',
'getBlockCount'
),
] );
} );
} );

Expand Down

0 comments on commit 73cb181

Please sign in to comment.