From af4755794bf2f8ecd32a4760a7ad2a2b9c1bf7a9 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 13 Nov 2018 16:06:00 +0100 Subject: [PATCH 01/10] Avoid getBlock in block-list/block --- .../block-list/block-invalid-warning.js | 36 ++++++++------ .../editor/src/components/block-list/block.js | 48 +++++++++++-------- packages/editor/src/hooks/align.js | 5 +- packages/editor/src/hooks/test/align.js | 16 +++---- packages/editor/src/store/selectors.js | 40 +++++++++++++--- 5 files changed, 90 insertions(+), 55 deletions(-) diff --git a/packages/editor/src/components/block-list/block-invalid-warning.js b/packages/editor/src/components/block-list/block-invalid-warning.js index 27520ac4b79bd..bc4555b1a3f0b 100644 --- a/packages/editor/src/components/block-list/block-invalid-warning.js +++ b/packages/editor/src/components/block-list/block-invalid-warning.js @@ -9,7 +9,8 @@ import { createBlock, rawHandler, } from '@wordpress/blocks'; -import { withDispatch } from '@wordpress/data'; +import { compose } from '@wordpress/compose'; +import { withDispatch, withSelect } from '@wordpress/data'; /** * Internal dependencies @@ -96,18 +97,23 @@ const blockToBlocks = ( block ) => rawHandler( { HTML: block.originalContent, } ); -export default withDispatch( ( dispatch, { block } ) => { - const { replaceBlock } = dispatch( 'core/editor' ); +export default compose( [ + withSelect( ( select, { clientId } ) => ( { + block: select( 'core/editor' ).getBlock( clientId ), + } ) ), + withDispatch( ( dispatch, { block } ) => { + const { replaceBlock } = dispatch( 'core/editor' ); - return { - convertToClassic() { - replaceBlock( block.clientId, blockToClassic( block ) ); - }, - convertToHTML() { - replaceBlock( block.clientId, blockToHTML( block ) ); - }, - convertToBlocks() { - replaceBlock( block.clientId, blockToBlocks( block ) ); - }, - }; -} )( BlockInvalidWarning ); + return { + convertToClassic() { + replaceBlock( block.clientId, blockToClassic( block ) ); + }, + convertToHTML() { + replaceBlock( block.clientId, blockToHTML( block ) ); + }, + convertToBlocks() { + replaceBlock( block.clientId, blockToBlocks( block ) ); + }, + }; + } ), +] )( BlockInvalidWarning ); diff --git a/packages/editor/src/components/block-list/block.js b/packages/editor/src/components/block-list/block.js index 98956980d0d55..eb188d5099563 100644 --- a/packages/editor/src/components/block-list/block.js +++ b/packages/editor/src/components/block-list/block.js @@ -165,9 +165,9 @@ export class BlockListBlock extends Component { } setAttributes( attributes ) { - const { block, onChange } = this.props; - const type = getBlockType( block.name ); - onChange( block.clientId, attributes ); + const { clientId, blockName, onChange } = this.props; + const type = getBlockType( blockName ); + onChange( clientId, attributes ); const metaAttributes = reduce( attributes, ( result, value, key ) => { if ( get( type, [ 'attributes', key, 'source' ] ) === 'meta' ) { @@ -227,7 +227,7 @@ export class BlockListBlock extends Component { } mergeBlocks( forward = false ) { - const { block, previousBlockClientId, nextBlockClientId, onMerge } = this.props; + const { clientId, previousBlockClientId, nextBlockClientId, onMerge } = this.props; // Do nothing when it's the first block. if ( @@ -238,9 +238,9 @@ export class BlockListBlock extends Component { } if ( forward ) { - onMerge( block.clientId, nextBlockClientId ); + onMerge( clientId, nextBlockClientId ); } else { - onMerge( previousBlockClientId, block.clientId ); + onMerge( previousBlockClientId, clientId ); } } @@ -372,7 +372,6 @@ export class BlockListBlock extends Component { { ( { hoverArea } ) => { const { - block, order, mode, isFocusMode, @@ -394,16 +393,18 @@ export class BlockListBlock extends Component { isParentOfSelectedBlock, isDraggable, className, + blockName, + isValid, + blockAttributes, } = this.props; const isHovered = this.state.isHovered && ! isMultiSelecting; - const { name: blockName, isValid } = block; const blockType = getBlockType( blockName ); // translators: %s: Type of block (i.e. Text, Image etc) const blockLabel = sprintf( __( 'Block: %s' ), blockType.title ); // The block as rendered in the editor is composed of general block UI // (mover, toolbar, wrapper) and the display of the block content. - const isUnregisteredBlock = block.name === getUnregisteredTypeHandlerName(); + const isUnregisteredBlock = blockName === getUnregisteredTypeHandlerName(); // If the block is selected and we're typing the block should not appear. // Empty paragraph blocks should always show up as unselected. @@ -444,7 +445,7 @@ export class BlockListBlock extends Component { if ( blockType.getEditWrapperProps ) { wrapperProps = { ...wrapperProps, - ...blockType.getEditWrapperProps( block.attributes ), + ...blockType.getEditWrapperProps( blockAttributes ), }; } const blockElementId = `block-${ clientId }`; @@ -457,7 +458,7 @@ export class BlockListBlock extends Component { ,
- { getSaveElement( blockType, block.attributes ) } + { getSaveElement( blockType, blockAttributes ) }
, ] } @@ -620,7 +621,9 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId, isLargeV isBlockSelected, getPreviousBlockClientId, getNextBlockClientId, - getBlock, + getBlockName, + isBlockValid, + getBlockAttributes, isAncestorMultiSelected, isBlockMultiSelected, isFirstMultiSelectedBlock, @@ -637,11 +640,11 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId, isLargeV } = select( 'core/editor' ); const isSelected = isBlockSelected( clientId ); const { hasFixedToolbar, focusMode } = getEditorSettings(); - const block = getBlock( clientId ); const previousBlockClientId = getPreviousBlockClientId( clientId ); - const previousBlock = getBlock( previousBlockClientId ); const templateLock = getTemplateLock( rootClientId ); const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId, true ); + const blockName = getBlockName( clientId ); + const blockAttributes = getBlockAttributes( clientId ); return { nextBlockClientId: getNextBlockClientId( clientId ), @@ -656,14 +659,19 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId, isLargeV mode: getBlockMode( clientId ), isSelectionEnabled: isSelectionEnabled(), initialPosition: getSelectedBlocksInitialCaretPosition(), - isEmptyDefaultBlock: block && isUnmodifiedDefaultBlock( block ), - isPreviousBlockADefaultEmptyBlock: previousBlock && isUnmodifiedDefaultBlock( previousBlock ), + isEmptyDefaultBlock: blockName && isUnmodifiedDefaultBlock( { name: blockName, attributes: blockAttributes } ), + isPreviousBlockADefaultEmptyBlock: previousBlockClientId && isUnmodifiedDefaultBlock( { + name: getBlockName( previousBlockClientId ), + attributes: getBlockAttributes( previousBlockClientId ), + } ), + isValid: isBlockValid( clientId ), isMovable: 'all' !== templateLock, isLocked: !! templateLock, isFocusMode: focusMode && isLargeViewport, hasFixedToolbar: hasFixedToolbar && isLargeViewport, + blockName, + blockAttributes, previousBlockClientId, - block, isSelected, isParentOfSelectedBlock, }; diff --git a/packages/editor/src/hooks/align.js b/packages/editor/src/hooks/align.js index 7b7062ba558f5..08c429e199561 100644 --- a/packages/editor/src/hooks/align.js +++ b/packages/editor/src/hooks/align.js @@ -141,9 +141,8 @@ export const withToolbarControls = createHigherOrderComponent( // Exported just for testing purposes, not exported outside the module. export const insideSelectWithDataAlign = ( BlockListBlock ) => ( ( props ) => { - const { block, hasWideEnabled } = props; - const { name: blockName } = block; - const { align } = block.attributes; + const { blockName, blockAttributes, hasWideEnabled } = props; + const { align } = blockAttributes; const validAlignments = getValidAlignments( getBlockSupport( blockName, 'align' ), hasBlockSupport( blockName, 'alignWide', true ), diff --git a/packages/editor/src/hooks/test/align.js b/packages/editor/src/hooks/test/align.js index 5d3f3dba87c28..8c83cf6b6a49f 100644 --- a/packages/editor/src/hooks/test/align.js +++ b/packages/editor/src/hooks/test/align.js @@ -175,12 +175,10 @@ describe( 'align', () => { const wrapper = renderer.create( ); expect( wrapper.toTree().rendered.props.wrapperProps ).toEqual( { @@ -230,11 +228,9 @@ describe( 'align', () => { const wrapper = renderer.create( ); diff --git a/packages/editor/src/store/selectors.js b/packages/editor/src/store/selectors.js index 099abab1b49d8..af819e72fc169 100644 --- a/packages/editor/src/store/selectors.js +++ b/packages/editor/src/store/selectors.js @@ -627,17 +627,15 @@ export function isBlockValid( state, clientId ) { } /** - * Returns a block given its client ID. This is a parsed copy of the block, - * containing its `blockName`, `clientId`, and current `attributes` state. This - * is not the block's registration settings, which must be retrieved from the - * blocks module registration store. + * Returns a block's attributes given its client ID, or null if no block exists with + * the client ID. * * @param {Object} state Editor state. * @param {string} clientId Block client ID. * - * @return {Object} Parsed block object. + * @return {Object?} Block attributes. */ -export const getBlock = createSelector( +export const getBlockAttributes = createSelector( ( state, clientId ) => { const block = state.editor.present.blocks.byClientId[ clientId ]; if ( ! block ) { @@ -665,9 +663,37 @@ export const getBlock = createSelector( }, attributes ); } + return attributes; + }, + ( state, clientId ) => [ + state.editor.present.blocks.byClientId[ clientId ], + state.editor.present.edits.meta, + state.initialEdits.meta, + state.currentPost.meta, + ] +); + +/** + * Returns a block given its client ID. This is a parsed copy of the block, + * containing its `blockName`, `clientId`, and current `attributes` state. This + * is not the block's registration settings, which must be retrieved from the + * blocks module registration store. + * + * @param {Object} state Editor state. + * @param {string} clientId Block client ID. + * + * @return {Object} Parsed block object. + */ +export const getBlock = createSelector( + ( state, clientId ) => { + const block = state.editor.present.blocks.byClientId[ clientId ]; + if ( ! block ) { + return null; + } + return { ...block, - attributes, + attributes: getBlockAttributes( state, clientId ), innerBlocks: getBlocks( state, clientId ), }; }, From ffcd3c7922fd76639e407e442047f8cbf7121876 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 16 Nov 2018 12:46:38 +0100 Subject: [PATCH 02/10] Update data docs --- .../developers/data/data-core-editor.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/designers-developers/developers/data/data-core-editor.md b/docs/designers-developers/developers/data/data-core-editor.md index f48dc8539dd2e..800537ba65d22 100644 --- a/docs/designers-developers/developers/data/data-core-editor.md +++ b/docs/designers-developers/developers/data/data-core-editor.md @@ -411,6 +411,20 @@ Returns whether a block is valid or not. Is Valid. +### getBlockAttributes + +Returns a block's attributes given its client ID, or null if no block exists with +the client ID. + +*Parameters* + + * state: Editor state. + * clientId: Block client ID. + +*Returns* + +Block attributes. + ### getBlock Returns a block given its client ID. This is a parsed copy of the block, From bcb0c0aee37e0495e30190280a22368be9119dfe Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 27 Nov 2018 15:03:51 +0100 Subject: [PATCH 03/10] Fix unit tests post rebase :) --- packages/editor/src/hooks/test/align.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/hooks/test/align.js b/packages/editor/src/hooks/test/align.js index 8c83cf6b6a49f..245a11dfde1a1 100644 --- a/packages/editor/src/hooks/test/align.js +++ b/packages/editor/src/hooks/test/align.js @@ -201,11 +201,9 @@ describe( 'align', () => { const wrapper = renderer.create( From 9b9bfc46ce0c31b48db87a5571c7edadac8d84c6 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 28 Nov 2018 10:15:16 +0100 Subject: [PATCH 04/10] Rename props --- .../editor/src/components/block-list/block.js | 32 +++++++++---------- packages/editor/src/hooks/align.js | 8 ++--- packages/editor/src/hooks/test/align.js | 12 +++---- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/editor/src/components/block-list/block.js b/packages/editor/src/components/block-list/block.js index eb188d5099563..d1fbae0fbe584 100644 --- a/packages/editor/src/components/block-list/block.js +++ b/packages/editor/src/components/block-list/block.js @@ -165,8 +165,8 @@ export class BlockListBlock extends Component { } setAttributes( attributes ) { - const { clientId, blockName, onChange } = this.props; - const type = getBlockType( blockName ); + const { clientId, name, onChange } = this.props; + const type = getBlockType( name ); onChange( clientId, attributes ); const metaAttributes = reduce( attributes, ( result, value, key ) => { @@ -393,18 +393,18 @@ export class BlockListBlock extends Component { isParentOfSelectedBlock, isDraggable, className, - blockName, + name, isValid, - blockAttributes, + attributes, } = this.props; const isHovered = this.state.isHovered && ! isMultiSelecting; - const blockType = getBlockType( blockName ); + const blockType = getBlockType( name ); // translators: %s: Type of block (i.e. Text, Image etc) const blockLabel = sprintf( __( 'Block: %s' ), blockType.title ); // The block as rendered in the editor is composed of general block UI // (mover, toolbar, wrapper) and the display of the block content. - const isUnregisteredBlock = blockName === getUnregisteredTypeHandlerName(); + const isUnregisteredBlock = name === getUnregisteredTypeHandlerName(); // If the block is selected and we're typing the block should not appear. // Empty paragraph blocks should always show up as unselected. @@ -445,7 +445,7 @@ export class BlockListBlock extends Component { if ( blockType.getEditWrapperProps ) { wrapperProps = { ...wrapperProps, - ...blockType.getEditWrapperProps( blockAttributes ), + ...blockType.getEditWrapperProps( attributes ), }; } const blockElementId = `block-${ clientId }`; @@ -456,9 +456,9 @@ export class BlockListBlock extends Component { // `BlockHTML`, even in HTML mode. let blockEdit = ( ,
- { getSaveElement( blockType, blockAttributes ) } + { getSaveElement( blockType, attributes ) }
, ] } @@ -643,8 +643,8 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId, isLargeV const previousBlockClientId = getPreviousBlockClientId( clientId ); const templateLock = getTemplateLock( rootClientId ); const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId, true ); - const blockName = getBlockName( clientId ); - const blockAttributes = getBlockAttributes( clientId ); + const name = getBlockName( clientId ); + const attributes = getBlockAttributes( clientId ); return { nextBlockClientId: getNextBlockClientId( clientId ), @@ -659,7 +659,7 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId, isLargeV mode: getBlockMode( clientId ), isSelectionEnabled: isSelectionEnabled(), initialPosition: getSelectedBlocksInitialCaretPosition(), - isEmptyDefaultBlock: blockName && isUnmodifiedDefaultBlock( { name: blockName, attributes: blockAttributes } ), + isEmptyDefaultBlock: name && isUnmodifiedDefaultBlock( { name, attributes } ), isPreviousBlockADefaultEmptyBlock: previousBlockClientId && isUnmodifiedDefaultBlock( { name: getBlockName( previousBlockClientId ), attributes: getBlockAttributes( previousBlockClientId ), @@ -669,8 +669,8 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId, isLargeV isLocked: !! templateLock, isFocusMode: focusMode && isLargeViewport, hasFixedToolbar: hasFixedToolbar && isLargeViewport, - blockName, - blockAttributes, + name, + attributes, previousBlockClientId, isSelected, isParentOfSelectedBlock, diff --git a/packages/editor/src/hooks/align.js b/packages/editor/src/hooks/align.js index 08c429e199561..e22922c198b2c 100644 --- a/packages/editor/src/hooks/align.js +++ b/packages/editor/src/hooks/align.js @@ -141,11 +141,11 @@ export const withToolbarControls = createHigherOrderComponent( // Exported just for testing purposes, not exported outside the module. export const insideSelectWithDataAlign = ( BlockListBlock ) => ( ( props ) => { - const { blockName, blockAttributes, hasWideEnabled } = props; - const { align } = blockAttributes; + const { name, attributes, hasWideEnabled } = props; + const { align } = attributes; const validAlignments = getValidAlignments( - getBlockSupport( blockName, 'align' ), - hasBlockSupport( blockName, 'alignWide', true ), + getBlockSupport( name, 'align' ), + hasBlockSupport( name, 'alignWide', true ), hasWideEnabled ); diff --git a/packages/editor/src/hooks/test/align.js b/packages/editor/src/hooks/test/align.js index 245a11dfde1a1..995d3a9a59c4c 100644 --- a/packages/editor/src/hooks/test/align.js +++ b/packages/editor/src/hooks/test/align.js @@ -175,10 +175,10 @@ describe( 'align', () => { const wrapper = renderer.create( ); expect( wrapper.toTree().rendered.props.wrapperProps ).toEqual( { @@ -201,8 +201,8 @@ describe( 'align', () => { const wrapper = renderer.create( { const wrapper = renderer.create( From f273996b4a3aee1799eb8837cddbb471a2085082 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 28 Nov 2018 10:23:34 +0100 Subject: [PATCH 05/10] Clarify the filter position --- .../developers/filters/block-filters.md | 27 ++++++------------- .../editor/src/components/block-list/block.js | 3 ++- packages/editor/src/hooks/align.js | 2 +- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/docs/designers-developers/developers/filters/block-filters.md b/docs/designers-developers/developers/filters/block-filters.md index 378241356578a..df3a5d4567ca9 100644 --- a/docs/designers-developers/developers/filters/block-filters.md +++ b/docs/designers-developers/developers/filters/block-filters.md @@ -198,19 +198,13 @@ _Example:_ ```js var el = wp.element.createElement; -var withDataAlign = wp.compose.createHigherOrderComponent( function( BlockListBlock ) { +var withClientIdClassName = wp.compose.createHigherOrderComponent( function( BlockListBlock ) { return function( props ) { var newProps = lodash.assign( {}, props, { - wrapperProps: lodash.assign( - {}, - props.wrapperProps, - { - 'data-align': props.block.attributes.align - } - ) + classsName: "block-" + props.clientID, } ); @@ -219,27 +213,22 @@ var withDataAlign = wp.compose.createHigherOrderComponent( function( BlockListBl newProps ); }; -}, 'withAlign' ); +}, 'withClientIdClassName' ); -wp.hooks.addFilter( 'editor.BlockListBlock', 'my-plugin/with-data-align', withDataAlign ); +wp.hooks.addFilter( 'editor.BlockListBlock', 'my-plugin/with-client-id-class-name', withClientIdClassName ); ``` {% ESNext %} ```js const { createHigherOrderComponent } = wp.compose; -const withDataAlign = createHigherOrderComponent( ( BlockListBlock ) => { +const withClientIdClassName = createHigherOrderComponent( ( BlockListBlock ) => { return ( props ) => { - const { align } = props.block.attributes; - - let wrapperProps = props.wrapperProps; - wrapperProps = { ...wrapperProps, 'data-align': align }; - - return ; + return ; }; -}, 'withDataAlign' ); +}, 'withClientIdClassName' ); -wp.hooks.addFilter( 'editor.BlockListBlock', 'my-plugin/with-data-align', withDataAlign ); +wp.hooks.addFilter( 'editor.BlockListBlock', 'my-plugin/with-client-id-class-name', withClientIdClassName ); ``` {% end %} diff --git a/packages/editor/src/components/block-list/block.js b/packages/editor/src/components/block-list/block.js index d1fbae0fbe584..2b30eed8a965b 100644 --- a/packages/editor/src/components/block-list/block.js +++ b/packages/editor/src/components/block-list/block.js @@ -737,8 +737,9 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => { } ); export default compose( + withFilters( 'editor.BlockListBlock' ), withViewportMatch( { isLargeViewport: 'medium' } ), applyWithSelect, applyWithDispatch, - withFilters( 'editor.BlockListBlock' ), + withFilters( 'editor.__experimentalBlockListBlock' ), )( BlockListBlock ); diff --git a/packages/editor/src/hooks/align.js b/packages/editor/src/hooks/align.js index e22922c198b2c..46adcc0ba3ede 100644 --- a/packages/editor/src/hooks/align.js +++ b/packages/editor/src/hooks/align.js @@ -206,7 +206,7 @@ export function addAssignedAlign( props, blockType, attributes ) { } addFilter( 'blocks.registerBlockType', 'core/align/addAttribute', addAttribute ); -addFilter( 'editor.BlockListBlock', 'core/editor/align/with-data-align', withDataAlign ); +addFilter( 'editor.__experimentalBlockListBlock', 'core/editor/align/with-data-align', withDataAlign ); addFilter( 'editor.BlockEdit', 'core/editor/align/with-toolbar-controls', withToolbarControls ); addFilter( 'blocks.getSaveContent.extraProps', 'core/align/addAssignedAlign', addAssignedAlign ); From 94658f0925454c6c9c44e6bd5286bb24accea680 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 29 Nov 2018 09:06:25 +0100 Subject: [PATCH 06/10] Avoid repeating the selector dependants --- packages/editor/src/store/selectors.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/editor/src/store/selectors.js b/packages/editor/src/store/selectors.js index af819e72fc169..d8b019930d1a0 100644 --- a/packages/editor/src/store/selectors.js +++ b/packages/editor/src/store/selectors.js @@ -700,9 +700,7 @@ export const getBlock = createSelector( ( state, clientId ) => [ state.editor.present.blocks.byClientId[ clientId ], getBlockDependantsCacheBust( state, clientId ), - state.editor.present.edits.meta, - state.initialEdits.meta, - state.currentPost.meta, + ...getBlockAttributes.getDependants( state, clientId ), ] ); From 12f91a5d18484b508a63ab3dc214818b27b3d394 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 29 Nov 2018 09:13:13 +0100 Subject: [PATCH 07/10] Fix small typo in the docs --- docs/designers-developers/developers/filters/block-filters.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/designers-developers/developers/filters/block-filters.md b/docs/designers-developers/developers/filters/block-filters.md index df3a5d4567ca9..84c5db31c4de7 100644 --- a/docs/designers-developers/developers/filters/block-filters.md +++ b/docs/designers-developers/developers/filters/block-filters.md @@ -204,7 +204,7 @@ var withClientIdClassName = wp.compose.createHigherOrderComponent( function( Blo {}, props, { - classsName: "block-" + props.clientID, + classsName: "block-" + props.clientId, } ); @@ -224,7 +224,7 @@ const { createHigherOrderComponent } = wp.compose; const withClientIdClassName = createHigherOrderComponent( ( BlockListBlock ) => { return ( props ) => { - return ; + return ; }; }, 'withClientIdClassName' ); From 69aa30325cab541436627b25634ea3ea04df3660 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 30 Nov 2018 09:15:04 +0100 Subject: [PATCH 08/10] Avoid rerending the current block if the previous block change (#12379) * Avoid rerending the current block if the previous block change * Always show the sibling inserter * Optimize the insertion point component (#12384) --- .../developers/filters/block-filters.md | 4 - packages/blocks/src/api/utils.js | 13 +- .../editor/src/components/block-list/block.js | 722 ++++++++++-------- .../components/block-list/insertion-point.js | 51 +- 4 files changed, 409 insertions(+), 381 deletions(-) diff --git a/docs/designers-developers/developers/filters/block-filters.md b/docs/designers-developers/developers/filters/block-filters.md index 84c5db31c4de7..5f57b9e57e97c 100644 --- a/docs/designers-developers/developers/filters/block-filters.md +++ b/docs/designers-developers/developers/filters/block-filters.md @@ -113,10 +113,6 @@ wp.hooks.addFilter( ); ``` -#### `blocks.isUnmodifiedDefaultBlock.attributes` - -Used internally by the default block (paragraph) to exclude the attributes from the check if the block was modified. - #### `blocks.switchToBlockType.transformedBlock` Used to filters an individual transform result from block transformation. All of the original blocks are passed, since transformations are many-to-many, not one-to-one. diff --git a/packages/blocks/src/api/utils.js b/packages/blocks/src/api/utils.js index d5552a492aaa1..392593b440096 100644 --- a/packages/blocks/src/api/utils.js +++ b/packages/blocks/src/api/utils.js @@ -1,13 +1,12 @@ /** * External dependencies */ -import { every, has, keys, isEqual, isFunction, isString } from 'lodash'; +import { every, has, isFunction, isString } from 'lodash'; import { default as tinycolor, mostReadable } from 'tinycolor2'; /** * WordPress dependencies */ -import { applyFilters } from '@wordpress/hooks'; import { Component, isValidElement } from '@wordpress/element'; /** @@ -40,14 +39,10 @@ export function isUnmodifiedDefaultBlock( block ) { } const newDefaultBlock = createBlock( defaultBlockName ); + const blockType = getBlockType( defaultBlockName ); - const attributeKeys = applyFilters( 'blocks.isUnmodifiedDefaultBlock.attributes', [ - ...keys( newDefaultBlock.attributes ), - ...keys( block.attributes ), - ] ); - - return every( attributeKeys, ( key ) => - isEqual( newDefaultBlock.attributes[ key ], block.attributes[ key ] ) + return every( blockType.attributes, ( value, key ) => + newDefaultBlock.attributes[ key ] === block.attributes[ key ] ); } diff --git a/packages/editor/src/components/block-list/block.js b/packages/editor/src/components/block-list/block.js index 2b30eed8a965b..cf8ed0ef160a8 100644 --- a/packages/editor/src/components/block-list/block.js +++ b/packages/editor/src/components/block-list/block.js @@ -1,116 +1,120 @@ /** * External dependencies */ -import classnames from 'classnames'; -import { get, reduce, size, first, last } from 'lodash'; +import classnames from "classnames"; +import { get, reduce, size, first, last } from "lodash"; /** * WordPress dependencies */ -import { Component, Fragment } from '@wordpress/element'; +import { Component, Fragment } from "@wordpress/element"; import { focus, isTextField, placeCaretAtHorizontalEdge, - placeCaretAtVerticalEdge, -} from '@wordpress/dom'; -import { BACKSPACE, DELETE, ENTER } from '@wordpress/keycodes'; + placeCaretAtVerticalEdge +} from "@wordpress/dom"; +import { BACKSPACE, DELETE, ENTER } from "@wordpress/keycodes"; import { getBlockType, getSaveElement, isReusableBlock, isUnmodifiedDefaultBlock, - getUnregisteredTypeHandlerName, -} from '@wordpress/blocks'; -import { KeyboardShortcuts, withFilters } from '@wordpress/components'; -import { __, sprintf } from '@wordpress/i18n'; -import { withDispatch, withSelect } from '@wordpress/data'; -import { withViewportMatch } from '@wordpress/viewport'; -import { compose } from '@wordpress/compose'; + getUnregisteredTypeHandlerName +} from "@wordpress/blocks"; +import { KeyboardShortcuts, withFilters } from "@wordpress/components"; +import { __, sprintf } from "@wordpress/i18n"; +import { withDispatch, withSelect } from "@wordpress/data"; +import { withViewportMatch } from "@wordpress/viewport"; +import { compose } from "@wordpress/compose"; /** * Internal dependencies */ -import BlockEdit from '../block-edit'; -import BlockMover from '../block-mover'; -import BlockDropZone from '../block-drop-zone'; -import BlockInvalidWarning from './block-invalid-warning'; -import BlockCrashWarning from './block-crash-warning'; -import BlockCrashBoundary from './block-crash-boundary'; -import BlockHtml from './block-html'; -import BlockBreadcrumb from './breadcrumb'; -import BlockContextualToolbar from './block-contextual-toolbar'; -import BlockMultiControls from './multi-controls'; -import BlockMobileToolbar from './block-mobile-toolbar'; -import BlockInsertionPoint from './insertion-point'; -import IgnoreNestedEvents from '../ignore-nested-events'; -import InserterWithShortcuts from '../inserter-with-shortcuts'; -import Inserter from '../inserter'; -import HoverArea from './hover-area'; -import { isInsideRootBlock } from '../../utils/dom'; +import BlockEdit from "../block-edit"; +import BlockMover from "../block-mover"; +import BlockDropZone from "../block-drop-zone"; +import BlockInvalidWarning from "./block-invalid-warning"; +import BlockCrashWarning from "./block-crash-warning"; +import BlockCrashBoundary from "./block-crash-boundary"; +import BlockHtml from "./block-html"; +import BlockBreadcrumb from "./breadcrumb"; +import BlockContextualToolbar from "./block-contextual-toolbar"; +import BlockMultiControls from "./multi-controls"; +import BlockMobileToolbar from "./block-mobile-toolbar"; +import BlockInsertionPoint from "./insertion-point"; +import IgnoreNestedEvents from "../ignore-nested-events"; +import InserterWithShortcuts from "../inserter-with-shortcuts"; +import Inserter from "../inserter"; +import HoverArea from "./hover-area"; +import { isInsideRootBlock } from "../../utils/dom"; export class BlockListBlock extends Component { constructor() { - super( ...arguments ); - - this.setBlockListRef = this.setBlockListRef.bind( this ); - this.bindBlockNode = this.bindBlockNode.bind( this ); - this.setAttributes = this.setAttributes.bind( this ); - this.maybeHover = this.maybeHover.bind( this ); - this.forceFocusedContextualToolbar = this.forceFocusedContextualToolbar.bind( this ); - this.hideHoverEffects = this.hideHoverEffects.bind( this ); - this.mergeBlocks = this.mergeBlocks.bind( this ); - this.insertBlocksAfter = this.insertBlocksAfter.bind( this ); - this.onFocus = this.onFocus.bind( this ); - this.preventDrag = this.preventDrag.bind( this ); - this.onPointerDown = this.onPointerDown.bind( this ); - this.deleteOrInsertAfterWrapper = this.deleteOrInsertAfterWrapper.bind( this ); - this.onBlockError = this.onBlockError.bind( this ); - this.onTouchStart = this.onTouchStart.bind( this ); - this.onClick = this.onClick.bind( this ); - this.onDragStart = this.onDragStart.bind( this ); - this.onDragEnd = this.onDragEnd.bind( this ); - this.selectOnOpen = this.selectOnOpen.bind( this ); + super(...arguments); + + this.setBlockListRef = this.setBlockListRef.bind(this); + this.bindBlockNode = this.bindBlockNode.bind(this); + this.setAttributes = this.setAttributes.bind(this); + this.maybeHover = this.maybeHover.bind(this); + this.forceFocusedContextualToolbar = this.forceFocusedContextualToolbar.bind( + this + ); + this.hideHoverEffects = this.hideHoverEffects.bind(this); + this.mergeBlocks = this.mergeBlocks.bind(this); + this.insertBlocksAfter = this.insertBlocksAfter.bind(this); + this.onFocus = this.onFocus.bind(this); + this.preventDrag = this.preventDrag.bind(this); + this.onPointerDown = this.onPointerDown.bind(this); + this.deleteOrInsertAfterWrapper = this.deleteOrInsertAfterWrapper.bind( + this + ); + this.onBlockError = this.onBlockError.bind(this); + this.onTouchStart = this.onTouchStart.bind(this); + this.onClick = this.onClick.bind(this); + this.onDragStart = this.onDragStart.bind(this); + this.onDragEnd = this.onDragEnd.bind(this); + this.selectOnOpen = this.selectOnOpen.bind(this); this.hadTouchStart = false; this.state = { error: null, dragging: false, - isHovered: false, + isHovered: false }; this.isForcingContextualToolbar = false; } componentDidMount() { - if ( this.props.isSelected ) { + if (this.props.isSelected) { this.focusTabbable(); } } - componentDidUpdate( prevProps ) { - if ( this.isForcingContextualToolbar ) { + componentDidUpdate(prevProps) { + if (this.isForcingContextualToolbar) { // The forcing of contextual toolbar should only be true during one update, // after the first update normal conditions should apply. this.isForcingContextualToolbar = false; } - if ( this.props.isTypingWithinBlock || this.props.isSelected ) { + if (this.props.isTypingWithinBlock || this.props.isSelected) { this.hideHoverEffects(); } - if ( this.props.isSelected && ! prevProps.isSelected ) { - this.focusTabbable( true ); + if (this.props.isSelected && !prevProps.isSelected) { + this.focusTabbable(true); } // When triggering a multi-selection, // move the focus to the wrapper of the first selected block. - if ( this.props.isFirstMultiSelected && ! prevProps.isFirstMultiSelected ) { + if (this.props.isFirstMultiSelected && !prevProps.isFirstMultiSelected) { this.wrapperNode.focus(); } } - setBlockListRef( node ) { + setBlockListRef(node) { this.wrapperNode = node; - this.props.blockRef( node, this.props.clientId ); + this.props.blockRef(node, this.props.clientId); // We need to rerender to trigger a rerendering of HoverArea // it depents on this.wrapperNode but we can't keep this.wrapperNode in state @@ -118,7 +122,7 @@ export class BlockListBlock extends Component { this.forceUpdate(); } - bindBlockNode( node ) { + bindBlockNode(node) { this.node = node; } @@ -127,30 +131,30 @@ export class BlockListBlock extends Component { * * @param {boolean} ignoreInnerBlocks Should not focus inner blocks. */ - focusTabbable( ignoreInnerBlocks ) { + focusTabbable(ignoreInnerBlocks) { const { initialPosition } = this.props; // Focus is captured by the wrapper node, so while focus transition // should only consider tabbables within editable display, since it // may be the wrapper itself or a side control which triggered the // focus event, don't unnecessary transition to an inner tabbable. - if ( this.wrapperNode.contains( document.activeElement ) ) { + if (this.wrapperNode.contains(document.activeElement)) { return; } // Find all tabbables within node. const textInputs = focus.tabbable - .find( this.node ) - .filter( isTextField ) + .find(this.node) + .filter(isTextField) // Exclude inner blocks - .filter( ( node ) => ! ignoreInnerBlocks || isInsideRootBlock( this.node, node ) ); + .filter(node => !ignoreInnerBlocks || isInsideRootBlock(this.node, node)); // If reversed (e.g. merge via backspace), use the last in the set of // tabbables. const isReverse = -1 === initialPosition; - const target = ( isReverse ? last : first )( textInputs ); + const target = (isReverse ? last : first)(textInputs); - if ( ! target ) { + if (!target) { this.wrapperNode.focus(); return; } @@ -158,27 +162,31 @@ export class BlockListBlock extends Component { target.focus(); // In reverse case, need to explicitly place caret position. - if ( isReverse ) { - placeCaretAtHorizontalEdge( target, true ); - placeCaretAtVerticalEdge( target, true ); + if (isReverse) { + placeCaretAtHorizontalEdge(target, true); + placeCaretAtVerticalEdge(target, true); } } - setAttributes( attributes ) { + setAttributes(attributes) { const { clientId, name, onChange } = this.props; - const type = getBlockType( name ); - onChange( clientId, attributes ); - - const metaAttributes = reduce( attributes, ( result, value, key ) => { - if ( get( type, [ 'attributes', key, 'source' ] ) === 'meta' ) { - result[ type.attributes[ key ].meta ] = value; - } - - return result; - }, {} ); + const type = getBlockType(name); + onChange(clientId, attributes); + + const metaAttributes = reduce( + attributes, + (result, value, key) => { + if (get(type, ["attributes", key, "source"]) === "meta") { + result[type.attributes[key].meta] = value; + } + + return result; + }, + {} + ); - if ( size( metaAttributes ) ) { - this.props.onMetaChange( metaAttributes ); + if (size(metaAttributes)) { + this.props.onMetaChange(metaAttributes); } } @@ -207,12 +215,17 @@ export class BlockListBlock extends Component { const { isPartOfMultiSelection, isSelected } = this.props; const { isHovered } = this.state; - if ( isHovered || isPartOfMultiSelection || isSelected || - this.props.isMultiSelecting || this.hadTouchStart ) { + if ( + isHovered || + isPartOfMultiSelection || + isSelected || + this.props.isMultiSelecting || + this.hadTouchStart + ) { return; } - this.setState( { isHovered: true } ); + this.setState({ isHovered: true }); } /** @@ -221,31 +234,37 @@ export class BlockListBlock extends Component { * so to avoid unnecesary renders, the state is only set if hovered. */ hideHoverEffects() { - if ( this.state.isHovered ) { - this.setState( { isHovered: false } ); + if (this.state.isHovered) { + this.setState({ isHovered: false }); } } - mergeBlocks( forward = false ) { - const { clientId, previousBlockClientId, nextBlockClientId, onMerge } = this.props; - + mergeBlocks(forward = false) { + const { + clientId, + getPreviousBlockClientId, + getNextBlockClientId, + onMerge + } = this.props; + const previousBlockClientId = getPreviousBlockClientId(clientId); + const nextBlockClientId = getNextBlockClientId(clientId); // Do nothing when it's the first block. if ( - ( ! forward && ! previousBlockClientId ) || - ( forward && ! nextBlockClientId ) + (!forward && !previousBlockClientId) || + (forward && !nextBlockClientId) ) { return; } - if ( forward ) { - onMerge( clientId, nextBlockClientId ); + if (forward) { + onMerge(clientId, nextBlockClientId); } else { - onMerge( previousBlockClientId, clientId ); + onMerge(previousBlockClientId, clientId); } } - insertBlocksAfter( blocks ) { - this.props.onInsertBlocks( blocks, this.props.order + 1 ); + insertBlocksAfter(blocks) { + this.props.onInsertBlocks(blocks, this.props.order + 1); } /** @@ -256,7 +275,7 @@ export class BlockListBlock extends Component { * @return {void} */ onFocus() { - if ( ! this.props.isSelected && ! this.props.isPartOfMultiSelection ) { + if (!this.props.isSelected && !this.props.isPartOfMultiSelection) { this.props.onSelect(); } } @@ -269,7 +288,7 @@ export class BlockListBlock extends Component { * * @return {void} */ - preventDrag( event ) { + preventDrag(event) { event.preventDefault(); } @@ -280,27 +299,27 @@ export class BlockListBlock extends Component { * * @return {void} */ - onPointerDown( event ) { + onPointerDown(event) { // Not the main button. // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button - if ( event.button !== 0 ) { + if (event.button !== 0) { return; } - if ( event.shiftKey ) { - if ( ! this.props.isSelected ) { + if (event.shiftKey) { + if (!this.props.isSelected) { this.props.onShiftSelection(); event.preventDefault(); } } else { - this.props.onSelectionStart( this.props.clientId ); + this.props.onSelectionStart(this.props.clientId); // Allow user to escape out of a multi-selection to a singular // selection of a block via click. This is handled here since // onFocus excludes blocks involved in a multiselection, as // focus can be incurred by starting a multiselection (focus // moved to first block's multi-controls). - if ( this.props.isPartOfMultiSelection ) { + if (this.props.isPartOfMultiSelection) { this.props.onSelect(); } } @@ -314,18 +333,18 @@ export class BlockListBlock extends Component { * * @param {KeyboardEvent} event Keydown event. */ - deleteOrInsertAfterWrapper( event ) { + deleteOrInsertAfterWrapper(event) { const { keyCode, target } = event; if ( - ! this.props.isSelected || + !this.props.isSelected || target !== this.wrapperNode || this.props.isLocked ) { return; } - switch ( keyCode ) { + switch (keyCode) { case ENTER: // Insert default block after current block if enter and event // not already handled by descendant. @@ -337,26 +356,26 @@ export class BlockListBlock extends Component { case DELETE: // Remove block on backspace. const { clientId, onRemove } = this.props; - onRemove( clientId ); + onRemove(clientId); event.preventDefault(); break; } } - onBlockError( error ) { - this.setState( { error } ); + onBlockError(error) { + this.setState({ error }); } onDragStart() { - this.setState( { dragging: true } ); + this.setState({ dragging: true }); } onDragEnd() { - this.setState( { dragging: false } ); + this.setState({ dragging: false }); } - selectOnOpen( open ) { - if ( open && ! this.props.isSelected ) { + selectOnOpen(open) { + if (open && !this.props.isSelected) { this.props.onSelect(); } } @@ -364,13 +383,13 @@ export class BlockListBlock extends Component { forceFocusedContextualToolbar() { this.isForcingContextualToolbar = true; // trigger a re-render - this.setState( () => ( {} ) ); + this.setState(() => ({})); } render() { return ( - - { ( { hoverArea } ) => { + + {({ hoverArea }) => { const { order, mode, @@ -389,18 +408,17 @@ export class BlockListBlock extends Component { isMultiSelecting, isEmptyDefaultBlock, isMovable, - isPreviousBlockADefaultEmptyBlock, isParentOfSelectedBlock, isDraggable, className, name, isValid, - attributes, + attributes } = this.props; - const isHovered = this.state.isHovered && ! isMultiSelecting; - const blockType = getBlockType( name ); + const isHovered = this.state.isHovered && !isMultiSelecting; + const blockType = getBlockType(name); // translators: %s: Type of block (i.e. Text, Image etc) - const blockLabel = sprintf( __( 'Block: %s' ), blockType.title ); + const blockLabel = sprintf(__("Block: %s"), blockType.title); // The block as rendered in the editor is composed of general block UI // (mover, toolbar, wrapper) and the display of the block content. @@ -408,47 +426,75 @@ export class BlockListBlock extends Component { // If the block is selected and we're typing the block should not appear. // Empty paragraph blocks should always show up as unselected. - const showEmptyBlockSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock && isValid; - const showSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock; - const shouldAppearSelected = ! isFocusMode && ! showSideInserter && isSelected && ! isTypingWithinBlock; - const shouldAppearHovered = ! isFocusMode && ! hasFixedToolbar && isHovered && ! isEmptyDefaultBlock; + const showEmptyBlockSideInserter = + (isSelected || isHovered) && isEmptyDefaultBlock && isValid; + const showSideInserter = + (isSelected || isHovered) && isEmptyDefaultBlock; + const shouldAppearSelected = + !isFocusMode && + !showSideInserter && + isSelected && + !isTypingWithinBlock; + const shouldAppearHovered = + !isFocusMode && + !hasFixedToolbar && + isHovered && + !isEmptyDefaultBlock; // We render block movers and block settings to keep them tabbale even if hidden - const shouldRenderMovers = ! isFocusMode && ( isSelected || hoverArea === 'left' ) && ! showEmptyBlockSideInserter && ! isMultiSelecting && ! isPartOfMultiSelection && ! isTypingWithinBlock; - const shouldShowBreadcrumb = ! isFocusMode && isHovered && ! isEmptyDefaultBlock; - const shouldShowContextualToolbar = ! hasFixedToolbar && ! showSideInserter && ( ( isSelected && ( ! isTypingWithinBlock || isCaretWithinFormattedText ) ) || isFirstMultiSelected ); + const shouldRenderMovers = + !isFocusMode && + (isSelected || hoverArea === "left") && + !showEmptyBlockSideInserter && + !isMultiSelecting && + !isPartOfMultiSelection && + !isTypingWithinBlock; + const shouldShowBreadcrumb = + !isFocusMode && isHovered && !isEmptyDefaultBlock; + const shouldShowContextualToolbar = + !hasFixedToolbar && + !showSideInserter && + ((isSelected && + (!isTypingWithinBlock || isCaretWithinFormattedText)) || + isFirstMultiSelected); const shouldShowMobileToolbar = shouldAppearSelected; const { error, dragging } = this.state; // Insertion point can only be made visible if the block is at the // the extent of a multi-selection, or not in a multi-selection. - const shouldShowInsertionPoint = ( isPartOfMultiSelection && isFirstMultiSelected ) || ! isPartOfMultiSelection; - const canShowInBetweenInserter = ! isEmptyDefaultBlock && ! isPreviousBlockADefaultEmptyBlock; + const shouldShowInsertionPoint = + (isPartOfMultiSelection && isFirstMultiSelected) || + !isPartOfMultiSelection; // The wp-block className is important for editor styles. // Generate the wrapper class names handling the different states of the block. - const wrapperClassName = classnames( 'wp-block editor-block-list__block', { - 'has-warning': ! isValid || !! error || isUnregisteredBlock, - 'is-selected': shouldAppearSelected, - 'is-multi-selected': isPartOfMultiSelection, - 'is-hovered': shouldAppearHovered, - 'is-reusable': isReusableBlock( blockType ), - 'is-dragging': dragging, - 'is-typing': isTypingWithinBlock, - 'is-focused': isFocusMode && ( isSelected || isParentOfSelectedBlock ), - 'is-focus-mode': isFocusMode, - }, className ); + const wrapperClassName = classnames( + "wp-block editor-block-list__block", + { + "has-warning": !isValid || !!error || isUnregisteredBlock, + "is-selected": shouldAppearSelected, + "is-multi-selected": isPartOfMultiSelection, + "is-hovered": shouldAppearHovered, + "is-reusable": isReusableBlock(blockType), + "is-dragging": dragging, + "is-typing": isTypingWithinBlock, + "is-focused": + isFocusMode && (isSelected || isParentOfSelectedBlock), + "is-focus-mode": isFocusMode + }, + className + ); const { onReplace } = this.props; // Determine whether the block has props to apply to the wrapper. let wrapperProps = this.props.wrapperProps; - if ( blockType.getEditWrapperProps ) { + if (blockType.getEditWrapperProps) { wrapperProps = { ...wrapperProps, - ...blockType.getEditWrapperProps( attributes ), + ...blockType.getEditWrapperProps(attributes) }; } - const blockElementId = `block-${ clientId }`; + const blockElementId = `block-${clientId}`; // We wrap the BlockEdit component in a div that hides it when editing in // HTML mode. This allows us to render all of the ancillary pieces @@ -456,20 +502,20 @@ export class BlockListBlock extends Component { // `BlockHTML`, even in HTML mode. let blockEdit = ( ); - if ( mode !== 'visual' ) { - blockEdit =
{ blockEdit }
; + if (mode !== "visual") { + blockEdit =
{blockEdit}
; } // Disable reasons: @@ -484,201 +530,199 @@ export class BlockListBlock extends Component { return ( - { shouldShowInsertionPoint && ( + {shouldShowInsertionPoint && ( - ) } + )} - { shouldRenderMovers && ( + {shouldRenderMovers && ( - ) } - { isFirstMultiSelected && ( - - ) } + )} + {isFirstMultiSelected && ( + + )}
- { shouldShowBreadcrumb && ( + {shouldShowBreadcrumb && ( - ) } - { ( - shouldShowContextualToolbar || - this.isForcingContextualToolbar - ) && ( + )} + {(shouldShowContextualToolbar || + this.isForcingContextualToolbar) && ( - ) } - { ( - ! shouldShowContextualToolbar && + )} + {!shouldShowContextualToolbar && isSelected && - ! hasFixedToolbar && - ! isEmptyDefaultBlock - ) && ( - - ) } + !hasFixedToolbar && + !isEmptyDefaultBlock && ( + + )} - - { isValid && blockEdit } - { isValid && mode === 'html' && ( - - ) } - { ! isValid && [ + + {isValid && blockEdit} + {isValid && mode === "html" && ( + + )} + {!isValid && [ ,
- { getSaveElement( blockType, attributes ) } -
, - ] } + {getSaveElement(blockType, attributes)} +
+ ]} - { shouldShowMobileToolbar && ( - - ) } - { !! error && } + {shouldShowMobileToolbar && ( + + )} + {!!error && }
- { showEmptyBlockSideInserter && ( + {showEmptyBlockSideInserter && (
- ) } + )} ); /* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ - } } + }}
); } } -const applyWithSelect = withSelect( ( select, { clientId, rootClientId, isLargeViewport } ) => { - const { - isBlockSelected, - getPreviousBlockClientId, - getNextBlockClientId, - getBlockName, - isBlockValid, - getBlockAttributes, - isAncestorMultiSelected, - isBlockMultiSelected, - isFirstMultiSelectedBlock, - isMultiSelecting, - isTyping, - isCaretWithinFormattedText, - getBlockIndex, - getBlockMode, - isSelectionEnabled, - getSelectedBlocksInitialCaretPosition, - getEditorSettings, - hasSelectedInnerBlock, - getTemplateLock, - } = select( 'core/editor' ); - const isSelected = isBlockSelected( clientId ); - const { hasFixedToolbar, focusMode } = getEditorSettings(); - const previousBlockClientId = getPreviousBlockClientId( clientId ); - const templateLock = getTemplateLock( rootClientId ); - const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId, true ); - const name = getBlockName( clientId ); - const attributes = getBlockAttributes( clientId ); - - return { - nextBlockClientId: getNextBlockClientId( clientId ), - isPartOfMultiSelection: isBlockMultiSelected( clientId ) || isAncestorMultiSelected( clientId ), - isFirstMultiSelected: isFirstMultiSelectedBlock( clientId ), - isMultiSelecting: isMultiSelecting(), - // We only care about this prop when the block is selected - // Thus to avoid unnecessary rerenders we avoid updating the prop if the block is not selected. - isTypingWithinBlock: ( isSelected || isParentOfSelectedBlock ) && isTyping(), - isCaretWithinFormattedText: isCaretWithinFormattedText(), - order: getBlockIndex( clientId, rootClientId ), - mode: getBlockMode( clientId ), - isSelectionEnabled: isSelectionEnabled(), - initialPosition: getSelectedBlocksInitialCaretPosition(), - isEmptyDefaultBlock: name && isUnmodifiedDefaultBlock( { name, attributes } ), - isPreviousBlockADefaultEmptyBlock: previousBlockClientId && isUnmodifiedDefaultBlock( { - name: getBlockName( previousBlockClientId ), - attributes: getBlockAttributes( previousBlockClientId ), - } ), - isValid: isBlockValid( clientId ), - isMovable: 'all' !== templateLock, - isLocked: !! templateLock, - isFocusMode: focusMode && isLargeViewport, - hasFixedToolbar: hasFixedToolbar && isLargeViewport, - name, - attributes, - previousBlockClientId, - isSelected, - isParentOfSelectedBlock, - }; -} ); +const applyWithSelect = withSelect( + (select, { clientId, rootClientId, isLargeViewport }) => { + const { + isBlockSelected, + getBlockName, + isBlockValid, + getBlockAttributes, + isAncestorMultiSelected, + isBlockMultiSelected, + isFirstMultiSelectedBlock, + isMultiSelecting, + isTyping, + isCaretWithinFormattedText, + getBlockIndex, + getBlockMode, + isSelectionEnabled, + getSelectedBlocksInitialCaretPosition, + getEditorSettings, + hasSelectedInnerBlock, + getTemplateLock, + getPreviousBlockClientId, + getNextBlockClientId + } = select("core/editor"); + const isSelected = isBlockSelected(clientId); + const { hasFixedToolbar, focusMode } = getEditorSettings(); + const templateLock = getTemplateLock(rootClientId); + const isParentOfSelectedBlock = hasSelectedInnerBlock(clientId, true); + const name = getBlockName(clientId); + const attributes = getBlockAttributes(clientId); + + return { + isPartOfMultiSelection: + isBlockMultiSelected(clientId) || isAncestorMultiSelected(clientId), + isFirstMultiSelected: isFirstMultiSelectedBlock(clientId), + isMultiSelecting: isMultiSelecting(), + // We only care about this prop when the block is selected + // Thus to avoid unnecessary rerenders we avoid updating the prop if the block is not selected. + isTypingWithinBlock: + (isSelected || isParentOfSelectedBlock) && isTyping(), + isCaretWithinFormattedText: isCaretWithinFormattedText(), + order: getBlockIndex(clientId, rootClientId), + mode: getBlockMode(clientId), + isSelectionEnabled: isSelectionEnabled(), + initialPosition: getSelectedBlocksInitialCaretPosition(), + isEmptyDefaultBlock: + name && isUnmodifiedDefaultBlock({ name, attributes }), + isValid: isBlockValid(clientId), + isMovable: "all" !== templateLock, + isLocked: !!templateLock, + isFocusMode: focusMode && isLargeViewport, + hasFixedToolbar: hasFixedToolbar && isLargeViewport, + name, + attributes, + isSelected, + isParentOfSelectedBlock, + + // We only care about these selectors when events are triggered. + // We call them dynamically in the event handlers to avoid unnecessary re-renders. + getPreviousBlockClientId, + getNextBlockClientId + }; + } +); -const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => { - const { getBlockSelectionStart } = select( 'core/editor' ); +const applyWithDispatch = withDispatch((dispatch, ownProps, { select }) => { + const { getBlockSelectionStart } = select("core/editor"); const { updateBlockAttributes, selectBlock, @@ -689,57 +733,57 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => { mergeBlocks, replaceBlocks, editPost, - toggleSelection, - } = dispatch( 'core/editor' ); + toggleSelection + } = dispatch("core/editor"); return { - onChange( clientId, attributes ) { - updateBlockAttributes( clientId, attributes ); + onChange(clientId, attributes) { + updateBlockAttributes(clientId, attributes); }, - onSelect( clientId = ownProps.clientId, initialPosition ) { - selectBlock( clientId, initialPosition ); + onSelect(clientId = ownProps.clientId, initialPosition) { + selectBlock(clientId, initialPosition); }, - onInsertBlocks( blocks, index ) { + onInsertBlocks(blocks, index) { const { rootClientId } = ownProps; - insertBlocks( blocks, index, rootClientId ); + insertBlocks(blocks, index, rootClientId); }, onInsertDefaultBlockAfter() { const { order, rootClientId } = ownProps; - insertDefaultBlock( {}, rootClientId, order + 1 ); + insertDefaultBlock({}, rootClientId, order + 1); }, - onRemove( clientId ) { - removeBlock( clientId ); + onRemove(clientId) { + removeBlock(clientId); }, - onMerge( ...args ) { - mergeBlocks( ...args ); + onMerge(...args) { + mergeBlocks(...args); }, - onReplace( blocks ) { - replaceBlocks( [ ownProps.clientId ], blocks ); + onReplace(blocks) { + replaceBlocks([ownProps.clientId], blocks); }, - onMetaChange( meta ) { - editPost( { meta } ); + onMetaChange(meta) { + editPost({ meta }); }, onShiftSelection() { - if ( ! ownProps.isSelectionEnabled ) { + if (!ownProps.isSelectionEnabled) { return; } - if ( getBlockSelectionStart() ) { - multiSelect( getBlockSelectionStart(), ownProps.clientId ); + if (getBlockSelectionStart()) { + multiSelect(getBlockSelectionStart(), ownProps.clientId); } else { - selectBlock( ownProps.clientId ); + selectBlock(ownProps.clientId); } }, - toggleSelection( selectionEnabled ) { - toggleSelection( selectionEnabled ); - }, + toggleSelection(selectionEnabled) { + toggleSelection(selectionEnabled); + } }; -} ); +}); export default compose( - withFilters( 'editor.BlockListBlock' ), - withViewportMatch( { isLargeViewport: 'medium' } ), + withFilters("editor.BlockListBlock"), + withViewportMatch({ isLargeViewport: "medium" }), applyWithSelect, applyWithDispatch, - withFilters( 'editor.__experimentalBlockListBlock' ), -)( BlockListBlock ); + withFilters("editor.__experimentalBlockListBlock") +)(BlockListBlock); diff --git a/packages/editor/src/components/block-list/insertion-point.js b/packages/editor/src/components/block-list/insertion-point.js index ba5c98d21924f..252925cc3a6c0 100644 --- a/packages/editor/src/components/block-list/insertion-point.js +++ b/packages/editor/src/components/block-list/insertion-point.js @@ -6,7 +6,6 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { isUnmodifiedDefaultBlock } from '@wordpress/blocks'; import { Component } from '@wordpress/element'; import { withSelect } from '@wordpress/data'; @@ -47,7 +46,6 @@ class BlockInsertionPoint extends Component { const { isInserterFocused } = this.state; const { showInsertionPoint, - canShowInserter, rootClientId, insertIndex, } = this.props; @@ -57,29 +55,27 @@ class BlockInsertionPoint extends Component { { showInsertionPoint && (
) } - { canShowInserter && ( -
- -
- ) } +
+ +
); } @@ -88,18 +84,15 @@ export default withSelect( ( select, { clientId, rootClientId } ) => { const { getBlockIndex, getBlockInsertionPoint, - getBlock, isBlockInsertionPointVisible, } = select( 'core/editor' ); const blockIndex = getBlockIndex( clientId, rootClientId ); const insertIndex = blockIndex; const insertionPoint = getBlockInsertionPoint(); - const block = getBlock( clientId ); const showInsertionPoint = ( isBlockInsertionPointVisible() && insertionPoint.index === insertIndex && - insertionPoint.rootClientId === rootClientId && - ! isUnmodifiedDefaultBlock( block ) + insertionPoint.rootClientId === rootClientId ); return { showInsertionPoint, insertIndex }; From 81c57914d116cfa47f93a1f5ff08923fd2d38447 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 30 Nov 2018 14:45:42 +0100 Subject: [PATCH 09/10] Fix lock file --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index b0c66aaf0ab23..09879192a1aaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7596,7 +7596,7 @@ }, "eslint-plugin-react": { "version": "7.7.0", - "resolved": "http://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz", "integrity": "sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA==", "dev": true, "requires": { From cda9eefe65ebf5d9627230d5c2dd72e4aa3cd2f9 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 30 Nov 2018 15:23:09 +0100 Subject: [PATCH 10/10] Fix linting --- .../editor/src/components/block-list/block.js | 590 +++++++++--------- 1 file changed, 293 insertions(+), 297 deletions(-) diff --git a/packages/editor/src/components/block-list/block.js b/packages/editor/src/components/block-list/block.js index cf8ed0ef160a8..2523029c010ed 100644 --- a/packages/editor/src/components/block-list/block.js +++ b/packages/editor/src/components/block-list/block.js @@ -1,120 +1,116 @@ /** * External dependencies */ -import classnames from "classnames"; -import { get, reduce, size, first, last } from "lodash"; +import classnames from 'classnames'; +import { get, reduce, size, first, last } from 'lodash'; /** * WordPress dependencies */ -import { Component, Fragment } from "@wordpress/element"; +import { Component, Fragment } from '@wordpress/element'; import { focus, isTextField, placeCaretAtHorizontalEdge, - placeCaretAtVerticalEdge -} from "@wordpress/dom"; -import { BACKSPACE, DELETE, ENTER } from "@wordpress/keycodes"; + placeCaretAtVerticalEdge, +} from '@wordpress/dom'; +import { BACKSPACE, DELETE, ENTER } from '@wordpress/keycodes'; import { getBlockType, getSaveElement, isReusableBlock, isUnmodifiedDefaultBlock, - getUnregisteredTypeHandlerName -} from "@wordpress/blocks"; -import { KeyboardShortcuts, withFilters } from "@wordpress/components"; -import { __, sprintf } from "@wordpress/i18n"; -import { withDispatch, withSelect } from "@wordpress/data"; -import { withViewportMatch } from "@wordpress/viewport"; -import { compose } from "@wordpress/compose"; + getUnregisteredTypeHandlerName, +} from '@wordpress/blocks'; +import { KeyboardShortcuts, withFilters } from '@wordpress/components'; +import { __, sprintf } from '@wordpress/i18n'; +import { withDispatch, withSelect } from '@wordpress/data'; +import { withViewportMatch } from '@wordpress/viewport'; +import { compose } from '@wordpress/compose'; /** * Internal dependencies */ -import BlockEdit from "../block-edit"; -import BlockMover from "../block-mover"; -import BlockDropZone from "../block-drop-zone"; -import BlockInvalidWarning from "./block-invalid-warning"; -import BlockCrashWarning from "./block-crash-warning"; -import BlockCrashBoundary from "./block-crash-boundary"; -import BlockHtml from "./block-html"; -import BlockBreadcrumb from "./breadcrumb"; -import BlockContextualToolbar from "./block-contextual-toolbar"; -import BlockMultiControls from "./multi-controls"; -import BlockMobileToolbar from "./block-mobile-toolbar"; -import BlockInsertionPoint from "./insertion-point"; -import IgnoreNestedEvents from "../ignore-nested-events"; -import InserterWithShortcuts from "../inserter-with-shortcuts"; -import Inserter from "../inserter"; -import HoverArea from "./hover-area"; -import { isInsideRootBlock } from "../../utils/dom"; +import BlockEdit from '../block-edit'; +import BlockMover from '../block-mover'; +import BlockDropZone from '../block-drop-zone'; +import BlockInvalidWarning from './block-invalid-warning'; +import BlockCrashWarning from './block-crash-warning'; +import BlockCrashBoundary from './block-crash-boundary'; +import BlockHtml from './block-html'; +import BlockBreadcrumb from './breadcrumb'; +import BlockContextualToolbar from './block-contextual-toolbar'; +import BlockMultiControls from './multi-controls'; +import BlockMobileToolbar from './block-mobile-toolbar'; +import BlockInsertionPoint from './insertion-point'; +import IgnoreNestedEvents from '../ignore-nested-events'; +import InserterWithShortcuts from '../inserter-with-shortcuts'; +import Inserter from '../inserter'; +import HoverArea from './hover-area'; +import { isInsideRootBlock } from '../../utils/dom'; export class BlockListBlock extends Component { constructor() { - super(...arguments); - - this.setBlockListRef = this.setBlockListRef.bind(this); - this.bindBlockNode = this.bindBlockNode.bind(this); - this.setAttributes = this.setAttributes.bind(this); - this.maybeHover = this.maybeHover.bind(this); - this.forceFocusedContextualToolbar = this.forceFocusedContextualToolbar.bind( - this - ); - this.hideHoverEffects = this.hideHoverEffects.bind(this); - this.mergeBlocks = this.mergeBlocks.bind(this); - this.insertBlocksAfter = this.insertBlocksAfter.bind(this); - this.onFocus = this.onFocus.bind(this); - this.preventDrag = this.preventDrag.bind(this); - this.onPointerDown = this.onPointerDown.bind(this); - this.deleteOrInsertAfterWrapper = this.deleteOrInsertAfterWrapper.bind( - this - ); - this.onBlockError = this.onBlockError.bind(this); - this.onTouchStart = this.onTouchStart.bind(this); - this.onClick = this.onClick.bind(this); - this.onDragStart = this.onDragStart.bind(this); - this.onDragEnd = this.onDragEnd.bind(this); - this.selectOnOpen = this.selectOnOpen.bind(this); + super( ...arguments ); + + this.setBlockListRef = this.setBlockListRef.bind( this ); + this.bindBlockNode = this.bindBlockNode.bind( this ); + this.setAttributes = this.setAttributes.bind( this ); + this.maybeHover = this.maybeHover.bind( this ); + this.forceFocusedContextualToolbar = this.forceFocusedContextualToolbar.bind( this ); + this.hideHoverEffects = this.hideHoverEffects.bind( this ); + this.mergeBlocks = this.mergeBlocks.bind( this ); + this.insertBlocksAfter = this.insertBlocksAfter.bind( this ); + this.onFocus = this.onFocus.bind( this ); + this.preventDrag = this.preventDrag.bind( this ); + this.onPointerDown = this.onPointerDown.bind( this ); + this.deleteOrInsertAfterWrapper = this.deleteOrInsertAfterWrapper.bind( this ); + this.onBlockError = this.onBlockError.bind( this ); + this.onTouchStart = this.onTouchStart.bind( this ); + this.onClick = this.onClick.bind( this ); + this.onDragStart = this.onDragStart.bind( this ); + this.onDragEnd = this.onDragEnd.bind( this ); + this.selectOnOpen = this.selectOnOpen.bind( this ); this.hadTouchStart = false; this.state = { error: null, dragging: false, - isHovered: false + isHovered: false, }; this.isForcingContextualToolbar = false; } componentDidMount() { - if (this.props.isSelected) { + if ( this.props.isSelected ) { this.focusTabbable(); } } - componentDidUpdate(prevProps) { - if (this.isForcingContextualToolbar) { + componentDidUpdate( prevProps ) { + if ( this.isForcingContextualToolbar ) { // The forcing of contextual toolbar should only be true during one update, // after the first update normal conditions should apply. this.isForcingContextualToolbar = false; } - if (this.props.isTypingWithinBlock || this.props.isSelected) { + if ( this.props.isTypingWithinBlock || this.props.isSelected ) { this.hideHoverEffects(); } - if (this.props.isSelected && !prevProps.isSelected) { - this.focusTabbable(true); + if ( this.props.isSelected && ! prevProps.isSelected ) { + this.focusTabbable( true ); } // When triggering a multi-selection, // move the focus to the wrapper of the first selected block. - if (this.props.isFirstMultiSelected && !prevProps.isFirstMultiSelected) { + if ( this.props.isFirstMultiSelected && ! prevProps.isFirstMultiSelected ) { this.wrapperNode.focus(); } } - setBlockListRef(node) { + setBlockListRef( node ) { this.wrapperNode = node; - this.props.blockRef(node, this.props.clientId); + this.props.blockRef( node, this.props.clientId ); // We need to rerender to trigger a rerendering of HoverArea // it depents on this.wrapperNode but we can't keep this.wrapperNode in state @@ -122,7 +118,7 @@ export class BlockListBlock extends Component { this.forceUpdate(); } - bindBlockNode(node) { + bindBlockNode( node ) { this.node = node; } @@ -131,30 +127,30 @@ export class BlockListBlock extends Component { * * @param {boolean} ignoreInnerBlocks Should not focus inner blocks. */ - focusTabbable(ignoreInnerBlocks) { + focusTabbable( ignoreInnerBlocks ) { const { initialPosition } = this.props; // Focus is captured by the wrapper node, so while focus transition // should only consider tabbables within editable display, since it // may be the wrapper itself or a side control which triggered the // focus event, don't unnecessary transition to an inner tabbable. - if (this.wrapperNode.contains(document.activeElement)) { + if ( this.wrapperNode.contains( document.activeElement ) ) { return; } // Find all tabbables within node. const textInputs = focus.tabbable - .find(this.node) - .filter(isTextField) + .find( this.node ) + .filter( isTextField ) // Exclude inner blocks - .filter(node => !ignoreInnerBlocks || isInsideRootBlock(this.node, node)); + .filter( ( node ) => ! ignoreInnerBlocks || isInsideRootBlock( this.node, node ) ); // If reversed (e.g. merge via backspace), use the last in the set of // tabbables. const isReverse = -1 === initialPosition; - const target = (isReverse ? last : first)(textInputs); + const target = ( isReverse ? last : first )( textInputs ); - if (!target) { + if ( ! target ) { this.wrapperNode.focus(); return; } @@ -162,22 +158,22 @@ export class BlockListBlock extends Component { target.focus(); // In reverse case, need to explicitly place caret position. - if (isReverse) { - placeCaretAtHorizontalEdge(target, true); - placeCaretAtVerticalEdge(target, true); + if ( isReverse ) { + placeCaretAtHorizontalEdge( target, true ); + placeCaretAtVerticalEdge( target, true ); } } - setAttributes(attributes) { + setAttributes( attributes ) { const { clientId, name, onChange } = this.props; - const type = getBlockType(name); - onChange(clientId, attributes); + const type = getBlockType( name ); + onChange( clientId, attributes ); const metaAttributes = reduce( attributes, - (result, value, key) => { - if (get(type, ["attributes", key, "source"]) === "meta") { - result[type.attributes[key].meta] = value; + ( result, value, key ) => { + if ( get( type, [ 'attributes', key, 'source' ] ) === 'meta' ) { + result[ type.attributes[ key ].meta ] = value; } return result; @@ -185,8 +181,8 @@ export class BlockListBlock extends Component { {} ); - if (size(metaAttributes)) { - this.props.onMetaChange(metaAttributes); + if ( size( metaAttributes ) ) { + this.props.onMetaChange( metaAttributes ); } } @@ -225,7 +221,7 @@ export class BlockListBlock extends Component { return; } - this.setState({ isHovered: true }); + this.setState( { isHovered: true } ); } /** @@ -234,37 +230,37 @@ export class BlockListBlock extends Component { * so to avoid unnecesary renders, the state is only set if hovered. */ hideHoverEffects() { - if (this.state.isHovered) { - this.setState({ isHovered: false }); + if ( this.state.isHovered ) { + this.setState( { isHovered: false } ); } } - mergeBlocks(forward = false) { + mergeBlocks( forward = false ) { const { clientId, getPreviousBlockClientId, getNextBlockClientId, - onMerge + onMerge, } = this.props; - const previousBlockClientId = getPreviousBlockClientId(clientId); - const nextBlockClientId = getNextBlockClientId(clientId); + const previousBlockClientId = getPreviousBlockClientId( clientId ); + const nextBlockClientId = getNextBlockClientId( clientId ); // Do nothing when it's the first block. if ( - (!forward && !previousBlockClientId) || - (forward && !nextBlockClientId) + ( ! forward && ! previousBlockClientId ) || + ( forward && ! nextBlockClientId ) ) { return; } - if (forward) { - onMerge(clientId, nextBlockClientId); + if ( forward ) { + onMerge( clientId, nextBlockClientId ); } else { - onMerge(previousBlockClientId, clientId); + onMerge( previousBlockClientId, clientId ); } } - insertBlocksAfter(blocks) { - this.props.onInsertBlocks(blocks, this.props.order + 1); + insertBlocksAfter( blocks ) { + this.props.onInsertBlocks( blocks, this.props.order + 1 ); } /** @@ -275,7 +271,7 @@ export class BlockListBlock extends Component { * @return {void} */ onFocus() { - if (!this.props.isSelected && !this.props.isPartOfMultiSelection) { + if ( ! this.props.isSelected && ! this.props.isPartOfMultiSelection ) { this.props.onSelect(); } } @@ -288,7 +284,7 @@ export class BlockListBlock extends Component { * * @return {void} */ - preventDrag(event) { + preventDrag( event ) { event.preventDefault(); } @@ -299,27 +295,27 @@ export class BlockListBlock extends Component { * * @return {void} */ - onPointerDown(event) { + onPointerDown( event ) { // Not the main button. // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button - if (event.button !== 0) { + if ( event.button !== 0 ) { return; } - if (event.shiftKey) { - if (!this.props.isSelected) { + if ( event.shiftKey ) { + if ( ! this.props.isSelected ) { this.props.onShiftSelection(); event.preventDefault(); } } else { - this.props.onSelectionStart(this.props.clientId); + this.props.onSelectionStart( this.props.clientId ); // Allow user to escape out of a multi-selection to a singular // selection of a block via click. This is handled here since // onFocus excludes blocks involved in a multiselection, as // focus can be incurred by starting a multiselection (focus // moved to first block's multi-controls). - if (this.props.isPartOfMultiSelection) { + if ( this.props.isPartOfMultiSelection ) { this.props.onSelect(); } } @@ -333,18 +329,18 @@ export class BlockListBlock extends Component { * * @param {KeyboardEvent} event Keydown event. */ - deleteOrInsertAfterWrapper(event) { + deleteOrInsertAfterWrapper( event ) { const { keyCode, target } = event; if ( - !this.props.isSelected || + ! this.props.isSelected || target !== this.wrapperNode || this.props.isLocked ) { return; } - switch (keyCode) { + switch ( keyCode ) { case ENTER: // Insert default block after current block if enter and event // not already handled by descendant. @@ -356,26 +352,26 @@ export class BlockListBlock extends Component { case DELETE: // Remove block on backspace. const { clientId, onRemove } = this.props; - onRemove(clientId); + onRemove( clientId ); event.preventDefault(); break; } } - onBlockError(error) { - this.setState({ error }); + onBlockError( error ) { + this.setState( { error } ); } onDragStart() { - this.setState({ dragging: true }); + this.setState( { dragging: true } ); } onDragEnd() { - this.setState({ dragging: false }); + this.setState( { dragging: false } ); } - selectOnOpen(open) { - if (open && !this.props.isSelected) { + selectOnOpen( open ) { + if ( open && ! this.props.isSelected ) { this.props.onSelect(); } } @@ -383,13 +379,13 @@ export class BlockListBlock extends Component { forceFocusedContextualToolbar() { this.isForcingContextualToolbar = true; // trigger a re-render - this.setState(() => ({})); + this.setState( () => ( {} ) ); } render() { return ( - - {({ hoverArea }) => { + + { ( { hoverArea } ) => { const { order, mode, @@ -413,12 +409,12 @@ export class BlockListBlock extends Component { className, name, isValid, - attributes + attributes, } = this.props; - const isHovered = this.state.isHovered && !isMultiSelecting; - const blockType = getBlockType(name); + const isHovered = this.state.isHovered && ! isMultiSelecting; + const blockType = getBlockType( name ); // translators: %s: Type of block (i.e. Text, Image etc) - const blockLabel = sprintf(__("Block: %s"), blockType.title); + const blockLabel = sprintf( __( 'Block: %s' ), blockType.title ); // The block as rendered in the editor is composed of general block UI // (mover, toolbar, wrapper) and the display of the block content. @@ -427,59 +423,59 @@ export class BlockListBlock extends Component { // If the block is selected and we're typing the block should not appear. // Empty paragraph blocks should always show up as unselected. const showEmptyBlockSideInserter = - (isSelected || isHovered) && isEmptyDefaultBlock && isValid; + ( isSelected || isHovered ) && isEmptyDefaultBlock && isValid; const showSideInserter = - (isSelected || isHovered) && isEmptyDefaultBlock; + ( isSelected || isHovered ) && isEmptyDefaultBlock; const shouldAppearSelected = - !isFocusMode && - !showSideInserter && + ! isFocusMode && + ! showSideInserter && isSelected && - !isTypingWithinBlock; + ! isTypingWithinBlock; const shouldAppearHovered = - !isFocusMode && - !hasFixedToolbar && + ! isFocusMode && + ! hasFixedToolbar && isHovered && - !isEmptyDefaultBlock; + ! isEmptyDefaultBlock; // We render block movers and block settings to keep them tabbale even if hidden const shouldRenderMovers = - !isFocusMode && - (isSelected || hoverArea === "left") && - !showEmptyBlockSideInserter && - !isMultiSelecting && - !isPartOfMultiSelection && - !isTypingWithinBlock; + ! isFocusMode && + ( isSelected || hoverArea === 'left' ) && + ! showEmptyBlockSideInserter && + ! isMultiSelecting && + ! isPartOfMultiSelection && + ! isTypingWithinBlock; const shouldShowBreadcrumb = - !isFocusMode && isHovered && !isEmptyDefaultBlock; + ! isFocusMode && isHovered && ! isEmptyDefaultBlock; const shouldShowContextualToolbar = - !hasFixedToolbar && - !showSideInserter && - ((isSelected && - (!isTypingWithinBlock || isCaretWithinFormattedText)) || - isFirstMultiSelected); + ! hasFixedToolbar && + ! showSideInserter && + ( ( isSelected && + ( ! isTypingWithinBlock || isCaretWithinFormattedText ) ) || + isFirstMultiSelected ); const shouldShowMobileToolbar = shouldAppearSelected; const { error, dragging } = this.state; // Insertion point can only be made visible if the block is at the // the extent of a multi-selection, or not in a multi-selection. const shouldShowInsertionPoint = - (isPartOfMultiSelection && isFirstMultiSelected) || - !isPartOfMultiSelection; + ( isPartOfMultiSelection && isFirstMultiSelected ) || + ! isPartOfMultiSelection; // The wp-block className is important for editor styles. // Generate the wrapper class names handling the different states of the block. const wrapperClassName = classnames( - "wp-block editor-block-list__block", + 'wp-block editor-block-list__block', { - "has-warning": !isValid || !!error || isUnregisteredBlock, - "is-selected": shouldAppearSelected, - "is-multi-selected": isPartOfMultiSelection, - "is-hovered": shouldAppearHovered, - "is-reusable": isReusableBlock(blockType), - "is-dragging": dragging, - "is-typing": isTypingWithinBlock, - "is-focused": - isFocusMode && (isSelected || isParentOfSelectedBlock), - "is-focus-mode": isFocusMode + 'has-warning': ! isValid || !! error || isUnregisteredBlock, + 'is-selected': shouldAppearSelected, + 'is-multi-selected': isPartOfMultiSelection, + 'is-hovered': shouldAppearHovered, + 'is-reusable': isReusableBlock( blockType ), + 'is-dragging': dragging, + 'is-typing': isTypingWithinBlock, + 'is-focused': + isFocusMode && ( isSelected || isParentOfSelectedBlock ), + 'is-focus-mode': isFocusMode, }, className ); @@ -488,13 +484,13 @@ export class BlockListBlock extends Component { // Determine whether the block has props to apply to the wrapper. let wrapperProps = this.props.wrapperProps; - if (blockType.getEditWrapperProps) { + if ( blockType.getEditWrapperProps ) { wrapperProps = { ...wrapperProps, - ...blockType.getEditWrapperProps(attributes) + ...blockType.getEditWrapperProps( attributes ), }; } - const blockElementId = `block-${clientId}`; + const blockElementId = `block-${ clientId }`; // We wrap the BlockEdit component in a div that hides it when editing in // HTML mode. This allows us to render all of the ancillary pieces @@ -502,20 +498,20 @@ export class BlockListBlock extends Component { // `BlockHTML`, even in HTML mode. let blockEdit = ( ); - if (mode !== "visual") { - blockEdit =
{blockEdit}
; + if ( mode !== 'visual' ) { + blockEdit =
{ blockEdit }
; } // Disable reasons: @@ -530,135 +526,135 @@ export class BlockListBlock extends Component { return ( - {shouldShowInsertionPoint && ( + { shouldShowInsertionPoint && ( - )} + ) } - {shouldRenderMovers && ( + { shouldRenderMovers && ( - )} - {isFirstMultiSelected && ( - - )} + ) } + { isFirstMultiSelected && ( + + ) }
- {shouldShowBreadcrumb && ( + { shouldShowBreadcrumb && ( - )} - {(shouldShowContextualToolbar || - this.isForcingContextualToolbar) && ( + ) } + { ( shouldShowContextualToolbar || + this.isForcingContextualToolbar ) && ( - )} - {!shouldShowContextualToolbar && + ) } + { ! shouldShowContextualToolbar && isSelected && - !hasFixedToolbar && - !isEmptyDefaultBlock && ( - - )} + ! hasFixedToolbar && + ! isEmptyDefaultBlock && ( + + ) } - - {isValid && blockEdit} - {isValid && mode === "html" && ( - - )} - {!isValid && [ + + { isValid && blockEdit } + { isValid && mode === 'html' && ( + + ) } + { ! isValid && [ ,
- {getSaveElement(blockType, attributes)} -
- ]} + { getSaveElement( blockType, attributes ) } +
, + ] } - {shouldShowMobileToolbar && ( - - )} - {!!error && } + { shouldShowMobileToolbar && ( + + ) } + { !! error && }
- {showEmptyBlockSideInserter && ( + { showEmptyBlockSideInserter && (
- )} + ) } ); /* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ - }} + } }
); } } const applyWithSelect = withSelect( - (select, { clientId, rootClientId, isLargeViewport }) => { + ( select, { clientId, rootClientId, isLargeViewport } ) => { const { isBlockSelected, getBlockName, @@ -678,34 +674,34 @@ const applyWithSelect = withSelect( hasSelectedInnerBlock, getTemplateLock, getPreviousBlockClientId, - getNextBlockClientId - } = select("core/editor"); - const isSelected = isBlockSelected(clientId); + getNextBlockClientId, + } = select( 'core/editor' ); + const isSelected = isBlockSelected( clientId ); const { hasFixedToolbar, focusMode } = getEditorSettings(); - const templateLock = getTemplateLock(rootClientId); - const isParentOfSelectedBlock = hasSelectedInnerBlock(clientId, true); - const name = getBlockName(clientId); - const attributes = getBlockAttributes(clientId); + const templateLock = getTemplateLock( rootClientId ); + const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId, true ); + const name = getBlockName( clientId ); + const attributes = getBlockAttributes( clientId ); return { isPartOfMultiSelection: - isBlockMultiSelected(clientId) || isAncestorMultiSelected(clientId), - isFirstMultiSelected: isFirstMultiSelectedBlock(clientId), + isBlockMultiSelected( clientId ) || isAncestorMultiSelected( clientId ), + isFirstMultiSelected: isFirstMultiSelectedBlock( clientId ), isMultiSelecting: isMultiSelecting(), // We only care about this prop when the block is selected // Thus to avoid unnecessary rerenders we avoid updating the prop if the block is not selected. isTypingWithinBlock: - (isSelected || isParentOfSelectedBlock) && isTyping(), + ( isSelected || isParentOfSelectedBlock ) && isTyping(), isCaretWithinFormattedText: isCaretWithinFormattedText(), - order: getBlockIndex(clientId, rootClientId), - mode: getBlockMode(clientId), + order: getBlockIndex( clientId, rootClientId ), + mode: getBlockMode( clientId ), isSelectionEnabled: isSelectionEnabled(), initialPosition: getSelectedBlocksInitialCaretPosition(), isEmptyDefaultBlock: - name && isUnmodifiedDefaultBlock({ name, attributes }), - isValid: isBlockValid(clientId), - isMovable: "all" !== templateLock, - isLocked: !!templateLock, + name && isUnmodifiedDefaultBlock( { name, attributes } ), + isValid: isBlockValid( clientId ), + isMovable: 'all' !== templateLock, + isLocked: !! templateLock, isFocusMode: focusMode && isLargeViewport, hasFixedToolbar: hasFixedToolbar && isLargeViewport, name, @@ -716,13 +712,13 @@ const applyWithSelect = withSelect( // We only care about these selectors when events are triggered. // We call them dynamically in the event handlers to avoid unnecessary re-renders. getPreviousBlockClientId, - getNextBlockClientId + getNextBlockClientId, }; } ); -const applyWithDispatch = withDispatch((dispatch, ownProps, { select }) => { - const { getBlockSelectionStart } = select("core/editor"); +const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => { + const { getBlockSelectionStart } = select( 'core/editor' ); const { updateBlockAttributes, selectBlock, @@ -733,57 +729,57 @@ const applyWithDispatch = withDispatch((dispatch, ownProps, { select }) => { mergeBlocks, replaceBlocks, editPost, - toggleSelection - } = dispatch("core/editor"); + toggleSelection, + } = dispatch( 'core/editor' ); return { - onChange(clientId, attributes) { - updateBlockAttributes(clientId, attributes); + onChange( clientId, attributes ) { + updateBlockAttributes( clientId, attributes ); }, - onSelect(clientId = ownProps.clientId, initialPosition) { - selectBlock(clientId, initialPosition); + onSelect( clientId = ownProps.clientId, initialPosition ) { + selectBlock( clientId, initialPosition ); }, - onInsertBlocks(blocks, index) { + onInsertBlocks( blocks, index ) { const { rootClientId } = ownProps; - insertBlocks(blocks, index, rootClientId); + insertBlocks( blocks, index, rootClientId ); }, onInsertDefaultBlockAfter() { const { order, rootClientId } = ownProps; - insertDefaultBlock({}, rootClientId, order + 1); + insertDefaultBlock( {}, rootClientId, order + 1 ); }, - onRemove(clientId) { - removeBlock(clientId); + onRemove( clientId ) { + removeBlock( clientId ); }, - onMerge(...args) { - mergeBlocks(...args); + onMerge( ...args ) { + mergeBlocks( ...args ); }, - onReplace(blocks) { - replaceBlocks([ownProps.clientId], blocks); + onReplace( blocks ) { + replaceBlocks( [ ownProps.clientId ], blocks ); }, - onMetaChange(meta) { - editPost({ meta }); + onMetaChange( meta ) { + editPost( { meta } ); }, onShiftSelection() { - if (!ownProps.isSelectionEnabled) { + if ( ! ownProps.isSelectionEnabled ) { return; } - if (getBlockSelectionStart()) { - multiSelect(getBlockSelectionStart(), ownProps.clientId); + if ( getBlockSelectionStart() ) { + multiSelect( getBlockSelectionStart(), ownProps.clientId ); } else { - selectBlock(ownProps.clientId); + selectBlock( ownProps.clientId ); } }, - toggleSelection(selectionEnabled) { - toggleSelection(selectionEnabled); - } + toggleSelection( selectionEnabled ) { + toggleSelection( selectionEnabled ); + }, }; -}); +} ); export default compose( - withFilters("editor.BlockListBlock"), - withViewportMatch({ isLargeViewport: "medium" }), + withFilters( 'editor.BlockListBlock' ), + withViewportMatch( { isLargeViewport: 'medium' } ), applyWithSelect, applyWithDispatch, - withFilters("editor.__experimentalBlockListBlock") -)(BlockListBlock); + withFilters( 'editor.__experimentalBlockListBlock' ) +)( BlockListBlock );