diff --git a/packages/block-library/src/heading/index.js b/packages/block-library/src/heading/index.js index 6f98add18effe0..148d0629340744 100644 --- a/packages/block-library/src/heading/index.js +++ b/packages/block-library/src/heading/index.js @@ -11,7 +11,6 @@ import { createBlock, getPhrasingContentSchema, getBlockAttributes, - getBlockType, } from '@wordpress/blocks'; import { RichText } from '@wordpress/editor'; import { @@ -101,7 +100,7 @@ export const settings = { transform( node ) { return createBlock( 'core/heading', { ...getBlockAttributes( - getBlockType( 'core/heading' ), + 'core/heading', node.outerHTML ), level: getLevelFromHeadingNodeName( node.nodeName ), diff --git a/packages/block-library/src/image/index.js b/packages/block-library/src/image/index.js index 83a022388d35dc..4f6619a6c6e527 100644 --- a/packages/block-library/src/image/index.js +++ b/packages/block-library/src/image/index.js @@ -11,7 +11,6 @@ import { __ } from '@wordpress/i18n'; import { createBlock, getBlockAttributes, - getBlockType, getPhrasingContentSchema, } from '@wordpress/blocks'; import { RichText } from '@wordpress/editor'; @@ -133,8 +132,7 @@ export const settings = { const anchorElement = node.querySelector( 'a' ); const linkDestination = anchorElement && anchorElement.href ? 'custom' : undefined; const href = anchorElement && anchorElement.href ? anchorElement.href : undefined; - const blockType = getBlockType( 'core/image' ); - const attributes = getBlockAttributes( blockType, node.outerHTML, { align, id, linkDestination, href } ); + const attributes = getBlockAttributes( 'core/image', node.outerHTML, { align, id, linkDestination, href } ); return createBlock( 'core/image', attributes ); }, }, diff --git a/packages/block-library/src/list/index.js b/packages/block-library/src/list/index.js index e7c38a543f56b3..0bff9abcaab4f0 100644 --- a/packages/block-library/src/list/index.js +++ b/packages/block-library/src/list/index.js @@ -12,7 +12,6 @@ import { createBlock, getPhrasingContentSchema, getBlockAttributes, - getBlockType, } from '@wordpress/blocks'; import { BlockControls, @@ -108,7 +107,7 @@ export const settings = { transform( node ) { return createBlock( 'core/list', { ...getBlockAttributes( - getBlockType( 'core/list' ), + 'core/list', node.outerHTML ), ordered: node.nodeName === 'OL', diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index f77cfe3b809a6e..b3eaf4372a0de5 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.3.0 (Unreleased) + +### New feature + +- `getBlockAttributes`, `getBlockTransforms`, `getSaveContent`, `getSaveElement` and `isValidBlockContent` methods can now take also block's name as the first param ([#11490](https://github.com/WordPress/gutenberg/pull/11490)). Passing a block's type object continues to work as before. + ## 5.2.0 (2018-11-09) - Paste: Google Docs: fix nested formatting, sub, sup and del. diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index d59707e59bd899..f51dfb7e6576d2 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -25,6 +25,7 @@ import { createHooks, applyFilters } from '@wordpress/hooks'; * Internal dependencies */ import { getBlockType, getBlockTypes } from './registration'; +import { normalizeBlockType } from './utils'; /** * Returns a block object given its type and attributes. @@ -279,13 +280,13 @@ export function findTransform( transforms, predicate ) { * transform object includes `blockName` as a property. * * @param {string} direction Transform direction ("to", "from"). - * @param {?string} blockName Optional block name. + * @param {string|Object} blockTypeOrName Block type or name. * * @return {Array} Block transforms for direction. */ -export function getBlockTransforms( direction, blockName ) { +export function getBlockTransforms( direction, blockTypeOrName ) { // When retrieving transforms for all block types, recurse into self. - if ( blockName === undefined ) { + if ( blockTypeOrName === undefined ) { return flatMap( getBlockTypes(), ( { name } ) => getBlockTransforms( direction, name ) @@ -293,7 +294,8 @@ export function getBlockTransforms( direction, blockName ) { } // Validate that block type exists and has array of direction. - const { transforms } = getBlockType( blockName ) || {}; + const blockType = normalizeBlockType( blockTypeOrName ); + const { name: blockName, transforms } = blockType || {}; if ( ! transforms || ! Array.isArray( transforms[ direction ] ) ) { return []; } diff --git a/packages/blocks/src/api/parser.js b/packages/blocks/src/api/parser.js index 3e9ce946409ab8..597ceffff726c2 100644 --- a/packages/blocks/src/api/parser.js +++ b/packages/blocks/src/api/parser.js @@ -23,6 +23,7 @@ import { createBlock } from './factory'; import { isValidBlockContent } from './validation'; import { getCommentDelimitedContent } from './serializer'; import { attr, html, text, query, node, children, prop } from './matchers'; +import { normalizeBlockType } from './utils'; /** * Sources which are guaranteed to return a string value. @@ -277,13 +278,14 @@ export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, com /** * Returns the block attributes of a registered block node given its type. * - * @param {?Object} blockType Block type. - * @param {string} innerHTML Raw block content. - * @param {?Object} attributes Known block attributes (from delimiters). + * @param {string|Object} blockTypeOrName Block type or name. + * @param {string} innerHTML Raw block content. + * @param {?Object} attributes Known block attributes (from delimiters). * * @return {Object} All block attributes. */ -export function getBlockAttributes( blockType, innerHTML, attributes = {} ) { +export function getBlockAttributes( blockTypeOrName, innerHTML, attributes = {} ) { + const blockType = normalizeBlockType( blockTypeOrName ); const blockAttributes = mapValues( blockType.attributes, ( attributeSchema, attributeKey ) => { return getBlockAttribute( attributeKey, attributeSchema, innerHTML, attributes ); } ); diff --git a/packages/blocks/src/api/raw-handling/index.js b/packages/blocks/src/api/raw-handling/index.js index c38cdab46e0dcc..db51f13e0fc6cf 100644 --- a/packages/blocks/src/api/raw-handling/index.js +++ b/packages/blocks/src/api/raw-handling/index.js @@ -7,7 +7,6 @@ import { flatMap, filter, compact } from 'lodash'; * Internal dependencies */ import { createBlock, getBlockTransforms, findTransform } from '../factory'; -import { getBlockType } from '../registration'; import { getBlockContent } from '../serializer'; import { getBlockAttributes, parseWithGrammar } from '../parser'; import normaliseBlocks from './normalise-blocks'; @@ -103,7 +102,7 @@ function htmlToBlocks( { html, rawTransforms } ) { return createBlock( blockName, getBlockAttributes( - getBlockType( blockName ), + blockName, node.outerHTML ) ); diff --git a/packages/blocks/src/api/serializer.js b/packages/blocks/src/api/serializer.js index c3fc87e8f70237..443b68a14a5938 100644 --- a/packages/blocks/src/api/serializer.js +++ b/packages/blocks/src/api/serializer.js @@ -18,6 +18,7 @@ import { getFreeformContentHandlerName, getUnregisteredTypeHandlerName, } from './registration'; +import { normalizeBlockType } from './utils'; import BlockContentProvider from '../block-content-provider'; /** @@ -54,13 +55,14 @@ export function getBlockMenuDefaultClassName( blockName ) { * Given a block type containing a save render implementation and attributes, returns the * enhanced element to be saved or string when raw HTML expected. * - * @param {Object} blockType Block type. - * @param {Object} attributes Block attributes. - * @param {?Array} innerBlocks Nested blocks. + * @param {string|Object} blockTypeOrName Block type or name. + * @param {Object} attributes Block attributes. + * @param {?Array} innerBlocks Nested blocks. * * @return {Object|string} Save element or raw HTML string. */ -export function getSaveElement( blockType, attributes, innerBlocks = [] ) { +export function getSaveElement( blockTypeOrName, attributes, innerBlocks = [] ) { + const blockType = normalizeBlockType( blockTypeOrName ); let { save } = blockType; // Component classes are unsupported for save since serialization must @@ -113,13 +115,15 @@ export function getSaveElement( blockType, attributes, innerBlocks = [] ) { * Given a block type containing a save render implementation and attributes, returns the * static markup to be saved. * - * @param {Object} blockType Block type. - * @param {Object} attributes Block attributes. - * @param {?Array} innerBlocks Nested blocks. + * @param {string|Object} blockTypeOrName Block type or name. + * @param {Object} attributes Block attributes. + * @param {?Array} innerBlocks Nested blocks. * * @return {string} Save content. */ -export function getSaveContent( blockType, attributes, innerBlocks ) { +export function getSaveContent( blockTypeOrName, attributes, innerBlocks ) { + const blockType = normalizeBlockType( blockTypeOrName ); + return renderToString( getSaveElement( blockType, attributes, innerBlocks ) ); } @@ -199,7 +203,6 @@ export function serializeAttributes( attributes ) { */ export function getBlockContent( block ) { // @todo why not getBlockInnerHtml? - const blockType = getBlockType( block.name ); // If block was parsed as invalid or encounters an error while generating // save content, use original content instead to avoid content loss. If a @@ -209,7 +212,7 @@ export function getBlockContent( block ) { let saveContent = block.originalContent; if ( block.isValid || block.innerBlocks.length ) { try { - saveContent = getSaveContent( blockType, block.attributes, block.innerBlocks ); + saveContent = getSaveContent( block.name, block.attributes, block.innerBlocks ); } catch ( error ) {} } diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index d8c46a857f90dd..eaf222b8b5c866 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -15,7 +15,12 @@ import { getBlockTransforms, findTransform, } from '../factory'; -import { getBlockTypes, unregisterBlockType, registerBlockType } from '../registration'; +import { + getBlockType, + getBlockTypes, + registerBlockType, + unregisterBlockType, +} from '../registration'; describe( 'block factory', () => { const defaultBlockSettings = { @@ -1181,6 +1186,20 @@ describe( 'block factory', () => { }, ] ); } ); + + it( 'should return single block type transforms when passed as an object', () => { + const transforms = getBlockTransforms( + 'from', + getBlockType( 'core/transform-from-text-block-1' ) + ); + + expect( transforms ).toEqual( [ + { + blocks: [ 'core/text-block' ], + blockName: 'core/transform-from-text-block-1', + }, + ] ); + } ); } ); describe( 'findTransform', () => { diff --git a/packages/blocks/src/api/test/parser.js b/packages/blocks/src/api/test/parser.js index e55a2546a9bca5..bc059542b01422 100644 --- a/packages/blocks/src/api/test/parser.js +++ b/packages/blocks/src/api/test/parser.js @@ -343,6 +343,26 @@ describe( 'block parser', () => { undefAmbiguousStringWithDefault: 'ok', } ); } ); + + it( 'should work when block type is passed as string', () => { + registerBlockType( 'core/meal', { + title: 'Meal', + category: 'widgets', + attributes: { + content: { + source: 'text', + selector: 'div', + }, + }, + save: () => {}, + } ); + + const innerHTML = '
Ribs
'; + + expect( getBlockAttributes( 'core/meal', innerHTML ) ).toEqual( { + content: 'Ribs', + } ); + } ); } ); describe( 'getMigratedBlock', () => { diff --git a/packages/blocks/src/api/test/serializer.js b/packages/blocks/src/api/test/serializer.js index d0be732c60efb9..a0a5eb2461d3bb 100644 --- a/packages/blocks/src/api/test/serializer.js +++ b/packages/blocks/src/api/test/serializer.js @@ -39,17 +39,34 @@ describe( 'block serializer', () => { describe( 'getSaveContent()', () => { describe( 'function save', () => { + const fruitBlockSave = ( { attributes } ) => createElement( 'div', null, attributes.fruit ); + it( 'should return element as string if save returns element', () => { const saved = getSaveContent( { - save: ( { attributes } ) => createElement( 'div', null, attributes.fruit ), name: 'core/fruit', + save: fruitBlockSave, }, { fruit: 'Bananas' } ); expect( saved ).toBe( '
Bananas
' ); } ); + + it( 'should work when block type is passed as string', () => { + registerBlockType( 'core/fruit', { + title: 'Fruit', + category: 'widgets', + save: fruitBlockSave, + } ); + + const saved = getSaveContent( + 'core/fruit', + { fruit: 'Bananas' } + ); + + expect( saved ).toBe( '
Bananas
' ); + } ); } ); describe( 'component save', () => { diff --git a/packages/blocks/src/api/test/validation.js b/packages/blocks/src/api/test/validation.js index fcc02e490447d8..0fd199f43b4776 100644 --- a/packages/blocks/src/api/test/validation.js +++ b/packages/blocks/src/api/test/validation.js @@ -558,7 +558,7 @@ describe( 'validation', () => { registerBlockType( 'core/test-block', defaultBlockSettings ); const isValid = isValidBlockContent( - getBlockType( 'core/test-block' ), + 'core/test-block', { fruit: 'Bananas' }, 'Apples' ); @@ -577,7 +577,7 @@ describe( 'validation', () => { } ); const isValid = isValidBlockContent( - getBlockType( 'core/test-block' ), + 'core/test-block', { fruit: 'Bananas' }, 'Bananas' ); @@ -589,6 +589,18 @@ describe( 'validation', () => { it( 'returns true is block is valid', () => { registerBlockType( 'core/test-block', defaultBlockSettings ); + const isValid = isValidBlockContent( + 'core/test-block', + { fruit: 'Bananas' }, + 'Bananas' + ); + + expect( isValid ).toBe( true ); + } ); + + it( 'works also when block type object is passed as object', () => { + registerBlockType( 'core/test-block', defaultBlockSettings ); + const isValid = isValidBlockContent( getBlockType( 'core/test-block' ), { fruit: 'Bananas' }, diff --git a/packages/blocks/src/api/utils.js b/packages/blocks/src/api/utils.js index 810aa242784568..d5552a492aaa19 100644 --- a/packages/blocks/src/api/utils.js +++ b/packages/blocks/src/api/utils.js @@ -13,7 +13,7 @@ import { Component, isValidElement } from '@wordpress/element'; /** * Internal dependencies */ -import { getDefaultBlockName } from './registration'; +import { getBlockType, getDefaultBlockName } from './registration'; import { createBlock } from './factory'; /** @@ -104,3 +104,20 @@ export function normalizeIconObject( icon ) { return icon; } + +/** + * Normalizes block type passed as param. When string is passed then + * it converts it to the matching block type object. + * It passes the original object otherwise. + * + * @param {string|Object} blockTypeOrName Block type or name. + * + * @return {?Object} Block type. + */ +export function normalizeBlockType( blockTypeOrName ) { + if ( isString( blockTypeOrName ) ) { + return getBlockType( blockTypeOrName ); + } + + return blockTypeOrName; +} diff --git a/packages/blocks/src/api/validation.js b/packages/blocks/src/api/validation.js index a1ac55c1dbe483..5685756d7f4dc9 100644 --- a/packages/blocks/src/api/validation.js +++ b/packages/blocks/src/api/validation.js @@ -13,6 +13,7 @@ import deprecated from '@wordpress/deprecated'; * Internal dependencies */ import { getSaveContent } from './serializer'; +import { normalizeBlockType } from './utils'; /** * Globally matches any consecutive whitespace @@ -508,13 +509,14 @@ export function isValidBlock( innerHTML, blockType, attributes ) { * * Logs to console in development environments when invalid. * - * @param {string} blockType Block type. - * @param {Object} attributes Parsed block attributes. - * @param {string} innerHTML Original block content. + * @param {string|Object} blockTypeOrName Block type. + * @param {Object} attributes Parsed block attributes. + * @param {string} innerHTML Original block content. * * @return {boolean} Whether block is valid. */ -export function isValidBlockContent( blockType, attributes, innerHTML ) { +export function isValidBlockContent( blockTypeOrName, attributes, innerHTML ) { + const blockType = normalizeBlockType( blockTypeOrName ); let saveContent; try { saveContent = getSaveContent( blockType, attributes ); diff --git a/packages/editor/src/components/block-compare/index.js b/packages/editor/src/components/block-compare/index.js index 87ec2208a8108a..0782976519201b 100644 --- a/packages/editor/src/components/block-compare/index.js +++ b/packages/editor/src/components/block-compare/index.js @@ -10,7 +10,7 @@ import { diffChars } from 'diff'; */ import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; -import { getBlockType, getSaveContent, getSaveElement } from '@wordpress/blocks'; +import { getSaveContent, getSaveElement } from '@wordpress/blocks'; /** * Internal dependencies @@ -32,12 +32,9 @@ class BlockCompare extends Component { } getOriginalContent( block ) { - // Get current block details - const blockType = getBlockType( block.name ); - return { rawContent: block.originalContent, - renderedContent: getSaveElement( blockType, block.attributes ), + renderedContent: getSaveElement( block.name, block.attributes ), }; } @@ -46,8 +43,8 @@ class BlockCompare extends Component { const newBlocks = castArray( block ); // Get converted block details - const newContent = newBlocks.map( ( item ) => getSaveContent( getBlockType( item.name ), item.attributes, item.innerBlocks ) ); - const renderedContent = newBlocks.map( ( item ) => getSaveElement( getBlockType( item.name ), item.attributes, item.innerBlocks ) ); + const newContent = newBlocks.map( ( item ) => getSaveContent( item.name, item.attributes, item.innerBlocks ) ); + const renderedContent = newBlocks.map( ( item ) => getSaveElement( item.name, item.attributes, item.innerBlocks ) ); return { rawContent: newContent.join( '' ), diff --git a/packages/editor/src/components/inner-blocks/test/index.js b/packages/editor/src/components/inner-blocks/test/index.js index 6bca8a8d761eaf..19bfd1bc383d7c 100644 --- a/packages/editor/src/components/inner-blocks/test/index.js +++ b/packages/editor/src/components/inner-blocks/test/index.js @@ -3,7 +3,6 @@ */ import { createBlock, - getBlockType, getBlockTypes, getSaveElement, registerBlockType, @@ -52,7 +51,7 @@ describe( 'InnerBlocks', () => { const saved = renderToString( getSaveElement( - getBlockType( 'core/fruit' ), + 'core/fruit', { fruit: 'Bananas' }, [ createBlock( 'core/fruit', { fruit: 'Apples' } ) ], )