diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index a3de21f5c01b61..128b167f697617 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1667,16 +1667,14 @@ export function canRemoveBlock( state, clientId, rootClientId = null ) { if ( attributes === null ) { return true; } - if ( attributes.lock?.remove ) { - return false; + if ( attributes.lock?.remove !== undefined ) { + return ! attributes.lock.remove; } if ( getTemplateLock( state, rootClientId ) ) { return false; } - if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { - return false; - } - return true; + + return getBlockEditingMode( state, rootClientId ) !== 'disabled'; } /** @@ -1706,18 +1704,16 @@ export function canRemoveBlocks( state, clientIds, rootClientId = null ) { export function canMoveBlock( state, clientId, rootClientId = null ) { const attributes = getBlockAttributes( state, clientId ); if ( attributes === null ) { - return; + return true; } - if ( attributes.lock?.move ) { - return false; + if ( attributes.lock?.move !== undefined ) { + return ! attributes.lock.move; } if ( getTemplateLock( state, rootClientId ) === 'all' ) { return false; } - if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { - return false; - } - return true; + + return getBlockEditingMode( state, rootClientId ) !== 'disabled'; } /** diff --git a/test/e2e/specs/editor/various/block-locking.spec.js b/test/e2e/specs/editor/various/block-locking.spec.js index 2c0a9d3f0bf565..c374c4ee2b0b54 100644 --- a/test/e2e/specs/editor/various/block-locking.spec.js +++ b/test/e2e/specs/editor/various/block-locking.spec.js @@ -8,79 +8,135 @@ test.describe( 'Block Locking', () => { await admin.createNewPost(); } ); - test.describe( 'General', () => { - test( 'can prevent removal', async ( { editor, page } ) => { - await editor.insertBlock( { name: 'core/paragraph' } ); - await page.keyboard.type( 'Some paragraph' ); + test( 'can prevent removal', async ( { editor, page } ) => { + await editor.canvas.click( 'role=button[name="Add default block"i]' ); + await page.keyboard.type( 'Some paragraph' ); - await editor.clickBlockOptionsMenuItem( 'Lock' ); + await editor.clickBlockOptionsMenuItem( 'Lock' ); - await page.click( 'role=checkbox[name="Prevent removal"]' ); - await page.click( 'role=button[name="Apply"]' ); + await page.click( 'role=checkbox[name="Prevent removal"]' ); + await page.click( 'role=button[name="Apply"]' ); - await expect( - page.locator( 'role=menuitem[name="Delete"]' ) - ).not.toBeVisible(); - } ); + await expect( + page.locator( 'role=menuitem[name="Delete"]' ) + ).not.toBeVisible(); + } ); - test( 'can disable movement', async ( { editor, page } ) => { - await editor.insertBlock( { name: 'core/paragraph' } ); - await page.keyboard.type( 'First paragraph' ); + test( 'can disable movement', async ( { editor, page } ) => { + await editor.canvas.click( 'role=button[name="Add default block"i]' ); + await page.keyboard.type( 'First paragraph' ); - await editor.insertBlock( { name: 'core/paragraph' } ); - await page.keyboard.type( 'Second paragraph' ); + await page.keyboard.type( 'Enter' ); + await page.keyboard.type( 'Second paragraph' ); - await editor.clickBlockOptionsMenuItem( 'Lock' ); + await editor.clickBlockOptionsMenuItem( 'Lock' ); - await page.click( 'role=checkbox[name="Disable movement"]' ); - await page.click( 'role=button[name="Apply"]' ); + await page.click( 'role=checkbox[name="Disable movement"]' ); + await page.click( 'role=button[name="Apply"]' ); - // Hide options. - await editor.clickBlockToolbarButton( 'Options' ); + // Hide options. + await editor.clickBlockToolbarButton( 'Options' ); - // Drag handle is hidden. - await expect( - page.locator( 'role=button[name="Drag"]' ) - ).not.toBeVisible(); + // Drag handle is hidden. + await expect( + page.locator( 'role=button[name="Drag"]' ) + ).not.toBeVisible(); - // Movers are hidden. No need to check for both. - await expect( - page.locator( 'role=button[name="Move up"]' ) - ).not.toBeVisible(); - } ); + // Movers are hidden. No need to check for both. + await expect( + page.locator( 'role=button[name="Move up"]' ) + ).not.toBeVisible(); + } ); - test( 'can lock everything', async ( { editor, page } ) => { - await editor.insertBlock( { name: 'core/paragraph' } ); - await page.keyboard.type( 'Some paragraph' ); + test( 'can lock everything', async ( { editor, page } ) => { + await editor.canvas.click( 'role=button[name="Add default block"i]' ); + await page.keyboard.type( 'Some paragraph' ); - await editor.clickBlockOptionsMenuItem( 'Lock' ); + await editor.clickBlockOptionsMenuItem( 'Lock' ); - await page.click( 'role=checkbox[name="Lock all"]' ); - await page.click( 'role=button[name="Apply"]' ); + await page.click( 'role=checkbox[name="Lock all"]' ); + await page.click( 'role=button[name="Apply"]' ); - expect( await editor.getEditedPostContent() ) - .toBe( ` + expect( await editor.getEditedPostContent() ) + .toBe( `

Some paragraph

` ); - } ); + } ); - test( 'can unlock from toolbar', async ( { editor, page } ) => { - await editor.insertBlock( { name: 'core/paragraph' } ); - await page.keyboard.type( 'Some paragraph' ); + test( 'can unlock from toolbar', async ( { editor, page } ) => { + await editor.canvas.click( 'role=button[name="Add default block"i]' ); + await page.keyboard.type( 'Some paragraph' ); - await editor.clickBlockOptionsMenuItem( 'Lock' ); + await editor.clickBlockOptionsMenuItem( 'Lock' ); - await page.click( 'role=checkbox[name="Lock all"]' ); - await page.click( 'role=button[name="Apply"]' ); + await page.click( 'role=checkbox[name="Lock all"]' ); + await page.click( 'role=button[name="Apply"]' ); - await editor.clickBlockToolbarButton( 'Unlock' ); - await page.click( 'role=checkbox[name="Lock all"]' ); - await page.click( 'role=button[name="Apply"]' ); + await editor.clickBlockToolbarButton( 'Unlock' ); + await page.click( 'role=checkbox[name="Lock all"]' ); + await page.click( 'role=button[name="Apply"]' ); - expect( await editor.getEditedPostContent() ) - .toBe( ` + expect( await editor.getEditedPostContent() ) + .toBe( `

Some paragraph

` ); + } ); + + test( 'block locking supersedes template locking', async ( { + editor, + page, + pageUtils, + } ) => { + await editor.insertBlock( { + name: 'core/group', + attributes: { + layout: { type: 'constrained' }, + templateLock: 'all', + }, + innerBlocks: [ + { + name: 'core/heading', + attributes: { content: 'Hello, hello' }, + }, + { + name: 'core/paragraph', + attributes: { content: 'WordPress' }, + }, + ], + } ); + + const paragraph = editor.canvas.getByRole( 'document', { + name: 'Paragraph block', } ); + await paragraph.click(); + + await editor.clickBlockToolbarButton( 'Unlock' ); + await page.click( 'role=checkbox[name="Lock all"]' ); + await page.click( 'role=button[name="Apply"]' ); + + await expect( + page + .getByRole( 'toolbar', { name: 'Block tools' } ) + .getByRole( 'button', { name: 'Move up' } ) + ).toBeVisible(); + + await paragraph.click(); + await pageUtils.pressKeys( 'access+z' ); + + await expect.poll( editor.getBlocks ).toMatchObject( [ + { + name: 'core/group', + attributes: { + layout: { type: 'constrained' }, + templateLock: 'all', + }, + innerBlocks: [ + { + name: 'core/heading', + attributes: { content: 'Hello, hello' }, + }, + ], + }, + ] ); } ); } );