diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 5cb748cdd8dfad..ff85b4fb3f20b4 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -72,45 +72,40 @@ export function getLastInsertedBlocksClientIds( state ) { * @return {BlockEditingMode} The block editing mode. One of `'disabled'`, * `'contentOnly'`, or `'default'`. */ -export const getBlockEditingMode = ( state, clientId = '' ) => { - const explicitEditingMode = getExplicitBlockEditingMode( state, clientId ); - const rootClientId = getBlockRootClientId( state, clientId ); - const templateLock = getTemplateLock( state, rootClientId ); - const name = getBlockName( state, clientId ); - // TODO: Terrible hack! We're calling the global select() function here - // instead of using createRegistrySelector(). The problem with using - // createRegistrySelector() is that then the public block-editor selectors - // (e.g. canInsertBlockTypeUnmemoized) can't call this private block-editor - // selector due to a bug in @wordpress/data. See - // https://github.com/WordPress/gutenberg/pull/50985. - const isContent = - select( blocksStore ).__experimentalHasContentRoleAttribute( name ); - if ( - explicitEditingMode === 'disabled' || - ( templateLock === 'contentOnly' && ! isContent ) - ) { - return 'disabled'; - } - if ( - explicitEditingMode === 'contentOnly' || - ( templateLock === 'contentOnly' && isContent ) - ) { - return 'contentOnly'; - } - return 'default'; -}; - -const getExplicitBlockEditingMode = createSelector( +export const getBlockEditingMode = createSelector( ( state, clientId = '' ) => { - while ( - ! state.blockEditingModes.has( clientId ) && - state.blocks.parents.has( clientId ) - ) { - clientId = state.blocks.parents.get( clientId ); + if ( state.blockEditingModes.has( clientId ) ) { + return state.blockEditingModes.get( clientId ); + } + if ( ! clientId ) { + return 'default'; } - return state.blockEditingModes.get( clientId ) ?? 'default'; + const rootClientId = getBlockRootClientId( state, clientId ); + const templateLock = getTemplateLock( state, rootClientId ); + if ( templateLock === 'contentOnly' ) { + const name = getBlockName( state, clientId ); + // TODO: Terrible hack! We're calling the global select() function + // here instead of using createRegistrySelector(). The problem with + // using createRegistrySelector() is that then the public + // block-editor selectors (e.g. canInsertBlockTypeUnmemoized) can't + // call this private block-editor selector due to a bug in + // @wordpress/data. See + // https://github.com/WordPress/gutenberg/pull/50985. + const isContent = + select( blocksStore ).__experimentalHasContentRoleAttribute( + name + ); + return isContent ? 'contentOnly' : 'disabled'; + } + const parentMode = getBlockEditingMode( state, rootClientId ); + return parentMode === 'contentOnly' ? 'default' : parentMode; }, - ( state ) => [ state.blockEditingModes, state.blocks.parents ] + ( state ) => [ + state.blockEditingModes, + state.blocks.parents, + state.settings.templateLock, + state.blockListSettings, + ] ); /** @@ -134,7 +129,7 @@ export const isBlockSubtreeDisabled = createSelector( ); }; return ( - getExplicitBlockEditingMode( state, clientId ) === 'disabled' && + getBlockEditingMode( state, clientId ) === 'disabled' && getBlockOrder( state, clientId ).every( isChildSubtreeDisabled ) ); }, diff --git a/packages/block-editor/src/store/test/private-selectors.js b/packages/block-editor/src/store/test/private-selectors.js index cbe890a8dc9732..ecae342317ce18 100644 --- a/packages/block-editor/src/store/test/private-selectors.js +++ b/packages/block-editor/src/store/test/private-selectors.js @@ -139,69 +139,113 @@ describe( 'private selectors', () => { ).toBe( 'default' ); } ); - [ 'disabled', 'contentOnly' ].forEach( ( mode ) => { - it( `should return ${ mode } if explicitly set`, () => { - const state = { - ...baseState, - blockEditingModes: new Map( [ - [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', mode ], - ] ), - }; - expect( - getBlockEditingMode( - state, - 'b3247f75-fd94-4fef-97f9-5bfd162cc416' - ) - ).toBe( mode ); - } ); + it( 'should return disabled if explicitly set', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', 'disabled' ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'disabled' ); + } ); - it( `should return ${ mode } if explicitly set on a parent`, () => { - const state = { - ...baseState, - blockEditingModes: new Map( [ - [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', mode ], - ] ), - }; - expect( - getBlockEditingMode( - state, - 'b3247f75-fd94-4fef-97f9-5bfd162cc416' - ) - ).toBe( mode ); - } ); + it( 'should return contentOnly if explicitly set', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ + 'b3247f75-fd94-4fef-97f9-5bfd162cc416', + 'contentOnly', + ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'contentOnly' ); + } ); - it( `should return ${ mode } if overridden by a parent`, () => { - const state = { - ...baseState, - blockEditingModes: new Map( [ - [ '', mode ], - [ - 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', - 'default', - ], - [ '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', mode ], - ] ), - }; - expect( - getBlockEditingMode( - state, - 'b3247f75-fd94-4fef-97f9-5bfd162cc416' - ) - ).toBe( mode ); - } ); + it( 'should return disabled if explicitly set on a parent', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', 'disabled' ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'disabled' ); + } ); - it( `should return ${ mode } if explicitly set on root`, () => { - const state = { - ...baseState, - blockEditingModes: new Map( [ [ '', mode ] ] ), - }; - expect( - getBlockEditingMode( - state, - 'b3247f75-fd94-4fef-97f9-5bfd162cc416' - ) - ).toBe( mode ); - } ); + it( 'should return default if parent is set to contentOnly', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', + 'contentOnly', + ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'default' ); + } ); + + it( 'should return disabled if overridden by a parent', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ '', 'disabled' ], + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', 'default' ], + [ '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', 'disabled' ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'disabled' ); + } ); + + it( 'should return disabled if explicitly set on root', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ [ '', 'disabled' ] ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'disabled' ); + } ); + + it( 'should return default if root is contentOnly', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ [ '', 'contentOnly' ] ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'default' ); } ); it( 'should return disabled if parent is locked and the block has no content role', () => {