diff --git a/blocks/library/heading/index.js b/blocks/library/heading/index.js index 972638871d592..9fbca6f3c4bda 100644 --- a/blocks/library/heading/index.js +++ b/blocks/library/heading/index.js @@ -151,13 +151,17 @@ registerBlockType( 'core/heading', { onFocus={ setFocus } onChange={ ( value ) => setAttributes( { content: value } ) } onMerge={ mergeBlocks } - onSplit={ ( before, after, ...blocks ) => { - setAttributes( { content: before } ); - insertBlocksAfter( [ - ...blocks, - createBlock( 'core/paragraph', { content: after } ), - ] ); - } } + onSplit={ + insertBlocksAfter ? + ( before, after, ...blocks ) => { + setAttributes( { content: before } ); + insertBlocksAfter( [ + ...blocks, + createBlock( 'core/paragraph', { content: after } ), + ] ); + } : + undefined + } style={ { textAlign: align } } placeholder={ placeholder || __( 'Write heading…' ) } />, diff --git a/blocks/library/list/index.js b/blocks/library/list/index.js index ead16de6ce29c..724a43cf6d29e 100644 --- a/blocks/library/list/index.js +++ b/blocks/library/list/index.js @@ -332,21 +332,25 @@ registerBlockType( 'core/list', { wrapperClassName="blocks-list" placeholder={ __( 'Write list…' ) } onMerge={ mergeBlocks } - onSplit={ ( before, after, ...blocks ) => { - if ( ! blocks.length ) { - blocks.push( createBlock( 'core/paragraph' ) ); - } - - if ( after.length ) { - blocks.push( createBlock( 'core/list', { - nodeName, - values: after, - } ) ); - } - - setAttributes( { values: before } ); - insertBlocksAfter( blocks ); - } } + onSplit={ + insertBlocksAfter ? + ( before, after, ...blocks ) => { + if ( ! blocks.length ) { + blocks.push( createBlock( 'core/paragraph' ) ); + } + + if ( after.length ) { + blocks.push( createBlock( 'core/list', { + nodeName, + values: after, + } ) ); + } + + setAttributes( { values: before } ); + insertBlocksAfter( blocks ); + } : + undefined + } />, ]; } diff --git a/blocks/library/paragraph/index.js b/blocks/library/paragraph/index.js index 88fc473f0c6a8..983661ce52446 100644 --- a/blocks/library/paragraph/index.js +++ b/blocks/library/paragraph/index.js @@ -170,13 +170,16 @@ class ParagraphBlock extends Component { } } focus={ focus } onFocus={ setFocus } - onSplit={ ( before, after, ...blocks ) => { - setAttributes( { content: before } ); - insertBlocksAfter( [ - ...blocks, - createBlock( 'core/paragraph', { content: after } ), - ] ); - } } + onSplit={ insertBlocksAfter ? + ( before, after, ...blocks ) => { + setAttributes( { content: before } ); + insertBlocksAfter( [ + ...blocks, + createBlock( 'core/paragraph', { content: after } ), + ] ); + } : + undefined + } onMerge={ mergeBlocks } onReplace={ onReplace } placeholder={ placeholder || __( 'Add text or type / to insert content' ) } diff --git a/editor/components/block-drop-zone/index.js b/editor/components/block-drop-zone/index.js index ef8da49f0e459..832ad2f5f7ed2 100644 --- a/editor/components/block-drop-zone/index.js +++ b/editor/components/block-drop-zone/index.js @@ -2,12 +2,12 @@ * External Dependencies */ import { connect } from 'react-redux'; -import { reduce, get, find } from 'lodash'; +import { reduce, get, find, flow } from 'lodash'; /** * WordPress dependencies */ -import { DropZone } from '@wordpress/components'; +import { DropZone, withContext } from '@wordpress/components'; import { getBlockTypes } from '@wordpress/blocks'; /** @@ -15,7 +15,11 @@ import { getBlockTypes } from '@wordpress/blocks'; */ import { insertBlocks } from '../../actions'; -function BlockDropZone( { index, ...props } ) { +function BlockDropZone( { index, isLocked, ...props } ) { + if ( isLocked ) { + return null; + } + const dropFiles = ( files, position ) => { const transformation = reduce( getBlockTypes(), ( ret, blockType ) => { if ( ret ) { @@ -45,7 +49,16 @@ function BlockDropZone( { index, ...props } ) { ); } -export default connect( - undefined, - { insertBlocks } +export default flow( + connect( + undefined, + { insertBlocks } + ), + withContext( 'editor' )( ( settings ) => { + const { templateLock } = settings; + + return { + isLocked: !! templateLock, + }; + } ) )( BlockDropZone ); diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js index bb0f7a9d74cb1..429a79440c563 100644 --- a/editor/components/block-list/block.js +++ b/editor/components/block-list/block.js @@ -11,7 +11,7 @@ import { get, partial, reduce, size } from 'lodash'; import { Component, compose, createElement } from '@wordpress/element'; import { keycodes } from '@wordpress/utils'; import { getBlockType, BlockEdit, getBlockDefaultClassname, createBlock, hasBlockSupport } from '@wordpress/blocks'; -import { withFilters } from '@wordpress/components'; +import { withFilters, withContext } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; /** @@ -296,7 +296,7 @@ class BlockListBlock extends Component { case ENTER: // Insert default block after current block if enter and event // not already handled by descendant. - if ( target === this.node ) { + if ( target === this.node && ! this.props.isLocked ) { event.preventDefault(); this.props.onInsertBlocks( [ @@ -318,12 +318,14 @@ class BlockListBlock extends Component { case DELETE: // Remove block on backspace. if ( target === this.node ) { + const { uid, onRemove, previousBlock, onFocus, isLocked } = this.props; event.preventDefault(); - const { uid, onRemove, previousBlock, onFocus } = this.props; - onRemove( uid ); + if ( ! isLocked ) { + onRemove( uid ); - if ( previousBlock ) { - onFocus( previousBlock.uid, { offset: -1 } ); + if ( previousBlock ) { + onFocus( previousBlock.uid, { offset: -1 } ); + } } } break; @@ -340,7 +342,7 @@ class BlockListBlock extends Component { } render() { - const { block, order, mode, showContextualToolbar } = this.props; + const { block, order, mode, showContextualToolbar, isLocked } = this.props; const { name: blockName, isValid } = block; const blockType = getBlockType( blockName ); // translators: %s: Type of block (i.e. Text, Image etc) @@ -410,10 +412,10 @@ class BlockListBlock extends Component { focus={ focus } attributes={ block.attributes } setAttributes={ this.setAttributes } - insertBlocksAfter={ this.insertBlocksAfter } - onReplace={ onReplace } + insertBlocksAfter={ isLocked ? undefined : this.insertBlocksAfter } + onReplace={ isLocked ? undefined : onReplace } setFocus={ partial( onFocus, block.uid ) } - mergeBlocks={ this.mergeBlocks } + mergeBlocks={ isLocked ? undefined : this.mergeBlocks } className={ className } id={ block.uid } isSelectionEnabled={ this.props.isSelectionEnabled } @@ -524,5 +526,12 @@ const mapDispatchToProps = ( dispatch, ownProps ) => ( { export default compose( withFilters( 'Editor.BlockItem' ), - connect( mapStateToProps, mapDispatchToProps ) + connect( mapStateToProps, mapDispatchToProps ), + withContext( 'editor' )( ( settings ) => { + const { templateLock } = settings; + + return { + isLocked: !! templateLock, + }; + } ), )( BlockListBlock ); diff --git a/editor/components/block-mover/index.js b/editor/components/block-mover/index.js index 0d3430f26b437..ad1d5b2650580 100644 --- a/editor/components/block-mover/index.js +++ b/editor/components/block-mover/index.js @@ -2,13 +2,13 @@ * External dependencies */ import { connect } from 'react-redux'; -import { first, last } from 'lodash'; +import { first, last, flow } from 'lodash'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { IconButton } from '@wordpress/components'; +import { IconButton, withContext } from '@wordpress/components'; import { getBlockType } from '@wordpress/blocks'; /** @@ -19,7 +19,11 @@ import { getBlockMoverLabel } from './mover-label'; import { isFirstBlock, isLastBlock, getBlockIndex, getBlock } from '../../selectors'; import { selectBlock } from '../../actions'; -export function BlockMover( { onMoveUp, onMoveDown, isFirst, isLast, uids, blockType, firstIndex } ) { +export function BlockMover( { onMoveUp, onMoveDown, isFirst, isLast, uids, blockType, firstIndex, isLocked } ) { + if ( isLocked ) { + return null; + } + // We emulate a disabled state because forcefully applying the `disabled` // attribute on the button while it has focus causes the screen to change // to an unfocused state (body as active element) without firing blur on, @@ -60,37 +64,46 @@ export function BlockMover( { onMoveUp, onMoveDown, isFirst, isLast, uids, block ); } -export default connect( - ( state, ownProps ) => { - const block = getBlock( state, first( ownProps.uids ) ); - - return ( { - isFirst: isFirstBlock( state, first( ownProps.uids ) ), - isLast: isLastBlock( state, last( ownProps.uids ) ), - firstIndex: getBlockIndex( state, first( ownProps.uids ) ), - blockType: block ? getBlockType( block.name ) : null, - } ); - }, - ( dispatch, ownProps ) => ( { - onMoveDown() { - if ( ownProps.uids.length === 1 ) { - dispatch( selectBlock( first( ownProps.uids ) ) ); - } +export default flow( + connect( + ( state, ownProps ) => { + const block = getBlock( state, first( ownProps.uids ) ); - dispatch( { - type: 'MOVE_BLOCKS_DOWN', - uids: ownProps.uids, + return ( { + isFirst: isFirstBlock( state, first( ownProps.uids ) ), + isLast: isLastBlock( state, last( ownProps.uids ) ), + firstIndex: getBlockIndex( state, first( ownProps.uids ) ), + blockType: block ? getBlockType( block.name ) : null, } ); }, - onMoveUp() { - if ( ownProps.uids.length === 1 ) { - dispatch( selectBlock( first( ownProps.uids ) ) ); - } + ( dispatch, ownProps ) => ( { + onMoveDown() { + if ( ownProps.uids.length === 1 ) { + dispatch( selectBlock( first( ownProps.uids ) ) ); + } - dispatch( { - type: 'MOVE_BLOCKS_UP', - uids: ownProps.uids, - } ); - }, - } ) + dispatch( { + type: 'MOVE_BLOCKS_DOWN', + uids: ownProps.uids, + } ); + }, + onMoveUp() { + if ( ownProps.uids.length === 1 ) { + dispatch( selectBlock( first( ownProps.uids ) ) ); + } + + dispatch( { + type: 'MOVE_BLOCKS_UP', + uids: ownProps.uids, + } ); + }, + } ) + ), + withContext( 'editor' )( ( settings ) => { + const { templateLock } = settings; + + return { + isLocked: templateLock === 'all', + }; + } ), )( BlockMover ); diff --git a/editor/components/block-mover/test/index.js b/editor/components/block-mover/test/index.js index 32d0c221624f3..f6f785b24b7e1 100644 --- a/editor/components/block-mover/test/index.js +++ b/editor/components/block-mover/test/index.js @@ -16,6 +16,11 @@ describe( 'BlockMover', () => { title: 'yolo-block', }; + it( 'should not render if the editor is locked', () => { + const wrapper = shallow( ); + expect( wrapper.type() ).toBe( null ); + } ); + it( 'should render two IconButton components with the following props', () => { const blockMover = shallow( ); expect( blockMover.hasClass( 'editor-block-mover' ) ).toBe( true ); diff --git a/editor/components/block-settings-menu/block-delete-button.js b/editor/components/block-settings-menu/block-delete-button.js index 57ed7e0d3f8a3..fef2fecf06406 100644 --- a/editor/components/block-settings-menu/block-delete-button.js +++ b/editor/components/block-settings-menu/block-delete-button.js @@ -8,14 +8,18 @@ import { flow, noop } from 'lodash'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { IconButton } from '@wordpress/components'; +import { IconButton, withContext } from '@wordpress/components'; /** * Internal dependencies */ import { removeBlocks } from '../../actions'; -export function BlockDeleteButton( { onDelete, onClick = noop, small = false } ) { +export function BlockDeleteButton( { onDelete, onClick = noop, isLocked, small = false } ) { + if ( isLocked ) { + return null; + } + const label = __( 'Delete' ); return ( @@ -30,11 +34,20 @@ export function BlockDeleteButton( { onDelete, onClick = noop, small = false } ) ); } -export default connect( - undefined, - ( dispatch, ownProps ) => ( { - onDelete() { - dispatch( removeBlocks( ownProps.uids ) ); - }, - } ) +export default flow( + connect( + undefined, + ( dispatch, ownProps ) => ( { + onDelete() { + dispatch( removeBlocks( ownProps.uids ) ); + }, + } ) + ), + withContext( 'editor' )( ( settings ) => { + const { templateLock } = settings; + + return { + isLocked: !! templateLock, + }; + } ), )( BlockDeleteButton ); diff --git a/editor/components/block-switcher/index.js b/editor/components/block-switcher/index.js index 54be221ea1e9e..138ae63cc40b5 100644 --- a/editor/components/block-switcher/index.js +++ b/editor/components/block-switcher/index.js @@ -2,13 +2,13 @@ * External dependencies */ import { connect } from 'react-redux'; -import { every, uniq, get, reduce, find } from 'lodash'; +import { every, uniq, get, reduce, find, flow } from 'lodash'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { Dropdown, Dashicon, IconButton, Toolbar, NavigableMenu } from '@wordpress/components'; +import { Dropdown, Dashicon, IconButton, Toolbar, NavigableMenu, withContext } from '@wordpress/components'; import { getBlockType, getBlockTypes, switchToBlockType, BlockIcon } from '@wordpress/blocks'; import { keycodes } from '@wordpress/utils'; @@ -24,8 +24,8 @@ import { getBlock } from '../../selectors'; */ const { DOWN } = keycodes; -function BlockSwitcher( { blocks, onTransform } ) { - if ( ! blocks || ! blocks[ 0 ] ) { +function BlockSwitcher( { blocks, onTransform, isLocked } ) { + if ( ! blocks || ! blocks[ 0 ] || isLocked ) { return null; } const isMultiBlock = blocks.length > 1; @@ -126,18 +126,27 @@ function BlockSwitcher( { blocks, onTransform } ) { ); } -export default connect( - ( state, ownProps ) => { +export default flow( + connect( + ( state, ownProps ) => { + return { + blocks: ownProps.uids.map( ( uid ) => getBlock( state, uid ) ), + }; + }, + ( dispatch, ownProps ) => ( { + onTransform( blocks, name ) { + dispatch( replaceBlocks( + ownProps.uids, + switchToBlockType( blocks, name ) + ) ); + }, + } ) + ), + withContext( 'editor' )( ( settings ) => { + const { templateLock } = settings; + return { - blocks: ownProps.uids.map( ( uid ) => getBlock( state, uid ) ), + isLocked: !! templateLock, }; - }, - ( dispatch, ownProps ) => ( { - onTransform( blocks, name ) { - dispatch( replaceBlocks( - ownProps.uids, - switchToBlockType( blocks, name ) - ) ); - }, - } ) + } ), )( BlockSwitcher ); diff --git a/editor/components/default-block-appender/test/__snapshots__/index.js.snap b/editor/components/default-block-appender/test/__snapshots__/index.js.snap index f407a818dd32a..a32487237ad7d 100644 --- a/editor/components/default-block-appender/test/__snapshots__/index.js.snap +++ b/editor/components/default-block-appender/test/__snapshots__/index.js.snap @@ -6,7 +6,7 @@ exports[`DefaultBlockAppender no block present should match snapshot 1`] = `
- + { +export default flow( + connect( + ( state ) => { + return { + uids: getBlockUids( state ), + multiSelectedBlockUids: getMultiSelectedBlockUids( state ), + }; + }, + { + clearSelectedBlock, + onMultiSelect: multiSelect, + onRedo: redo, + onUndo: undo, + onRemove: removeBlocks, + } + ), + withContext( 'editor' )( ( settings ) => { + const { templateLock } = settings; + return { - uids: getBlockUids( state ), - multiSelectedBlockUids: getMultiSelectedBlockUids( state ), + isLocked: !! templateLock, }; - }, - { - clearSelectedBlock, - onMultiSelect: multiSelect, - onRedo: redo, - onUndo: undo, - onRemove: removeBlocks, - } + } ), )( EditorGlobalKeyboardShortcuts ); diff --git a/editor/components/inserter/index.js b/editor/components/inserter/index.js index 1c5ecd4b82d6b..4976b4ed03ad0 100644 --- a/editor/components/inserter/index.js +++ b/editor/components/inserter/index.js @@ -63,9 +63,10 @@ class Inserter extends Component { onInsertBlock, insertionPoint, hasSupportedBlocks, + isLocked, } = this.props; - if ( ! hasSupportedBlocks ) { + if ( ! hasSupportedBlocks || isLocked ) { return null; } @@ -127,10 +128,11 @@ export default flowRight( [ } ) ), withContext( 'editor' )( ( settings ) => { - const { blockTypes } = settings; + const { blockTypes, templateLock } = settings; return { hasSupportedBlocks: true === blockTypes || ! isEmpty( blockTypes ), + isLocked: !! templateLock, }; } ), ] )( Inserter ); diff --git a/editor/edit-post/modes/visual-editor/inserter.js b/editor/edit-post/modes/visual-editor/inserter.js index ad2ae85eeacb2..0f4f865643643 100644 --- a/editor/edit-post/modes/visual-editor/inserter.js +++ b/editor/edit-post/modes/visual-editor/inserter.js @@ -3,12 +3,13 @@ */ import { connect } from 'react-redux'; import classnames from 'classnames'; +import { flow } from 'lodash'; /** * WordPress dependencies */ import { __, sprintf } from '@wordpress/i18n'; -import { IconButton } from '@wordpress/components'; +import { IconButton, withContext } from '@wordpress/components'; import { Component } from '@wordpress/element'; import { createBlock, BlockIcon } from '@wordpress/blocks'; @@ -41,13 +42,17 @@ export class VisualEditorInserter extends Component { } render() { - const { blockCount } = this.props; + const { blockCount, isLocked } = this.props; const { isShowingControls } = this.state; const { mostFrequentlyUsedBlocks } = this.props; const classes = classnames( 'editor-visual-editor__inserter', { 'is-showing-controls': isShowingControls, } ); + if ( isLocked ) { + return null; + } + return (
{ +export default flow( + connect( + ( state ) => { + return { + mostFrequentlyUsedBlocks: getMostFrequentlyUsedBlocks( state ), + blockCount: getBlockCount( state ), + }; + }, + { onInsertBlock: insertBlock }, + ), + withContext( 'editor' )( ( settings ) => { + const { templateLock } = settings; + return { - mostFrequentlyUsedBlocks: getMostFrequentlyUsedBlocks( state ), - blockCount: getBlockCount( state ), + isLocked: !! templateLock, }; - }, - { onInsertBlock: insertBlock }, + } ), )( VisualEditorInserter ); diff --git a/lib/client-assets.php b/lib/client-assets.php index 3ca7424d646ad..87ed4b99eb062 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -790,7 +790,8 @@ function gutenberg_editor_scripts_and_styles( $hook ) { $post_type_object = get_post_type_object( $post_to_edit['type'] ); if ( ! empty( $post_type_object->template ) ) { - $editor_settings['template'] = $post_type_object->template; + $editor_settings['template'] = $post_type_object->template; + $editor_settings['templateLock'] = ! empty( $post_type_object->template_lock ) ? $post_type_object->template_lock : false; } $script = '( function() {';