Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to set templateLock = 'contentOnly' in editor settings #50082

Closed
wants to merge 3 commits into from
Closed
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
32 changes: 32 additions & 0 deletions docs/reference-guides/data/data-core-block-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,23 @@ _Returns_

- `boolean`: Whether the caret is within formatted text.

### isContentLockedBlock

Returns whether or not the given block is _content locked_.

A block is _content locked_ if it is nested within a block that has a `templateLock` attribute set to `'contentOnly'` (a _content locking_ block), or if the editor has a `templateLock` of `'contentOnly'`.

If the block is nested within a content block type (see `settings.contentBlockTypes`) then it is not _content locked_.

_Parameters_

- _state_ `Object`: Global application state.
- _clientId_ `string`: The client ID of the block to check.

_Returns_

- `boolean`: Whether or not the block is content locked.

### isDraggingBlocks

Returns true if the user is dragging blocks, or false otherwise.
Expand All @@ -1025,6 +1042,21 @@ _Returns_

- `boolean`: Whether block is first in multi-selection.

### isInsertionLocked

Determines if the editor or a given container is locked and does not allow block insertion.

Only the `templateLock` settings of the editor or container block are checked. For more rigorous checking that checks the `allowedBlockTypes` attribute, use `canInsertBlockType()`.

_Parameters_

- _state_ `Object`: Editor state.
- _rootClientId_ `?string`: Container block's client ID, or `null` to check the editor.

_Returns_

- `boolean`: Whether block insertion is locked.

### isLastBlockChangePersistent

Returns true if the most recent block change is be considered persistent, or false otherwise. A persistent change is one committed by BlockEditorProvider via its `onChange` callback, in addition to `onInput`.
Expand Down
140 changes: 32 additions & 108 deletions packages/block-editor/src/components/block-inspector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,8 @@ import {
hasBlockSupport,
store as blocksStore,
} from '@wordpress/blocks';
import {
FlexItem,
PanelBody,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
Button,
__unstableMotion as motion,
} from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { useMemo, useCallback } from '@wordpress/element';
import { PanelBody, __unstableMotion as motion } from '@wordpress/components';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
Expand All @@ -28,7 +20,6 @@ import MultiSelectionInspector from '../multi-selection-inspector';
import BlockVariationTransforms from '../block-variation-transforms';
import useBlockDisplayInformation from '../use-block-display-information';
import { store as blockEditorStore } from '../../store';
import BlockIcon from '../block-icon';
import BlockStyles from '../block-styles';
import DefaultStylePicker from '../default-style-picker';
import { default as InspectorControls } from '../inspector-controls';
Expand All @@ -38,102 +29,34 @@ import AdvancedControls from '../inspector-controls-tabs/advanced-controls-panel
import PositionControls from '../inspector-controls-tabs/position-controls-panel';
import useBlockInspectorAnimationSettings from './useBlockInspectorAnimationSettings';
import BlockInfo from '../block-info-slot-fill';
import ContentBlocksList from '../content-blocks-list';
import { unlock } from '../../lock-unlock';

function useContentBlocks( blockTypes, block ) {
const contentBlocksObjectAux = useMemo( () => {
return blockTypes.reduce( ( result, blockType ) => {
if (
blockType.name !== 'core/list-item' &&
Object.entries( blockType.attributes ).some(
( [ , { __experimentalRole } ] ) =>
__experimentalRole === 'content'
)
) {
result[ blockType.name ] = true;
}
return result;
}, {} );
}, [ blockTypes ] );
const isContentBlock = useCallback(
( blockName ) => {
return !! contentBlocksObjectAux[ blockName ];
},
[ contentBlocksObjectAux ]
);
return useMemo( () => {
return getContentBlocks( [ block ], isContentBlock );
}, [ block, isContentBlock ] );
}

function getContentBlocks( blocks, isContentBlock ) {
const result = [];
for ( const block of blocks ) {
if ( isContentBlock( block.name ) ) {
result.push( block );
}
result.push( ...getContentBlocks( block.innerBlocks, isContentBlock ) );
}
return result;
}

function BlockNavigationButton( { blockTypes, block, selectedBlock } ) {
const { selectBlock } = useDispatch( blockEditorStore );
const blockType = blockTypes.find( ( { name } ) => name === block.name );
const isSelected =
selectedBlock && selectedBlock.clientId === block.clientId;
return (
<Button
isPressed={ isSelected }
onClick={ () => selectBlock( block.clientId ) }
>
<HStack justify="flex-start">
<BlockIcon icon={ blockType.icon } />
<FlexItem>{ blockType.title }</FlexItem>
</HStack>
</Button>
function BlockInspectorLockedBlocks( { contentLockingBlock } ) {
const selectedBlock = useSelect(
( select ) => select( blockEditorStore ).getSelectedBlockClientId(),
[]
);
}

function BlockInspectorLockedBlocks( { topLevelLockedBlock } ) {
const { blockTypes, block, selectedBlock } = useSelect(
( select ) => {
return {
blockTypes: select( blocksStore ).getBlockTypes(),
block: select( blockEditorStore ).getBlock(
topLevelLockedBlock
),
selectedBlock: select( blockEditorStore ).getSelectedBlock(),
};
},
[ topLevelLockedBlock ]
const blockInformation = useBlockDisplayInformation(
contentLockingBlock ?? selectedBlock
);
const blockInformation = useBlockDisplayInformation( topLevelLockedBlock );
const contentBlocks = useContentBlocks( blockTypes, block );
return (
<div className="block-editor-block-inspector">
<BlockCard
{ ...blockInformation }
className={ blockInformation.isSynced && 'is-synced' }
/>
<BlockVariationTransforms blockClientId={ topLevelLockedBlock } />
{ contentLockingBlock && (
<BlockVariationTransforms
blockClientId={ contentLockingBlock }
/>
) }
<BlockInfo.Slot />
<VStack
spacing={ 1 }
padding={ 4 }
className="block-editor-block-inspector__block-buttons-container"
>
<h2 className="block-editor-block-card__title">
{ __( 'Content' ) }
</h2>
{ contentBlocks.map( ( contentBlock ) => (
<BlockNavigationButton
selectedBlock={ selectedBlock }
key={ contentBlock.clientId }
block={ contentBlock }
blockTypes={ blockTypes }
/>
) ) }
</VStack>
{ contentLockingBlock && (
<PanelBody title={ __( 'Content' ) }>
<ContentBlocksList rootClientId={ contentLockingBlock } />
</PanelBody>
) }
</div>
);
}
Expand All @@ -144,15 +67,16 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
selectedBlockName,
selectedBlockClientId,
blockType,
topLevelLockedBlock,
isContentLocked,
contentLockingBlock,
} = useSelect( ( select ) => {
const {
getSelectedBlockClientId,
getSelectedBlockCount,
getBlockName,
__unstableGetContentLockingParent,
getTemplateLock,
} = select( blockEditorStore );
isContentLockedBlock,
getContentLockingBlock,
} = unlock( select( blockEditorStore ) );

const _selectedBlockClientId = getSelectedBlockClientId();
const _selectedBlockName =
Expand All @@ -165,11 +89,10 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
selectedBlockClientId: _selectedBlockClientId,
selectedBlockName: _selectedBlockName,
blockType: _blockType,
topLevelLockedBlock:
__unstableGetContentLockingParent( _selectedBlockClientId ) ||
( getTemplateLock( _selectedBlockClientId ) === 'contentOnly'
? _selectedBlockClientId
: undefined ),
isContentLocked: isContentLockedBlock( _selectedBlockClientId ),
contentLockingBlock: getContentLockingBlock(
_selectedBlockClientId
),
};
}, [] );

Expand Down Expand Up @@ -241,10 +164,11 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
}
return null;
}
if ( topLevelLockedBlock ) {

if ( isContentLocked ) {
return (
<BlockInspectorLockedBlocks
topLevelLockedBlock={ topLevelLockedBlock }
contentLockingBlock={ contentLockingBlock }
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,3 @@
.block-editor-block-inspector__tab-item {
flex: 1 1 0px;
}

.block-editor-block-inspector__block-buttons-container {
border-top: $border-width solid $gray-200;
padding: $grid-unit-20;
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ function useAppender( rootClientId, CustomAppender ) {
const { hideInserter, isParentSelected } = useSelect(
( select ) => {
const {
getTemplateLock,
getSelectedBlockClientId,
__unstableGetEditorMode,
isInsertionLocked,
} = select( blockEditorStore );

const selectedBlockClientId = getSelectedBlockClientId();

return {
hideInserter:
!! getTemplateLock( rootClientId ) ||
isInsertionLocked( rootClientId ) ||
__unstableGetEditorMode() === 'zoom-out',
isParentSelected:
rootClientId === selectedBlockClientId ||
Expand Down
42 changes: 18 additions & 24 deletions packages/block-editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
isUnmodifiedDefaultBlock,
serializeRawBlock,
switchToBlockType,
store as blocksStore,
getDefaultBlockName,
isUnmodifiedBlock,
} from '@wordpress/blocks';
Expand All @@ -43,6 +42,8 @@ import BlockHtml from './block-html';
import { useBlockProps } from './use-block-props';
import { store as blockEditorStore } from '../../store';
import { useLayout } from './layout';
import { unlock } from '../../lock-unlock';

export const BlockListBlockContext = createContext();

/**
Expand Down Expand Up @@ -99,32 +100,26 @@ function BlockListBlock( {
} ) {
const {
themeSupportsLayout,
hasContentLockedParent,
isContentBlock,
isContentLocked,
isContent,
isContentLocking,
isTemporarilyEditingAsBlocks,
isTemporarilyUnlocked,
} = useSelect(
( select ) => {
const {
getSettings,
__unstableGetContentLockingParent,
getTemplateLock,
__unstableGetTemporarilyEditingAsBlocks,
} = select( blockEditorStore );
const _hasContentLockedParent =
!! __unstableGetContentLockingParent( clientId );
getTemporarilyUnlockedBlock,
isContentBlock,
isContentLockedBlock,
isContentLockingBlock,
} = unlock( select( blockEditorStore ) );
return {
themeSupportsLayout: getSettings().supportsLayout,
isContentBlock:
select( blocksStore ).__experimentalHasContentRoleAttribute(
name
),
hasContentLockedParent: _hasContentLockedParent,
isContentLocking:
getTemplateLock( clientId ) === 'contentOnly' &&
! _hasContentLockedParent,
isTemporarilyEditingAsBlocks:
__unstableGetTemporarilyEditingAsBlocks() === clientId,
isContent: isContentBlock( clientId ),
isContentLocked: isContentLockedBlock( clientId ),
isContentLocking: isContentLockingBlock( clientId ),
isTemporarilyUnlocked:
getTemporarilyUnlockedBlock() === clientId,
};
},
[ name, clientId ]
Expand Down Expand Up @@ -160,7 +155,7 @@ function BlockListBlock( {

const blockType = getBlockType( name );

if ( hasContentLockedParent && ! isContentBlock ) {
if ( isContentLocked && ! isContent ) {
wrapperProps = {
...wrapperProps,
tabIndex: -1,
Expand Down Expand Up @@ -235,9 +230,8 @@ function BlockListBlock( {
className: classnames(
{
'is-content-locked': isContentLocking,
'is-content-locked-temporarily-editing-as-blocks':
isTemporarilyEditingAsBlocks,
'is-content-block': hasContentLockedParent && isContentBlock,
'is-content-temporarily-unlocked': isTemporarilyUnlocked,
'is-content-block': isContentLocked && isContent,
},
dataAlign && themeSupportsLayout && `align${ dataAlign }`,
className
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@
.block-editor-block-list__block {
pointer-events: none;
}
.is-content-block {
.is-content-block,
.is-content-block .block-editor-block-list__block {
pointer-events: initial;
}
}
Expand Down Expand Up @@ -323,7 +324,7 @@
}

.is-focus-mode .block-editor-block-list__block.is-content-locked.has-child-selected,
.is-focus-mode .block-editor-block-list__block.is-content-locked-temporarily-editing-as-blocks.has-child-selected {
.is-focus-mode .block-editor-block-list__block.is-content-temporarily-unlocked.has-child-selected {
&,
& .block-editor-block-list__block {
opacity: 1;
Expand Down
Loading