Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 32 additions & 37 deletions packages/block-editor/src/store/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
]
);

/**
Expand All @@ -134,7 +129,7 @@ export const isBlockSubtreeDisabled = createSelector(
);
};
return (
getExplicitBlockEditingMode( state, clientId ) === 'disabled' &&
getBlockEditingMode( state, clientId ) === 'disabled' &&
getBlockOrder( state, clientId ).every( isChildSubtreeDisabled )
);
},
Expand Down
164 changes: 104 additions & 60 deletions packages/block-editor/src/store/test/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did anything change in what these tests check for, or did you just unfold the loop for better legibility?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I unfolded the loop so as to change one key thing which is that if the parent block has an editing mode of 'contentOnly' then the child block will now have an editing mode of 'default' not 'contentOnly'.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, got it, that makes sense!

} );

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', () => {
Expand Down