Skip to content

Commit

Permalink
Allow content blocks to be explicitly disabled even when they have a …
Browse files Browse the repository at this point in the history
…derived mode

First iteration of handling disabled blocks as derived block editing modes
  • Loading branch information
talldan committed Dec 9, 2024
1 parent 7a0e43c commit 631ac3a
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 160 deletions.
71 changes: 60 additions & 11 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2186,19 +2186,19 @@ function getBlockTreeBlock( state, clientId ) {
* The callback receives the current block as its argument.
*/
function traverseBlockTree( state, clientId, callback ) {
const parentTree = getBlockTreeBlock( state, clientId );
if ( ! parentTree ) {
const tree = getBlockTreeBlock( state, clientId );
if ( ! tree ) {
return;
}

callback( parentTree );
callback( tree );

if ( ! parentTree?.innerBlocks?.length ) {
if ( ! tree?.innerBlocks?.length ) {
return;
}

for ( const block of parentTree?.innerBlocks ) {
traverseBlockTree( state, block.clientId, callback );
for ( const innerBlock of tree?.innerBlocks ) {
traverseBlockTree( state, innerBlock.clientId, callback );
}
}

Expand All @@ -2217,14 +2217,32 @@ function findParentInClientIdsList( state, clientId, clientIds ) {
}

let parent = state.blocks.parents.get( clientId );
while ( parent ) {
while ( parent !== undefined ) {
if ( clientIds.includes( parent ) ) {
return parent;
}
parent = state.blocks.parents.get( parent );
}
}

/**
* Retrieves the block editing mode of the ancestor block of a given block.
*
* @param {Object} state The current state object.
* @param {string} clientId The client ID of the block to find the ancestor block for.
*
* @return {string|undefined} The block editing mode of the ancestor block, or undefined if not found.
*/
function getAncestorBlockEditingMode( state, clientId ) {
let parent = state.blocks.parents.get( clientId );
while ( parent !== undefined ) {
if ( state.blockEditingModes.has( parent ) ) {
return state.blockEditingModes.get( parent );
}
parent = state.blocks.parents.get( parent );
}
}

/**
* Checks if a block has any bindings in its metadata attributes.
*
Expand Down Expand Up @@ -2262,6 +2280,9 @@ function getDerivedBlockEditingModesForTree(
// so the default block editing mode is set to disabled.
const sectionRootClientId = state.settings?.[ sectionRootClientIdKey ];
const sectionClientIds = state.blocks.order.get( sectionRootClientId );
const hasDisabledBlocks = state.blockEditingModes
.entries()
.some( ( [ , mode ] ) => mode === 'disabled' );
const templatePartClientIds = [];
const syncedPatternClientIds = [];

Expand All @@ -2279,6 +2300,27 @@ function getDerivedBlockEditingModesForTree(

traverseBlockTree( state, treeClientId, ( block ) => {
const { clientId, name: blockName } = block;

// If the block already has an explicit block editing mode set,
// don't override it.
if ( state.blockEditingModes.has( clientId ) ) {
return;
}

// An explicitly disabled block editing mode cascades to all its children.
// Check ancestors of the current block to see if the nearest one with a block
// editing mode set is disabled.
if ( hasDisabledBlocks ) {
const ancestorBlockEditingMode = getAncestorBlockEditingMode(
state,
clientId
);
if ( ancestorBlockEditingMode === 'disabled' ) {
derivedBlockEditingModes.set( clientId, 'disabled' );
return;
}
}

if ( isZoomedOut || isNavMode ) {
// If the root block is the section root set its editing mode to contentOnly.
if ( clientId === sectionRootClientId ) {
Expand Down Expand Up @@ -2327,7 +2369,7 @@ function getDerivedBlockEditingModesForTree(
templatePartClientIds
);
// Allow contentOnly blocks in template parts outside of sections
// to be editable. Only disable blocks that aren't don't fit this criteria.
// to be editable. Only disable blocks that don't fit this criteria.
if ( ! isInTemplatePart && ! isContentBlock( blockName ) ) {
derivedBlockEditingModes.set( clientId, 'disabled' );
return;
Expand Down Expand Up @@ -2369,7 +2411,7 @@ function getDerivedBlockEditingModesForTree(
}
}

if ( blockName && isContentBlock( blockName ) ) {
if ( blockName && isContentBlock( blockName, clientId ) ) {
derivedBlockEditingModes.set( clientId, 'contentOnly' );
return;
}
Expand Down Expand Up @@ -2598,11 +2640,16 @@ export function withDerivedBlockEditingModes( reducer ) {
}
break;
}
case 'SET_BLOCK_EDITING_MODE':
case 'UNSET_BLOCK_EDITING_MODE':
case 'SET_HAS_CONTROLLED_INNER_BLOCKS': {
const updatedBlock = nextState.blocks.tree.get(
const updatedBlock = getBlockTreeBlock(
nextState,
action.clientId
);
// The block might have been removed.

// The block might have been removed in which case it'll be
// handled by the `REMOVE_BLOCKS` action.
if ( ! updatedBlock ) {
break;
}
Expand All @@ -2611,13 +2658,15 @@ export function withDerivedBlockEditingModes( reducer ) {
getDerivedBlockEditingModesUpdates( {
prevState: state,
nextState,
removedClientIds: [ action.clientId ],
addedBlocks: [ updatedBlock ],
isNavMode: false,
} );
const nextDerivedNavModeBlockEditingModes =
getDerivedBlockEditingModesUpdates( {
prevState: state,
nextState,
removedClientIds: [ action.clientId ],
addedBlocks: [ updatedBlock ],
isNavMode: true,
} );
Expand Down
4 changes: 1 addition & 3 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3085,9 +3085,7 @@ export const getBlockEditingMode = createRegistrySelector(
const isContent = hasContentRoleAttribute( name );
return isContent ? 'contentOnly' : 'disabled';
}
// Otherwise, check if there's an ancestor that is contentOnly
const parentMode = getBlockEditingMode( state, rootClientId );
return parentMode === 'contentOnly' ? 'default' : parentMode;
return 'default';
}
);

Expand Down
Loading

0 comments on commit 631ac3a

Please sign in to comment.