diff --git a/editor/components/block-drop-zone/index.js b/editor/components/block-drop-zone/index.js index 29f76029940b1..ff9bef73dfb68 100644 --- a/editor/components/block-drop-zone/index.js +++ b/editor/components/block-drop-zone/index.js @@ -2,7 +2,7 @@ * External Dependencies */ import { connect } from 'react-redux'; -import { reduce, get, find } from 'lodash'; +import { reduce, includes, get, find } from 'lodash'; /** * WordPress dependencies @@ -16,7 +16,7 @@ import { compose } from '@wordpress/element'; */ import { insertBlocks, updateBlockAttributes } from '../../store/actions'; -function BlockDropZone( { index, isLocked, ...props } ) { +export function BlockDropZone( { index, isLocked, allowedBlockTypes, ...props } ) { if ( isLocked ) { return null; } @@ -29,6 +29,10 @@ function BlockDropZone( { index, isLocked, ...props } ) { const onDropFiles = ( files, position ) => { const transformation = reduce( getBlockTypes(), ( ret, blockType ) => { + if ( Array.isArray( allowedBlockTypes ) && ! includes( allowedBlockTypes, blockType.name ) ) { + return ret; + } + if ( ret ) { return ret; } @@ -67,10 +71,11 @@ export default compose( { insertBlocks, updateBlockAttributes } ), withContext( 'editor' )( ( settings ) => { - const { templateLock } = settings; + const { templateLock, blockTypes } = settings; return { isLocked: !! templateLock, + allowedBlockTypes: blockTypes, }; } ) )( BlockDropZone ); diff --git a/editor/components/block-drop-zone/test/index.js b/editor/components/block-drop-zone/test/index.js new file mode 100644 index 0000000000000..ec83e0a4db7fb --- /dev/null +++ b/editor/components/block-drop-zone/test/index.js @@ -0,0 +1,179 @@ +/** + * External dependencies + */ +import { shallow } from 'enzyme'; +import { noop } from 'lodash'; + +/** + * WordPress dependencies + */ +import { + registerBlockType, + getBlockTypes, + unregisterBlockType, + createBlock, +} from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { BlockDropZone } from '../'; + +describe( 'BlockDropZone', () => { + beforeAll( () => { + registerBlockType( 'core/foo', { + save: noop, + + category: 'common', + + title: 'block title', + + attributes: { + fileType: { + type: 'string', + }, + }, + + transforms: { + from: [ + { + type: 'files', + isMatch: ( files ) => files.some( ( file ) => file.isFooMatch ), + transform( files ) { + return Promise.resolve( files.map( ( file ) => ( + createBlock( 'core/foo', { fileType: file.type } ) + ) ) ); + }, + }, + ], + }, + } ); + } ); + + afterAll( () => { + getBlockTypes().forEach( block => { + unregisterBlockType( block.name ); + } ); + } ); + + it( 'should render nothing if template locking in effect', () => { + const wrapper = shallow( ); + + expect( wrapper.type() ).toBe( null ); + } ); + + it( 'should do nothing if no matched transform for dropped files', ( done ) => { + const insertBlocks = jest.fn(); + const wrapper = shallow( + + ); + + wrapper.prop( 'onFilesDrop' )( [ + { + isBarMatch: true, + type: 'application/x-fake', + }, + ] ); + + process.nextTick( () => { + expect( insertBlocks ).not.toHaveBeenCalled(); + done(); + } ); + } ); + + it( 'should call insert callback with transformed files', ( done ) => { + const insertBlocks = jest.fn(); + const wrapper = shallow( + + ); + + wrapper.prop( 'onFilesDrop' )( [ + { + isFooMatch: true, + type: 'application/x-fake', + }, + ], { y: 'bottom' } ); + + process.nextTick( () => { + expect( insertBlocks ).toHaveBeenCalled(); + const [ blocks, index ] = insertBlocks.mock.calls[ 0 ]; + expect( blocks ).toHaveLength( 1 ); + expect( blocks[ 0 ] ).toMatchObject( { + name: 'core/foo', + attributes: { + fileType: 'application/x-fake', + }, + } ); + expect( index ).toBe( 1 ); + done(); + } ); + } ); + + it( 'should call insert callback with transformed files (top)', ( done ) => { + const insertBlocks = jest.fn(); + const wrapper = shallow( + + ); + + wrapper.prop( 'onFilesDrop' )( [ + { + isFooMatch: true, + type: 'application/x-fake', + }, + ], { y: 'top' } ); + + process.nextTick( () => { + const [ , index ] = insertBlocks.mock.calls[ 0 ]; + expect( index ).toBe( 0 ); + done(); + } ); + } ); + + it( 'should respect allowed block types (not allowed)', ( done ) => { + const insertBlocks = jest.fn(); + const wrapper = shallow( + + ); + + wrapper.prop( 'onFilesDrop' )( [ + { + isFooMatch: true, + type: 'application/x-fake', + }, + ], { y: 'top' } ); + + process.nextTick( () => { + expect( insertBlocks ).not.toHaveBeenCalled(); + done(); + } ); + } ); + + it( 'should respect allowed block types (allowed)', ( done ) => { + const insertBlocks = jest.fn(); + const wrapper = shallow( + + ); + + wrapper.prop( 'onFilesDrop' )( [ + { + isFooMatch: true, + type: 'application/x-fake', + }, + ], { y: 'top' } ); + + process.nextTick( () => { + expect( insertBlocks ).toHaveBeenCalled(); + done(); + } ); + } ); +} );