diff --git a/blocks/api/factory.js b/blocks/api/factory.js index c5514147f121c1..8e370abbbf5342 100644 --- a/blocks/api/factory.js +++ b/blocks/api/factory.js @@ -29,7 +29,7 @@ export function createBlock( blockType, attributes = {} ) { * * @param {Object} block Block object * @param {string} blockType BlockType - * @return {Object?} Block object + * @return {?Object|Error} Block object, null, or error with failure message */ export function switchToBlockType( block, blockType ) { // Find the right transformation by giving priority to the "to" transformation @@ -45,9 +45,15 @@ export function switchToBlockType( block, blockType ) { return null; } + const attributes = transformation.transform( block.attributes ); + if ( attributes instanceof Error ) { + // Blocks can perform validation and cancel transformations if needed. + return attributes; + } + return Object.assign( { uid: block.uid, - attributes: transformation.transform( block.attributes ), - blockType + attributes, + blockType, } ); } diff --git a/blocks/api/test/factory.js b/blocks/api/test/factory.js index cb1a0265738d59..e41c9fb2050e3e 100644 --- a/blocks/api/test/factory.js +++ b/blocks/api/test/factory.js @@ -32,7 +32,7 @@ describe( 'block factory', () => { } ); describe( 'switchBlockType()', () => { - it( 'should switch the blockType of a block using the "transform form"', () => { + it( 'should switch the blockType of a block using the "transform from"', () => { registerBlock( 'core/updated-text-block', { transforms: { from: [ { @@ -116,5 +116,30 @@ describe( 'block factory', () => { expect( updateBlock ).to.be.null(); } ); + + it( 'should allow blocks to abort a transformation', () => { + registerBlock( 'core/updated-text-block', {} ); + registerBlock( 'core/text-block', { + transforms: { + to: [ { + blocks: [ 'core/updated-text-block' ], + transform: () => new Error( 'no soup for you' ), + } ] + } + } ); + + const block = { + uid: 1, + blockType: 'core/text-block', + attributes: { + value: 'ribs' + } + }; + + const updateBlock = switchToBlockType( block, 'core/updated-text-block' ); + + expect( updateBlock ).to.be.an.instanceof( Error ); + expect( updateBlock.message ).to.eql( 'no soup for you' ); + } ); } ); } ); diff --git a/blocks/library/heading/index.js b/blocks/library/heading/index.js index acb6c5d0de4f2e..c83e1d1c62ea9d 100644 --- a/blocks/library/heading/index.js +++ b/blocks/library/heading/index.js @@ -31,29 +31,6 @@ registerBlock( 'core/heading', { } ) ) ], - edit( { attributes, setAttributes } ) { - const { content, tag, align } = attributes; - - return ( - setAttributes( { content: value } ) } - style={ align ? { textAlign: align } : null } - /> - ); - }, - - save( { attributes } ) { - const { align, tag: Tag, content } = attributes; - - return ( - - ); - }, - transforms: { from: [ { @@ -61,17 +38,20 @@ registerBlock( 'core/heading', { blocks: [ 'core/text' ], transform: ( { content, align } ) => { if ( Array.isArray( content ) ) { - // TODO this appears to always be true? - // TODO reject the switch if more than one paragraph + if ( content.length > 1 ) { + return new Error( + 'Block has more than one paragraph.' + ); + } content = content[ 0 ]; } return { tag: 'H2', content, - align + align, }; - } - } + }, + }, ], to: [ { @@ -80,10 +60,33 @@ registerBlock( 'core/heading', { transform: ( { content, align } ) => { return { content: [ content ], - align + align, }; - } - } + }, + }, ] - } + }, + + edit( { attributes, setAttributes } ) { + const { content, tag, align } = attributes; + + return ( + setAttributes( { content: value } ) } + style={ align ? { textAlign: align } : null } + /> + ); + }, + + save( { attributes } ) { + const { align, tag: Tag, content } = attributes; + + return ( + + ); + }, } ); diff --git a/blocks/library/quote/index.js b/blocks/library/quote/index.js index a88a47bdf5cbb3..f02b704c08e1b8 100644 --- a/blocks/library/quote/index.js +++ b/blocks/library/quote/index.js @@ -16,20 +16,48 @@ registerBlock( 'core/quote', { category: 'common', attributes: { - value: query( 'blockquote > p', html() ), + content: query( 'blockquote > p', html() ), citation: html( 'footer' ) }, + transforms: { + from: [ + { + type: 'block', + blocks: [ 'core/text' ], + transform: ( { content } ) => { + return { + content, + }; + }, + }, + ], + to: [ + { + type: 'block', + blocks: [ 'core/text' ], + transform: ( { content, citation } ) => { + if ( citation ) { + content = ( content || [] ).concat( citation ); + } + return { + content, + }; + }, + }, + ], + }, + edit( { attributes, setAttributes } ) { - const { value, citation } = attributes; + const { content, citation } = attributes; return (
setAttributes( { - value: fromParagraphsToValue( paragraphs ) + content: fromParagraphsToValue( paragraphs ) } ) } />