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 18, 2019
1 parent 7e5f1d8 commit e113599
Show file tree
Hide file tree
Showing 4 changed files with 416 additions and 91 deletions.
163 changes: 133 additions & 30 deletions packages/block-editor/src/store/actions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { castArray } from 'lodash';
import { castArray, first } from 'lodash';

/**
* WordPress dependencies
Expand All @@ -13,6 +13,25 @@ import { getDefaultBlockName, createBlock } from '@wordpress/blocks';
*/
import { select } from './controls';

/**
* 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',
);

// 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
* reset to the specified array of blocks, taking precedence over any other
Expand Down Expand Up @@ -201,16 +220,41 @@ export function toggleSelection( isSelectionEnabled = true ) {
*
* @param {(string|string[])} clientIds Block client ID(s) to replace.
* @param {(Object|Object[])} blocks Replacement block(s).
*
* @return {Object} Action object.
*/
export function replaceBlocks( clientIds, blocks ) {
return {
export function* replaceBlocks( clientIds, blocks ) {
clientIds = castArray( clientIds );
blocks = castArray( blocks );
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 ];
const canInsertBlock = yield select(
'core/block-editor',
'canInsertBlockType',
block.name,
rootClientId
);
if ( ! canInsertBlock ) {
const clientIdToReplace = clientIds[ index ];
const nameOfBlockToReplace = clientIdToReplace &&
( yield select( 'core/block-editor', 'getBlockName', clientIdToReplace ) );
if ( ! nameOfBlockToReplace || ( nameOfBlockToReplace !== block.name ) ) {
return;
}
}
}
yield {
type: 'REPLACE_BLOCKS',
clientIds: castArray( clientIds ),
blocks: castArray( blocks ),
clientIds,
blocks,
time: Date.now(),
};
yield* ensureDefaultBlock();
}

/**
Expand Down Expand Up @@ -258,14 +302,48 @@ export const moveBlocksUp = createOnMove( 'MOVE_BLOCKS_UP' );
*
* @return {Object} Action object.
*/
export function moveBlockToPosition( clientId, fromRootClientId, toRootClientId, index ) {
return {
export function* moveBlockToPosition( clientId, fromRootClientId, toRootClientId, index ) {
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;
}

const action = {
type: 'MOVE_BLOCK_TO_POSITION',
fromRootClientId,
toRootClientId,
clientId,
index,
};
// If moving inside the same root block the move is always possible.
if ( fromRootClientId === toRootClientId ) {
return action;
}

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 ) {
return action;
}
}

/**
Expand All @@ -279,8 +357,18 @@ export function moveBlockToPosition( clientId, fromRootClientId, toRootClientId,
*
* @return {Object} Action object.
*/
export function insertBlock( block, index, rootClientId, updateSelection = true ) {
return insertBlocks( [ block ], index, rootClientId, updateSelection );
export function insertBlock(
block,
index,
rootClientId,
updateSelection = true,
) {
return insertBlocks(
[ block ],
index,
rootClientId,
updateSelection
);
}

/**
Expand All @@ -292,17 +380,39 @@ export function insertBlock( block, index, rootClientId, updateSelection = true
* @param {?string} rootClientId Optional root client ID of block list on which to insert.
* @param {?boolean} updateSelection If true block selection will be updated. If false, block selection will not change. Defaults to true.
*
* @return {Object} Action object.
*/
export function insertBlocks( blocks, index, rootClientId, updateSelection = true ) {
return {
type: 'INSERT_BLOCKS',
blocks: castArray( blocks ),
index,
rootClientId,
time: Date.now(),
updateSelection,
};
* @return {Object} Action object.
*/
export function* insertBlocks(
blocks,
index,
rootClientId,
updateSelection = true
) {
blocks = castArray( blocks );
const allowedBlocks = [];
for ( const block of blocks ) {
if ( block ) {
const isValid = yield select(
'core/block-editor',
'canInsertBlockType',
block.name,
rootClientId
);
if ( isValid ) {
allowedBlocks.push( block );
}
}
}
if ( allowedBlocks.length ) {
return {
type: 'INSERT_BLOCKS',
blocks: allowedBlocks,
index,
rootClientId,
time: Date.now(),
updateSelection,
};
}
}

/**
Expand Down Expand Up @@ -394,16 +504,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
Loading

0 comments on commit e113599

Please sign in to comment.