Skip to content

Commit

Permalink
Add allowedBlocksMiddleware
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed Jul 10, 2018
1 parent 6042f35 commit 9af1365
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 10 deletions.
4 changes: 2 additions & 2 deletions editor/components/inner-blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ InnerBlocks = compose( [
replaceInnerBlocks( blocks ) {
const uids = map( block.innerBlocks, 'uid' );
if ( uids.length ) {
replaceBlocks( uids, blocks );
replaceBlocks( uids, blocks, true );
} else {
insertBlocks( blocks, undefined, uid );
insertBlocks( blocks, undefined, uid, true );
}
},
updateNestedSettings( settings ) {
Expand Down
18 changes: 11 additions & 7 deletions editor/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,17 +211,19 @@ export function toggleSelection( isSelectionEnabled = true ) {
* Returns an action object signalling that a blocks should be replaced with
* one or more replacement blocks.
*
* @param {(string|string[])} uids Block UID(s) to replace.
* @param {(Object|Object[])} blocks Replacement block(s).
* @param {(string|string[])} uids Block UID(s) to replace.
* @param {(Object|Object[])} blocks Replacement block(s).
* @param {?boolean} ignoreAllowedBlocksValidation Optional root UID of block list to insert.
*
* @return {Object} Action object.
*/
export function replaceBlocks( uids, blocks ) {
export function replaceBlocks( uids, blocks, ignoreAllowedBlocksValidation ) {
return {
type: 'REPLACE_BLOCKS',
uids: castArray( uids ),
blocks: castArray( blocks ),
time: Date.now(),
ignoreAllowedBlocksValidation,
};
}

Expand Down Expand Up @@ -301,19 +303,21 @@ export function insertBlock( block, index, rootUID ) {
* Returns an action object used in signalling that an array of blocks should
* be inserted, optionally at a specific index respective a root block list.
*
* @param {Object[]} blocks Block objects to insert.
* @param {?number} index Index at which block should be inserted.
* @param {?string} rootUID Optional root UID of block list to insert.
* @param {Object[]} blocks Block objects to insert.
* @param {?number} index Index at which block should be inserted.
* @param {?string} rootUID Optional root UID of block list to insert.
* @param {?boolean} ignoreAllowedBlocksValidation Optional root UID of block list to insert.
*
* @return {Object} Action object.
*/
export function insertBlocks( blocks, index, rootUID ) {
export function insertBlocks( blocks, index, rootUID, ignoreAllowedBlocksValidation ) {
return {
type: 'INSERT_BLOCKS',
blocks: castArray( blocks ),
index,
rootUID,
time: Date.now(),
ignoreAllowedBlocksValidation,
};
}

Expand Down
70 changes: 69 additions & 1 deletion editor/store/middlewares.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,79 @@
*/
import refx from 'refx';
import multi from 'redux-multi';
import { flowRight } from 'lodash';
import { every, filter, first, flowRight } from 'lodash';

/**
* Internal dependencies
*/
import effects from './effects';
import { canInsertBlockType, getBlock, getBlockName, getBlockRootUID, getTemplateLock } from './selectors';

/**
* The allowedBlocksMiddleware middleware makes sure we never add a block when that addition is not possible.
* In order to accomplish this validation allowedBlocksMiddleware makes use of canInsertBlockType selector
* and custom logic for replace, move and multi-block insertion.
* The primary objective of middleware is to make sure the store never gets in an inconsistent state with a block
* added inside in a forbidden area. So for example, if an external plugin tries to insert blocks when a locking exists
* the action will be discarded.
*
* @param {Object} store Middleware Store Object.
* @return {Function} Redux Middleware.
*/
const allowedBlocksMiddleware = ( store ) => ( next ) => ( action ) => {
if ( action.ignoreAllowedBlocksValidation ) {
next( action );
return;
}
switch ( action.type ) {
// When inserting we allow the action if at least one of the blocks can be inserted.
// Blocks that can not be inserted are removed from the action.
case 'INSERT_BLOCKS':
const allowedBlocks = filter( action.blocks, ( block ) =>
block &&
canInsertBlockType( store.getState(), block.name, action.rootUID )
);
if ( allowedBlocks.length ) {
next( {
...action,
blocks: allowedBlocks,
} );
}
return;
case 'MOVE_BLOCK_TO_POSITION':
const { fromRootUID, toRootUID, uid } = action;
const state = store.getState();
const blockName = getBlockName( state, uid );

// If locking is equal to all on the original rootUID (fromRootUID) 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 (
getTemplateLock( state, fromRootUID ) !== 'all' &&
( fromRootUID === toRootUID || canInsertBlockType( store.getState(), blockName, toRootUID ) )
) {
next( action );
}
return;
case 'REPLACE_BLOCKS':
const rootUID = getBlockRootUID( store.getState(), first( action.uids ) );
// 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.
const isOperationValid = every( action.blocks, ( block, index ) => {
if ( canInsertBlockType( store.getState(), block.name, rootUID ) ) {
return true;
}
const uidToReplace = action.uids[ index ];
const blockToReplace = uidToReplace && getBlock( store.getState(), uidToReplace );
return blockToReplace && blockToReplace.name === block.name;
} );
if ( isOperationValid ) {
next( action );
}
return;
}
next( action );
};

/**
* Applies the custom middlewares used specifically in the editor module.
Expand All @@ -21,6 +88,7 @@ function applyMiddlewares( store ) {
const middlewares = [
refx( effects ),
multi,
allowedBlocksMiddleware,
];

let enhancedDispatch = () => {
Expand Down

0 comments on commit 9af1365

Please sign in to comment.