From ec83e294ded123cbeb52fb6dc04a43ece0c75abd Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 10 Apr 2019 16:15:01 +0100 Subject: [PATCH 01/76] Experiment with rudity mentory mechanic to allow Block Grouping Tried a few approaches via `insertBlock/removeBlocks` and even `replaceBlocks` but nothing preserved the undo history apart from this rather brute force method. --- .../convert-button.js | 83 +++++++++++++++++++ .../convert-to-group-buttons/index.js | 33 ++++++++ .../editor/src/components/provider/index.js | 2 + 3 files changed, 118 insertions(+) create mode 100644 packages/editor/src/components/convert-to-group-buttons/convert-button.js create mode 100644 packages/editor/src/components/convert-to-group-buttons/index.js diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js new file mode 100644 index 0000000000000..b1689b4ef5b9e --- /dev/null +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -0,0 +1,83 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Fragment } from '@wordpress/element'; +import { MenuItem } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { createBlock } from '@wordpress/blocks'; +import { withSelect, withDispatch } from '@wordpress/data'; +import { compose } from '@wordpress/compose'; + +export function ConvertToGroupButton( { + onConvertToGroup, +} ) { + return ( + + + { __( 'Convert to Group' ) } + + + ); +} + +export default compose( [ + withSelect( ( select, { clientIds } ) => { + const { + getBlocksByClientId, + getBlockRootClientId, + } = select( 'core/block-editor' ); + + const blocksToGroup = getBlocksByClientId( clientIds ); + + const isGroupable = ( + blocksToGroup.length === 1 && + blocksToGroup[ 0 ] + ); + + // Define any edge cases here + const isVisible = true; + + return { + isGroupable, + isVisible, + blocksToGroup, + getBlockRootClientId, + }; + } ), + withDispatch( ( dispatch, { clientIds, onToggle = noop, blocksToGroup = [], getBlockRootClientId } ) => { + const { + insertBlock, + moveBlockToPosition, + } = dispatch( 'core/block-editor' ); + + return { + onConvertToGroup() { + if ( ! blocksToGroup.length ) { + return; + } + + const wrapperBlock = createBlock( 'core/section', { + backgroundColor: 'lighter-blue', + } ); + + const firstBlockIndex = blocksToGroup[ 0 ].clientId; + + insertBlock( wrapperBlock, firstBlockIndex ); + + clientIds.forEach( ( blockClientId ) => { + moveBlockToPosition( blockClientId, getBlockRootClientId( blockClientId ), wrapperBlock.clientId ); + } ); + onToggle(); + }, + }; + } ), +] )( ConvertToGroupButton ); diff --git a/packages/editor/src/components/convert-to-group-buttons/index.js b/packages/editor/src/components/convert-to-group-buttons/index.js new file mode 100644 index 0000000000000..304da07c5d5a6 --- /dev/null +++ b/packages/editor/src/components/convert-to-group-buttons/index.js @@ -0,0 +1,33 @@ +/** + * WordPress dependencies + */ +import { Fragment } from '@wordpress/element'; +import { __experimentalBlockSettingsMenuPluginsExtension } from '@wordpress/block-editor'; +import { withSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import ConvertToGroupButton from './convert-button'; + +function ReusableBlocksButtons( { clientIds } ) { + return ( + <__experimentalBlockSettingsMenuPluginsExtension> + { ( { onClose } ) => ( + + + + ) } + + ); +} + +export default withSelect( ( select ) => { + const { getSelectedBlockClientIds } = select( 'core/block-editor' ); + return { + clientIds: getSelectedBlockClientIds(), + }; +} )( ReusableBlocksButtons ); diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 601a44c0260cf..e897931daf6c4 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -21,6 +21,7 @@ import { decodeEntities } from '@wordpress/html-entities'; */ import { mediaUpload } from '../../utils'; import ReusableBlocksButtons from '../reusable-blocks-buttons'; +import ConvertToGroupButtons from '../convert-to-group-buttons'; const fetchLinkSuggestions = async ( search ) => { const posts = await apiFetch( { @@ -159,6 +160,7 @@ class EditorProvider extends Component { > { children } + ); } From 84cedd1c21ad6fc7ab52c2618c7507c30f986a62 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 12 Apr 2019 10:19:12 +0100 Subject: [PATCH 02/76] Migrate to `core/group` due to renaming of container Block from `core/section` --- .../src/components/convert-to-group-buttons/convert-button.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index b1689b4ef5b9e..d8fe03231e746 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -65,7 +65,7 @@ export default compose( [ return; } - const wrapperBlock = createBlock( 'core/section', { + const wrapperBlock = createBlock( 'core/group', { backgroundColor: 'lighter-blue', } ); From 449917217e2a0bfb2b58abc97d817ef5b6e51915 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 12 Apr 2019 10:25:10 +0100 Subject: [PATCH 03/76] Adds conditionals to hide Group btn if selection is only a single `core/group` Block --- .../convert-to-group-buttons/convert-button.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index d8fe03231e746..ca63c4eb78667 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -15,7 +15,12 @@ import { compose } from '@wordpress/compose'; export function ConvertToGroupButton( { onConvertToGroup, + isVisible = true, } ) { + if ( ! isVisible ) { + return null; + } + return ( - { __( 'Convert to Group' ) } + { __( 'Group' ) } ); @@ -38,16 +43,18 @@ export default compose( [ const blocksToGroup = getBlocksByClientId( clientIds ); + const isSingleContainerBlock = blocksToGroup.length === 1 && blocksToGroup[ 0 ].name === 'core/group'; + const isGroupable = ( - blocksToGroup.length === 1 && - blocksToGroup[ 0 ] + blocksToGroup.length && + blocksToGroup[ 0 ] && + ! isSingleContainerBlock ); // Define any edge cases here - const isVisible = true; + const isVisible = isGroupable; return { - isGroupable, isVisible, blocksToGroup, getBlockRootClientId, From ec38f097b5da0c1dc30103bc934c76a405858a86 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 12 Apr 2019 10:56:13 +0100 Subject: [PATCH 04/76] Adds transform and updates Group button implementation to mirror Adds a `from` transform to the `core/group` Block. Currently this only works for `core/paragraph` but will need to work for all Block types. Updates the convert button to utilise `switchToBlockType` which invokes the same functionality as used in Block transform thereby unifiying the two methods of grouping. --- packages/block-library/src/group/index.js | 21 ++++++++++++++++ .../convert-button.js | 24 +++++++------------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index 9bab779f5863b..0e48ce0dde44e 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -25,6 +25,27 @@ export const settings = { anchor: true, html: false, }, + + transforms: { + from: [ + { + type: 'block', + isMultiBlock: true, + blocks: [ 'core/paragraph' ], + transform: ( attributes ) => { + const innerBlocks = attributes.map( ( blockAttrs ) => { + return createBlock( 'core/paragraph', blockAttrs ); + } ); + + return createBlock( 'core/group', { + backgroundColor: 'lighter-blue', // TODO: remove this once https://github.com/WordPress/gutenberg/pull/14241 is activated on `core/group` + }, innerBlocks ); + }, + }, + + ], + }, + edit, save, }; diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index ca63c4eb78667..912527f74daae 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -9,7 +9,7 @@ import { noop } from 'lodash'; import { Fragment } from '@wordpress/element'; import { MenuItem } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { createBlock } from '@wordpress/blocks'; +import { switchToBlockType } from '@wordpress/blocks'; import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; @@ -38,7 +38,6 @@ export default compose( [ withSelect( ( select, { clientIds } ) => { const { getBlocksByClientId, - getBlockRootClientId, } = select( 'core/block-editor' ); const blocksToGroup = getBlocksByClientId( clientIds ); @@ -57,13 +56,11 @@ export default compose( [ return { isVisible, blocksToGroup, - getBlockRootClientId, }; } ), - withDispatch( ( dispatch, { clientIds, onToggle = noop, blocksToGroup = [], getBlockRootClientId } ) => { + withDispatch( ( dispatch, { clientIds, onToggle = noop, blocksToGroup = [] } ) => { const { - insertBlock, - moveBlockToPosition, + replaceBlocks, } = dispatch( 'core/block-editor' ); return { @@ -72,17 +69,14 @@ export default compose( [ return; } - const wrapperBlock = createBlock( 'core/group', { - backgroundColor: 'lighter-blue', - } ); + // Activate the `transform` on `core/group` which does the conversion + const newBlocks = switchToBlockType( blocksToGroup, 'core/group' ); - const firstBlockIndex = blocksToGroup[ 0 ].clientId; + replaceBlocks( + clientIds, + newBlocks + ); - insertBlock( wrapperBlock, firstBlockIndex ); - - clientIds.forEach( ( blockClientId ) => { - moveBlockToPosition( blockClientId, getBlockRootClientId( blockClientId ), wrapperBlock.clientId ); - } ); onToggle(); }, }; From 6a340cce0e84e6083f474e96bcd739ff3a750130 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 12 Apr 2019 11:06:30 +0100 Subject: [PATCH 05/76] Adds and applies Group icon As provided here https://github.com/WordPress/gutenberg/pull/14908#issuecomment-482196334 --- .../convert-to-group-buttons/convert-button.js | 7 ++++++- .../components/convert-to-group-buttons/icons.js | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 packages/editor/src/components/convert-to-group-buttons/icons.js diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index 912527f74daae..7991a19c4798f 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -13,6 +13,11 @@ import { switchToBlockType } from '@wordpress/blocks'; import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; +/** + * Internal dependencies + */ +import { Group } from './icons'; + export function ConvertToGroupButton( { onConvertToGroup, isVisible = true, @@ -25,7 +30,7 @@ export function ConvertToGroupButton( { { __( 'Group' ) } diff --git a/packages/editor/src/components/convert-to-group-buttons/icons.js b/packages/editor/src/components/convert-to-group-buttons/icons.js new file mode 100644 index 0000000000000..af2f70e0c37ec --- /dev/null +++ b/packages/editor/src/components/convert-to-group-buttons/icons.js @@ -0,0 +1,13 @@ +/** + * WordPress dependencies + */ +import { Icon, SVG, Path } from '@wordpress/components'; + +const GroupSVG = + + +; + +export const Group = ; From 9250dfe9f6531abc79bbb5f87fda37372176c4b9 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 12 Apr 2019 11:29:41 +0100 Subject: [PATCH 06/76] Adds editor shortcut for Grouping Blocks --- .../src/components/block-actions/index.js | 18 +++++++++++++++++- .../block-editor-keyboard-shortcuts/index.js | 11 ++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/block-actions/index.js b/packages/block-editor/src/components/block-actions/index.js index 3b3f8032432e8..336d93b65a2ae 100644 --- a/packages/block-editor/src/components/block-actions/index.js +++ b/packages/block-editor/src/components/block-actions/index.js @@ -8,13 +8,14 @@ import { castArray, first, last, every } from 'lodash'; */ import { compose } from '@wordpress/compose'; import { withSelect, withDispatch } from '@wordpress/data'; -import { cloneBlock, hasBlockSupport } from '@wordpress/blocks'; +import { cloneBlock, hasBlockSupport, switchToBlockType } from '@wordpress/blocks'; function BlockActions( { onDuplicate, onRemove, onInsertBefore, onInsertAfter, + onGroup, isLocked, canDuplicate, children, @@ -24,6 +25,7 @@ function BlockActions( { onRemove, onInsertAfter, onInsertBefore, + onGroup, isLocked, canDuplicate, } ); @@ -65,6 +67,7 @@ export default compose( [ multiSelect, removeBlocks, insertDefaultBlock, + replaceBlocks, } = dispatch( 'core/block-editor' ); return { @@ -107,6 +110,19 @@ export default compose( [ insertDefaultBlock( {}, rootClientId, lastSelectedIndex + 1 ); } }, + onGroup() { + if ( ! blocks.length ) { + return; + } + + // Activate the `transform` on `core/group` which does the conversion + const newBlocks = switchToBlockType( blocks, 'core/group' ); + + replaceBlocks( + clientIds, + newBlocks + ); + }, }; } ), ] )( BlockActions ); diff --git a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js index 7e9a433182eba..28db0f877210d 100644 --- a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js +++ b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js @@ -39,6 +39,11 @@ export const shortcuts = { raw: rawShortcut.primaryAlt( 'y' ), display: displayShortcut.primaryAlt( 'y' ), }, + group: { + raw: rawShortcut.primaryAlt( 'g' ), + display: displayShortcut.primaryAlt( 'g' ), + }, + }; class BlockEditorKeyboardShortcuts extends Component { @@ -91,7 +96,7 @@ class BlockEditorKeyboardShortcuts extends Component { /> { selectedBlockClientIds.length > 0 && ( - { ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore } ) => ( + { ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore, onGroup } ) => ( ) } From 81bbde657a77af60b77333c37e36d2824bfda5d4 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 12 Apr 2019 15:59:09 +0100 Subject: [PATCH 07/76] Add test to check for blocks before attempting replace --- .../block-editor/src/components/block-actions/index.js | 3 +++ .../convert-to-group-buttons/convert-button.js | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/block-actions/index.js b/packages/block-editor/src/components/block-actions/index.js index 336d93b65a2ae..4c93bb2867037 100644 --- a/packages/block-editor/src/components/block-actions/index.js +++ b/packages/block-editor/src/components/block-actions/index.js @@ -118,6 +118,9 @@ export default compose( [ // Activate the `transform` on `core/group` which does the conversion const newBlocks = switchToBlockType( blocks, 'core/group' ); + if ( ! newBlocks ) { + return; + } replaceBlocks( clientIds, newBlocks diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index 7991a19c4798f..e3b3f7fbe0d85 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -77,10 +77,12 @@ export default compose( [ // Activate the `transform` on `core/group` which does the conversion const newBlocks = switchToBlockType( blocksToGroup, 'core/group' ); - replaceBlocks( - clientIds, - newBlocks - ); + if ( newBlocks ) { + replaceBlocks( + clientIds, + newBlocks + ); + } onToggle(); }, From 5417118a4208689966d89dd7ca814142960ee460 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 12 Apr 2019 16:04:14 +0100 Subject: [PATCH 08/76] Adds wildcard Block transforms A major update to the transforms logic to enable wildcard Block transforms. * Pass Block names into transform callback function - enables dynamic Block creation in wildcard transforms (see `core/group`) * Add edge cases to Block transformation logic to account for specifying `*` (all) Block types as valid for a transformation * Remove unwanted test that checks all Blocks are of the same type before allowing a transform on a Multi Block selection --- packages/block-library/src/group/index.js | 10 ++++---- packages/blocks/src/api/factory.js | 30 +++++++++++++---------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index 0e48ce0dde44e..eb1dfc2c115b7 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -31,15 +31,15 @@ export const settings = { { type: 'block', isMultiBlock: true, - blocks: [ 'core/paragraph' ], - transform: ( attributes ) => { - const innerBlocks = attributes.map( ( blockAttrs ) => { - return createBlock( 'core/paragraph', blockAttrs ); + blocks: [ '*' ], + transform: ( attributes, innerBlocks, names ) => { + const groupInnerBlocks = attributes.map( ( attrs, index ) => { + return createBlock( names[ index ], attrs, innerBlocks[ index ] ); } ); return createBlock( 'core/group', { backgroundColor: 'lighter-blue', // TODO: remove this once https://github.com/WordPress/gutenberg/pull/14241 is activated on `core/group` - }, innerBlocks ); + }, groupInnerBlocks ); }, }, diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index c7bd01f2c699c..1813ae1f6579d 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -171,7 +171,9 @@ const getBlockTypesForPossibleFromTransforms = ( blocks ) => { return !! findTransform( fromTransforms, - ( transform ) => isPossibleTransformForSource( transform, 'from', blocks ) + ( transform ) => { + return ( transform && transform.blocks && transform.blocks[ 0 ] === '*' ) || isPossibleTransformForSource( transform, 'from', blocks ); + } ); }, ); @@ -199,7 +201,9 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { // filter all 'to' transforms to find those that are possible. const possibleTransforms = filter( transformsTo, - ( transform ) => isPossibleTransformForSource( transform, 'to', blocks ) + ( transform ) => { + return ( transform && transform.blocks && transform.blocks[ 0 ] === '*' ) || isPossibleTransformForSource( transform, 'to', blocks ); + } ); // Build a list of block names using the possible 'to' transforms. @@ -225,12 +229,6 @@ export function getPossibleBlockTransformations( blocks ) { return []; } - const sourceBlock = first( blocks ); - const isMultiBlock = blocks.length > 1; - if ( isMultiBlock && ! every( blocks, { name: sourceBlock.name } ) ) { - return []; - } - const blockTypesForFromTransforms = getBlockTypesForPossibleFromTransforms( blocks ); const blockTypesForToTransforms = getBlockTypesForPossibleToTransforms( blocks ); @@ -321,7 +319,10 @@ export function switchToBlockType( blocks, name ) { const firstBlock = blocksArray[ 0 ]; const sourceName = firstBlock.name; - if ( isMultiBlock && ! every( blocksArray, ( block ) => ( block.name === sourceName ) ) ) { + // Unless it's a `core/group` Block then check + // that all Blocks are of the same type otherwise + // we can't run a conversion + if ( isMultiBlock && ! name === 'core/group' && ! every( blocksArray, ( block ) => ( block.name === sourceName ) ) ) { return null; } @@ -329,14 +330,15 @@ export function switchToBlockType( blocks, name ) { // transformation. const transformationsFrom = getBlockTransforms( 'from', name ); const transformationsTo = getBlockTransforms( 'to', sourceName ); + const transformation = findTransform( transformationsTo, - ( t ) => t.type === 'block' && t.blocks.indexOf( name ) !== -1 && ( ! isMultiBlock || t.isMultiBlock ) + ( t ) => t.type === 'block' && ( ( t.blocks.length && t.blocks[ 0 ] === '*' ) || t.blocks.indexOf( name ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) ) || findTransform( transformationsFrom, - ( t ) => t.type === 'block' && t.blocks.indexOf( sourceName ) !== -1 && ( ! isMultiBlock || t.isMultiBlock ) + ( t ) => t.type === 'block' && ( ( t.blocks.length && t.blocks[ 0 ] === '*' ) || t.blocks.indexOf( sourceName ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) ); // Stop if there is no valid transformation. @@ -345,13 +347,15 @@ export function switchToBlockType( blocks, name ) { } let transformationResults; + if ( transformation.isMultiBlock ) { transformationResults = transformation.transform( blocksArray.map( ( currentBlock ) => currentBlock.attributes ), - blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ) + blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ), + blocksArray.map( ( currentBlock ) => currentBlock.name ), ); } else { - transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks ); + transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks, firstBlock.name ); } // Ensure that the transformation function returned an object or an array From 10cc37378445eaa8a6d7c5279281f71effb146af Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 30 Apr 2019 14:43:00 +0100 Subject: [PATCH 09/76] Reinstate missing createBlock dep after rebase --- packages/block-library/src/group/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index eb1dfc2c115b7..60e365fbd9122 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies From 0d0d259c9e6d2aca560b32870a071302b3fe330a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 1 May 2019 10:51:32 +0100 Subject: [PATCH 10/76] Fix to avoid allowing single Group Block to be Grouped --- packages/block-library/src/group/index.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index 60e365fbd9122..b034aac6a5ae5 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -34,13 +34,16 @@ export const settings = { isMultiBlock: true, blocks: [ '*' ], transform: ( attributes, innerBlocks, names ) => { + // Avoid transforming a single `core/group` Block + if ( names.length === 1 && names[ 0 ] === 'core/group' ) { + return; + } + const groupInnerBlocks = attributes.map( ( attrs, index ) => { return createBlock( names[ index ], attrs, innerBlocks[ index ] ); } ); - return createBlock( 'core/group', { - backgroundColor: 'lighter-blue', // TODO: remove this once https://github.com/WordPress/gutenberg/pull/14241 is activated on `core/group` - }, groupInnerBlocks ); + return createBlock( 'core/group', {}, groupInnerBlocks ); }, }, From febf5b01b2b33acf8b8747e528177bbf2b3a1fb0 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 1 May 2019 10:54:30 +0100 Subject: [PATCH 11/76] Update to use more appropriate logical negation operator for comparison Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r279828282 --- packages/blocks/src/api/factory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 1813ae1f6579d..da70566fcd885 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -322,7 +322,7 @@ export function switchToBlockType( blocks, name ) { // Unless it's a `core/group` Block then check // that all Blocks are of the same type otherwise // we can't run a conversion - if ( isMultiBlock && ! name === 'core/group' && ! every( blocksArray, ( block ) => ( block.name === sourceName ) ) ) { + if ( isMultiBlock && name !== 'core/group' && ! every( blocksArray, ( block ) => ( block.name === sourceName ) ) ) { return null; } From 6bcfe3330ac50e3c6df690369bf109ecbffec060 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 1 May 2019 11:32:08 +0100 Subject: [PATCH 12/76] Extracts key transform test logic into dedicated methods Previously hard coded values and difficult to follow logic were making the `switchToBlockType` overly complex. Extracted to well name methods to improve readability and allow to further refactoring. --- packages/blocks/src/api/factory.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index da70566fcd885..a5afa311d66b7 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -216,6 +216,32 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { return blockNames.map( ( name ) => getBlockType( name ) ); }; +/** + * Determines whether the given Block is the core Block which + * acts as a container Block for other Blocks as part of the + * Grouping mechanocs + * @param {string} name the name of the Block to test against + * @return {boolean} whether or not the Block is the container Block type + */ +const isContainerGroupBlock = ( name ) => name === 'core/group'; + +/** + * Determines whether the provided Blocks are a multi Block selection + * and of the same type (eg: all `core/paragraph`). + * + * @param {Array} blocksArray the Block definitions + * @return {boolean} whether or not the given Blocks pass the criteria + */ +const isMultiBlockSelectionOfSameType = ( blocksArray = [] ) => { + // Is it a Multi Block selection? + if ( ! blocksArray.length > 1 ) { + return false; + } + const sourceName = blocksArray[ 0 ].name; + + return ! every( blocksArray, ( block ) => ( block.name === sourceName ) ); +}; + /** * Returns an array of block types that the set of blocks received as argument * can be transformed into. @@ -322,7 +348,7 @@ export function switchToBlockType( blocks, name ) { // Unless it's a `core/group` Block then check // that all Blocks are of the same type otherwise // we can't run a conversion - if ( isMultiBlock && name !== 'core/group' && ! every( blocksArray, ( block ) => ( block.name === sourceName ) ) ) { + if ( ! isContainerGroupBlock( name ) && isMultiBlockSelectionOfSameType( blocksArray ) ) { return null; } From b7691dca71c12d300f7df8ec8dd92741ebca3d9d Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 1 May 2019 11:56:23 +0100 Subject: [PATCH 13/76] Extract method to test for wildcard block transforms DRYs up code by extracting a function to test for the presence of a wildcard block transform --- packages/blocks/src/api/factory.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index a5afa311d66b7..7622c1d1a8707 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -172,7 +172,7 @@ const getBlockTypesForPossibleFromTransforms = ( blocks ) => { return !! findTransform( fromTransforms, ( transform ) => { - return ( transform && transform.blocks && transform.blocks[ 0 ] === '*' ) || isPossibleTransformForSource( transform, 'from', blocks ); + return ( transform && isWildCardBlockTransform( transform ) ) || isPossibleTransformForSource( transform, 'from', blocks ); } ); }, @@ -202,7 +202,7 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { const possibleTransforms = filter( transformsTo, ( transform ) => { - return ( transform && transform.blocks && transform.blocks[ 0 ] === '*' ) || isPossibleTransformForSource( transform, 'to', blocks ); + return ( transform && isWildCardBlockTransform( transform ) ) || isPossibleTransformForSource( transform, 'to', blocks ); } ); @@ -216,6 +216,16 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { return blockNames.map( ( name ) => getBlockType( name ) ); }; +/** + * Determines whether transform is a "block" type + * and if so whether it is a "wildcard" transform + * ie: targets "any" block type + * + * @param {Object} t Block transform object + * @return {boolean} whether transform is a wildcard transform + */ +const isWildCardBlockTransform = ( t ) => t && t.type === 'block' && t.blocks.length && t.blocks[ 0 ] === '*'; + /** * Determines whether the given Block is the core Block which * acts as a container Block for other Blocks as part of the @@ -360,11 +370,11 @@ export function switchToBlockType( blocks, name ) { const transformation = findTransform( transformationsTo, - ( t ) => t.type === 'block' && ( ( t.blocks.length && t.blocks[ 0 ] === '*' ) || t.blocks.indexOf( name ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) + ( t ) => t.type === 'block' && ( ( isWildCardBlockTransform( t ) ) || t.blocks.indexOf( name ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) ) || findTransform( transformationsFrom, - ( t ) => t.type === 'block' && ( ( t.blocks.length && t.blocks[ 0 ] === '*' ) || t.blocks.indexOf( sourceName ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) + ( t ) => t.type === 'block' && ( ( isWildCardBlockTransform( t ) ) || t.blocks.indexOf( sourceName ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) ); // Stop if there is no valid transformation. From be26e72a9920bea7c81dcfc2f2d1e697b39ad17d Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 1 May 2019 13:12:52 +0100 Subject: [PATCH 14/76] Moves logic to allow for wildcard transform into central transform checking method Previously test to allow wildcard transform to be valid were manually added as edge cases in conditions in predicate functions. This update centralises all logic to test whether a given transform is possible but including the logic that allows wildcard transforms within the main method `isPossibleTransformForSource` which determines whether a given transform is possible. --- packages/blocks/src/api/factory.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 7622c1d1a8707..e6ab0f8e7fd88 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -117,9 +117,10 @@ const isPossibleTransformForSource = ( transform, direction, blocks ) => { return false; } - // If multiple blocks are selected, only multi block transforms are allowed. + // If multiple blocks are selected, only multi block transforms + // or wildcard transforms are allowed. const isMultiBlock = blocks.length > 1; - const isValidForMultiBlocks = ! isMultiBlock || transform.isMultiBlock; + const isValidForMultiBlocks = isWildCardBlockTransform( transform ) || ! isMultiBlock || transform.isMultiBlock; if ( ! isValidForMultiBlocks ) { return false; } @@ -130,13 +131,20 @@ const isPossibleTransformForSource = ( transform, direction, blocks ) => { return false; } - // Check if the transform's block name matches the source block only if this is a transform 'from'. + // Check if the transform's block name matches the source block (or is a wildcard) + // only if this is a transform 'from'. const sourceBlock = first( blocks ); - const hasMatchingName = direction !== 'from' || transform.blocks.indexOf( sourceBlock.name ) !== -1; + const hasMatchingName = direction !== 'from' || transform.blocks.indexOf( sourceBlock.name ) !== -1 || isWildCardBlockTransform( transform ); if ( ! hasMatchingName ) { return false; } + // Don't allow single 'core/group' blocks to be transformed into + // a 'core/group' block. + if ( ! isMultiBlock && isContainerGroupBlock( sourceBlock.name ) && isContainerGroupBlock( transform.blockName ) ) { + return false; + } + // If the transform has a `isMatch` function specified, check that it returns true. if ( isFunction( transform.isMatch ) ) { const attributes = transform.isMultiBlock ? blocks.map( ( block ) => block.attributes ) : sourceBlock.attributes; @@ -172,7 +180,7 @@ const getBlockTypesForPossibleFromTransforms = ( blocks ) => { return !! findTransform( fromTransforms, ( transform ) => { - return ( transform && isWildCardBlockTransform( transform ) ) || isPossibleTransformForSource( transform, 'from', blocks ); + return transform && isPossibleTransformForSource( transform, 'from', blocks ); } ); }, @@ -202,7 +210,7 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { const possibleTransforms = filter( transformsTo, ( transform ) => { - return ( transform && isWildCardBlockTransform( transform ) ) || isPossibleTransformForSource( transform, 'to', blocks ); + return transform && isPossibleTransformForSource( transform, 'to', blocks ); } ); From f05f7bb3036aa0272d7efe62a2712df38630f6f8 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 1 May 2019 13:29:36 +0100 Subject: [PATCH 15/76] Adds UnGrouping mechanic --- .../convert-button.js | 76 +++++++++++++------ 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index e3b3f7fbe0d85..d2a5d5e2351e5 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -20,21 +20,30 @@ import { Group } from './icons'; export function ConvertToGroupButton( { onConvertToGroup, - isVisible = true, + onUnCovertFromGroup, + isGroupable = false, + isUnGroupable = false, } ) { - if ( ! isVisible ) { - return null; - } - return ( - - { __( 'Group' ) } - + { isGroupable && ( + + { __( 'Group' ) } + + ) } + { isUnGroupable && ( + + { __( 'Ungroup' ) } + + ) } ); } @@ -45,37 +54,40 @@ export default compose( [ getBlocksByClientId, } = select( 'core/block-editor' ); - const blocksToGroup = getBlocksByClientId( clientIds ); + const blocksSelection = getBlocksByClientId( clientIds ); - const isSingleContainerBlock = blocksToGroup.length === 1 && blocksToGroup[ 0 ].name === 'core/group'; + const isSingleContainerBlock = blocksSelection.length === 1 && blocksSelection[ 0 ].name === 'core/group'; + // Do we have one or more blocks selected + // (we allow single Blocks to become groups unless + // they are a soltiary group block themselves) const isGroupable = ( - blocksToGroup.length && - blocksToGroup[ 0 ] && + blocksSelection.length && ! isSingleContainerBlock ); - // Define any edge cases here - const isVisible = isGroupable; + // Do we have a single Group Block selected? + const isUnGroupable = isSingleContainerBlock; return { - isVisible, - blocksToGroup, + isGroupable, + isUnGroupable, + blocksSelection, }; } ), - withDispatch( ( dispatch, { clientIds, onToggle = noop, blocksToGroup = [] } ) => { + withDispatch( ( dispatch, { clientIds, onToggle = noop, blocksSelection = [] } ) => { const { replaceBlocks, } = dispatch( 'core/block-editor' ); return { onConvertToGroup() { - if ( ! blocksToGroup.length ) { + if ( ! blocksSelection.length ) { return; } // Activate the `transform` on `core/group` which does the conversion - const newBlocks = switchToBlockType( blocksToGroup, 'core/group' ); + const newBlocks = switchToBlockType( blocksSelection, 'core/group' ); if ( newBlocks ) { replaceBlocks( @@ -84,6 +96,24 @@ export default compose( [ ); } + onToggle(); + }, + onUnCovertFromGroup() { + if ( ! blocksSelection.length ) { + return; + } + + const innerBlocks = blocksSelection[ 0 ].innerBlocks; + + if ( ! innerBlocks.length ) { + return; + } + + replaceBlocks( + clientIds, + innerBlocks + ); + onToggle(); }, }; From 322ec737779257fd119ed3da445378ac08071762 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 1 May 2019 13:32:12 +0100 Subject: [PATCH 16/76] Adds UnGroup Icon --- .../convert-to-group-buttons/convert-button.js | 4 ++-- .../src/components/convert-to-group-buttons/icons.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index d2a5d5e2351e5..9cd94eeb807bb 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -16,7 +16,7 @@ import { compose } from '@wordpress/compose'; /** * Internal dependencies */ -import { Group } from './icons'; +import { Group, UnGroup } from './icons'; export function ConvertToGroupButton( { onConvertToGroup, @@ -38,7 +38,7 @@ export function ConvertToGroupButton( { { isUnGroupable && ( { __( 'Ungroup' ) } diff --git a/packages/editor/src/components/convert-to-group-buttons/icons.js b/packages/editor/src/components/convert-to-group-buttons/icons.js index af2f70e0c37ec..89b060fd9cc5d 100644 --- a/packages/editor/src/components/convert-to-group-buttons/icons.js +++ b/packages/editor/src/components/convert-to-group-buttons/icons.js @@ -11,3 +11,13 @@ const GroupSVG = ; export const Group = ; + +const UnGroupSVG = + + +; + +export const UnGroup = ; + From 68a16f2952ac15eb54ea7d514ff5bfbde6ed5735 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 3 May 2019 16:52:06 +0100 Subject: [PATCH 17/76] Adds e2e test to cover basic grouping for single and multiple blocks --- .../__snapshots__/block-grouping.test.js.snap | 65 +++++++++++ .../e2e-tests/specs/block-grouping.test.js | 110 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap create mode 100644 packages/e2e-tests/specs/block-grouping.test.js diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap new file mode 100644 index 0000000000000..6c240fa933e4c --- /dev/null +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Block Grouping creates a group from multiple blocks of different types via block transforms 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; + +exports[`Block Grouping creates a group from multiple blocks of different types via options toolbar 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; + +exports[`Block Grouping creates a group from multiple blocks of the same type via block transforms 1`] = ` +" +
+

First Paragraph

+ + + +

Second Paragraph

+ + + +

Third Paragraph

+
+" +`; + +exports[`Block Grouping creates a group from multiple blocks of the same type via options toolbar 1`] = ` +" +
+

First Options Paragraph

+ + + +

Second Options Paragraph

+ + + +

Third Options Paragraph

+
+" +`; diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js new file mode 100644 index 0000000000000..d0a2e5c492076 --- /dev/null +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -0,0 +1,110 @@ +/** + * WordPress dependencies + */ +import { + insertBlock, + createNewPost, + clickBlockToolbarButton, + pressKeyWithModifier, + getEditedPostContent, + transformBlockTo, +} from '@wordpress/e2e-test-utils'; + +describe( 'Block Grouping', () => { + beforeAll( async () => { + await createNewPost(); + } ); + + beforeEach( async () => { + // Remove all blocks from the post so that we're working with a clean slate + await page.evaluate( () => { + const blocks = wp.data.select( 'core/editor' ).getBlocks(); + const clientIds = blocks.map( ( block ) => block.clientId ); + wp.data.dispatch( 'core/editor' ).removeBlocks( clientIds ); + } ); + } ); + + it( 'creates a group from multiple blocks of the same type via block transforms', async () => { + // Creating test blocks + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'First Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Second Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Third Paragraph' ); + + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await transformBlockTo( 'Group' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'creates a group from multiple blocks of different types via block transforms', async () => { + // Creating test blocks + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + + await insertBlock( 'Image' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); + + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await transformBlockTo( 'Group' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'creates a group from multiple blocks of the same type via options toolbar', async () => { + // Creating test blocks + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'First Options Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Second Options Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Third Options Paragraph' ); + + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await clickBlockToolbarButton( 'More options' ); + + const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); + await groupButton.click(); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'creates a group from multiple blocks of different types via options toolbar', async () => { + // Creating test blocks + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + + await insertBlock( 'Image' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); + + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await clickBlockToolbarButton( 'More options' ); + + const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); + await groupButton.click(); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); +} ); From 824a168e3d2c0c1aace1c0ed3bb35a787b3bbdb2 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 6 May 2019 11:11:03 +0200 Subject: [PATCH 18/76] Fix edge case with test to detect a single group container Block --- .../src/components/convert-to-group-buttons/convert-button.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index 9cd94eeb807bb..b9fc4a0d8ed01 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -56,7 +56,7 @@ export default compose( [ const blocksSelection = getBlocksByClientId( clientIds ); - const isSingleContainerBlock = blocksSelection.length === 1 && blocksSelection[ 0 ].name === 'core/group'; + const isSingleContainerBlock = blocksSelection.length === 1 && blocksSelection[ 0 ] && blocksSelection[ 0 ].name === 'core/group'; // Do we have one or more blocks selected // (we allow single Blocks to become groups unless From 1effcde1f8170c371cfce799e5440478497c791a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 6 May 2019 11:11:53 +0200 Subject: [PATCH 19/76] Adds UnGroup keyboard shortcut --- .../src/components/block-actions/index.js | 19 +++++++++++++++++++ .../block-editor-keyboard-shortcuts/index.js | 10 +++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-actions/index.js b/packages/block-editor/src/components/block-actions/index.js index 4c93bb2867037..170869d808655 100644 --- a/packages/block-editor/src/components/block-actions/index.js +++ b/packages/block-editor/src/components/block-actions/index.js @@ -16,6 +16,7 @@ function BlockActions( { onInsertBefore, onInsertAfter, onGroup, + onUnGroup, isLocked, canDuplicate, children, @@ -26,6 +27,7 @@ function BlockActions( { onInsertAfter, onInsertBefore, onGroup, + onUnGroup, isLocked, canDuplicate, } ); @@ -126,6 +128,23 @@ export default compose( [ newBlocks ); }, + + onUnGroup() { + if ( ! blocks.length ) { + return; + } + + const innerBlocks = blocks[ 0 ].innerBlocks; + + if ( ! innerBlocks.length ) { + return; + } + + replaceBlocks( + clientIds, + innerBlocks + ); + }, }; } ), ] )( BlockActions ); diff --git a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js index 28db0f877210d..30eefe80e3bb9 100644 --- a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js +++ b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js @@ -43,6 +43,10 @@ export const shortcuts = { raw: rawShortcut.primaryAlt( 'g' ), display: displayShortcut.primaryAlt( 'g' ), }, + ungroup: { + raw: rawShortcut.secondary( 'g' ), + display: displayShortcut.secondary( 'g' ), + }, }; @@ -96,7 +100,7 @@ class BlockEditorKeyboardShortcuts extends Component { /> { selectedBlockClientIds.length > 0 && ( - { ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore, onGroup } ) => ( + { ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore, onGroup, onUnGroup } ) => ( ) } From 45b7b804e328640382c7e12fc0d50513f1bc3871 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 6 May 2019 11:13:18 +0200 Subject: [PATCH 20/76] Adds more e2e test coverage Includes testing grouping via transforms, options menu and keyboard shortcuts --- .../__snapshots__/block-grouping.test.js.snap | 52 ++++- .../e2e-tests/specs/block-grouping.test.js | 178 ++++++++++++------ 2 files changed, 170 insertions(+), 60 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap index 6c240fa933e4c..8a0830847afea 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Block Grouping creates a group from multiple blocks of different types via block transforms 1`] = ` +exports[`Block Grouping Group creation creates a group from multiple blocks of different types via block transforms 1`] = ` "

Group Heading

@@ -16,7 +16,7 @@ exports[`Block Grouping creates a group from multiple blocks of different types " `; -exports[`Block Grouping creates a group from multiple blocks of different types via options toolbar 1`] = ` +exports[`Block Grouping Group creation creates a group from multiple blocks of different types via options toolbar 1`] = ` "

Group Heading

@@ -32,7 +32,7 @@ exports[`Block Grouping creates a group from multiple blocks of different types " `; -exports[`Block Grouping creates a group from multiple blocks of the same type via block transforms 1`] = ` +exports[`Block Grouping Group creation creates a group from multiple blocks of the same type via block transforms 1`] = ` "

First Paragraph

@@ -48,7 +48,7 @@ exports[`Block Grouping creates a group from multiple blocks of the same type vi " `; -exports[`Block Grouping creates a group from multiple blocks of the same type via options toolbar 1`] = ` +exports[`Block Grouping Group creation creates a group from multiple blocks of the same type via options toolbar 1`] = ` "

First Options Paragraph

@@ -63,3 +63,47 @@ exports[`Block Grouping creates a group from multiple blocks of the same type vi
" `; + +exports[`Block Grouping Keyboard shortcuts groups using keyboard shortcut 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; + +exports[`Block Grouping Keyboard shortcuts ungroups using keyboard shortcut 1`] = ` +" +

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+" +`; + +exports[`Block Grouping Ungrouping ungroups an existing group via options menu 1`] = ` +" +

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+" +`; diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index d0a2e5c492076..a0e4fa1aca68b 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -8,6 +8,7 @@ import { pressKeyWithModifier, getEditedPostContent, transformBlockTo, + getAllBlocks, } from '@wordpress/e2e-test-utils'; describe( 'Block Grouping', () => { @@ -24,87 +25,152 @@ describe( 'Block Grouping', () => { } ); } ); - it( 'creates a group from multiple blocks of the same type via block transforms', async () => { - // Creating test blocks - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'First Paragraph' ); + describe( 'Group creation', () => { + it( 'creates a group from multiple blocks of the same type via block transforms', async () => { + // Creating test blocks + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'First Paragraph' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Second Paragraph' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Second Paragraph' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Third Paragraph' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Third Paragraph' ); - // Multiselect via keyboard. - await pressKeyWithModifier( 'primary', 'a' ); - await pressKeyWithModifier( 'primary', 'a' ); + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); - await transformBlockTo( 'Group' ); + await transformBlockTo( 'Group' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); - it( 'creates a group from multiple blocks of different types via block transforms', async () => { - // Creating test blocks - await insertBlock( 'Heading' ); - await page.keyboard.type( 'Group Heading' ); + it( 'creates a group from multiple blocks of different types via block transforms', async () => { + // Creating test blocks + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); - await insertBlock( 'Image' ); + await insertBlock( 'Image' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Some paragraph' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); - // Multiselect via keyboard. - await pressKeyWithModifier( 'primary', 'a' ); - await pressKeyWithModifier( 'primary', 'a' ); + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); - await transformBlockTo( 'Group' ); + await transformBlockTo( 'Group' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'creates a group from multiple blocks of the same type via options toolbar', async () => { + // Creating test blocks + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'First Options Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Second Options Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Third Options Paragraph' ); + + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await clickBlockToolbarButton( 'More options' ); + + const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); + await groupButton.click(); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); - it( 'creates a group from multiple blocks of the same type via options toolbar', async () => { - // Creating test blocks - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'First Options Paragraph' ); + it( 'creates a group from multiple blocks of different types via options toolbar', async () => { + // Creating test blocks + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Second Options Paragraph' ); + await insertBlock( 'Image' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Third Options Paragraph' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); - // Multiselect via keyboard. - await pressKeyWithModifier( 'primary', 'a' ); - await pressKeyWithModifier( 'primary', 'a' ); + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); - await clickBlockToolbarButton( 'More options' ); + await clickBlockToolbarButton( 'More options' ); - const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); - await groupButton.click(); + const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); + await groupButton.click(); - expect( await getEditedPostContent() ).toMatchSnapshot(); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); } ); - it( 'creates a group from multiple blocks of different types via options toolbar', async () => { - // Creating test blocks - await insertBlock( 'Heading' ); - await page.keyboard.type( 'Group Heading' ); + describe( 'Ungrouping', () => { + it( 'ungroups an existing group via options menu', async () => { + // Create a Group + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + await insertBlock( 'Image' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + await transformBlockTo( 'Group' ); + + await clickBlockToolbarButton( 'More options' ); + + const unGroupButton = await page.waitForXPath( '//button[text()="Ungroup"]' ); - await insertBlock( 'Image' ); + await unGroupButton.click(); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Some paragraph' ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + } ); - // Multiselect via keyboard. - await pressKeyWithModifier( 'primary', 'a' ); - await pressKeyWithModifier( 'primary', 'a' ); + describe( 'Keyboard shortcuts', () => { + it( 'groups using keyboard shortcut', async () => { + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + await insertBlock( 'Image' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + await transformBlockTo( 'Group' ); - await clickBlockToolbarButton( 'More options' ); + // Group + await pressKeyWithModifier( 'primaryAlt', 'g' ); - const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); - await groupButton.click(); + const allBlocks = await getAllBlocks(); - expect( await getEditedPostContent() ).toMatchSnapshot(); + expect( allBlocks[ 0 ].name ).toBe( 'core/group' ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'ungroups using keyboard shortcut', async () => { + // Create a Group + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + await insertBlock( 'Image' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + await transformBlockTo( 'Group' ); + + // Ungroup (Primary, Shift, Alt) + await pressKeyWithModifier( 'secondary', 'g' ); + + const allBlocks = await getAllBlocks(); + + expect( allBlocks[ 0 ].name ).not.toBe( 'core/group' ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); } ); } ); From 1666e97d3ac1215654128999c6441c9a0728f9cf Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 6 May 2019 18:21:49 +0200 Subject: [PATCH 21/76] Adds check for group block availability before displaying grouping UI Also adds e2e tests to cover this. --- .../e2e-tests/specs/block-grouping.test.js | 51 +++++++++++++++++++ .../convert-button.js | 8 ++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index a0e4fa1aca68b..fee8e4089e918 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -9,6 +9,7 @@ import { getEditedPostContent, transformBlockTo, getAllBlocks, + getAvailableBlockTransforms, } from '@wordpress/e2e-test-utils'; describe( 'Block Grouping', () => { @@ -173,4 +174,54 @@ describe( 'Block Grouping', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); } ); + + describe( 'Container Block availability', () => { + it( 'does not show group transform if container block is disabled', async () => { + // Disable the Group block + await page.evaluate( () => { + const { dispatch } = wp.data; + dispatch( 'core/edit-post' ).hideBlockTypes( [ 'core/group' ] ); + } ); + + // Create a Group + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + await insertBlock( 'Image' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + const availableTransforms = await getAvailableBlockTransforms(); + + expect( + availableTransforms + ).not.toEqual( expect.arrayContaining( [ + 'Group', + ] ) ); + } ); + + it( 'does not show group option in the options toolbar if container block is disabled ', async () => { + // Disable the Group block + await page.evaluate( () => { + const { dispatch } = wp.data; + dispatch( 'core/edit-post' ).hideBlockTypes( [ 'core/group' ] ); + } ); + + // Create a Group + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + await insertBlock( 'Image' ); + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await clickBlockToolbarButton( 'More options' ); + + const blockOptionsDropdownHTML = await page.evaluate( () => document.querySelector( '.block-editor-block-settings-menu__content' ).innerHTML ); + + expect( blockOptionsDropdownHTML ).not.toContain( 'Group' ); + } ); + } ); } ); diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index b9fc4a0d8ed01..360f6aea2a8fe 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -52,16 +52,22 @@ export default compose( [ withSelect( ( select, { clientIds } ) => { const { getBlocksByClientId, + canInsertBlockType, } = select( 'core/block-editor' ); + const containerBlockAvailable = canInsertBlockType( 'core/group' ); + const blocksSelection = getBlocksByClientId( clientIds ); const isSingleContainerBlock = blocksSelection.length === 1 && blocksSelection[ 0 ] && blocksSelection[ 0 ].name === 'core/group'; - // Do we have one or more blocks selected + // Do we have + // 1. Container block available to be inserted? + // 2. One or more blocks selected // (we allow single Blocks to become groups unless // they are a soltiary group block themselves) const isGroupable = ( + containerBlockAvailable && blocksSelection.length && ! isSingleContainerBlock ); From 0e4a2d331d2692043e8be78584a97defd30615d1 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 6 May 2019 18:28:34 +0200 Subject: [PATCH 22/76] Updates misnamned components Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r280851925 --- .../editor/src/components/convert-to-group-buttons/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/index.js b/packages/editor/src/components/convert-to-group-buttons/index.js index 304da07c5d5a6..a276ed4434bca 100644 --- a/packages/editor/src/components/convert-to-group-buttons/index.js +++ b/packages/editor/src/components/convert-to-group-buttons/index.js @@ -10,7 +10,7 @@ import { withSelect } from '@wordpress/data'; */ import ConvertToGroupButton from './convert-button'; -function ReusableBlocksButtons( { clientIds } ) { +function ConvertToGroupButtons( { clientIds } ) { return ( <__experimentalBlockSettingsMenuPluginsExtension> { ( { onClose } ) => ( @@ -30,4 +30,4 @@ export default withSelect( ( select ) => { return { clientIds: getSelectedBlockClientIds(), }; -} )( ReusableBlocksButtons ); +} )( ConvertToGroupButtons ); From d6cb0ccaf4f746cf91250c35fc013832ef6bc5f5 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 6 May 2019 22:14:11 +0200 Subject: [PATCH 23/76] Updates to preserve widest width alignment of child block on group container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously if one of the child blocks being grouped had a width alignment (eg: wide or full) then the group block did not respect this. This meant that layouts weren’t preserved when grouping. Adds functionality and tests to ensure that when a group is created the widest alignment setting of the child blocks is set on the group block. --- packages/block-library/src/group/index.js | 13 ++++- .../__snapshots__/block-grouping.test.js.snap | 20 ++++++++ .../e2e-tests/specs/block-grouping.test.js | 48 +++++++++++++++---- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index b034aac6a5ae5..c336441aad5fc 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -39,11 +39,22 @@ export const settings = { return; } + const alignments = [ 'wide', 'full' ]; + + let widestAlignment; + const groupInnerBlocks = attributes.map( ( attrs, index ) => { + // Determines the widest setting of all the blocks to be grouped + const currBlockAlignment = attrs.align; + widestAlignment = alignments.indexOf( currBlockAlignment ) > alignments.indexOf( widestAlignment ) ? currBlockAlignment : widestAlignment; + + // Creates the new Block return createBlock( names[ index ], attrs, innerBlocks[ index ] ); } ); - return createBlock( 'core/group', {}, groupInnerBlocks ); + return createBlock( 'core/group', { + align: widestAlignment, + }, groupInnerBlocks ); }, }, diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap index 8a0830847afea..ce8b2d4c6c1ae 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -94,6 +94,26 @@ exports[`Block Grouping Keyboard shortcuts ungroups using keyboard shortcut 1`] " `; +exports[`Block Grouping Preserving selected blocks attributes preserves width alignment settings of selected blocks 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; + exports[`Block Grouping Ungrouping ungroups an existing group via options menu 1`] = ` "

Group Heading

diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index fee8e4089e918..b12e10cc0e6bd 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -176,13 +176,15 @@ describe( 'Block Grouping', () => { } ); describe( 'Container Block availability', () => { - it( 'does not show group transform if container block is disabled', async () => { + beforeAll( async () => { // Disable the Group block await page.evaluate( () => { const { dispatch } = wp.data; dispatch( 'core/edit-post' ).hideBlockTypes( [ 'core/group' ] ); } ); + } ); + beforeEach( async () => { // Create a Group await insertBlock( 'Heading' ); await page.keyboard.type( 'Group Heading' ); @@ -191,7 +193,17 @@ describe( 'Block Grouping', () => { await page.keyboard.type( 'Some paragraph' ); await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'a' ); + } ); + afterAll( async () => { + // Re-enable the Group block + await page.evaluate( () => { + const { dispatch } = wp.data; + dispatch( 'core/edit-post' ).showBlockTypes( [ 'core/group' ] ); + } ); + } ); + + it( 'does not show group transform if container block is disabled', async () => { const availableTransforms = await getAvailableBlockTransforms(); expect( @@ -202,26 +214,42 @@ describe( 'Block Grouping', () => { } ); it( 'does not show group option in the options toolbar if container block is disabled ', async () => { - // Disable the Group block - await page.evaluate( () => { - const { dispatch } = wp.data; - dispatch( 'core/edit-post' ).hideBlockTypes( [ 'core/group' ] ); - } ); + await clickBlockToolbarButton( 'More options' ); - // Create a Group + const blockOptionsDropdownHTML = await page.evaluate( () => document.querySelector( '.block-editor-block-settings-menu__content' ).innerHTML ); + + expect( blockOptionsDropdownHTML ).not.toContain( 'Group' ); + } ); + } ); + + describe( 'Preserving selected blocks attributes', () => { + it( 'preserves width alignment settings of selected blocks', async () => { await insertBlock( 'Heading' ); await page.keyboard.type( 'Group Heading' ); + + // Full width image + await insertBlock( 'Image' ); + await clickBlockToolbarButton( 'Full width' ); + + // Wide width image) await insertBlock( 'Image' ); + await clickBlockToolbarButton( 'Wide width' ); + await insertBlock( 'Paragraph' ); await page.keyboard.type( 'Some paragraph' ); + await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'a' ); - await clickBlockToolbarButton( 'More options' ); + await transformBlockTo( 'Group' ); - const blockOptionsDropdownHTML = await page.evaluate( () => document.querySelector( '.block-editor-block-settings-menu__content' ).innerHTML ); + const allBlocks = await getAllBlocks(); - expect( blockOptionsDropdownHTML ).not.toContain( 'Group' ); + // We expect Group block align setting to match that + // of the widest of it's "child" innerBlocks + expect( allBlocks[ 0 ].attributes.align ).toBe( 'full' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); } ); } ); } ); From 3e76175716cc41909c594c6332bd2b58552a0aad Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 6 May 2019 22:30:49 +0200 Subject: [PATCH 24/76] Updates to DRY out tests --- .../__snapshots__/block-grouping.test.js.snap | 6 +- .../e2e-tests/specs/block-grouping.test.js | 79 +++++++------------ 2 files changed, 32 insertions(+), 53 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap index ce8b2d4c6c1ae..bd383e9e52d28 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -51,15 +51,15 @@ exports[`Block Grouping Group creation creates a group from multiple blocks of t exports[`Block Grouping Group creation creates a group from multiple blocks of the same type via options toolbar 1`] = ` "
-

First Options Paragraph

+

First Paragraph

-

Second Options Paragraph

+

Second Paragraph

-

Third Options Paragraph

+

Third Paragraph

" `; diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index b12e10cc0e6bd..32b8a9142b44f 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -12,6 +12,27 @@ import { getAvailableBlockTransforms, } from '@wordpress/e2e-test-utils'; +async function insertBlocksOfSameType() { + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'First Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Second Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Third Paragraph' ); +} + +async function insertBlocksOfMultipleTypes() { + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + + await insertBlock( 'Image' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); +} + describe( 'Block Grouping', () => { beforeAll( async () => { await createNewPost(); @@ -29,14 +50,7 @@ describe( 'Block Grouping', () => { describe( 'Group creation', () => { it( 'creates a group from multiple blocks of the same type via block transforms', async () => { // Creating test blocks - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'First Paragraph' ); - - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Second Paragraph' ); - - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Third Paragraph' ); + await insertBlocksOfSameType(); // Multiselect via keyboard. await pressKeyWithModifier( 'primary', 'a' ); @@ -49,13 +63,7 @@ describe( 'Block Grouping', () => { it( 'creates a group from multiple blocks of different types via block transforms', async () => { // Creating test blocks - await insertBlock( 'Heading' ); - await page.keyboard.type( 'Group Heading' ); - - await insertBlock( 'Image' ); - - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Some paragraph' ); + await insertBlocksOfMultipleTypes(); // Multiselect via keyboard. await pressKeyWithModifier( 'primary', 'a' ); @@ -68,14 +76,7 @@ describe( 'Block Grouping', () => { it( 'creates a group from multiple blocks of the same type via options toolbar', async () => { // Creating test blocks - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'First Options Paragraph' ); - - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Second Options Paragraph' ); - - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Third Options Paragraph' ); + await insertBlocksOfSameType(); // Multiselect via keyboard. await pressKeyWithModifier( 'primary', 'a' ); @@ -91,13 +92,7 @@ describe( 'Block Grouping', () => { it( 'creates a group from multiple blocks of different types via options toolbar', async () => { // Creating test blocks - await insertBlock( 'Heading' ); - await page.keyboard.type( 'Group Heading' ); - - await insertBlock( 'Image' ); - - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Some paragraph' ); + await insertBlocksOfMultipleTypes(); // Multiselect via keyboard. await pressKeyWithModifier( 'primary', 'a' ); @@ -115,11 +110,7 @@ describe( 'Block Grouping', () => { describe( 'Ungrouping', () => { it( 'ungroups an existing group via options menu', async () => { // Create a Group - await insertBlock( 'Heading' ); - await page.keyboard.type( 'Group Heading' ); - await insertBlock( 'Image' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Some paragraph' ); + await insertBlocksOfMultipleTypes(); await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'a' ); await transformBlockTo( 'Group' ); @@ -136,11 +127,7 @@ describe( 'Block Grouping', () => { describe( 'Keyboard shortcuts', () => { it( 'groups using keyboard shortcut', async () => { - await insertBlock( 'Heading' ); - await page.keyboard.type( 'Group Heading' ); - await insertBlock( 'Image' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Some paragraph' ); + await insertBlocksOfMultipleTypes(); await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'a' ); await transformBlockTo( 'Group' ); @@ -156,11 +143,7 @@ describe( 'Block Grouping', () => { it( 'ungroups using keyboard shortcut', async () => { // Create a Group - await insertBlock( 'Heading' ); - await page.keyboard.type( 'Group Heading' ); - await insertBlock( 'Image' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Some paragraph' ); + await insertBlocksOfMultipleTypes(); await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'a' ); await transformBlockTo( 'Group' ); @@ -186,11 +169,7 @@ describe( 'Block Grouping', () => { beforeEach( async () => { // Create a Group - await insertBlock( 'Heading' ); - await page.keyboard.type( 'Group Heading' ); - await insertBlock( 'Image' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'Some paragraph' ); + await insertBlocksOfMultipleTypes(); await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'a' ); } ); From 2627694214de5a0ef53165fc7beee2b8071465a7 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 10 May 2019 08:59:05 +0200 Subject: [PATCH 25/76] Updates to simplify test setup Previously API calls were cleaning up blocks. This can be removed because all posts are auto removed before each test is run. Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r281445117 --- packages/e2e-tests/specs/block-grouping.test.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index 32b8a9142b44f..9cbad21f64a19 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -34,17 +34,9 @@ async function insertBlocksOfMultipleTypes() { } describe( 'Block Grouping', () => { - beforeAll( async () => { - await createNewPost(); - } ); - beforeEach( async () => { - // Remove all blocks from the post so that we're working with a clean slate - await page.evaluate( () => { - const blocks = wp.data.select( 'core/editor' ).getBlocks(); - const clientIds = blocks.map( ( block ) => block.clientId ); - wp.data.dispatch( 'core/editor' ).removeBlocks( clientIds ); - } ); + // Posts are auto-removed at the end of each test run + await createNewPost(); } ); describe( 'Group creation', () => { @@ -159,15 +151,13 @@ describe( 'Block Grouping', () => { } ); describe( 'Container Block availability', () => { - beforeAll( async () => { + beforeEach( async () => { // Disable the Group block await page.evaluate( () => { const { dispatch } = wp.data; dispatch( 'core/edit-post' ).hideBlockTypes( [ 'core/group' ] ); } ); - } ); - beforeEach( async () => { // Create a Group await insertBlocksOfMultipleTypes(); await pressKeyWithModifier( 'primary', 'a' ); From 29b5ed4da68f0f1724e05c4e377e5b9793215c36 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 10 May 2019 09:03:25 +0200 Subject: [PATCH 26/76] Updates to simplify test assertion Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r281452179 --- packages/e2e-tests/specs/block-grouping.test.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index 9cbad21f64a19..6b08add6a2ef1 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -177,9 +177,7 @@ describe( 'Block Grouping', () => { expect( availableTransforms - ).not.toEqual( expect.arrayContaining( [ - 'Group', - ] ) ); + ).not.toContain( 'Group' ); } ); it( 'does not show group option in the options toolbar if container block is disabled ', async () => { From fd257ff07d8c10e86d11002e3cb3cf8eae9f1933 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 10 May 2019 09:11:18 +0200 Subject: [PATCH 27/76] Combines test cases to simplify and reduce number of test required Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r281450978 --- .../__snapshots__/block-grouping.test.js.snap | 30 +++++++++++++++++++ .../e2e-tests/specs/block-grouping.test.js | 17 ++++------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap index bd383e9e52d28..7cf68a9190277 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -64,6 +64,36 @@ exports[`Block Grouping Group creation creates a group from multiple blocks of t " `; +exports[`Block Grouping Keyboard shortcuts groups and ungroups using keyboard shortcuts 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; + +exports[`Block Grouping Keyboard shortcuts groups and ungroups using keyboard shortcuts 2`] = ` +" +

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+" +`; + exports[`Block Grouping Keyboard shortcuts groups using keyboard shortcut 1`] = ` "
diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index 6b08add6a2ef1..31f791621f9e5 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -118,32 +118,25 @@ describe( 'Block Grouping', () => { } ); describe( 'Keyboard shortcuts', () => { - it( 'groups using keyboard shortcut', async () => { + it( 'groups and ungroups using keyboard shortcuts', async () => { + let allBlocks; + await insertBlocksOfMultipleTypes(); await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'a' ); - await transformBlockTo( 'Group' ); // Group await pressKeyWithModifier( 'primaryAlt', 'g' ); - const allBlocks = await getAllBlocks(); + allBlocks = await getAllBlocks(); expect( allBlocks[ 0 ].name ).toBe( 'core/group' ); expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - - it( 'ungroups using keyboard shortcut', async () => { - // Create a Group - await insertBlocksOfMultipleTypes(); - await pressKeyWithModifier( 'primary', 'a' ); - await pressKeyWithModifier( 'primary', 'a' ); - await transformBlockTo( 'Group' ); // Ungroup (Primary, Shift, Alt) await pressKeyWithModifier( 'secondary', 'g' ); - const allBlocks = await getAllBlocks(); + allBlocks = await getAllBlocks(); expect( allBlocks[ 0 ].name ).not.toBe( 'core/group' ); expect( await getEditedPostContent() ).toMatchSnapshot(); From 4bdce112128f84fa20bae2b99309b646288e4ba0 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 10 May 2019 09:15:50 +0200 Subject: [PATCH 28/76] Updates to combine test for grouping and ungrouping via options menu Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r281450690 --- .../__snapshots__/block-grouping.test.js.snap | 30 +++++++++++++++++++ .../e2e-tests/specs/block-grouping.test.js | 19 ++---------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap index 7cf68a9190277..7374a98e3f064 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -64,6 +64,36 @@ exports[`Block Grouping Group creation creates a group from multiple blocks of t " `; +exports[`Block Grouping Group creation groups and ungroups multiple blocks of different types via options toolbar 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; + +exports[`Block Grouping Group creation groups and ungroups multiple blocks of different types via options toolbar 2`] = ` +" +

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+" +`; + exports[`Block Grouping Keyboard shortcuts groups and ungroups using keyboard shortcuts 1`] = ` "
diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index 31f791621f9e5..1762e92a68747 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -82,35 +82,22 @@ describe( 'Block Grouping', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); - it( 'creates a group from multiple blocks of different types via options toolbar', async () => { + it( 'groups and ungroups multiple blocks of different types via options toolbar', async () => { // Creating test blocks await insertBlocksOfMultipleTypes(); - - // Multiselect via keyboard. await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'a' ); + // Group await clickBlockToolbarButton( 'More options' ); - const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); await groupButton.click(); expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - } ); - - describe( 'Ungrouping', () => { - it( 'ungroups an existing group via options menu', async () => { - // Create a Group - await insertBlocksOfMultipleTypes(); - await pressKeyWithModifier( 'primary', 'a' ); - await pressKeyWithModifier( 'primary', 'a' ); - await transformBlockTo( 'Group' ); + // UnGroup await clickBlockToolbarButton( 'More options' ); - const unGroupButton = await page.waitForXPath( '//button[text()="Ungroup"]' ); - await unGroupButton.click(); expect( await getEditedPostContent() ).toMatchSnapshot(); From 27143f99e804728119d58eccbaef66eaa962d626 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 15 May 2019 15:54:02 +0100 Subject: [PATCH 29/76] Adds keyboard shortcut to global keyboard shortcuts modal --- .../src/components/keyboard-shortcut-help-modal/config.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js index 5c6037c0467f4..e4cd3f24fbeef 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js @@ -118,6 +118,14 @@ const blockShortcuts = { /* translators: The forward-slash character. e.g. '/'. */ ariaLabel: __( 'Forward-slash' ), }, + { + keyCombination: primaryAlt( 'G' ), + description: __( 'Group the selected blocks.' ), + }, + { + keyCombination: secondary( 'G' ), + description: __( 'Ungroup the selected blocks.' ), + }, ], }; From 77a4268d8b0dfa72372006afb00f42edfad14b4f Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 15 May 2019 16:12:42 +0100 Subject: [PATCH 30/76] Ensure correct case for group shortcut (ie: lower) --- .../src/components/keyboard-shortcut-help-modal/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js index e4cd3f24fbeef..0a1f4f489a0f2 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js @@ -119,11 +119,11 @@ const blockShortcuts = { ariaLabel: __( 'Forward-slash' ), }, { - keyCombination: primaryAlt( 'G' ), + keyCombination: primaryAlt( 'g' ), description: __( 'Group the selected blocks.' ), }, { - keyCombination: secondary( 'G' ), + keyCombination: secondary( 'g' ), description: __( 'Ungroup the selected blocks.' ), }, ], From 2ef8e039dd7899f69ffb92f31e4348ac085df3d2 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 15 May 2019 16:13:06 +0100 Subject: [PATCH 31/76] Add shortcut to Block settings menu dropdown items --- .../src/components/convert-to-group-buttons/convert-button.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index 360f6aea2a8fe..da1e5f645881f 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -12,6 +12,7 @@ import { __ } from '@wordpress/i18n'; import { switchToBlockType } from '@wordpress/blocks'; import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; +import { displayShortcut } from '@wordpress/keycodes'; /** * Internal dependencies @@ -31,6 +32,7 @@ export function ConvertToGroupButton( { className="editor-block-settings-menu__control block-editor-block-settings-menu__control" icon={ Group } onClick={ onConvertToGroup } + shortcut={ displayShortcut.primaryAlt( 'g' ) } > { __( 'Group' ) } @@ -40,6 +42,7 @@ export function ConvertToGroupButton( { className="editor-block-settings-menu__control block-editor-block-settings-menu__control" icon={ UnGroup } onClick={ onUnCovertFromGroup } + shortcut={ displayShortcut.secondary( 'g' ) } > { __( 'Ungroup' ) } From 2c8adfd51dd83586e0a5cd192cf60439f49f1105 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 16 May 2019 09:26:35 +0100 Subject: [PATCH 32/76] Adds translation context to Group actions in menus Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r283683456 --- .../components/convert-to-group-buttons/convert-button.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index da1e5f645881f..a721503d9e877 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -8,7 +8,7 @@ import { noop } from 'lodash'; */ import { Fragment } from '@wordpress/element'; import { MenuItem } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; +import { _x } from '@wordpress/i18n'; import { switchToBlockType } from '@wordpress/blocks'; import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; @@ -34,7 +34,7 @@ export function ConvertToGroupButton( { onClick={ onConvertToGroup } shortcut={ displayShortcut.primaryAlt( 'g' ) } > - { __( 'Group' ) } + { _x( 'Group', 'Grouping a selection of blocks together within the Editor' ) } ) } { isUnGroupable && ( @@ -44,7 +44,7 @@ export function ConvertToGroupButton( { onClick={ onUnCovertFromGroup } shortcut={ displayShortcut.secondary( 'g' ) } > - { __( 'Ungroup' ) } + { _x( 'Ungroup', 'Ungrouping blocks from within a Group block back into individual blocks within the Editor ' ) } ) } From 96c11bab56a65608af10a4f5134f85bfa2fbc86a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 16 May 2019 14:09:22 +0100 Subject: [PATCH 33/76] Update Block Transforms fixtures to show all Blocks can transform to Group Block --- .../e2e-tests/fixtures/block-transforms.js | 138 ++++- .../block-transforms.test.js.snap | 510 ++++++++++++++++++ 2 files changed, 622 insertions(+), 26 deletions(-) diff --git a/packages/e2e-tests/fixtures/block-transforms.js b/packages/e2e-tests/fixtures/block-transforms.js index 79d4d7bc80456..913953d69d2b3 100644 --- a/packages/e2e-tests/fixtures/block-transforms.js +++ b/packages/e2e-tests/fixtures/block-transforms.js @@ -1,131 +1,166 @@ export const EXPECTED_TRANSFORMS = { core__archives: { originalBlock: 'Archives', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__archives__showPostCounts: { originalBlock: 'Archives', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__audio: { originalBlock: 'Audio', availableTransforms: [ 'File', + 'Group', ], }, core__button__center: { originalBlock: 'Button', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__calendar: { originalBlock: 'Calendar', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__media-text': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__image-alt-no-align': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__image-fill-no-focal-point-selected': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__image-fill-with-focal-point-selected': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__is-stacked-on-mobile': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Video', ], }, 'core__media-text__media-right-custom-width': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Video', ], }, 'core__media-text__vertical-align-bottom': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__video': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Video', ], }, core__categories: { originalBlock: 'Categories', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__code: { originalBlock: 'Code', availableTransforms: [ + 'Group', 'Preformatted', ], }, core__columns: { originalBlock: 'Columns', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__cover: { availableTransforms: [ + 'Group', 'Image', ], originalBlock: 'Cover', }, core__cover__video: { availableTransforms: [ + 'Group', 'Video', ], originalBlock: 'Cover', }, 'core__cover__video-overlay': { availableTransforms: [ + 'Group', 'Video', ], originalBlock: 'Cover', }, core__embed: { originalBlock: 'Embed', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__file__new-window': { originalBlock: 'File', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__file__no-download-button': { originalBlock: 'File', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__file__no-text-link': { originalBlock: 'File', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__gallery: { originalBlock: 'Gallery', availableTransforms: [ + 'Group', 'Image', ], }, core__gallery__columns: { originalBlock: 'Gallery', availableTransforms: [ + 'Group', 'Image', ], }, @@ -137,6 +172,7 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Heading', availableTransforms: [ 'Quote', + 'Group', 'Paragraph', ], }, @@ -144,12 +180,15 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Heading', availableTransforms: [ 'Quote', + 'Group', 'Paragraph', ], }, core__html: { originalBlock: 'Custom HTML', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__image: { originalBlock: 'Image', @@ -157,6 +196,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -166,6 +206,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -175,6 +216,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -184,6 +226,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -193,6 +236,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -202,6 +246,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -211,43 +256,59 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, 'core__latest-comments': { originalBlock: 'Latest Comments', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__latest-posts': { originalBlock: 'Latest Posts', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__latest-posts__displayPostDate': { originalBlock: 'Latest Posts', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__legacy-widget': { originalBlock: 'Legacy Widget (Experimental)', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__list__ul: { originalBlock: 'List', availableTransforms: [ + 'Group', 'Paragraph', 'Quote', ], }, core__more: { originalBlock: 'More', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__more__custom-text-teaser': { originalBlock: 'More', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__nextpage: { originalBlock: 'Page Break', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__paragraph__align-right': { originalBlock: 'Paragraph', @@ -255,6 +316,7 @@ export const EXPECTED_TRANSFORMS = { 'Heading', 'List', 'Quote', + 'Group', 'Preformatted', 'Verse', ], @@ -262,6 +324,7 @@ export const EXPECTED_TRANSFORMS = { core__preformatted: { originalBlock: 'Preformatted', availableTransforms: [ + 'Group', 'Paragraph', ], }, @@ -269,18 +332,21 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Pullquote', availableTransforms: [ 'Quote', + 'Group', ], }, 'core__pullquote__multi-paragraph': { originalBlock: 'Pullquote', availableTransforms: [ 'Quote', + 'Group', ], }, 'core__quote__style-1': { originalBlock: 'Quote', availableTransforms: [ 'List', + 'Group', 'Paragraph', 'Heading', 'Pullquote', @@ -290,6 +356,7 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Quote', availableTransforms: [ 'List', + 'Group', 'Paragraph', 'Heading', 'Pullquote', @@ -297,44 +364,62 @@ export const EXPECTED_TRANSFORMS = { }, core__rss: { originalBlock: 'RSS', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__search: { originalBlock: 'Search', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__search__custom-text': { originalBlock: 'Search', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__separator: { originalBlock: 'Separator', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__shortcode: { originalBlock: 'Shortcode', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__spacer: { originalBlock: 'Spacer', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__table: { originalBlock: 'Table', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__tag-cloud': { originalBlock: 'Tag Cloud', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__tag-cloud__showTagCounts': { originalBlock: 'Tag Cloud', availableTransforms: [ + 'Group', ], }, core__verse: { originalBlock: 'Verse', availableTransforms: [ + 'Group', 'Paragraph', ], }, @@ -343,6 +428,7 @@ export const EXPECTED_TRANSFORMS = { availableTransforms: [ 'Cover', 'File', + 'Group', 'Media & Text', ], }, diff --git a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap index ce9dfc0be7e55..2bea6f2fde236 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap @@ -1,11 +1,61 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Block transforms correctly transform block Archives in fixture core__archives into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Archives in fixture core__archives__showPostCounts into the Group block 1`] = ` +" +
+" +`; + exports[`Block transforms correctly transform block Audio in fixture core__audio into the File block 1`] = ` " " `; +exports[`Block transforms correctly transform block Audio in fixture core__audio into the Group block 1`] = ` +" +
+
+
+" +`; + +exports[`Block transforms correctly transform block Button in fixture core__button__center into the Group block 1`] = ` +" + +" +`; + +exports[`Block transforms correctly transform block Calendar in fixture core__calendar into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Categories in fixture core__categories into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Code in fixture core__code into the Group block 1`] = ` +" +
+
export default function MyButton() {
+	return <Button>Click Me!</Button>;
+}
+
+" +`; + exports[`Block transforms correctly transform block Code in fixture core__code into the Preformatted block 1`] = ` "
export default function MyButton() {
@@ -14,24 +64,141 @@ exports[`Block transforms correctly transform block Code in fixture core__code i
 "
 `;
 
+exports[`Block transforms correctly transform block Columns in fixture core__columns into the Group block 1`] = `
+"
+
+
+
+

Column One, Paragraph One

+ + + +

Column One, Paragraph Two

+
+ + + +
+

Column Two, Paragraph One

+ + + +

Column Three, Paragraph One

+
+ + + +
+
+
+" +`; + +exports[`Block transforms correctly transform block Cover in fixture core__cover into the Group block 1`] = ` +" +
+
+

+ Guten Berg! +

+
+
+" +`; + exports[`Block transforms correctly transform block Cover in fixture core__cover into the Image block 1`] = ` "
\\"\\"/
" `; +exports[`Block transforms correctly transform block Cover in fixture core__cover__video into the Group block 1`] = ` +" +
+
+

+ Guten Berg! +

+
+
+" +`; + exports[`Block transforms correctly transform block Cover in fixture core__cover__video into the Video block 1`] = ` "
" `; +exports[`Block transforms correctly transform block Cover in fixture core__cover__video-overlay into the Group block 1`] = ` +" +
+
+

+ Guten Berg! +

+
+
+" +`; + exports[`Block transforms correctly transform block Cover in fixture core__cover__video-overlay into the Video block 1`] = ` "
" `; +exports[`Block transforms correctly transform block Custom HTML in fixture core__html into the Group block 1`] = ` +" +
+

Some HTML code

+This text will scroll from right to left +
+" +`; + +exports[`Block transforms correctly transform block Embed in fixture core__embed into the Group block 1`] = ` +" +
+
+https://example.com/ +
Embedded content from an example URL
+
+" +`; + +exports[`Block transforms correctly transform block File in fixture core__file__new-window into the Group block 1`] = ` +" + +" +`; + +exports[`Block transforms correctly transform block File in fixture core__file__no-download-button into the Group block 1`] = ` +" + +" +`; + +exports[`Block transforms correctly transform block File in fixture core__file__no-text-link into the Group block 1`] = ` +" + +" +`; + +exports[`Block transforms correctly transform block Gallery in fixture core__gallery into the Group block 1`] = ` +" +
+ +
+" +`; + exports[`Block transforms correctly transform block Gallery in fixture core__gallery into the Image block 1`] = ` "
\\"title\\"/
@@ -42,6 +209,14 @@ exports[`Block transforms correctly transform block Gallery in fixture core__gal " `; +exports[`Block transforms correctly transform block Gallery in fixture core__gallery__columns into the Group block 1`] = ` +" +
+ +
+" +`; + exports[`Block transforms correctly transform block Gallery in fixture core__gallery__columns into the Image block 1`] = ` "
\\"title\\"/
@@ -52,6 +227,14 @@ exports[`Block transforms correctly transform block Gallery in fixture core__gal " `; +exports[`Block transforms correctly transform block Heading in fixture core__heading__h2 into the Group block 1`] = ` +" +
+

A picture is worth a thousand words, or so the saying goes

+
+" +`; + exports[`Block transforms correctly transform block Heading in fixture core__heading__h2 into the Paragraph block 1`] = ` "

A picture is worth a thousand words, or so the saying goes

@@ -64,6 +247,14 @@ exports[`Block transforms correctly transform block Heading in fixture core__hea " `; +exports[`Block transforms correctly transform block Heading in fixture core__heading__h2-em into the Group block 1`] = ` +" +
+

The Inserter Tool

+
+" +`; + exports[`Block transforms correctly transform block Heading in fixture core__heading__h2-em into the Paragraph block 1`] = ` "

The Inserter Tool

@@ -96,6 +287,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image into the Group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image into the Media & Text block 1`] = ` "
\\"\\"/
@@ -124,6 +323,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image__attachment-link into the Group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image__attachment-link into the Media & Text block 1`] = ` "
\\"\\"/
@@ -152,6 +359,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image__center-caption into the Group block 1`] = ` +" +
+
\\"\\"/
Give it a try. Press the \\"really wide\\" button on the image toolbar.
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image__center-caption into the Media & Text block 1`] = ` "
\\"\\"/
@@ -180,6 +395,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image__custom-link into the Group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image__custom-link into the Media & Text block 1`] = ` "
\\"\\"/
@@ -208,6 +431,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image__custom-link-class into the Group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image__custom-link-class into the Media & Text block 1`] = ` "
\\"\\"/
@@ -236,6 +467,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image__custom-link-rel into the Group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image__custom-link-rel into the Media & Text block 1`] = ` "
\\"\\"/
@@ -264,6 +503,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image__media-link into the Group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image__media-link into the Media & Text block 1`] = ` "
\\"\\"/
@@ -272,6 +519,38 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Latest Comments in fixture core__latest-comments into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Latest Posts in fixture core__latest-posts into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Latest Posts in fixture core__latest-posts__displayPostDate into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Legacy Widget (Experimental) in fixture core__legacy-widget into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block List in fixture core__list__ul into the Group block 1`] = ` +" +
+
  • Text & Headings
  • Images & Videos
  • Galleries
  • Embeds, like YouTube, Tweets, or other WordPress posts.
  • Layout blocks, like Buttons, Hero Images, Separators, etc.
  • And Lists like this one of course :)
+
+" +`; + exports[`Block transforms correctly transform block List in fixture core__list__ul into the Paragraph block 1`] = ` "

Text & Headings

@@ -304,54 +583,167 @@ exports[`Block transforms correctly transform block List in fixture core__list__ " `; +exports[`Block transforms correctly transform block Media & Text in fixture core__media-text into the Group block 1`] = ` +" +
+
\\"\\"/
+

My Content

+
+
+" +`; + exports[`Block transforms correctly transform block Media & Text in fixture core__media-text into the Image block 1`] = ` "
\\"\\"/
" `; +exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-alt-no-align into the Group block 1`] = ` +" +
+
\\"my
+

Content

+
+
+" +`; + exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-alt-no-align into the Image block 1`] = ` "
\\"my
" `; +exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-fill-no-focal-point-selected into the Group block 1`] = ` +" +
+
\\"My
+

My Content

+
+
+" +`; + exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-fill-no-focal-point-selected into the Image block 1`] = ` "
\\"My
" `; +exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-fill-with-focal-point-selected into the Group block 1`] = ` +" +
+
\\"My
+

My Content

+
+
+" +`; + exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-fill-with-focal-point-selected into the Image block 1`] = ` "
\\"My
" `; +exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__is-stacked-on-mobile into the Group block 1`] = ` +" +
+
+

My Content

+
+
+" +`; + exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__is-stacked-on-mobile into the Video block 1`] = ` "
" `; +exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__media-right-custom-width into the Group block 1`] = ` +" +
+
+

My video

+
+
+" +`; + exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__media-right-custom-width into the Video block 1`] = ` "
" `; +exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__vertical-align-bottom into the Group block 1`] = ` +" +
+
\\"My
+

My content

+
+
+" +`; + exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__vertical-align-bottom into the Image block 1`] = ` "
\\"My
" `; +exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__video into the Group block 1`] = ` +" +
+
+

My Content

+
+
+" +`; + exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__video into the Video block 1`] = ` "
" `; +exports[`Block transforms correctly transform block More in fixture core__more into the Group block 1`] = ` +" +
+ +
+" +`; + +exports[`Block transforms correctly transform block More in fixture core__more__custom-text-teaser into the Group block 1`] = ` +" +
+ + +
+" +`; + +exports[`Block transforms correctly transform block Page Break in fixture core__nextpage into the Group block 1`] = ` +" +
+ +
+" +`; + +exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the Group block 1`] = ` +" +
+

... like this one, which is separate from the above and right aligned.

+
+" +`; + exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the Heading block 1`] = ` "

... like this one, which is separate from the above and right aligned.

@@ -382,24 +774,56 @@ exports[`Block transforms correctly transform block Paragraph in fixture core__p " `; +exports[`Block transforms correctly transform block Preformatted in fixture core__preformatted into the Group block 1`] = ` +" +
+
Some preformatted text...
And more!
+
+" +`; + exports[`Block transforms correctly transform block Preformatted in fixture core__preformatted into the Paragraph block 1`] = ` "

Some preformatted text...
And more!

" `; +exports[`Block transforms correctly transform block Pullquote in fixture core__pullquote into the Group block 1`] = ` +" +
+

Testing pullquote block...

...with a caption
+
+" +`; + exports[`Block transforms correctly transform block Pullquote in fixture core__pullquote into the Quote block 1`] = ` "

Testing pullquote block...

...with a caption
" `; +exports[`Block transforms correctly transform block Pullquote in fixture core__pullquote__multi-paragraph into the Group block 1`] = ` +" +
+

Paragraph one

Paragraph two

by whomever
+
+" +`; + exports[`Block transforms correctly transform block Pullquote in fixture core__pullquote__multi-paragraph into the Quote block 1`] = ` "

Paragraph one

Paragraph two

by whomever
" `; +exports[`Block transforms correctly transform block Quote in fixture core__quote__style-1 into the Group block 1`] = ` +" +
+

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

Matt Mullenweg, 2017
+
+" +`; + exports[`Block transforms correctly transform block Quote in fixture core__quote__style-1 into the Heading block 1`] = ` "

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

@@ -432,6 +856,14 @@ exports[`Block transforms correctly transform block Quote in fixture core__quote " `; +exports[`Block transforms correctly transform block Quote in fixture core__quote__style-2 into the Group block 1`] = ` +" +
+

There is no greater agony than bearing an untold story inside you.

Maya Angelou
+
+" +`; + exports[`Block transforms correctly transform block Quote in fixture core__quote__style-2 into the Heading block 1`] = ` "

There is no greater agony than bearing an untold story inside you.

@@ -464,6 +896,76 @@ exports[`Block transforms correctly transform block Quote in fixture core__quote " `; +exports[`Block transforms correctly transform block RSS in fixture core__rss into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Search in fixture core__search into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Search in fixture core__search__custom-text into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Separator in fixture core__separator into the Group block 1`] = ` +" +
+
+
+" +`; + +exports[`Block transforms correctly transform block Shortcode in fixture core__shortcode into the Group block 1`] = ` +" +
+[gallery ids=\\"238,338\\"] +
+" +`; + +exports[`Block transforms correctly transform block Spacer in fixture core__spacer into the Group block 1`] = ` +" +
+
+
+" +`; + +exports[`Block transforms correctly transform block Table in fixture core__table into the Group block 1`] = ` +" +
+
VersionMusicianDate
.70No musician chosen.May 27, 2003
1.0Miles DavisJanuary 3, 2004
Lots of versions skipped, see the full list
4.4Clifford BrownDecember 8, 2015
4.5Coleman HawkinsApril 12, 2016
4.6Pepper AdamsAugust 16, 2016
4.7Sarah VaughanDecember 6, 2016
+
+" +`; + +exports[`Block transforms correctly transform block Tag Cloud in fixture core__tag-cloud into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Tag Cloud in fixture core__tag-cloud__showTagCounts into the Group block 1`] = ` +" +
+" +`; + +exports[`Block transforms correctly transform block Verse in fixture core__verse into the Group block 1`] = ` +" +
+
A verse
And more!
+
+" +`; + exports[`Block transforms correctly transform block Verse in fixture core__verse into the Paragraph block 1`] = ` "

A verse
And more!

@@ -484,6 +986,14 @@ exports[`Block transforms correctly transform block Video in fixture core__video " `; +exports[`Block transforms correctly transform block Video in fixture core__video into the Group block 1`] = ` +" +
+
+
+" +`; + exports[`Block transforms correctly transform block Video in fixture core__video into the Media & Text block 1`] = ` "
From 607404e3d6287560f1d905e0b99375d74f1d01dd Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 16 May 2019 14:16:17 +0100 Subject: [PATCH 34/76] Updates Keyboard Shortcut test snapshot to include Group/UnGroup --- .../test/__snapshots__/index.js.snap | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap index fe522a985d3b9..a3424e31727b5 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap @@ -211,6 +211,28 @@ exports[`KeyboardShortcutHelpModal should match snapshot when the modal is activ "description": "Change the block type after adding a new paragraph.", "keyCombination": "/", }, + Object { + "description": "Group the selected blocks.", + "keyCombination": Array [ + "Ctrl", + "+", + "Alt", + "+", + "G", + ], + }, + Object { + "description": "Ungroup the selected blocks.", + "keyCombination": Array [ + "Ctrl", + "+", + "Shift", + "+", + "Alt", + "+", + "G", + ], + }, ] } title="Block shortcuts" From 2328b54f6f0af34d765f48a03dd0746d0aa31e0b Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 16 May 2019 14:21:11 +0100 Subject: [PATCH 35/76] Fix to ensure Group block accounted for --- packages/e2e-tests/specs/block-switcher.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/e2e-tests/specs/block-switcher.test.js b/packages/e2e-tests/specs/block-switcher.test.js index 0d2fcf2adfe9e..9282e83dc855f 100644 --- a/packages/e2e-tests/specs/block-switcher.test.js +++ b/packages/e2e-tests/specs/block-switcher.test.js @@ -27,6 +27,7 @@ describe( 'adding blocks', () => { expect( await getAvailableBlockTransforms() ).toEqual( [ + 'Group', 'Paragraph', 'Quote', ] ); @@ -50,6 +51,7 @@ describe( 'adding blocks', () => { expect( await getAvailableBlockTransforms() ).toEqual( [ + 'Group', 'Paragraph', ] ); } ); @@ -60,6 +62,7 @@ describe( 'adding blocks', () => { ( [ 'core/quote', 'core/paragraph', + 'core/group', ] ).map( ( block ) => wp.blocks.unregisterBlockType( block ) ); } ); From a99d98f6bf61a2a3e50ce753351be988f301af39 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 16 May 2019 15:02:46 +0100 Subject: [PATCH 36/76] Fix Block deletion test failure via keyboard workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to the addition of the “Group” item into the Block Options toolbar the “Remove Block” item had been removed outside the viewable portion of the Popover (not the popover has a restricted height and allows scrolling to see the additional items if there is insufficient space to display them all). Pupeteer isn’t able to click on items that are not visible. The simplest work around is to us the keyboard to select the “Remove Block” menu item rather. Trying to scroll a div within Pupeteer is fraught with problems and inconsistencies. --- .../e2e-tests/specs/block-deletion.test.js | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/e2e-tests/specs/block-deletion.test.js b/packages/e2e-tests/specs/block-deletion.test.js index 194ff847328c1..48a0220ee2265 100644 --- a/packages/e2e-tests/specs/block-deletion.test.js +++ b/packages/e2e-tests/specs/block-deletion.test.js @@ -8,7 +8,8 @@ import { createNewPost, isInDefaultBlock, pressKeyWithModifier, - insertBlock, + pressKeyTimes, + clickBlockToolbarButton, } from '@wordpress/e2e-test-utils'; const addThreeParagraphsToNewPost = async () => { @@ -22,10 +23,17 @@ const addThreeParagraphsToNewPost = async () => { await page.keyboard.press( 'Enter' ); }; -const clickOnBlockSettingsMenuItem = async ( buttonLabel ) => { +/** + * Note Puppeteer has a problem clicking on items in the Popover that require + * scrolling the Popover to be visible. To work around this we use the keyboard + * to select the "Remove Block" button + */ +const clickOnBlockSettingsMenuRemoveBlockButton = async () => { await clickBlockToolbarButton( 'More options' ); - const itemButton = ( await page.$x( `//*[contains(@class, "block-editor-block-settings-menu__popover")]//button[contains(text(), '${ buttonLabel }')]` ) )[ 0 ]; - await itemButton.click(); + + await pressKeyTimes( 'Tab', 7 ); + + await pressKeyTimes( 'Enter', 1 ); }; describe( 'block deletion -', () => { @@ -39,7 +47,8 @@ describe( 'block deletion -', () => { // Press Escape to show the block toolbar await page.keyboard.press( 'Escape' ); - await clickOnBlockSettingsMenuItem( 'Remove Block' ); + await clickOnBlockSettingsMenuRemoveBlockButton(); + expect( await getEditedPostContent() ).toMatchSnapshot(); // Type additional text and assert that caret position is correct by comparing to snapshot. @@ -121,7 +130,7 @@ describe( 'deleting all blocks', () => { await page.keyboard.press( 'Escape' ); - await clickOnBlockSettingsMenuItem( 'Remove Block' ); + await clickOnBlockSettingsMenuRemoveBlockButton(); // There is a default block: expect( await page.$$( '.block-editor-block-list__block' ) ).toHaveLength( 1 ); From 0f51ec5ced5b7a0cdcddf02e48fb4f8cdec3e867 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 22 May 2019 09:48:30 +0100 Subject: [PATCH 37/76] Fixes Remove Block button helper to be more resilient to change Previously we relied on the number of tab stops to locate the correct button in the menu. This change uses the actual text of the button to identify it and uses an assertion to ensure that the correct button is explicitly required. --- .../e2e-tests/specs/block-deletion.test.js | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/e2e-tests/specs/block-deletion.test.js b/packages/e2e-tests/specs/block-deletion.test.js index 48a0220ee2265..fb5fd2b357140 100644 --- a/packages/e2e-tests/specs/block-deletion.test.js +++ b/packages/e2e-tests/specs/block-deletion.test.js @@ -24,14 +24,26 @@ const addThreeParagraphsToNewPost = async () => { }; /** - * Note Puppeteer has a problem clicking on items in the Popover that require - * scrolling the Popover to be visible. To work around this we use the keyboard - * to select the "Remove Block" button + * Due to an issue with the Popover component not being scrollable + * under certain conditions, Pupeteer cannot "see" the "Remove Block" + * button. This is a workaround until that issue is resolved. + * + * see: https://github.com/WordPress/gutenberg/pull/14908#discussion_r284725956 */ const clickOnBlockSettingsMenuRemoveBlockButton = async () => { + let isRemoveButton = false; + await clickBlockToolbarButton( 'More options' ); - await pressKeyTimes( 'Tab', 7 ); + while ( false === isRemoveButton ) { + await page.keyboard.press( 'Tab' ); + + isRemoveButton = await page.evaluate( () => { + return document.activeElement.innerText.includes( 'Remove Block' ); + } ); + } + + await expect( isRemoveButton ).toBe( true ); await pressKeyTimes( 'Enter', 1 ); }; From 7b95fabb3faf813585eb0a22878d89d2ba539141 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 22 May 2019 09:57:11 +0100 Subject: [PATCH 38/76] Rename function to better convey intent Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r286106077 --- .../components/convert-to-group-buttons/convert-button.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index a721503d9e877..c6cdd15470c95 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -21,7 +21,7 @@ import { Group, UnGroup } from './icons'; export function ConvertToGroupButton( { onConvertToGroup, - onUnCovertFromGroup, + onConvertFromGroup, isGroupable = false, isUnGroupable = false, } ) { @@ -41,7 +41,7 @@ export function ConvertToGroupButton( { { _x( 'Ungroup', 'Ungrouping blocks from within a Group block back into individual blocks within the Editor ' ) } @@ -107,7 +107,7 @@ export default compose( [ onToggle(); }, - onUnCovertFromGroup() { + onConvertFromGroup() { if ( ! blocksSelection.length ) { return; } From 1ba77c01dece33d2ab5e772491e6a1c265b6e61e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 22 May 2019 10:23:39 +0100 Subject: [PATCH 39/76] Fixes to catch transforms which are invalid for blocks of different types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A check was accidentally removed in `b2af0f2611e2a2bc66c62959dbf483abcbe103a9` which allowed multiple blocks of different types to be considered valid even if they were not. Adds conditional to ensure that unless the transform is a wildcard then we test that all the blocks are of the same type as the first block’s type before considering the transform to be valid. --- packages/blocks/src/api/factory.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index e6ab0f8e7fd88..bf01a02d4aefd 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -120,11 +120,18 @@ const isPossibleTransformForSource = ( transform, direction, blocks ) => { // If multiple blocks are selected, only multi block transforms // or wildcard transforms are allowed. const isMultiBlock = blocks.length > 1; + const firstBlockName = first( blocks ).name; const isValidForMultiBlocks = isWildCardBlockTransform( transform ) || ! isMultiBlock || transform.isMultiBlock; if ( ! isValidForMultiBlocks ) { return false; } + // Check non-wildcard transforms to ensure that transform is valid + // for a block selection of multiple blocks of different types + if ( ! isWildCardBlockTransform( transform ) && ! every( blocks, { name: firstBlockName } ) ) { + return false; + } + // Only consider 'block' type transforms as valid. const isBlockType = transform.type === 'block'; if ( ! isBlockType ) { From 6d2d3d7ddff8503c255d4aee58eed7c0ed4f54f1 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 22 May 2019 10:23:59 +0100 Subject: [PATCH 40/76] Removes redundant snapshots --- .../__snapshots__/block-grouping.test.js.snap | 60 ------------------- 1 file changed, 60 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap index 7374a98e3f064..857ab92d84c1a 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -16,22 +16,6 @@ exports[`Block Grouping Group creation creates a group from multiple blocks of d " `; -exports[`Block Grouping Group creation creates a group from multiple blocks of different types via options toolbar 1`] = ` -" -
-

Group Heading

- - - -
\\"\\"/
- - - -

Some paragraph

-
-" -`; - exports[`Block Grouping Group creation creates a group from multiple blocks of the same type via block transforms 1`] = ` "
@@ -124,36 +108,6 @@ exports[`Block Grouping Keyboard shortcuts groups and ungroups using keyboard sh " `; -exports[`Block Grouping Keyboard shortcuts groups using keyboard shortcut 1`] = ` -" -
-

Group Heading

- - - -
\\"\\"/
- - - -

Some paragraph

-
-" -`; - -exports[`Block Grouping Keyboard shortcuts ungroups using keyboard shortcut 1`] = ` -" -

Group Heading

- - - -
\\"\\"/
- - - -

Some paragraph

-" -`; - exports[`Block Grouping Preserving selected blocks attributes preserves width alignment settings of selected blocks 1`] = ` "
@@ -173,17 +127,3 @@ exports[`Block Grouping Preserving selected blocks attributes preserves width al
" `; - -exports[`Block Grouping Ungrouping ungroups an existing group via options menu 1`] = ` -" -

Group Heading

- - - -
\\"\\"/
- - - -

Some paragraph

-" -`; From 7328bbf593cf5159660991be43734ec59681e5b4 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 24 May 2019 10:24:12 +0100 Subject: [PATCH 41/76] Fixes Transforms test to not over-test Group transforms Previously we tested every block transforming into the Group Block. This was unwanted overhead. Fixed to only test 1 single Block transforming into Group. Removed redundant snapshots as a result of removing it. --- .../block-transforms.test.js.snap | 516 +----------------- .../e2e-tests/specs/block-transforms.test.js | 21 +- 2 files changed, 26 insertions(+), 511 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap index 2bea6f2fde236..6750503d68575 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap @@ -1,61 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Block transforms correctly transform block Archives in fixture core__archives into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Archives in fixture core__archives__showPostCounts into the Group block 1`] = ` -" -
-" -`; - exports[`Block transforms correctly transform block Audio in fixture core__audio into the File block 1`] = ` " " `; -exports[`Block transforms correctly transform block Audio in fixture core__audio into the Group block 1`] = ` -" -
-
-
-" -`; - -exports[`Block transforms correctly transform block Button in fixture core__button__center into the Group block 1`] = ` -" - -" -`; - -exports[`Block transforms correctly transform block Calendar in fixture core__calendar into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Categories in fixture core__categories into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Code in fixture core__code into the Group block 1`] = ` -" -
-
export default function MyButton() {
-	return <Button>Click Me!</Button>;
-}
-
-" -`; - exports[`Block transforms correctly transform block Code in fixture core__code into the Preformatted block 1`] = ` "
export default function MyButton() {
@@ -64,141 +14,24 @@ exports[`Block transforms correctly transform block Code in fixture core__code i
 "
 `;
 
-exports[`Block transforms correctly transform block Columns in fixture core__columns into the Group block 1`] = `
-"
-
-
-
-

Column One, Paragraph One

- - - -

Column One, Paragraph Two

-
- - - -
-

Column Two, Paragraph One

- - - -

Column Three, Paragraph One

-
- - - -
-
-
-" -`; - -exports[`Block transforms correctly transform block Cover in fixture core__cover into the Group block 1`] = ` -" -
-
-

- Guten Berg! -

-
-
-" -`; - exports[`Block transforms correctly transform block Cover in fixture core__cover into the Image block 1`] = ` "
\\"\\"/
" `; -exports[`Block transforms correctly transform block Cover in fixture core__cover__video into the Group block 1`] = ` -" -
-
-

- Guten Berg! -

-
-
-" -`; - exports[`Block transforms correctly transform block Cover in fixture core__cover__video into the Video block 1`] = ` "
" `; -exports[`Block transforms correctly transform block Cover in fixture core__cover__video-overlay into the Group block 1`] = ` -" -
-
-

- Guten Berg! -

-
-
-" -`; - exports[`Block transforms correctly transform block Cover in fixture core__cover__video-overlay into the Video block 1`] = ` "
" `; -exports[`Block transforms correctly transform block Custom HTML in fixture core__html into the Group block 1`] = ` -" -
-

Some HTML code

-This text will scroll from right to left -
-" -`; - -exports[`Block transforms correctly transform block Embed in fixture core__embed into the Group block 1`] = ` -" -
-
-https://example.com/ -
Embedded content from an example URL
-
-" -`; - -exports[`Block transforms correctly transform block File in fixture core__file__new-window into the Group block 1`] = ` -" - -" -`; - -exports[`Block transforms correctly transform block File in fixture core__file__no-download-button into the Group block 1`] = ` -" - -" -`; - -exports[`Block transforms correctly transform block File in fixture core__file__no-text-link into the Group block 1`] = ` -" - -" -`; - -exports[`Block transforms correctly transform block Gallery in fixture core__gallery into the Group block 1`] = ` -" -
- -
-" -`; - exports[`Block transforms correctly transform block Gallery in fixture core__gallery into the Image block 1`] = ` "
\\"title\\"/
@@ -209,14 +42,6 @@ exports[`Block transforms correctly transform block Gallery in fixture core__gal " `; -exports[`Block transforms correctly transform block Gallery in fixture core__gallery__columns into the Group block 1`] = ` -" -
- -
-" -`; - exports[`Block transforms correctly transform block Gallery in fixture core__gallery__columns into the Image block 1`] = ` "
\\"title\\"/
@@ -227,14 +52,6 @@ exports[`Block transforms correctly transform block Gallery in fixture core__gal " `; -exports[`Block transforms correctly transform block Heading in fixture core__heading__h2 into the Group block 1`] = ` -" -
-

A picture is worth a thousand words, or so the saying goes

-
-" -`; - exports[`Block transforms correctly transform block Heading in fixture core__heading__h2 into the Paragraph block 1`] = ` "

A picture is worth a thousand words, or so the saying goes

@@ -247,14 +64,6 @@ exports[`Block transforms correctly transform block Heading in fixture core__hea " `; -exports[`Block transforms correctly transform block Heading in fixture core__heading__h2-em into the Group block 1`] = ` -" -
-

The Inserter Tool

-
-" -`; - exports[`Block transforms correctly transform block Heading in fixture core__heading__h2-em into the Paragraph block 1`] = ` "

The Inserter Tool

@@ -287,14 +96,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Image in fixture core__image into the Group block 1`] = ` -" -
-
\\"\\"/
-
-" -`; - exports[`Block transforms correctly transform block Image in fixture core__image into the Media & Text block 1`] = ` "
\\"\\"/
@@ -323,14 +124,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Image in fixture core__image__attachment-link into the Group block 1`] = ` -" -
-
\\"\\"/
-
-" -`; - exports[`Block transforms correctly transform block Image in fixture core__image__attachment-link into the Media & Text block 1`] = ` "
\\"\\"/
@@ -359,14 +152,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Image in fixture core__image__center-caption into the Group block 1`] = ` -" -
-
\\"\\"/
Give it a try. Press the \\"really wide\\" button on the image toolbar.
-
-" -`; - exports[`Block transforms correctly transform block Image in fixture core__image__center-caption into the Media & Text block 1`] = ` "
\\"\\"/
@@ -395,14 +180,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Image in fixture core__image__custom-link into the Group block 1`] = ` -" -
-
\\"\\"/
-
-" -`; - exports[`Block transforms correctly transform block Image in fixture core__image__custom-link into the Media & Text block 1`] = ` "
\\"\\"/
@@ -431,14 +208,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Image in fixture core__image__custom-link-class into the Group block 1`] = ` -" -
-
\\"\\"/
-
-" -`; - exports[`Block transforms correctly transform block Image in fixture core__image__custom-link-class into the Media & Text block 1`] = ` "
\\"\\"/
@@ -467,14 +236,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Image in fixture core__image__custom-link-rel into the Group block 1`] = ` -" -
-
\\"\\"/
-
-" -`; - exports[`Block transforms correctly transform block Image in fixture core__image__custom-link-rel into the Media & Text block 1`] = ` "
\\"\\"/
@@ -503,14 +264,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Image in fixture core__image__media-link into the Group block 1`] = ` -" -
-
\\"\\"/
-
-" -`; - exports[`Block transforms correctly transform block Image in fixture core__image__media-link into the Media & Text block 1`] = ` "
\\"\\"/
@@ -519,38 +272,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Latest Comments in fixture core__latest-comments into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Latest Posts in fixture core__latest-posts into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Latest Posts in fixture core__latest-posts__displayPostDate into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Legacy Widget (Experimental) in fixture core__legacy-widget into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block List in fixture core__list__ul into the Group block 1`] = ` -" -
-
  • Text & Headings
  • Images & Videos
  • Galleries
  • Embeds, like YouTube, Tweets, or other WordPress posts.
  • Layout blocks, like Buttons, Hero Images, Separators, etc.
  • And Lists like this one of course :)
-
-" -`; - exports[`Block transforms correctly transform block List in fixture core__list__ul into the Paragraph block 1`] = ` "

Text & Headings

@@ -583,167 +304,54 @@ exports[`Block transforms correctly transform block List in fixture core__list__ " `; -exports[`Block transforms correctly transform block Media & Text in fixture core__media-text into the Group block 1`] = ` -" -
-
\\"\\"/
-

My Content

-
-
-" -`; - exports[`Block transforms correctly transform block Media & Text in fixture core__media-text into the Image block 1`] = ` "
\\"\\"/
" `; -exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-alt-no-align into the Group block 1`] = ` -" -
-
\\"my
-

Content

-
-
-" -`; - exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-alt-no-align into the Image block 1`] = ` "
\\"my
" `; -exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-fill-no-focal-point-selected into the Group block 1`] = ` -" -
-
\\"My
-

My Content

-
-
-" -`; - exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-fill-no-focal-point-selected into the Image block 1`] = ` "
\\"My
" `; -exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-fill-with-focal-point-selected into the Group block 1`] = ` -" -
-
\\"My
-

My Content

-
-
-" -`; - exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__image-fill-with-focal-point-selected into the Image block 1`] = ` "
\\"My
" `; -exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__is-stacked-on-mobile into the Group block 1`] = ` -" -
-
-

My Content

-
-
-" -`; - exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__is-stacked-on-mobile into the Video block 1`] = ` "
" `; -exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__media-right-custom-width into the Group block 1`] = ` -" -
-
-

My video

-
-
-" -`; - exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__media-right-custom-width into the Video block 1`] = ` "
" `; -exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__vertical-align-bottom into the Group block 1`] = ` -" -
-
\\"My
-

My content

-
-
-" -`; - exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__vertical-align-bottom into the Image block 1`] = ` "
\\"My
" `; -exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__video into the Group block 1`] = ` -" -
-
-

My Content

-
-
-" -`; - exports[`Block transforms correctly transform block Media & Text in fixture core__media-text__video into the Video block 1`] = ` "
" `; -exports[`Block transforms correctly transform block More in fixture core__more into the Group block 1`] = ` -" -
- -
-" -`; - -exports[`Block transforms correctly transform block More in fixture core__more__custom-text-teaser into the Group block 1`] = ` -" -
- - -
-" -`; - -exports[`Block transforms correctly transform block Page Break in fixture core__nextpage into the Group block 1`] = ` -" -
- -
-" -`; - -exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the Group block 1`] = ` -" -
-

... like this one, which is separate from the above and right aligned.

-
-" -`; - exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the Heading block 1`] = ` "

... like this one, which is separate from the above and right aligned.

@@ -774,56 +382,24 @@ exports[`Block transforms correctly transform block Paragraph in fixture core__p " `; -exports[`Block transforms correctly transform block Preformatted in fixture core__preformatted into the Group block 1`] = ` -" -
-
Some preformatted text...
And more!
-
-" -`; - exports[`Block transforms correctly transform block Preformatted in fixture core__preformatted into the Paragraph block 1`] = ` "

Some preformatted text...
And more!

" `; -exports[`Block transforms correctly transform block Pullquote in fixture core__pullquote into the Group block 1`] = ` -" -
-

Testing pullquote block...

...with a caption
-
-" -`; - exports[`Block transforms correctly transform block Pullquote in fixture core__pullquote into the Quote block 1`] = ` "

Testing pullquote block...

...with a caption
" `; -exports[`Block transforms correctly transform block Pullquote in fixture core__pullquote__multi-paragraph into the Group block 1`] = ` -" -
-

Paragraph one

Paragraph two

by whomever
-
-" -`; - exports[`Block transforms correctly transform block Pullquote in fixture core__pullquote__multi-paragraph into the Quote block 1`] = ` "

Paragraph one

Paragraph two

by whomever
" `; -exports[`Block transforms correctly transform block Quote in fixture core__quote__style-1 into the Group block 1`] = ` -" -
-

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

Matt Mullenweg, 2017
-
-" -`; - exports[`Block transforms correctly transform block Quote in fixture core__quote__style-1 into the Heading block 1`] = ` "

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

@@ -856,14 +432,6 @@ exports[`Block transforms correctly transform block Quote in fixture core__quote " `; -exports[`Block transforms correctly transform block Quote in fixture core__quote__style-2 into the Group block 1`] = ` -" -
-

There is no greater agony than bearing an untold story inside you.

Maya Angelou
-
-" -`; - exports[`Block transforms correctly transform block Quote in fixture core__quote__style-2 into the Heading block 1`] = ` "

There is no greater agony than bearing an untold story inside you.

@@ -896,76 +464,6 @@ exports[`Block transforms correctly transform block Quote in fixture core__quote " `; -exports[`Block transforms correctly transform block RSS in fixture core__rss into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Search in fixture core__search into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Search in fixture core__search__custom-text into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Separator in fixture core__separator into the Group block 1`] = ` -" -
-
-
-" -`; - -exports[`Block transforms correctly transform block Shortcode in fixture core__shortcode into the Group block 1`] = ` -" -
-[gallery ids=\\"238,338\\"] -
-" -`; - -exports[`Block transforms correctly transform block Spacer in fixture core__spacer into the Group block 1`] = ` -" -
-
-
-" -`; - -exports[`Block transforms correctly transform block Table in fixture core__table into the Group block 1`] = ` -" -
-
VersionMusicianDate
.70No musician chosen.May 27, 2003
1.0Miles DavisJanuary 3, 2004
Lots of versions skipped, see the full list
4.4Clifford BrownDecember 8, 2015
4.5Coleman HawkinsApril 12, 2016
4.6Pepper AdamsAugust 16, 2016
4.7Sarah VaughanDecember 6, 2016
-
-" -`; - -exports[`Block transforms correctly transform block Tag Cloud in fixture core__tag-cloud into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Tag Cloud in fixture core__tag-cloud__showTagCounts into the Group block 1`] = ` -" -
-" -`; - -exports[`Block transforms correctly transform block Verse in fixture core__verse into the Group block 1`] = ` -" -
-
A verse
And more!
-
-" -`; - exports[`Block transforms correctly transform block Verse in fixture core__verse into the Paragraph block 1`] = ` "

A verse
And more!

@@ -986,14 +484,6 @@ exports[`Block transforms correctly transform block Video in fixture core__video " `; -exports[`Block transforms correctly transform block Video in fixture core__video into the Group block 1`] = ` -" -
-
-
-" -`; - exports[`Block transforms correctly transform block Video in fixture core__video into the Media & Text block 1`] = ` "
@@ -1001,3 +491,9 @@ exports[`Block transforms correctly transform block Video in fixture core__video
" `; + +exports[`Block transforms correctly transform correctly transforms one of the available blocks into a group block 1`] = ` +" +
+" +`; diff --git a/packages/e2e-tests/specs/block-transforms.test.js b/packages/e2e-tests/specs/block-transforms.test.js index a16a7a1ec1003..c979d25025d46 100644 --- a/packages/e2e-tests/specs/block-transforms.test.js +++ b/packages/e2e-tests/specs/block-transforms.test.js @@ -153,7 +153,12 @@ describe( 'Block transforms', () => { ) ); - it.each( testTable )( + // Group is an available transform on all Blocks. Testing each transform adds + // significant overhead to the tests. Therefore we filter these out and test + // Group transforms separately. + const testTableWithoutGroup = testTable.filter( ( transform ) => ! transform.includes( 'Group' ) ); + + it.each( testTableWithoutGroup )( 'block %s in fixture %s into the %s block', async ( originalBlock, fixture, destinationBlock ) => { const { content } = transformStructure[ fixture ]; @@ -162,5 +167,19 @@ describe( 'Block transforms', () => { ).toMatchSnapshot(); } ); + + // Test one of the Group transforms separately to avoid creating unecessary tests + it( 'correctly transforms one of the available blocks into a group block', async () => { + // Get the first available block fixture which supports a transform to Group + const firstTransformWithGroup = testTable.find( ( transform ) => { + return transform[ 2 ] === 'Group'; + } ); + + const { content } = transformStructure[ firstTransformWithGroup[ 1 ] ]; + + expect( + await getTransformResult( content, firstTransformWithGroup[ 2 ] ) + ).toMatchSnapshot(); + } ); } ); } ); From c950c2e86dc105c503b63078e235ecd55d880d31 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 24 May 2019 11:10:37 +0100 Subject: [PATCH 42/76] Fixes e2e test by reinstating helper lost during rebase --- packages/e2e-tests/specs/block-deletion.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/e2e-tests/specs/block-deletion.test.js b/packages/e2e-tests/specs/block-deletion.test.js index fb5fd2b357140..ba98a013f1aef 100644 --- a/packages/e2e-tests/specs/block-deletion.test.js +++ b/packages/e2e-tests/specs/block-deletion.test.js @@ -10,6 +10,7 @@ import { pressKeyWithModifier, pressKeyTimes, clickBlockToolbarButton, + insertBlock, } from '@wordpress/e2e-test-utils'; const addThreeParagraphsToNewPost = async () => { From 16c20c6c4bba78c87f20f349554949372ee354e3 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 24 May 2019 13:05:22 +0100 Subject: [PATCH 43/76] Fix to make Group transform snapshot tests more resilient to change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now explicity selects paragraph and image blocks to test the Group transform rather than simply testing the first block that transform into a Group. This ensures that if the order of transforms changes in the fixtures the test won’t be accidentally invalidated. Resolves: https://github.com/WordPress/gutenberg/pull/14908/#discussion_r287315363 --- .../block-transforms.test.js.snap | 22 +++++++++++----- .../e2e-tests/specs/block-transforms.test.js | 25 +++++++++---------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap index 6750503d68575..2eba8e9f42fc8 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap @@ -104,6 +104,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image into the group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image__attachment-link into the Cover block 1`] = ` "
@@ -382,6 +390,14 @@ exports[`Block transforms correctly transform block Paragraph in fixture core__p " `; +exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the group block 1`] = ` +" +
+

... like this one, which is separate from the above and right aligned.

+
+" +`; + exports[`Block transforms correctly transform block Preformatted in fixture core__preformatted into the Paragraph block 1`] = ` "

Some preformatted text...
And more!

@@ -491,9 +507,3 @@ exports[`Block transforms correctly transform block Video in fixture core__video
" `; - -exports[`Block transforms correctly transform correctly transforms one of the available blocks into a group block 1`] = ` -" -
-" -`; diff --git a/packages/e2e-tests/specs/block-transforms.test.js b/packages/e2e-tests/specs/block-transforms.test.js index c979d25025d46..4d4a982725dbb 100644 --- a/packages/e2e-tests/specs/block-transforms.test.js +++ b/packages/e2e-tests/specs/block-transforms.test.js @@ -158,6 +158,9 @@ describe( 'Block transforms', () => { // Group transforms separately. const testTableWithoutGroup = testTable.filter( ( transform ) => ! transform.includes( 'Group' ) ); + // Select Paragraph and Image Blocks (only) to test the Group transform + const testTableWithSomeGroupsFiltered = testTable.filter( ( transform ) => ( transform[ 2 ] === 'Group' && ( transform[ 1 ] === 'core__paragraph__align-right' || transform[ 1 ] === 'core__image' ) ) ); + it.each( testTableWithoutGroup )( 'block %s in fixture %s into the %s block', async ( originalBlock, fixture, destinationBlock ) => { @@ -168,18 +171,14 @@ describe( 'Block transforms', () => { } ); - // Test one of the Group transforms separately to avoid creating unecessary tests - it( 'correctly transforms one of the available blocks into a group block', async () => { - // Get the first available block fixture which supports a transform to Group - const firstTransformWithGroup = testTable.find( ( transform ) => { - return transform[ 2 ] === 'Group'; - } ); - - const { content } = transformStructure[ firstTransformWithGroup[ 1 ] ]; - - expect( - await getTransformResult( content, firstTransformWithGroup[ 2 ] ) - ).toMatchSnapshot(); - } ); + it.each( testTableWithSomeGroupsFiltered )( + 'block %s in fixture %s into the group block', + async ( originalBlock, fixture, destinationBlock ) => { + const { content } = transformStructure[ fixture ]; + expect( + await getTransformResult( content, destinationBlock ) + ).toMatchSnapshot(); + } + ); } ); } ); From 587ec4bd2528e18775b0f41fd1b9746dfa80694e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 24 May 2019 14:50:58 +0100 Subject: [PATCH 44/76] Updates to DRY out test and reduce test redundancy and performance Through use of smarter filtering we can get away with a single `it.each()` block which improves perf and removes redundant tests. Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r287342432 --- .../block-transforms.test.js.snap | 32 +++++++++---------- .../e2e-tests/specs/block-transforms.test.js | 22 +++---------- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap index 2eba8e9f42fc8..25e50d75416a4 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap @@ -96,6 +96,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image into the Group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image into the Media & Text block 1`] = ` "
\\"\\"/
@@ -104,14 +112,6 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; -exports[`Block transforms correctly transform block Image in fixture core__image into the group block 1`] = ` -" -
-
\\"\\"/
-
-" -`; - exports[`Block transforms correctly transform block Image in fixture core__image__attachment-link into the Cover block 1`] = ` "
@@ -360,6 +360,14 @@ exports[`Block transforms correctly transform block Media & Text in fixture core " `; +exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the Group block 1`] = ` +" +
+

... like this one, which is separate from the above and right aligned.

+
+" +`; + exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the Heading block 1`] = ` "

... like this one, which is separate from the above and right aligned.

@@ -390,14 +398,6 @@ exports[`Block transforms correctly transform block Paragraph in fixture core__p " `; -exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the group block 1`] = ` -" -
-

... like this one, which is separate from the above and right aligned.

-
-" -`; - exports[`Block transforms correctly transform block Preformatted in fixture core__preformatted into the Paragraph block 1`] = ` "

Some preformatted text...
And more!

diff --git a/packages/e2e-tests/specs/block-transforms.test.js b/packages/e2e-tests/specs/block-transforms.test.js index 4d4a982725dbb..fafeb539f038c 100644 --- a/packages/e2e-tests/specs/block-transforms.test.js +++ b/packages/e2e-tests/specs/block-transforms.test.js @@ -153,26 +153,12 @@ describe( 'Block transforms', () => { ) ); - // Group is an available transform on all Blocks. Testing each transform adds - // significant overhead to the tests. Therefore we filter these out and test - // Group transforms separately. - const testTableWithoutGroup = testTable.filter( ( transform ) => ! transform.includes( 'Group' ) ); - - // Select Paragraph and Image Blocks (only) to test the Group transform - const testTableWithSomeGroupsFiltered = testTable.filter( ( transform ) => ( transform[ 2 ] === 'Group' && ( transform[ 1 ] === 'core__paragraph__align-right' || transform[ 1 ] === 'core__image' ) ) ); - - it.each( testTableWithoutGroup )( - 'block %s in fixture %s into the %s block', - async ( originalBlock, fixture, destinationBlock ) => { - const { content } = transformStructure[ fixture ]; - expect( - await getTransformResult( content, destinationBlock ) - ).toMatchSnapshot(); - } - ); + // Filter out Group transforms for perf reasons, expect for x2 tests + // (core/paragraph and core/image) + const testTableWithSomeGroupsFiltered = testTable.filter( ( transform ) => ( transform[ 2 ] !== 'Group' || transform[ 1 ] === 'core__paragraph__align-right' || transform[ 1 ] === 'core__image' ) ); it.each( testTableWithSomeGroupsFiltered )( - 'block %s in fixture %s into the group block', + 'block %s in fixture %s into the %s block', async ( originalBlock, fixture, destinationBlock ) => { const { content } = transformStructure[ fixture ]; expect( From 80741318c100254215bfff6d13fe05178944084a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 12:29:50 +0100 Subject: [PATCH 45/76] Adds unit tests to cover new conditionals added for wildcard blocks transforms --- packages/blocks/src/api/test/factory.js | 77 ++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index 11249b08d36ce..d0a9a4bb008ad 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -2,7 +2,7 @@ * External dependencies */ import deepFreeze from 'deep-freeze'; -import { noop } from 'lodash'; +import { noop, times } from 'lodash'; /** * Internal dependencies @@ -776,6 +776,81 @@ describe( 'block factory', () => { expect( isMatch ).toHaveBeenCalledWith( [ { value: 'ribs' }, { value: 'halloumi' } ] ); } ); + + describe( 'wildcard block transforms', () => { + beforeEach( () => { + registerBlockType( 'core/group', { + attributes: { + value: { + type: 'string', + }, + }, + transforms: { + from: [ { + type: 'block', + blocks: [ '*' ], + transform: noop, + } ], + }, + save: noop, + category: 'common', + title: 'A block that groups other blocks.', + } ); + } ); + + it( 'should should show wildcard "from" transformation as available for multiple blocks of the same type', () => { + registerBlockType( 'core/text-block', defaultBlockSettings ); + registerBlockType( 'core/image-block', defaultBlockSettings ); + + const textBlocks = times( 4, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const availableBlocks = getPossibleBlockTransformations( textBlocks ); + + expect( availableBlocks ).toHaveLength( 1 ); + expect( availableBlocks[ 0 ].name ).toBe( 'core/group' ); + } ); + + it( 'should should show wildcard "from" transformation as available for multiple blocks of different types', () => { + registerBlockType( 'core/text-block', defaultBlockSettings ); + registerBlockType( 'core/image-block', defaultBlockSettings ); + + const textBlocks = times( 2, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const imageBlocks = times( 2, ( index ) => { + return createBlock( 'core/image-block', { + value: `imageBlock${ index + 1 }`, + } ); + } ); + + const availableBlocks = getPossibleBlockTransformations( [ ...textBlocks, ...imageBlocks ] ); + + expect( availableBlocks ).toHaveLength( 1 ); + expect( availableBlocks[ 0 ].name ).toBe( 'core/group' ); + } ); + + it( 'should should show wildcard "from" transformation as available for single blocks', () => { + registerBlockType( 'core/text-block', defaultBlockSettings ); + + const blocks = times( 1, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const availableBlocks = getPossibleBlockTransformations( blocks ); + + expect( availableBlocks ).toHaveLength( 1 ); + expect( availableBlocks[ 0 ].name ).toBe( 'core/group' ); + } ); + } ); } ); describe( 'switchToBlockType()', () => { From 024cdae057b68fc952cc9666bd7be1a602007b1a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 12:33:45 +0100 Subject: [PATCH 46/76] Fixes capitalisation of UnGroup to Ungroup Resolves https://github.com/WordPress/gutenberg/pull/14908#discussion_r287415190 --- packages/block-editor/src/components/block-actions/index.js | 6 +++--- .../src/components/block-editor-keyboard-shortcuts/index.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/block-actions/index.js b/packages/block-editor/src/components/block-actions/index.js index 170869d808655..c10d03a5c060f 100644 --- a/packages/block-editor/src/components/block-actions/index.js +++ b/packages/block-editor/src/components/block-actions/index.js @@ -16,7 +16,7 @@ function BlockActions( { onInsertBefore, onInsertAfter, onGroup, - onUnGroup, + onUngroup, isLocked, canDuplicate, children, @@ -27,7 +27,7 @@ function BlockActions( { onInsertAfter, onInsertBefore, onGroup, - onUnGroup, + onUngroup, isLocked, canDuplicate, } ); @@ -129,7 +129,7 @@ export default compose( [ ); }, - onUnGroup() { + onUngroup() { if ( ! blocks.length ) { return; } diff --git a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js index 30eefe80e3bb9..6a19f660f5320 100644 --- a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js +++ b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js @@ -100,7 +100,7 @@ class BlockEditorKeyboardShortcuts extends Component { /> { selectedBlockClientIds.length > 0 && ( - { ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore, onGroup, onUnGroup } ) => ( + { ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore, onGroup, onUngroup } ) => ( ) } From 7453ef2b73fc9c343da0e85d1120de10de372670 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 12:38:09 +0100 Subject: [PATCH 47/76] Updates doc block to reflect possible nullable return type Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r287416745 --- packages/blocks/src/api/factory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index bf01a02d4aefd..70eca65e5910a 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -362,7 +362,7 @@ export function getBlockTransforms( direction, blockTypeOrName ) { * @param {Array|Object} blocks Blocks array or block object. * @param {string} name Block name. * - * @return {Array} Array of blocks. + * @return {?Array} Array of blocks or null. */ export function switchToBlockType( blocks, name ) { const blocksArray = castArray( blocks ); From 1b3f357591783cd95f20cb31e9fe2f8972625741 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 12:43:41 +0100 Subject: [PATCH 48/76] Updates Readme with doc update --- packages/blocks/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blocks/README.md b/packages/blocks/README.md index 9bc199a54452f..b7a8e5fd70c9d 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -679,7 +679,7 @@ _Parameters_ _Returns_ -- `Array`: Array of blocks. +- `?Array`: Array of blocks or null. # **synchronizeBlocksWithTemplate** From dbac411e02a43505ce04c76d43f090c3f87c801d Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 12:44:07 +0100 Subject: [PATCH 49/76] Updates to remove unwanted comments --- .../src/components/block-editor-keyboard-shortcuts/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js index 6a19f660f5320..001c25bbeaff0 100644 --- a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js +++ b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js @@ -119,12 +119,8 @@ class BlockEditorKeyboardShortcuts extends Component { // is used to prevent any obscure unknown shortcuts from triggering. [ shortcuts.insertAfter.raw ]: flow( preventDefault, onInsertAfter ), - // Does not clash with any known browser/native shortcuts, but preventDefault - // is used to prevent any obscure unknown shortcuts from triggering. [ shortcuts.group.raw ]: flow( preventDefault, onGroup ), - // Does not clash with any known browser/native shortcuts, but preventDefault - // is used to prevent any obscure unknown shortcuts from triggering. [ shortcuts.ungroup.raw ]: flow( preventDefault, onUngroup ), } } /> From 36fda5adb980c4ee8f9f7eb15a063a8ed256fb34 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 12:50:54 +0100 Subject: [PATCH 50/76] =?UTF-8?q?Updates=20capitalisatoin=20of=20=E2=80=9C?= =?UTF-8?q?wildcard=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r287435420 --- packages/blocks/src/api/factory.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 70eca65e5910a..4ff8d47ef58e3 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -121,14 +121,14 @@ const isPossibleTransformForSource = ( transform, direction, blocks ) => { // or wildcard transforms are allowed. const isMultiBlock = blocks.length > 1; const firstBlockName = first( blocks ).name; - const isValidForMultiBlocks = isWildCardBlockTransform( transform ) || ! isMultiBlock || transform.isMultiBlock; + const isValidForMultiBlocks = isWildcardBlockTransform( transform ) || ! isMultiBlock || transform.isMultiBlock; if ( ! isValidForMultiBlocks ) { return false; } // Check non-wildcard transforms to ensure that transform is valid // for a block selection of multiple blocks of different types - if ( ! isWildCardBlockTransform( transform ) && ! every( blocks, { name: firstBlockName } ) ) { + if ( ! isWildcardBlockTransform( transform ) && ! every( blocks, { name: firstBlockName } ) ) { return false; } @@ -141,7 +141,7 @@ const isPossibleTransformForSource = ( transform, direction, blocks ) => { // Check if the transform's block name matches the source block (or is a wildcard) // only if this is a transform 'from'. const sourceBlock = first( blocks ); - const hasMatchingName = direction !== 'from' || transform.blocks.indexOf( sourceBlock.name ) !== -1 || isWildCardBlockTransform( transform ); + const hasMatchingName = direction !== 'from' || transform.blocks.indexOf( sourceBlock.name ) !== -1 || isWildcardBlockTransform( transform ); if ( ! hasMatchingName ) { return false; } @@ -239,7 +239,7 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { * @param {Object} t Block transform object * @return {boolean} whether transform is a wildcard transform */ -const isWildCardBlockTransform = ( t ) => t && t.type === 'block' && t.blocks.length && t.blocks[ 0 ] === '*'; +const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && t.blocks.length && t.blocks[ 0 ] === '*'; /** * Determines whether the given Block is the core Block which @@ -385,11 +385,11 @@ export function switchToBlockType( blocks, name ) { const transformation = findTransform( transformationsTo, - ( t ) => t.type === 'block' && ( ( isWildCardBlockTransform( t ) ) || t.blocks.indexOf( name ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) + ( t ) => t.type === 'block' && ( ( isWildcardBlockTransform( t ) ) || t.blocks.indexOf( name ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) ) || findTransform( transformationsFrom, - ( t ) => t.type === 'block' && ( ( isWildCardBlockTransform( t ) ) || t.blocks.indexOf( sourceName ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) + ( t ) => t.type === 'block' && ( ( isWildcardBlockTransform( t ) ) || t.blocks.indexOf( sourceName ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) ); // Stop if there is no valid transformation. From 358bc1c7341c47a330c5f8c66333b8a5cd91cfcf Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 12:55:58 +0100 Subject: [PATCH 51/76] Update comment with more context for future maintainers Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r287436023 --- packages/e2e-tests/specs/block-transforms.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/specs/block-transforms.test.js b/packages/e2e-tests/specs/block-transforms.test.js index fafeb539f038c..89d14bf524491 100644 --- a/packages/e2e-tests/specs/block-transforms.test.js +++ b/packages/e2e-tests/specs/block-transforms.test.js @@ -153,8 +153,9 @@ describe( 'Block transforms', () => { ) ); - // Filter out Group transforms for perf reasons, expect for x2 tests - // (core/paragraph and core/image) + // As Group is available as a transform on *all* blocks this would create a lot of + // tests which would impact on the performance of the e2e test suite. + // To avoid this, we remove `core/group` from test table for all but 2 block types. const testTableWithSomeGroupsFiltered = testTable.filter( ( transform ) => ( transform[ 2 ] !== 'Group' || transform[ 1 ] === 'core__paragraph__align-right' || transform[ 1 ] === 'core__image' ) ); it.each( testTableWithSomeGroupsFiltered )( From 2b229fc9f73c078d08a3368d35d5bb18ee7c3944 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 12:58:27 +0100 Subject: [PATCH 52/76] Updates to remove unwanted level of context on the translation Co-Authored-By: Andrew Duthie --- .../src/components/convert-to-group-buttons/convert-button.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index c6cdd15470c95..e10eb9b8944fa 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -34,7 +34,7 @@ export function ConvertToGroupButton( { onClick={ onConvertToGroup } shortcut={ displayShortcut.primaryAlt( 'g' ) } > - { _x( 'Group', 'Grouping a selection of blocks together within the Editor' ) } + { _x( 'Group', 'verb' ) } ) } { isUnGroupable && ( From c3bdf0f15834fec3115b39720487987170fe4f87 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 13:16:35 +0100 Subject: [PATCH 53/76] Adds tests to cover isWildcardBlockTransform --- packages/blocks/src/api/factory.js | 2 +- packages/blocks/src/api/test/factory.js | 41 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 4ff8d47ef58e3..46ac11251b51b 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -239,7 +239,7 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { * @param {Object} t Block transform object * @return {boolean} whether transform is a wildcard transform */ -const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && t.blocks.length && t.blocks[ 0 ] === '*'; +export const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && t.blocks.length && t.blocks.includes( '*' ); /** * Determines whether the given Block is the core Block which diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index d0a9a4bb008ad..b78e3beb185c2 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -14,6 +14,7 @@ import { switchToBlockType, getBlockTransforms, findTransform, + isWildcardBlockTransform, } from '../factory'; import { getBlockType, @@ -1411,4 +1412,44 @@ describe( 'block factory', () => { expect( transform ).toBe( null ); } ); } ); + + describe( 'isWildcardBlockTransform', () => { + it( 'should return true for transforms with type of block and "*" alias as blocks', () => { + const validWildcardBlockTransform = { + type: 'block', + blocks: [ + 'core/some-other-block-first', // unlikely to happen but... + '*', + ], + blockName: 'core/test-block', + }; + + expect( isWildcardBlockTransform( validWildcardBlockTransform ) ).toBe( true ); + } ); + + it( 'should return false for transforms with a type which is not "block"', () => { + const invalidWildcardBlockTransform = { + type: 'file', + blocks: [ + '*', + ], + blockName: 'core/test-block', + }; + + expect( isWildcardBlockTransform( invalidWildcardBlockTransform ) ).toBe( false ); + } ); + + it( 'should return false for transforms which do not include "*" alias in "block" array', () => { + const invalidWildcardBlockTransform = { + type: 'block', + blocks: [ + 'core/some-block', + 'core/another-block', + ], + blockName: 'core/test-block', + }; + + expect( isWildcardBlockTransform( invalidWildcardBlockTransform ) ).toBe( false ); + } ); + } ); } ); From b2519faa38ab7e7a5f4dd5864a89e5a8cb318733 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 13:20:24 +0100 Subject: [PATCH 54/76] Adds tests for isContainerGroupBlock function Note these test will need updating when we land https://github.com/WordPress/gutenberg/pull/15774 --- packages/blocks/src/api/factory.js | 2 +- packages/blocks/src/api/test/factory.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 46ac11251b51b..104920691f65a 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -248,7 +248,7 @@ export const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && t.bl * @param {string} name the name of the Block to test against * @return {boolean} whether or not the Block is the container Block type */ -const isContainerGroupBlock = ( name ) => name === 'core/group'; +export const isContainerGroupBlock = ( name ) => name === 'core/group'; /** * Determines whether the provided Blocks are a multi Block selection diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index b78e3beb185c2..eee1a14f2c41d 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -15,6 +15,7 @@ import { getBlockTransforms, findTransform, isWildcardBlockTransform, + isContainerGroupBlock, } from '../factory'; import { getBlockType, @@ -1452,4 +1453,14 @@ describe( 'block factory', () => { expect( isWildcardBlockTransform( invalidWildcardBlockTransform ) ).toBe( false ); } ); } ); + + describe( 'isContainerGroupBlock', () => { + it( 'should return true when passed block name matches "core/group"', () => { + expect( isContainerGroupBlock( 'core/group' ) ).toBe( true ); + } ); + + it( 'should return false when passed block name does not match "core/group"', () => { + expect( isContainerGroupBlock( 'core/some-test-name' ) ).toBe( false ); + } ); + } ); } ); From b474df5228084e869e7d48e4939d678eca79d5d1 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 31 May 2019 14:16:45 +0100 Subject: [PATCH 55/76] Fixes logic around multi blocks of same type and adds tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevously we had 1 function attempting to test for multiple block selection and checking that the selection was all of the same block type. This caused bugs within `switchToBlockType` because the logic was confusing. For example, if a selection isn’t a multi block then we don’t need to test that all the blocks are the same. Separated the two functions and updated conditions in switchToBlockType to reflect this. Added unit tests to cover two new functions. --- packages/blocks/src/api/factory.js | 29 ++++++++----- packages/blocks/src/api/test/factory.js | 58 +++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 104920691f65a..a399c174ffc5e 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -251,20 +251,29 @@ export const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && t.bl export const isContainerGroupBlock = ( name ) => name === 'core/group'; /** - * Determines whether the provided Blocks are a multi Block selection - * and of the same type (eg: all `core/paragraph`). + * Determines whether the provided Blocks are of the same type + * (eg: all `core/paragraph`). * * @param {Array} blocksArray the Block definitions * @return {boolean} whether or not the given Blocks pass the criteria */ -const isMultiBlockSelectionOfSameType = ( blocksArray = [] ) => { - // Is it a Multi Block selection? - if ( ! blocksArray.length > 1 ) { +export const isBlockSelectionOfSameType = ( blocksArray = [] ) => { + if ( ! blocksArray.length ) { return false; } const sourceName = blocksArray[ 0 ].name; - return ! every( blocksArray, ( block ) => ( block.name === sourceName ) ); + return every( blocksArray, [ 'name', sourceName ] ); +}; + +/** + * Determines whether the provided Blocks constitute + * a multi-block selection (ie: more than 1) + * @param {Array} blocksArray [description] + * @return {boolean} [description] + */ +export const isMultiBlockSelection = ( blocksArray = [] ) => { + return blocksArray.length > 1; }; /** @@ -366,14 +375,14 @@ export function getBlockTransforms( direction, blockTypeOrName ) { */ export function switchToBlockType( blocks, name ) { const blocksArray = castArray( blocks ); - const isMultiBlock = blocksArray.length > 1; + const isMultiBlock = isMultiBlockSelection( blocksArray ); const firstBlock = blocksArray[ 0 ]; const sourceName = firstBlock.name; - // Unless it's a `core/group` Block then check - // that all Blocks are of the same type otherwise + // Unless it's a `core/group` Block then for multi block selections + // check that all Blocks are of the same type otherwise // we can't run a conversion - if ( ! isContainerGroupBlock( name ) && isMultiBlockSelectionOfSameType( blocksArray ) ) { + if ( ! isContainerGroupBlock( name ) && isMultiBlock && ! isBlockSelectionOfSameType( blocksArray ) ) { return null; } diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index eee1a14f2c41d..41eb02b3c2294 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -16,6 +16,8 @@ import { findTransform, isWildcardBlockTransform, isContainerGroupBlock, + isBlockSelectionOfSameType, + isMultiBlockSelection, } from '../factory'; import { getBlockType, @@ -1463,4 +1465,60 @@ describe( 'block factory', () => { expect( isContainerGroupBlock( 'core/some-test-name' ) ).toBe( false ); } ); } ); + + describe( 'isMultiBlockSelection', () => { + it( 'should return false when there is one block or less', () => { + const singleBlock = [ + { + name: 'core/test-block', + }, + ]; + + expect( isMultiBlockSelection( [] ) ).toBe( false ); + expect( isMultiBlockSelection( singleBlock ) ).toBe( false ); + } ); + } ); + + describe( 'isBlockSelectionOfSameType', () => { + it( 'should return false when all blocks do not match the name of the first block', () => { + const blocks = [ + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + { + name: 'core/another-block', + }, + { + name: 'core/test-block', + }, + ]; + + expect( isBlockSelectionOfSameType( blocks ) ).toBe( false ); + } ); + + it( 'should return true when all blocks match the name of the first block', () => { + const blocks = [ + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + ]; + + expect( isBlockSelectionOfSameType( blocks ) ).toBe( true ); + } ); + } ); } ); From 8c6ccd3a86ef0eb93f639316a380d82ae2271ecb Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 3 Jun 2019 11:58:44 +0100 Subject: [PATCH 56/76] Adds new generator based API signature to Block transforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the transforms function was pased two arguments 1. attributes 2. innerblocks This wasn’t extensible and more advanced transformations require more information about the block (eg: name). To avoid bloating the signature, a progressive enhancement approach is applied whereby if a generator function is passed as the transform then we pass the entire block object to the generator. This is opt-in only and is backwards compatible with all existing transform functions. --- packages/block-library/src/group/index.js | 33 ++++++++++-------- packages/blocks/src/api/factory.js | 35 +++++++++++++++---- packages/blocks/src/api/test/factory.js | 42 +++++++++++++++++++++++ 3 files changed, 89 insertions(+), 21 deletions(-) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index c336441aad5fc..0eed58337d86d 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -12,9 +12,10 @@ import icon from './icon'; import metadata from './block.json'; import save from './save'; -const { name } = metadata; - -export { metadata, name }; +export const info = { + ...metadata, + name: metadata.name, +}; export const settings = { title: __( 'Group' ), @@ -33,26 +34,30 @@ export const settings = { type: 'block', isMultiBlock: true, blocks: [ '*' ], - transform: ( attributes, innerBlocks, names ) => { + *transform( blocks ) { // Avoid transforming a single `core/group` Block - if ( names.length === 1 && names[ 0 ] === 'core/group' ) { + if ( blocks.length === 1 && blocks[ 0 ].name === 'core/group' ) { return; } const alignments = [ 'wide', 'full' ]; - let widestAlignment; - - const groupInnerBlocks = attributes.map( ( attrs, index ) => { - // Determines the widest setting of all the blocks to be grouped - const currBlockAlignment = attrs.align; - widestAlignment = alignments.indexOf( currBlockAlignment ) > alignments.indexOf( widestAlignment ) ? currBlockAlignment : widestAlignment; + // Determine the widest setting of all the blocks to be grouped + const widestAlignment = blocks.reduce( ( result, block ) => { + const { align } = block.attributes; + return alignments.indexOf( align ) > alignments.indexOf( result ) ? align : result; + }, undefined ); - // Creates the new Block - return createBlock( names[ index ], attrs, innerBlocks[ index ] ); + // Clone the Blocks to be Grouped + // Failing to create new block references causes the original blocks + // to be replaced in the switchToBlockType call thereby meaning they + // are removed both from their original location and within the + // new group block. + const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { + return createBlock( name, attributes, innerBlocks ); } ); - return createBlock( 'core/group', { + yield createBlock( 'core/group', { align: widestAlignment, }, groupInnerBlocks ); }, diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index a399c174ffc5e..012ca6a8e86ad 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -27,6 +27,16 @@ import { createHooks, applyFilters } from '@wordpress/hooks'; import { getBlockType, getBlockTypes } from './registration'; import { normalizeBlockType } from './utils'; +/** + * Determines whether a function is a Generator function + * @param {Function} fn the function to test + * @return {boolean} whether or not the function is a generator + */ +function isGenerator( fn ) { + const sampleGenerator = function*() {}; + return fn.constructor.name === 'GeneratorFunction' && fn.constructor === sampleGenerator.constructor; +} + /** * Returns a block object given its type and attributes. * @@ -408,14 +418,23 @@ export function switchToBlockType( blocks, name ) { let transformationResults; + // Progressively enhancing the function signature using Generators + // Generator based transform functions are passed the entire Block object if ( transformation.isMultiBlock ) { - transformationResults = transformation.transform( - blocksArray.map( ( currentBlock ) => currentBlock.attributes ), - blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ), - blocksArray.map( ( currentBlock ) => currentBlock.name ), - ); + if ( isGenerator( transformation.transform ) ) { + const gen = transformation.transform( blocksArray ); + transformationResults = Array.from( gen ); + } else { + transformationResults = transformation.transform( + blocksArray.map( ( currentBlock ) => currentBlock.attributes ), + blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ), + ); + } + } else if ( isGenerator( transformation.transform ) ) { + const gen = transformation.transform( [ firstBlock ] ); + transformationResults = Array.from( gen ); } else { - transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks, firstBlock.name ); + transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks ); } // Ensure that the transformation function returned an object or an array @@ -442,7 +461,7 @@ export function switchToBlockType( blocks, name ) { return null; } - return transformationResults.map( ( result, index ) => { + const rtn = transformationResults.map( ( result, index ) => { const transformedBlock = { ...result, // The first transformed block whose type matches the "destination" @@ -460,4 +479,6 @@ export function switchToBlockType( blocks, name ) { */ return applyFilters( 'blocks.switchToBlockType.transformedBlock', transformedBlock, blocks ); } ); + + return rtn; } diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index 41eb02b3c2294..80aaa0c8d4a3e 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -1301,6 +1301,48 @@ describe( 'block factory', () => { expect( transformedBlocks[ 1 ].innerBlocks ).toHaveLength( 1 ); expect( transformedBlocks[ 1 ].innerBlocks[ 0 ].attributes.value ).toBe( 'after1' ); } ); + + it( 'should pass entire block object to transform functions which are generators', () => { + registerBlockType( 'core/test-group-block', { + attributes: { + value: { + type: 'string', + }, + }, + transforms: { + from: [ { + type: 'block', + blocks: [ '*' ], + isMultiBlock: true, + *transform( blocks ) { + const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { + return createBlock( name, attributes, innerBlocks ); + } ); + + yield createBlock( 'core/test-group-block', {}, groupInnerBlocks ); + }, + } ], + }, + save: noop, + category: 'common', + title: 'Test Group Block', + } ); + + registerBlockType( 'core/text-block', defaultBlockSettings ); + + const numOfBlocksToGroup = 4; + const blocks = times( numOfBlocksToGroup, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const transformedBlocks = switchToBlockType( blocks, 'core/test-group-block' ); + + expect( transformedBlocks ).toHaveLength( 1 ); + expect( transformedBlocks[ 0 ].name ).toBe( 'core/test-group-block' ); + expect( transformedBlocks[ 0 ].innerBlocks ).toHaveLength( numOfBlocksToGroup ); + } ); } ); describe( 'getBlockTransforms', () => { From a30367de9813b0c5bd1ae3d53cb3b1258dae5eb1 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 3 Jun 2019 15:37:59 +0100 Subject: [PATCH 57/76] Adds new apply option method to transform API Previously we were modifying the existing transform function to conform to the requirements of a new API (ie: receiving the entire block object rather than the individual arguments). It was decided that introducing a new `apply` option and soft deprecating the old transform option would be preferable. The apply option if provided now takes precedence over the transform option. This is fully backwards compatible. See https://wordpress.slack.com/archives/C02QB2JS7/p1559567845087000 --- packages/block-library/src/group/index.js | 15 +++---- packages/blocks/src/api/factory.js | 23 +++------- packages/blocks/src/api/test/factory.js | 52 +++++++++++++++++++++-- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index 0eed58337d86d..6b74e04cbdbc0 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -12,10 +12,9 @@ import icon from './icon'; import metadata from './block.json'; import save from './save'; -export const info = { - ...metadata, - name: metadata.name, -}; +const { name } = metadata; + +export { metadata, name }; export const settings = { title: __( 'Group' ), @@ -34,7 +33,7 @@ export const settings = { type: 'block', isMultiBlock: true, blocks: [ '*' ], - *transform( blocks ) { + apply( blocks ) { // Avoid transforming a single `core/group` Block if ( blocks.length === 1 && blocks[ 0 ].name === 'core/group' ) { return; @@ -53,11 +52,11 @@ export const settings = { // to be replaced in the switchToBlockType call thereby meaning they // are removed both from their original location and within the // new group block. - const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { - return createBlock( name, attributes, innerBlocks ); + const groupInnerBlocks = blocks.map( ( block ) => { + return createBlock( block.name, block.attributes, block.innerBlocks ); } ); - yield createBlock( 'core/group', { + return createBlock( 'core/group', { align: widestAlignment, }, groupInnerBlocks ); }, diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 012ca6a8e86ad..683f5a455c2eb 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -11,6 +11,7 @@ import { filter, first, flatMap, + has, uniq, isFunction, isEmpty, @@ -27,16 +28,6 @@ import { createHooks, applyFilters } from '@wordpress/hooks'; import { getBlockType, getBlockTypes } from './registration'; import { normalizeBlockType } from './utils'; -/** - * Determines whether a function is a Generator function - * @param {Function} fn the function to test - * @return {boolean} whether or not the function is a generator - */ -function isGenerator( fn ) { - const sampleGenerator = function*() {}; - return fn.constructor.name === 'GeneratorFunction' && fn.constructor === sampleGenerator.constructor; -} - /** * Returns a block object given its type and attributes. * @@ -418,21 +409,17 @@ export function switchToBlockType( blocks, name ) { let transformationResults; - // Progressively enhancing the function signature using Generators - // Generator based transform functions are passed the entire Block object if ( transformation.isMultiBlock ) { - if ( isGenerator( transformation.transform ) ) { - const gen = transformation.transform( blocksArray ); - transformationResults = Array.from( gen ); + if ( has( transformation, 'apply' ) ) { + transformationResults = transformation.apply( blocksArray ); } else { transformationResults = transformation.transform( blocksArray.map( ( currentBlock ) => currentBlock.attributes ), blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ), ); } - } else if ( isGenerator( transformation.transform ) ) { - const gen = transformation.transform( [ firstBlock ] ); - transformationResults = Array.from( gen ); + } else if ( has( transformation, 'apply' ) ) { + transformationResults = transformation.apply( [ firstBlock ] ); } else { transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks ); } diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index 80aaa0c8d4a3e..a26e966d69be6 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -1302,7 +1302,7 @@ describe( 'block factory', () => { expect( transformedBlocks[ 1 ].innerBlocks[ 0 ].attributes.value ).toBe( 'after1' ); } ); - it( 'should pass entire block object to transform functions which are generators', () => { + it( 'should pass the entire block object to the "apply" method if defined', () => { registerBlockType( 'core/test-group-block', { attributes: { value: { @@ -1314,12 +1314,12 @@ describe( 'block factory', () => { type: 'block', blocks: [ '*' ], isMultiBlock: true, - *transform( blocks ) { + apply( blocks ) { const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { return createBlock( name, attributes, innerBlocks ); } ); - yield createBlock( 'core/test-group-block', {}, groupInnerBlocks ); + return createBlock( 'core/test-group-block', {}, groupInnerBlocks ); }, } ], }, @@ -1343,6 +1343,52 @@ describe( 'block factory', () => { expect( transformedBlocks[ 0 ].name ).toBe( 'core/test-group-block' ); expect( transformedBlocks[ 0 ].innerBlocks ).toHaveLength( numOfBlocksToGroup ); } ); + + it( 'should prefer "apply" method over "transform" method when running a transformation', () => { + const applySpy = jest.fn( ( blocks ) => { + const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { + return createBlock( name, attributes, innerBlocks ); + } ); + + return createBlock( 'core/test-group-block', {}, groupInnerBlocks ); + } ); + const transformSpy = jest.fn(); + + registerBlockType( 'core/test-group-block', { + attributes: { + value: { + type: 'string', + }, + }, + transforms: { + from: [ { + type: 'block', + blocks: [ '*' ], + isMultiBlock: true, + apply: applySpy, + transform: transformSpy, + } ], + }, + save: noop, + category: 'common', + title: 'Test Group Block', + } ); + + registerBlockType( 'core/text-block', defaultBlockSettings ); + + const numOfBlocksToGroup = 4; + const blocks = times( numOfBlocksToGroup, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const transformedBlocks = switchToBlockType( blocks, 'core/test-group-block' ); + + expect( transformedBlocks ).toHaveLength( 1 ); + expect( applySpy.mock.calls ).toHaveLength( 1 ); + expect( transformSpy.mock.calls ).toHaveLength( 0 ); + } ); } ); describe( 'getBlockTransforms', () => { From 1dc6c6d0c41748573d961de72bf1dfc8a60131c2 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 3 Jun 2019 15:47:36 +0100 Subject: [PATCH 58/76] Updates Block Reg docs to cover wildcard transforms --- .../block-api/block-registration.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/designers-developers/developers/block-api/block-registration.md b/docs/designers-developers/developers/block-api/block-registration.md index 8a2d6c26a7dab..4739e81b537a3 100644 --- a/docs/designers-developers/developers/block-api/block-registration.md +++ b/docs/designers-developers/developers/block-api/block-registration.md @@ -311,6 +311,40 @@ transforms: { ``` {% end %} +In addition to accepting an array of known block types, the `blocks` option also accepts a "wildcard" (`"*"`). This allows for transformations which apply to _all_ block types (eg: all blocks can transform into `core/group`): + +{% codetabs %} +{% ES5 %} +```js +transforms: { + from: [ + { + type: 'block', + blocks: [ '*' ], // wildcard - match any block + transform: function( attributes, innerBlocks ) { + // transform logic here + }, + }, + ], +}, +``` +{% ESNext %} +```js +transforms: { + from: [ + { + type: 'block', + blocks: blocks: [ '*' ], // wildcard - match any block + transform: ( attributes, innerBlocks ) => { + // transform logic here + }, + }, + ], +}, +``` +{% end %} + + A block with innerBlocks can also be transformed from and to another block with innerBlocks. {% codetabs %} From 19816615933e0669bf8f4a2a938866b73e9311f5 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 3 Jun 2019 15:53:04 +0100 Subject: [PATCH 59/76] Updates changelog to document wildcards and transform apply option --- packages/blocks/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index b13c58601e1e9..d85f3e3f6db4e 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -3,6 +3,8 @@ ### New Feature - Added a default implementation for `save` setting in `registerBlockType` which saves no markup in the post content. +- Added wildcard block transforms which allows for transforming all/any blocks in another block. +- Added `apply()` method option to `transforms` definition. It receives complete block object(s) as it's argument(s). It is now preferred over the older `transform()` (note that `transform()` is still fully supported). ## 6.1.0 (2019-03-06) From e8f7506faac92c1ce146b3e9a076c553af97ce9a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 3 Jun 2019 17:42:21 +0100 Subject: [PATCH 60/76] Fix linting error introduce in rebase --- packages/e2e-tests/specs/block-deletion.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/e2e-tests/specs/block-deletion.test.js b/packages/e2e-tests/specs/block-deletion.test.js index ba98a013f1aef..d9a0fde938d49 100644 --- a/packages/e2e-tests/specs/block-deletion.test.js +++ b/packages/e2e-tests/specs/block-deletion.test.js @@ -9,7 +9,6 @@ import { isInDefaultBlock, pressKeyWithModifier, pressKeyTimes, - clickBlockToolbarButton, insertBlock, } from '@wordpress/e2e-test-utils'; From 55700498cd3b0df4dddc818100278edd710fb3b8 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 08:38:49 +0100 Subject: [PATCH 61/76] Fixes test util to avoid infinite loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously if the button wasn’t found then the loop would continue forever looking for the button. This would have caused timeouts. Limits the loop to the number of buttons in the document. Also bails out immediately having found the button. Resolves https://github.com/WordPress/gutenberg/pull/14908#discussion_r290022464 --- packages/e2e-tests/specs/block-deletion.test.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/e2e-tests/specs/block-deletion.test.js b/packages/e2e-tests/specs/block-deletion.test.js index d9a0fde938d49..02cc0a0f5720e 100644 --- a/packages/e2e-tests/specs/block-deletion.test.js +++ b/packages/e2e-tests/specs/block-deletion.test.js @@ -31,21 +31,29 @@ const addThreeParagraphsToNewPost = async () => { * see: https://github.com/WordPress/gutenberg/pull/14908#discussion_r284725956 */ const clickOnBlockSettingsMenuRemoveBlockButton = async () => { + await clickBlockToolbarButton( 'More options' ); + let isRemoveButton = false; - await clickBlockToolbarButton( 'More options' ); + let numButtons = await page.$$eval( '.block-editor-block-toolbar button', ( btns ) => btns.length ); - while ( false === isRemoveButton ) { + // Limit by the number of buttons available + while ( --numButtons ) { await page.keyboard.press( 'Tab' ); isRemoveButton = await page.evaluate( () => { return document.activeElement.innerText.includes( 'Remove Block' ); } ); + + // Stop looping once we find the button + if ( isRemoveButton ) { + await pressKeyTimes( 'Enter', 1 ); + break; + } } + // Makes failures more explicit await expect( isRemoveButton ).toBe( true ); - - await pressKeyTimes( 'Enter', 1 ); }; describe( 'block deletion -', () => { From 8cb7c2f428bd049fc6479db3b33e0032e8cd1c38 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 08:47:26 +0100 Subject: [PATCH 62/76] Renames apply to convert to avoid confusion with Func.apply To avoid potential confusion and overlap with Function.apply, rename to `convert`. Slack discussion: https://wordpress.slack.com/archives/C02QB2JS7/p1559593099150300?thread_ts=1559571243.134500&cid=C02QB2JS7 MDN Function apply docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply Resolves: https://github.com/WordPress/gutenberg/pull/14908#discussion_r290021073 --- packages/block-library/src/group/index.js | 2 +- packages/blocks/CHANGELOG.md | 2 +- packages/blocks/src/api/factory.js | 8 ++++---- packages/blocks/src/api/test/factory.js | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index 6b74e04cbdbc0..386ab20a80955 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -33,7 +33,7 @@ export const settings = { type: 'block', isMultiBlock: true, blocks: [ '*' ], - apply( blocks ) { + convert( blocks ) { // Avoid transforming a single `core/group` Block if ( blocks.length === 1 && blocks[ 0 ].name === 'core/group' ) { return; diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index d85f3e3f6db4e..df5b183e688d4 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -4,7 +4,7 @@ - Added a default implementation for `save` setting in `registerBlockType` which saves no markup in the post content. - Added wildcard block transforms which allows for transforming all/any blocks in another block. -- Added `apply()` method option to `transforms` definition. It receives complete block object(s) as it's argument(s). It is now preferred over the older `transform()` (note that `transform()` is still fully supported). +- Added `convert()` method option to `transforms` definition. It receives complete block object(s) as it's argument(s). It is now preferred over the older `transform()` (note that `transform()` is still fully supported). ## 6.1.0 (2019-03-06) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 683f5a455c2eb..540aec00c2a92 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -410,16 +410,16 @@ export function switchToBlockType( blocks, name ) { let transformationResults; if ( transformation.isMultiBlock ) { - if ( has( transformation, 'apply' ) ) { - transformationResults = transformation.apply( blocksArray ); + if ( has( transformation, 'convert' ) ) { + transformationResults = transformation.convert( blocksArray ); } else { transformationResults = transformation.transform( blocksArray.map( ( currentBlock ) => currentBlock.attributes ), blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ), ); } - } else if ( has( transformation, 'apply' ) ) { - transformationResults = transformation.apply( [ firstBlock ] ); + } else if ( has( transformation, 'convert' ) ) { + transformationResults = transformation.convert( [ firstBlock ] ); } else { transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks ); } diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index a26e966d69be6..17860a35ade27 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -1302,7 +1302,7 @@ describe( 'block factory', () => { expect( transformedBlocks[ 1 ].innerBlocks[ 0 ].attributes.value ).toBe( 'after1' ); } ); - it( 'should pass the entire block object to the "apply" method if defined', () => { + it( 'should pass the entire block object to the "convert" method if defined', () => { registerBlockType( 'core/test-group-block', { attributes: { value: { @@ -1314,7 +1314,7 @@ describe( 'block factory', () => { type: 'block', blocks: [ '*' ], isMultiBlock: true, - apply( blocks ) { + convert( blocks ) { const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { return createBlock( name, attributes, innerBlocks ); } ); @@ -1344,8 +1344,8 @@ describe( 'block factory', () => { expect( transformedBlocks[ 0 ].innerBlocks ).toHaveLength( numOfBlocksToGroup ); } ); - it( 'should prefer "apply" method over "transform" method when running a transformation', () => { - const applySpy = jest.fn( ( blocks ) => { + it( 'should prefer "convert" method over "transform" method when running a transformation', () => { + const convertSpy = jest.fn( ( blocks ) => { const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { return createBlock( name, attributes, innerBlocks ); } ); @@ -1365,7 +1365,7 @@ describe( 'block factory', () => { type: 'block', blocks: [ '*' ], isMultiBlock: true, - apply: applySpy, + convert: convertSpy, transform: transformSpy, } ], }, @@ -1386,7 +1386,7 @@ describe( 'block factory', () => { const transformedBlocks = switchToBlockType( blocks, 'core/test-group-block' ); expect( transformedBlocks ).toHaveLength( 1 ); - expect( applySpy.mock.calls ).toHaveLength( 1 ); + expect( convertSpy.mock.calls ).toHaveLength( 1 ); expect( transformSpy.mock.calls ).toHaveLength( 0 ); } ); } ); From 4254769607205efad132aea6119c23c74a93812a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 08:49:24 +0100 Subject: [PATCH 63/76] Fixes unecessary additional var introduced during debugging --- packages/blocks/src/api/factory.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 540aec00c2a92..2f031412fc646 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -448,7 +448,7 @@ export function switchToBlockType( blocks, name ) { return null; } - const rtn = transformationResults.map( ( result, index ) => { + return transformationResults.map( ( result, index ) => { const transformedBlock = { ...result, // The first transformed block whose type matches the "destination" @@ -466,6 +466,4 @@ export function switchToBlockType( blocks, name ) { */ return applyFilters( 'blocks.switchToBlockType.transformedBlock', transformedBlock, blocks ); } ); - - return rtn; } From 60bb8a746afd8683c3f6b49e4098c0675d29280c Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 08:55:49 +0100 Subject: [PATCH 64/76] Fix convert API to match established patterns for consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously `convert` always passed an array of block objects even if there was only a single block. This is inconsistent with the implementation of the existing `transform` method which passes only a block’s attributes/innerBlocks pair when it is not a multi block. To retain consistency with the existing `isMultiBlock` paradiagm this updates the API of `convert` to pass a single block object when not in multiblock mode. --- packages/blocks/src/api/factory.js | 2 +- packages/blocks/src/api/test/factory.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 2f031412fc646..9c9d4aba214bf 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -419,7 +419,7 @@ export function switchToBlockType( blocks, name ) { ); } } else if ( has( transformation, 'convert' ) ) { - transformationResults = transformation.convert( [ firstBlock ] ); + transformationResults = transformation.convert( firstBlock ); } else { transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks ); } diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index 17860a35ade27..2734ceef43aec 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -1302,7 +1302,7 @@ describe( 'block factory', () => { expect( transformedBlocks[ 1 ].innerBlocks[ 0 ].attributes.value ).toBe( 'after1' ); } ); - it( 'should pass the entire block object to the "convert" method if defined', () => { + it( 'should pass entire block object(s) to the "convert" method if defined', () => { registerBlockType( 'core/test-group-block', { attributes: { value: { From 91f1868b9dfa5c9095aeb08db6d3533076de823a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 10:30:29 +0100 Subject: [PATCH 65/76] Fixes error in docs Co-Authored-By: Andrew Duthie --- .../developers/block-api/block-registration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/designers-developers/developers/block-api/block-registration.md b/docs/designers-developers/developers/block-api/block-registration.md index 4739e81b537a3..7986be28bee4b 100644 --- a/docs/designers-developers/developers/block-api/block-registration.md +++ b/docs/designers-developers/developers/block-api/block-registration.md @@ -334,7 +334,7 @@ transforms: { from: [ { type: 'block', - blocks: blocks: [ '*' ], // wildcard - match any block + blocks: [ '*' ], // wildcard - match any block transform: ( attributes, innerBlocks ) => { // transform logic here }, From a579c5ffd0174bb26f821084a8e23841b14e1dcf Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 10:36:34 +0100 Subject: [PATCH 66/76] Fixes doc blocks to match coding style Resolves https://github.com/WordPress/gutenberg/pull/14908#discussion_r290024877 --- packages/blocks/src/api/factory.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 9c9d4aba214bf..f0cc08f578ed8 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -237,17 +237,20 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { * and if so whether it is a "wildcard" transform * ie: targets "any" block type * - * @param {Object} t Block transform object - * @return {boolean} whether transform is a wildcard transform + * @param {Object} t the Block transform object + * + * @return {boolean} whether transform is a wildcard transform */ export const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && t.blocks.length && t.blocks.includes( '*' ); /** * Determines whether the given Block is the core Block which * acts as a container Block for other Blocks as part of the - * Grouping mechanocs + * Grouping mechanics + * * @param {string} name the name of the Block to test against - * @return {boolean} whether or not the Block is the container Block type + * + * @return {boolean} whether or not the Block is the container Block type */ export const isContainerGroupBlock = ( name ) => name === 'core/group'; @@ -256,7 +259,8 @@ export const isContainerGroupBlock = ( name ) => name === 'core/group'; * (eg: all `core/paragraph`). * * @param {Array} blocksArray the Block definitions - * @return {boolean} whether or not the given Blocks pass the criteria + * + * @return {boolean} whether or not the given Blocks pass the criteria */ export const isBlockSelectionOfSameType = ( blocksArray = [] ) => { if ( ! blocksArray.length ) { @@ -270,8 +274,10 @@ export const isBlockSelectionOfSameType = ( blocksArray = [] ) => { /** * Determines whether the provided Blocks constitute * a multi-block selection (ie: more than 1) - * @param {Array} blocksArray [description] - * @return {boolean} [description] + * + * @param {Array} blocksArray the array of blocks to test + * + * @return {boolean} whether or not the blocks consistute a multi-selection */ export const isMultiBlockSelection = ( blocksArray = [] ) => { return blocksArray.length > 1; From b6f7f555ba8383b5612703ccd34f77fc70623359 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 10:44:17 +0100 Subject: [PATCH 67/76] Fixes icon size and color in dropdown for Group/Ungroup --- .../components/convert-to-group-buttons/icons.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/icons.js b/packages/editor/src/components/convert-to-group-buttons/icons.js index 89b060fd9cc5d..ff96a5edfa007 100644 --- a/packages/editor/src/components/convert-to-group-buttons/icons.js +++ b/packages/editor/src/components/convert-to-group-buttons/icons.js @@ -3,20 +3,16 @@ */ import { Icon, SVG, Path } from '@wordpress/components'; -const GroupSVG = - - +const GroupSVG = + + ; export const Group = ; -const UnGroupSVG = - - +const UnGroupSVG = + + ; export const UnGroup = ; From 4707009fb7b30b14e2314a0a471efd31bb1957d1 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 13:18:29 +0100 Subject: [PATCH 68/76] Updates to remove keyboard shortcuts Following a discussion it was not possible to achieve a consensus on which shortcuts was most suitable (or indeed whether keyboard shortcuts for this were even a good idea). As a result this has been descoped from this PR and will be addressed elsewhere. Once merged I will push a new placeholder PR with the foundation for shortcuts in place and others can then amend it. --- .../block-editor-keyboard-shortcuts/index.js | 15 +-------------- .../keyboard-shortcut-help-modal/config.js | 8 -------- .../convert-to-group-buttons/convert-button.js | 3 --- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js index 001c25bbeaff0..7e9a433182eba 100644 --- a/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js +++ b/packages/block-editor/src/components/block-editor-keyboard-shortcuts/index.js @@ -39,15 +39,6 @@ export const shortcuts = { raw: rawShortcut.primaryAlt( 'y' ), display: displayShortcut.primaryAlt( 'y' ), }, - group: { - raw: rawShortcut.primaryAlt( 'g' ), - display: displayShortcut.primaryAlt( 'g' ), - }, - ungroup: { - raw: rawShortcut.secondary( 'g' ), - display: displayShortcut.secondary( 'g' ), - }, - }; class BlockEditorKeyboardShortcuts extends Component { @@ -100,7 +91,7 @@ class BlockEditorKeyboardShortcuts extends Component { /> { selectedBlockClientIds.length > 0 && ( - { ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore, onGroup, onUngroup } ) => ( + { ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore } ) => ( ) } diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js index 0a1f4f489a0f2..5c6037c0467f4 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js @@ -118,14 +118,6 @@ const blockShortcuts = { /* translators: The forward-slash character. e.g. '/'. */ ariaLabel: __( 'Forward-slash' ), }, - { - keyCombination: primaryAlt( 'g' ), - description: __( 'Group the selected blocks.' ), - }, - { - keyCombination: secondary( 'g' ), - description: __( 'Ungroup the selected blocks.' ), - }, ], }; diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index e10eb9b8944fa..9c6bcccf07aa5 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -12,7 +12,6 @@ import { _x } from '@wordpress/i18n'; import { switchToBlockType } from '@wordpress/blocks'; import { withSelect, withDispatch } from '@wordpress/data'; import { compose } from '@wordpress/compose'; -import { displayShortcut } from '@wordpress/keycodes'; /** * Internal dependencies @@ -32,7 +31,6 @@ export function ConvertToGroupButton( { className="editor-block-settings-menu__control block-editor-block-settings-menu__control" icon={ Group } onClick={ onConvertToGroup } - shortcut={ displayShortcut.primaryAlt( 'g' ) } > { _x( 'Group', 'verb' ) } @@ -42,7 +40,6 @@ export function ConvertToGroupButton( { className="editor-block-settings-menu__control block-editor-block-settings-menu__control" icon={ UnGroup } onClick={ onConvertFromGroup } - shortcut={ displayShortcut.secondary( 'g' ) } > { _x( 'Ungroup', 'Ungrouping blocks from within a Group block back into individual blocks within the Editor ' ) } From afec59407be841a59475555d5199a67497a19198 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 13:44:13 +0100 Subject: [PATCH 69/76] Updates snapshot to account for removing keyboard shortcuts --- .../test/__snapshots__/index.js.snap | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap index a3424e31727b5..fe522a985d3b9 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap @@ -211,28 +211,6 @@ exports[`KeyboardShortcutHelpModal should match snapshot when the modal is activ "description": "Change the block type after adding a new paragraph.", "keyCombination": "/", }, - Object { - "description": "Group the selected blocks.", - "keyCombination": Array [ - "Ctrl", - "+", - "Alt", - "+", - "G", - ], - }, - Object { - "description": "Ungroup the selected blocks.", - "keyCombination": Array [ - "Ctrl", - "+", - "Shift", - "+", - "Alt", - "+", - "G", - ], - }, ] } title="Block shortcuts" From 5dd34524c2a6bdd81b399d959ad71636ef0c3501 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 4 Jun 2019 13:55:02 +0100 Subject: [PATCH 70/76] Removes e2e tests covering keyboard shortcuts --- .../__snapshots__/block-grouping.test.js.snap | 30 ------------------- .../e2e-tests/specs/block-grouping.test.js | 26 ---------------- 2 files changed, 56 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap index 857ab92d84c1a..af571b2010ed2 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -78,36 +78,6 @@ exports[`Block Grouping Group creation groups and ungroups multiple blocks of di " `; -exports[`Block Grouping Keyboard shortcuts groups and ungroups using keyboard shortcuts 1`] = ` -" -
-

Group Heading

- - - -
\\"\\"/
- - - -

Some paragraph

-
-" -`; - -exports[`Block Grouping Keyboard shortcuts groups and ungroups using keyboard shortcuts 2`] = ` -" -

Group Heading

- - - -
\\"\\"/
- - - -

Some paragraph

-" -`; - exports[`Block Grouping Preserving selected blocks attributes preserves width alignment settings of selected blocks 1`] = ` "
diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js index 1762e92a68747..57300ec2b9de6 100644 --- a/packages/e2e-tests/specs/block-grouping.test.js +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -104,32 +104,6 @@ describe( 'Block Grouping', () => { } ); } ); - describe( 'Keyboard shortcuts', () => { - it( 'groups and ungroups using keyboard shortcuts', async () => { - let allBlocks; - - await insertBlocksOfMultipleTypes(); - await pressKeyWithModifier( 'primary', 'a' ); - await pressKeyWithModifier( 'primary', 'a' ); - - // Group - await pressKeyWithModifier( 'primaryAlt', 'g' ); - - allBlocks = await getAllBlocks(); - - expect( allBlocks[ 0 ].name ).toBe( 'core/group' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - - // Ungroup (Primary, Shift, Alt) - await pressKeyWithModifier( 'secondary', 'g' ); - - allBlocks = await getAllBlocks(); - - expect( allBlocks[ 0 ].name ).not.toBe( 'core/group' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - } ); - describe( 'Container Block availability', () => { beforeEach( async () => { // Disable the Group block From abbcd4e5e6cacd4428b3f33e7368beb4ccba00cf Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Jun 2019 09:33:04 +0100 Subject: [PATCH 71/76] Fixes unwanted check introduced during debugging Test for existence of transform is not required and was introduced during debugging. Can be removed. --- packages/blocks/src/api/factory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index f0cc08f578ed8..676a27b5f3760 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -188,7 +188,7 @@ const getBlockTypesForPossibleFromTransforms = ( blocks ) => { return !! findTransform( fromTransforms, ( transform ) => { - return transform && isPossibleTransformForSource( transform, 'from', blocks ); + return isPossibleTransformForSource( transform, 'from', blocks ); } ); }, From b9350e20a2cbbd7302e417c2f6fad70182131046 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Jun 2019 09:34:14 +0100 Subject: [PATCH 72/76] Updates to collapse spaces in doc blocks Co-Authored-By: Andrew Duthie --- packages/blocks/src/api/factory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 676a27b5f3760..4c1b01258e56f 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -237,7 +237,7 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { * and if so whether it is a "wildcard" transform * ie: targets "any" block type * - * @param {Object} t the Block transform object + * @param {Object} t the Block transform object * * @return {boolean} whether transform is a wildcard transform */ From efa7ac65a9ca4efe099a2eee1b9441b6269b6f67 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Jun 2019 09:37:03 +0100 Subject: [PATCH 73/76] Fixes isWildcardBlockTransform to test for Array-ness Resolves https://github.com/WordPress/gutenberg/pull/14908#discussion_r290459410 --- packages/blocks/src/api/factory.js | 2 +- packages/blocks/src/api/test/factory.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 4c1b01258e56f..7ed155250f20a 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -241,7 +241,7 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { * * @return {boolean} whether transform is a wildcard transform */ -export const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && t.blocks.length && t.blocks.includes( '*' ); +export const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && Array.isArray( t.blocks ) && t.blocks.includes( '*' ); /** * Determines whether the given Block is the core Block which diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index 2734ceef43aec..1206cccfcaef3 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -1542,6 +1542,16 @@ describe( 'block factory', () => { expect( isWildcardBlockTransform( invalidWildcardBlockTransform ) ).toBe( false ); } ); + + it( 'should return false for transforms which do not provide an array as the "blocks" option', () => { + const invalidWildcardBlockTransform = { + type: 'block', + blocks: noop, + blockName: 'core/test-block', + }; + + expect( isWildcardBlockTransform( invalidWildcardBlockTransform ) ).toBe( false ); + } ); } ); describe( 'isContainerGroupBlock', () => { From c6ee214daa7ed4fb8a44d69e76c3b16752c5ee6a Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Jun 2019 09:40:36 +0100 Subject: [PATCH 74/76] =?UTF-8?q?Fixes=20incorrect=20capitalisation=20of?= =?UTF-8?q?=20=E2=80=9CUnGroup=E2=80=9D=20to=20=E2=80=9CUngroup=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r290461528 --- .../convert-to-group-buttons/convert-button.js | 12 ++++++------ .../src/components/convert-to-group-buttons/icons.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js index 9c6bcccf07aa5..6a7299ed259c9 100644 --- a/packages/editor/src/components/convert-to-group-buttons/convert-button.js +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -16,13 +16,13 @@ import { compose } from '@wordpress/compose'; /** * Internal dependencies */ -import { Group, UnGroup } from './icons'; +import { Group, Ungroup } from './icons'; export function ConvertToGroupButton( { onConvertToGroup, onConvertFromGroup, isGroupable = false, - isUnGroupable = false, + isUngroupable = false, } ) { return ( @@ -35,10 +35,10 @@ export function ConvertToGroupButton( { { _x( 'Group', 'verb' ) } ) } - { isUnGroupable && ( + { isUngroupable && ( { _x( 'Ungroup', 'Ungrouping blocks from within a Group block back into individual blocks within the Editor ' ) } @@ -73,11 +73,11 @@ export default compose( [ ); // Do we have a single Group Block selected? - const isUnGroupable = isSingleContainerBlock; + const isUngroupable = isSingleContainerBlock; return { isGroupable, - isUnGroupable, + isUngroupable, blocksSelection, }; } ), diff --git a/packages/editor/src/components/convert-to-group-buttons/icons.js b/packages/editor/src/components/convert-to-group-buttons/icons.js index ff96a5edfa007..22fcfda4c2e04 100644 --- a/packages/editor/src/components/convert-to-group-buttons/icons.js +++ b/packages/editor/src/components/convert-to-group-buttons/icons.js @@ -10,10 +10,10 @@ const GroupSVG = ; -const UnGroupSVG = +const UngroupSVG = ; -export const UnGroup = ; +export const UnGroup = ; From f9fd251934cf561e5be30f698547fa71d3ca5a9f Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Jun 2019 11:17:26 +0100 Subject: [PATCH 75/76] Updates to remove redundant isMultiBlockSelection util function Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r290463266 --- packages/blocks/src/api/factory.js | 14 +------------- packages/blocks/src/api/test/factory.js | 14 -------------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 7ed155250f20a..304329d0be657 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -271,18 +271,6 @@ export const isBlockSelectionOfSameType = ( blocksArray = [] ) => { return every( blocksArray, [ 'name', sourceName ] ); }; -/** - * Determines whether the provided Blocks constitute - * a multi-block selection (ie: more than 1) - * - * @param {Array} blocksArray the array of blocks to test - * - * @return {boolean} whether or not the blocks consistute a multi-selection - */ -export const isMultiBlockSelection = ( blocksArray = [] ) => { - return blocksArray.length > 1; -}; - /** * Returns an array of block types that the set of blocks received as argument * can be transformed into. @@ -382,7 +370,7 @@ export function getBlockTransforms( direction, blockTypeOrName ) { */ export function switchToBlockType( blocks, name ) { const blocksArray = castArray( blocks ); - const isMultiBlock = isMultiBlockSelection( blocksArray ); + const isMultiBlock = blocksArray.length > 1; const firstBlock = blocksArray[ 0 ]; const sourceName = firstBlock.name; diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index 1206cccfcaef3..3e0d42c103bb9 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -17,7 +17,6 @@ import { isWildcardBlockTransform, isContainerGroupBlock, isBlockSelectionOfSameType, - isMultiBlockSelection, } from '../factory'; import { getBlockType, @@ -1564,19 +1563,6 @@ describe( 'block factory', () => { } ); } ); - describe( 'isMultiBlockSelection', () => { - it( 'should return false when there is one block or less', () => { - const singleBlock = [ - { - name: 'core/test-block', - }, - ]; - - expect( isMultiBlockSelection( [] ) ).toBe( false ); - expect( isMultiBlockSelection( singleBlock ) ).toBe( false ); - } ); - } ); - describe( 'isBlockSelectionOfSameType', () => { it( 'should return false when all blocks do not match the name of the first block', () => { const blocks = [ From 1a938adb4a291b1f78ff542e6ce2b61e58b08860 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Jun 2019 11:37:03 +0100 Subject: [PATCH 76/76] Reinstate missing Ungroup icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accidentally got lost during renaming of “UnGroup” to “Ungroup”! --- .../editor/src/components/convert-to-group-buttons/icons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/convert-to-group-buttons/icons.js b/packages/editor/src/components/convert-to-group-buttons/icons.js index 22fcfda4c2e04..8ca249c2fa7ee 100644 --- a/packages/editor/src/components/convert-to-group-buttons/icons.js +++ b/packages/editor/src/components/convert-to-group-buttons/icons.js @@ -15,5 +15,5 @@ const UngroupSVG = ; -export const UnGroup = ; +export const Ungroup = ;