Skip to content

Commit f3b59c2

Browse files
committed
Move contentOnly template locking code from selector to reducer
1 parent 44c09b2 commit f3b59c2

File tree

2 files changed

+261
-28
lines changed

2 files changed

+261
-28
lines changed

packages/block-editor/src/store/reducer.js

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2591,43 +2591,29 @@ export function withDerivedBlockEditingModes( reducer ) {
25912591
const addedBlocks = [];
25922592
const removedClientIds = [];
25932593

2594-
function isNewContentOnlyBlock( clientId, actionSettings ) {
2595-
const blockExists =
2596-
!! nextState.blocks.tree.get( clientId );
2597-
return (
2598-
blockExists &&
2599-
actionSettings.templateLock === 'contentOnly' &&
2600-
! state.blockListSettings[ clientId ]?.templateLock !==
2601-
'contentOnly'
2602-
);
2603-
}
2604-
2605-
function wasContentOnlyBlock( clientId, actionSettings ) {
2606-
const blockExists =
2607-
!! nextState.blocks.tree.get( clientId );
2608-
return (
2609-
blockExists &&
2610-
actionSettings.templateLock !== 'contentOnly' &&
2611-
state.blockListSettings[ clientId ]?.templateLock ===
2612-
'contentOnly'
2613-
);
2614-
}
2615-
26162594
const updates =
26172595
typeof action.clientId === 'string'
26182596
? { [ action.clientId ]: action.settings }
26192597
: action.clientId;
26202598

26212599
for ( const clientId in updates ) {
2622-
if (
2623-
isNewContentOnlyBlock( clientId, updates[ clientId ] )
2624-
) {
2600+
const isNewContentOnlyBlock =
2601+
state.blockListSettings[ clientId ]?.templateLock !==
2602+
'contentOnly' &&
2603+
nextState.blockListSettings[ clientId ]
2604+
?.templateLock === 'contentOnly';
2605+
2606+
const wasContentOnlyBlock =
2607+
state.blockListSettings[ clientId ]?.templateLock ===
2608+
'contentOnly' &&
2609+
nextState.blockListSettings[ clientId ]
2610+
?.templateLock !== 'contentOnly';
2611+
2612+
if ( isNewContentOnlyBlock ) {
26252613
addedBlocks.push(
26262614
nextState.blocks.tree.get( clientId )
26272615
);
2628-
} else if (
2629-
wasContentOnlyBlock( clientId, updates[ clientId ] )
2630-
) {
2616+
} else if ( wasContentOnlyBlock ) {
26312617
removedClientIds.push( clientId );
26322618
}
26332619
}
@@ -2669,6 +2655,47 @@ export function withDerivedBlockEditingModes( reducer ) {
26692655
}
26702656
break;
26712657
}
2658+
case 'SET_BLOCK_EDITING_MODE':
2659+
case 'UNSET_BLOCK_EDITING_MODE': {
2660+
const updatedBlock = nextState.blocks.tree.get(
2661+
action.clientId
2662+
);
2663+
// The block might have been removed.
2664+
if ( ! updatedBlock ) {
2665+
break;
2666+
}
2667+
2668+
const nextDerivedBlockEditingModes =
2669+
getDerivedBlockEditingModesUpdates( {
2670+
prevState: state,
2671+
nextState,
2672+
addedBlocks: [ updatedBlock ],
2673+
isNavMode: false,
2674+
} );
2675+
const nextDerivedNavModeBlockEditingModes =
2676+
getDerivedBlockEditingModesUpdates( {
2677+
prevState: state,
2678+
nextState,
2679+
addedBlocks: [ updatedBlock ],
2680+
isNavMode: true,
2681+
} );
2682+
2683+
if (
2684+
nextDerivedBlockEditingModes ||
2685+
nextDerivedNavModeBlockEditingModes
2686+
) {
2687+
return {
2688+
...nextState,
2689+
derivedBlockEditingModes:
2690+
nextDerivedBlockEditingModes ??
2691+
state.derivedBlockEditingModes,
2692+
derivedNavModeBlockEditingModes:
2693+
nextDerivedNavModeBlockEditingModes ??
2694+
state.derivedNavModeBlockEditingModes,
2695+
};
2696+
}
2697+
break;
2698+
}
26722699
case 'SET_HAS_CONTROLLED_INNER_BLOCKS': {
26732700
const updatedBlock = nextState.blocks.tree.get(
26742701
action.clientId

packages/block-editor/src/store/test/reducer.js

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3576,6 +3576,8 @@ describe( 'state', () => {
35763576
blocks,
35773577
settings,
35783578
zoomLevel,
3579+
blockListSettings,
3580+
blockEditingModes,
35793581
} )
35803582
);
35813583

@@ -3957,6 +3959,210 @@ describe( 'state', () => {
39573959
} );
39583960
} );
39593961

3962+
describe( 'contentOnly template locking', () => {
3963+
let initialState;
3964+
beforeAll( () => {
3965+
select.mockImplementation( ( storeName ) => {
3966+
if ( storeName === preferencesStore ) {
3967+
return {
3968+
get: jest.fn( () => 'edit' ),
3969+
};
3970+
}
3971+
return select( storeName );
3972+
} );
3973+
3974+
// Simulates how the editor typically inserts controlled blocks,
3975+
// - first the pattern is inserted with no inner blocks.
3976+
// - next the pattern is marked as a controlled block.
3977+
// - finally, once the inner blocks of the pattern are received, they're inserted.
3978+
// This process is repeated for the two patterns in this test.
3979+
initialState = dispatchActions(
3980+
[
3981+
{
3982+
type: 'UPDATE_SETTINGS',
3983+
settings: {
3984+
[ sectionRootClientIdKey ]: '',
3985+
},
3986+
},
3987+
{
3988+
type: 'RESET_BLOCKS',
3989+
blocks: [
3990+
{
3991+
name: 'core/group',
3992+
clientId: 'group-1',
3993+
attributes: {},
3994+
innerBlocks: [
3995+
{
3996+
name: 'core/paragraph',
3997+
clientId: 'paragraph-1',
3998+
attributes: {},
3999+
innerBlocks: [],
4000+
},
4001+
{
4002+
name: 'core/group',
4003+
clientId: 'group-2',
4004+
attributes: {},
4005+
innerBlocks: [
4006+
{
4007+
name: 'core/paragraph',
4008+
clientId: 'paragraph-2',
4009+
attributes: {},
4010+
innerBlocks: [],
4011+
},
4012+
],
4013+
},
4014+
],
4015+
},
4016+
],
4017+
},
4018+
{
4019+
type: 'UPDATE_BLOCK_LIST_SETTINGS',
4020+
clientId: 'group-1',
4021+
settings: {
4022+
templateLock: 'contentOnly',
4023+
},
4024+
},
4025+
],
4026+
testReducer,
4027+
initialState
4028+
);
4029+
} );
4030+
4031+
afterAll( () => {
4032+
select.mockRestore();
4033+
} );
4034+
4035+
it( 'returns the expected block editing modes for a parent block with contentOnly template locking', () => {
4036+
// Only the parent pattern and its own children that have bindings
4037+
// are in contentOnly mode. All other blocks are disabled.
4038+
expect( initialState.derivedBlockEditingModes ).toEqual(
4039+
new Map(
4040+
Object.entries( {
4041+
'paragraph-1': 'contentOnly',
4042+
'group-2': 'disabled',
4043+
'paragraph-2': 'contentOnly',
4044+
} )
4045+
)
4046+
);
4047+
} );
4048+
4049+
it( 'removes block editing modes when template locking is removed', () => {
4050+
const { derivedBlockEditingModes } = dispatchActions(
4051+
[
4052+
{
4053+
type: 'UPDATE_BLOCK_LIST_SETTINGS',
4054+
clientId: 'group-1',
4055+
settings: {
4056+
templateLock: false,
4057+
},
4058+
},
4059+
],
4060+
testReducer,
4061+
initialState
4062+
);
4063+
4064+
expect( derivedBlockEditingModes ).toEqual( new Map() );
4065+
} );
4066+
4067+
it( 'allows explicitly set blockEditingModes to override the contentOnly template locking', () => {
4068+
const { derivedBlockEditingModes } = dispatchActions(
4069+
[
4070+
{
4071+
type: 'SET_BLOCK_EDITING_MODE',
4072+
clientId: 'group-1',
4073+
mode: 'disabled',
4074+
},
4075+
{
4076+
type: 'SET_BLOCK_EDITING_MODE',
4077+
clientId: 'paragraph-2',
4078+
mode: 'disabled',
4079+
},
4080+
],
4081+
testReducer,
4082+
initialState
4083+
);
4084+
4085+
expect( derivedBlockEditingModes ).toEqual(
4086+
new Map(
4087+
Object.entries( {
4088+
'paragraph-1': 'contentOnly',
4089+
'group-2': 'disabled',
4090+
'paragraph-2': 'contentOnly',
4091+
} )
4092+
)
4093+
);
4094+
} );
4095+
4096+
it( 'returns the expected block editing modes for synced patterns when switching to navigation mode', () => {
4097+
select.mockImplementation( ( storeName ) => {
4098+
if ( storeName === preferencesStore ) {
4099+
return {
4100+
get: jest.fn( () => 'navigation' ),
4101+
};
4102+
}
4103+
return select( storeName );
4104+
} );
4105+
4106+
const { derivedNavModeBlockEditingModes } = dispatchActions(
4107+
[
4108+
{
4109+
type: 'SET_EDITOR_MODE',
4110+
mode: 'navigation',
4111+
},
4112+
],
4113+
testReducer,
4114+
initialState
4115+
);
4116+
4117+
expect( derivedNavModeBlockEditingModes ).toEqual(
4118+
new Map(
4119+
Object.entries( {
4120+
'': 'contentOnly', // Section root.
4121+
// Group 1 is now a section, so is set to contentOnly.
4122+
'group-1': 'contentOnly',
4123+
'group-2': 'disabled',
4124+
'paragraph-1': 'contentOnly',
4125+
'paragraph-2': 'contentOnly',
4126+
} )
4127+
)
4128+
);
4129+
4130+
select.mockImplementation( ( storeName ) => {
4131+
if ( storeName === preferencesStore ) {
4132+
return {
4133+
get: jest.fn( () => 'edit' ),
4134+
};
4135+
}
4136+
return select( storeName );
4137+
} );
4138+
} );
4139+
4140+
it( 'returns the expected block editing modes for synced patterns when switching to zoomed out mode', () => {
4141+
const { derivedBlockEditingModes } = dispatchActions(
4142+
[
4143+
{
4144+
type: 'SET_ZOOM_LEVEL',
4145+
zoom: 'auto-scaled',
4146+
},
4147+
],
4148+
testReducer,
4149+
initialState
4150+
);
4151+
4152+
expect( derivedBlockEditingModes ).toEqual(
4153+
new Map(
4154+
Object.entries( {
4155+
'': 'contentOnly', // Section root.
4156+
'group-1': 'contentOnly', // Section.
4157+
'group-2': 'disabled',
4158+
'paragraph-1': 'disabled',
4159+
'paragraph-2': 'disabled',
4160+
} )
4161+
)
4162+
);
4163+
} );
4164+
} );
4165+
39604166
describe( 'navigation mode', () => {
39614167
let initialState;
39624168

0 commit comments

Comments
 (0)