Skip to content

Commit

Permalink
Template Locking: readonly / disable editing attributes (without rewr…
Browse files Browse the repository at this point in the history
…ite)
  • Loading branch information
ellatrix committed Jul 22, 2019
1 parent 1a77aa0 commit 19adb5c
Show file tree
Hide file tree
Showing 16 changed files with 230 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ add_action( 'init', 'myplugin_register_template' );

*Options:*

- `all` — prevents all operations. It is not possible to insert new blocks, move existing blocks, or delete blocks.
- `readonly` — prevents all operations. It is not possible to edit any blocks, insert new blocks, move or delete existing blocks.
- `all` — prevents all block operations. It is not possible to insert new blocks, move or delete existing blocks.
- `insert` — prevents inserting or removing blocks, but allows moving existing blocks.

## Nested Templates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,10 @@ export default compose(
} ),
withSelect( ( select, { rootClientId } ) => {
const { getClientIdsOfDescendants, getTemplateLock, getBlockIndex } = select( 'core/block-editor' );
const templateLock = getTemplateLock( rootClientId );

return {
isLockedAll: getTemplateLock( rootClientId ) === 'all',
isLockedAll: templateLock === 'all' || templateLock === 'readonly',
getClientIdsOfDescendants,
getBlockIndex,
};
Expand Down
16 changes: 15 additions & 1 deletion packages/block-editor/src/components/block-inspector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ const BlockInspector = ( {
selectedBlockClientId,
selectedBlockName,
showNoBlockSelectedMessage = true,
isReadOnly,
} ) => {
if ( isReadOnly ) {
return __( 'The selected block is read-only.' );
}

if ( count > 1 ) {
return <MultiSelectionInspector />;
}
Expand Down Expand Up @@ -91,18 +96,27 @@ const BlockInspector = ( {

export default withSelect(
( select ) => {
const { getSelectedBlockClientId, getSelectedBlockCount, getBlockName } = select( 'core/block-editor' );
const {
getSelectedBlockClientId,
getSelectedBlockCount,
getBlockName,
getTemplateLock,
getBlockRootClientId,
} = select( 'core/block-editor' );
const { getBlockStyles } = select( 'core/blocks' );
const selectedBlockClientId = getSelectedBlockClientId();
const selectedBlockName = selectedBlockClientId && getBlockName( selectedBlockClientId );
const blockType = selectedBlockClientId && getBlockType( selectedBlockName );
const blockStyles = selectedBlockClientId && getBlockStyles( selectedBlockName );
const rootClientId = getBlockRootClientId( selectedBlockClientId );
const isReadOnly = getTemplateLock( rootClientId ) === 'readonly';
return {
count: getSelectedBlockCount(),
hasBlockStyles: blockStyles && blockStyles.length > 0,
selectedBlockName,
selectedBlockClientId,
blockType,
isReadOnly,
};
}
)( BlockInspector );
14 changes: 11 additions & 3 deletions packages/block-editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function BlockListBlock( {
isFocusMode,
hasFixedToolbar,
isLocked,
isReadOnly,
clientId,
rootClientId,
isSelected,
Expand Down Expand Up @@ -444,6 +445,7 @@ function BlockListBlock( {
insertBlocksAfter={ isLocked ? undefined : onInsertBlocksAfter }
onReplace={ isLocked ? undefined : onReplace }
mergeBlocks={ isLocked ? undefined : onMerge }
isReadOnly={ isReadOnly }
clientId={ clientId }
isSelectionEnabled={ isSelectionEnabled }
toggleSelection={ toggleSelection }
Expand Down Expand Up @@ -518,7 +520,7 @@ function BlockListBlock( {
}
/>
) }
{ ( shouldShowContextualToolbar || isForcingContextualToolbar.current ) && (
{ ( shouldShowContextualToolbar || isForcingContextualToolbar.current ) && ! isReadOnly && (
<BlockContextualToolbar
// If the toolbar is being shown because of being forced
// it should focus the toolbar right after the mount.
Expand Down Expand Up @@ -640,8 +642,9 @@ const applyWithSelect = withSelect(
initialPosition: isSelected ? getSelectedBlocksInitialCaretPosition() : null,
isEmptyDefaultBlock:
name && isUnmodifiedDefaultBlock( { name, attributes } ),
isMovable: 'all' !== templateLock,
isMovable: templateLock !== 'all' && templateLock !== 'readonly',
isLocked: !! templateLock,
isReadOnly: templateLock === 'readonly',
isFocusMode: focusMode && isLargeViewport,
hasFixedToolbar: hasFixedToolbar && isLargeViewport,
isLast: index === blockOrder.length - 1,
Expand Down Expand Up @@ -678,7 +681,12 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => {

return {
setAttributes( newAttributes ) {
const { clientId } = ownProps;
const { clientId, isReadOnly } = ownProps;

if ( isReadOnly ) {
return;
}

updateBlockAttributes( clientId, newAttributes );
},
onSelect( clientId = ownProps.clientId, initialPosition ) {
Expand Down
3 changes: 2 additions & 1 deletion packages/block-editor/src/components/block-mover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,11 @@ export default compose(
const blockOrder = getBlockOrder( rootClientId );
const firstIndex = getBlockIndex( firstClientId, rootClientId );
const lastIndex = getBlockIndex( last( normalizedClientIds ), rootClientId );
const templateLock = getTemplateLock( rootClientId );

return {
blockType: block ? getBlockType( block.name ) : null,
isLocked: getTemplateLock( rootClientId ) === 'all',
isLocked: templateLock === 'all' || templateLock === 'readonly',
rootClientId,
firstIndex,
isFirst: firstIndex === 0,
Expand Down
11 changes: 4 additions & 7 deletions packages/block-editor/src/components/inner-blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ To present the user with a set of template choices for the inner blocks, you may

A template option is an object consisting of the following properties:

- `title` (`string`): A human-readable label which describes the template.
- `title` (`string`): A human-readable label which describes the template.
- `icon` (`WPElement|string`): An element or [Dashicon](https://developer.wordpress.org/resource/dashicons/) slug to show as a visual approximation of the template.
- `template` (`Array<Array>`): The template to apply when the option has been selected. See [`template` documentation](#template) for more information.

Expand Down Expand Up @@ -168,7 +168,8 @@ Template locking of `InnerBlocks` is similar to [Custom Post Type templates lock
Template locking allows locking the `InnerBlocks` area for the current template.
*Options:*

- `'all'` — prevents all operations. It is not possible to insert new blocks. Move existing blocks or delete them.
- `'readonly'` — prevents all operations. It is not possible to edit any blocks, insert new blocks, or move or delete existing blocks.
- `'all'` — prevents all block operations. It is not possible to insert new blocks. Move existing blocks or delete them.
- `'insert'` — prevents inserting or removing blocks, but allows moving existing ones.
- `false` — prevents locking from being applied to an `InnerBlocks` area even if a parent block contains locking. ( Boolean )

Expand All @@ -184,7 +185,7 @@ A 'render prop' function that can be used to customize the block's appender.

#### Notes
* For convenience two predefined appender components are exposed on `InnerBlocks` which can be consumed within the render function:
- `<InnerBlocks.ButtonBlockAppender />` - display a `+` (plus) icon button that, when clicked, displays the block picker menu. No default Block is inserted.
- `<InnerBlocks.ButtonBlockAppender />` - display a `+` (plus) icon button that, when clicked, displays the block picker menu. No default Block is inserted.
- `<InnerBlocks.DefaultBlockAppender />` - display the default block appender as set by `wp.blocks.setDefaultBlockName`. Typically this is the `paragraph` block.
* Consumers are also free to pass any valid render function. This provides the full flexibility to define a bespoke block appender.

Expand All @@ -205,7 +206,3 @@ A 'render prop' function that can be used to customize the block's appender.
) }
/>
```




Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import classnames from 'classnames';
import {
Button,
FormFileUpload,
Placeholder,
DropZone,
IconButton,
withFilters,
Expand All @@ -32,6 +31,7 @@ import { withSelect } from '@wordpress/data';
import MediaUpload from '../media-upload';
import MediaUploadCheck from '../media-upload/check';
import URLPopover from '../url-popover';
import Placeholder from '../placeholder';

const InsertFromURLPopover = ( { src, onChange, onSubmit, onClose } ) => (
<URLPopover onClose={ onClose }>
Expand Down
34 changes: 34 additions & 0 deletions packages/block-editor/src/components/placeholder/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* WordPress dependencies
*/
import { Placeholder } from '@wordpress/components';
import { withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';

/**
* Internal dependencies
*/
import { withBlockEditContext } from '../block-edit/context';

function PlaceholderInBlockContext( { isReadOnly, ...props } ) {
if ( ! isReadOnly ) {
return null;
}

delete props.clientId;

return <Placeholder { ...props } />;
}

export default compose( [
withBlockEditContext( ( { clientId } ) => ( { clientId } ) ),
withSelect( ( select, { clientId } ) => {
const {
getBlockRootClientId,
getTemplateLock,
} = select( 'core/block-editor' );
const rootClientId = getBlockRootClientId( clientId );
const isReadOnly = getTemplateLock( rootClientId ) === 'readonly';
return { isReadOnly };
} ),
] )( PlaceholderInBlockContext );
30 changes: 26 additions & 4 deletions packages/block-editor/src/components/plain-text/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@

/**
* WordPress dependencies
*/
import { forwardRef } from '@wordpress/element';
import { withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';

/**
* External dependencies
Expand All @@ -11,17 +12,38 @@ import TextareaAutosize from 'react-autosize-textarea';
import classnames from 'classnames';

/**
* @see https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/plain-text/README.md
* Internal dependencies
*/
const PlainText = forwardRef( ( { onChange, className, ...props }, ref ) => {
import { withBlockEditContext } from '../block-edit/context';

const PlainText = forwardRef( ( { onChange, className, isReadOnly, ...props }, ref ) => {
delete props.clientId;
return (
<TextareaAutosize
ref={ ref }
className={ classnames( 'editor-plain-text block-editor-plain-text', className ) }
onChange={ ( event ) => onChange( event.target.value ) }
disabled={ isReadOnly }
{ ...props }
/>
);
} );

export default PlainText;
/**
* @see https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/plain-text/README.md
*/
export default compose( [
withBlockEditContext( ( { clientId } ) => ( { clientId } ) ),
withSelect( ( select, {
clientId,
} ) => {
const {
getBlockRootClientId,
getTemplateLock,
} = select( 'core/block-editor' );

const isReadOnly = getTemplateLock( getBlockRootClientId( clientId ) ) === 'readonly';

return { isReadOnly };
} ),
] )( PlainText );
6 changes: 6 additions & 0 deletions packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ class RichTextWraper extends Component {

render() {
const {
isReadOnly,
tagName,
value: originalValue,
onChange: originalOnChange,
Expand Down Expand Up @@ -307,6 +308,7 @@ class RichTextWraper extends Component {
return (
<RichText
{ ...experimentalProps }
isReadOnly={ isReadOnly }
value={ adjustedValue }
onChange={ adjustedOnChange }
selectionStart={ selectionStart }
Expand Down Expand Up @@ -375,8 +377,11 @@ const RichTextContainer = compose( [
getSelectionStart,
getSelectionEnd,
getSettings,
getBlockRootClientId,
getTemplateLock,
} = select( 'core/block-editor' );

const isReadOnly = getTemplateLock( getBlockRootClientId( clientId ) ) === 'readonly';
const selectionStart = getSelectionStart();
const selectionEnd = getSelectionEnd();
const { __experimentalCanUserUseUnfilteredHTML } = getSettings();
Expand All @@ -393,6 +398,7 @@ const RichTextContainer = compose( [
selectionStart: isSelected ? selectionStart.offset : undefined,
selectionEnd: isSelected ? selectionEnd.offset : undefined,
isSelected,
isReadOnly,
};
} ),
withDispatch( ( dispatch, {
Expand Down
7 changes: 4 additions & 3 deletions packages/block-library/src/classic/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ export default class ClassicEdit extends Component {
}

initialize() {
const { clientId } = this.props;
const { clientId, isReadOnly } = this.props;
const { settings } = window.wpEditorL10n.tinymce;
wp.oldEditor.initialize( `editor-${ clientId }`, {
tinymce: {
...settings,
readonly: isReadOnly,
inline: true,
content_css: false,
fixed_toolbar_container: `#toolbar-${ clientId }`,
Expand Down Expand Up @@ -176,7 +177,7 @@ export default class ClassicEdit extends Component {
}

render() {
const { clientId } = this.props;
const { clientId, isReadOnly } = this.props;

// Disable reasons:
//
Expand All @@ -190,7 +191,7 @@ export default class ClassicEdit extends Component {

/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
return [
<div
! isReadOnly && <div
key="toolbar"
id={ `toolbar-${ clientId }` }
ref={ ( ref ) => this.ref = ref }
Expand Down
10 changes: 10 additions & 0 deletions packages/e2e-tests/plugins/cpt-locking.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ function gutenberg_test_cpt_locking() {
),
array( 'core/quote' ),
);
register_post_type(
'locked-readonly-post',
array(
'public' => true,
'label' => 'Locked Readonly Post',
'show_in_rest' => true,
'template' => $template,
'template_lock' => 'readonly',
)
);
register_post_type(
'locked-all-post',
array(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,31 @@ exports[`cpt locking template_lock insert should allow blocks to be moved 1`] =
<blockquote class=\\"wp-block-quote\\"><p></p></blockquote>
<!-- /wp:quote -->"
`;
exports[`cpt locking template_lock readonly should only allow block selection 1`] = `
"<!-- wp:image -->
<figure class=\\"wp-block-image\\"><img alt=\\"\\"/></figure>
<!-- /wp:image -->
<!-- wp:paragraph {\\"placeholder\\":\\"Add a description\\"} -->
<p></p>
<!-- /wp:paragraph -->
<!-- wp:quote -->
<blockquote class=\\"wp-block-quote\\"><p></p></blockquote>
<!-- /wp:quote -->"
`;
exports[`cpt locking template_lock readonly should only allow block selection 2`] = `
"<!-- wp:image -->
<figure class=\\"wp-block-image\\"><img alt=\\"\\"/></figure>
<!-- /wp:image -->
<!-- wp:paragraph {\\"placeholder\\":\\"Add a description\\"} -->
<p></p>
<!-- /wp:paragraph -->
<!-- wp:quote -->
<blockquote class=\\"wp-block-quote\\"><p></p></blockquote>
<!-- /wp:quote -->"
`;
Loading

0 comments on commit 19adb5c

Please sign in to comment.