-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reusable Blocks: Add reusable blocks UI (#3378)
* Add UI for editing a reusable block Adds the UI which displays when a reusable block is asked for its `edit` component. This includes a panel which includes UI that indicates whether a reusable block is loading and lets a user change the name of the block. * Allow a reusable block to be rendered as HTML Adds the necessary PHP code for rendering a reusable block as HTML on the blog's front-end. * Present reusable blocks with a dashed outline Changes BlockListBlock to display selected reusable blocks with a dashed outline. * Fix reusable blocks not loading Fix reusable blocks not loading by looking at the correct path in the state tree (state.reusableBlocks.data) and by adding a trailing slash to the /gutenberg/v1/ API versionString. * Add UI for inserting a reusable block Patches the Inserter to display all reusable blocks in a seperate group, and to insert a reusable block when one is clicked. * Add UI for converting blocks to/from a reusable block Add a block settings menu control which allows users to convert a regular block to a reusable block and convert a reusable block to a regular block. * Resolve ambiguity around `onSelect( attributes )` Distinguish between initialAttributes which are passed into createBlock and attributes which define which attributes a block type supports. * Change copy of 'Convert to Reusable Block' * Mark gutenberg_render_block as being available @SInCE 1.9.0 * Fix inability to search for reusable blocks Make the Inserter search both static blocks and reusable blocks. * Display reusable blocks in a seperate Inserter tab Moves reusbale blocks from the Blocks tab to a new Saved tab in the Inserter. * Reusable Blocks: Fix reusable blocks classname * Rename core/reusable-block to core/block This way, just as <!-- wp:image --> inserts an image, <!-- wp:block --> inserts a wp_block. * Fix Reusable Block saving state Ensure that the Save button indicates that the block is being saved. * DRY up block.name === 'core/block' logic Move block.name === 'core/block' logic to a new isReusableBlock function. * Reusable Blocks: Avoiding using a generated uid and rely on the post_id instead
- Loading branch information
1 parent
76060d4
commit e437939
Showing
33 changed files
with
698 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,5 +14,6 @@ export { | |
getBlockType, | ||
getBlockTypes, | ||
hasBlockSupport, | ||
isReusableBlock, | ||
} from './registration'; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Button } from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import './style.scss'; | ||
|
||
function ReusableBlockEditPanel( props ) { | ||
const { isEditing, name, isSaving, onEdit, onDetach, onChangeName, onSave, onCancel } = props; | ||
|
||
return ( | ||
<div className="reusable-block-edit-panel"> | ||
{ ! isEditing && ! isSaving && [ | ||
<span key="info" className="reusable-block-edit-panel__info"> | ||
<b>{ name }</b> | ||
</span>, | ||
<Button | ||
key="edit" | ||
isLarge | ||
className="reusable-block-edit-panel__button" | ||
onClick={ onEdit }> | ||
{ __( 'Edit' ) } | ||
</Button>, | ||
<Button | ||
key="detach" | ||
isLarge | ||
className="reusable-block-edit-panel__button" | ||
onClick={ onDetach }> | ||
{ __( 'Detach' ) } | ||
</Button>, | ||
] } | ||
{ ( isEditing || isSaving ) && [ | ||
<input | ||
key="name" | ||
type="text" | ||
disabled={ isSaving } | ||
className="reusable-block-edit-panel__name" | ||
value={ name } | ||
onChange={ ( event ) => onChangeName( event.target.value ) } />, | ||
<Button | ||
key="save" | ||
isPrimary | ||
isLarge | ||
isBusy={ isSaving } | ||
disabled={ ! name || isSaving } | ||
className="reusable-block-edit-panel__button" | ||
onClick={ onSave }> | ||
{ __( 'Save' ) } | ||
</Button>, | ||
<Button | ||
key="cancel" | ||
isLarge | ||
disabled={ isSaving } | ||
className="reusable-block-edit-panel__button" | ||
onClick={ onCancel }> | ||
{ __( 'Cancel' ) } | ||
</Button>, | ||
] } | ||
</div> | ||
); | ||
} | ||
|
||
export default ReusableBlockEditPanel; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
.reusable-block-edit-panel { | ||
align-items: center; | ||
background: $light-gray-100; | ||
color: $dark-gray-500; | ||
display: flex; | ||
font-family: $default-font; | ||
font-size: $default-font-size; | ||
justify-content: flex-end; | ||
margin: $block-padding (-$block-padding) (-$block-padding); | ||
padding: 10px $block-padding; | ||
|
||
.reusable-block-edit-panel__spinner { | ||
margin: 0 5px; | ||
} | ||
|
||
.reusable-block-edit-panel__info { | ||
margin-right: auto; | ||
} | ||
|
||
.reusable-block-edit-panel__name { | ||
flex-grow: 1; | ||
font-size: 14px; | ||
height: 30px; | ||
margin: 0 auto 0 0; | ||
max-width: 230px; | ||
} | ||
|
||
// Needs specificity to override the margin-bottom set by .button | ||
.wp-core-ui & .reusable-block-edit-panel__button { | ||
margin: 0 0 0 5px; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { pickBy, noop } from 'lodash'; | ||
import { connect } from 'react-redux'; | ||
import classnames from 'classnames'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { Component } from '@wordpress/element'; | ||
import { Placeholder, Spinner } from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { getBlockType, registerBlockType, hasBlockSupport, getBlockDefaultClassname } from '../../api'; | ||
import ReusableBlockEditPanel from './edit-panel'; | ||
|
||
class ReusableBlockEdit extends Component { | ||
constructor() { | ||
super( ...arguments ); | ||
|
||
this.startEditing = this.startEditing.bind( this ); | ||
this.stopEditing = this.stopEditing.bind( this ); | ||
this.setAttributes = this.setAttributes.bind( this ); | ||
this.setName = this.setName.bind( this ); | ||
this.updateReusableBlock = this.updateReusableBlock.bind( this ); | ||
|
||
this.state = { | ||
isEditing: false, | ||
name: null, | ||
attributes: null, | ||
}; | ||
} | ||
|
||
componentDidMount() { | ||
if ( ! this.props.reusableBlock ) { | ||
this.props.fetchReusableBlock(); | ||
} | ||
} | ||
|
||
startEditing() { | ||
this.setState( { isEditing: true } ); | ||
} | ||
|
||
stopEditing() { | ||
this.setState( { | ||
isEditing: false, | ||
name: null, | ||
attributes: null, | ||
} ); | ||
} | ||
|
||
setAttributes( attributes ) { | ||
this.setState( ( prevState ) => ( { | ||
attributes: { ...prevState.attributes, ...attributes }, | ||
} ) ); | ||
} | ||
|
||
setName( name ) { | ||
this.setState( { name } ); | ||
} | ||
|
||
updateReusableBlock() { | ||
const { name, attributes } = this.state; | ||
|
||
// Use pickBy to include only changed (assigned) values in payload | ||
const payload = pickBy( { | ||
name, | ||
attributes, | ||
} ); | ||
|
||
this.props.updateReusableBlock( payload ); | ||
this.props.saveReusableBlock(); | ||
this.stopEditing(); | ||
} | ||
|
||
render() { | ||
const { focus, reusableBlock, isSaving, convertBlockToStatic } = this.props; | ||
const { isEditing, name, attributes } = this.state; | ||
|
||
if ( ! reusableBlock ) { | ||
return <Placeholder><Spinner /></Placeholder>; | ||
} | ||
|
||
const reusableBlockAttributes = { ...reusableBlock.attributes, ...attributes }; | ||
const blockType = getBlockType( reusableBlock.type ); | ||
const BlockEdit = blockType.edit || blockType.save; | ||
|
||
// Generate a class name for the block's editable form | ||
const generatedClassName = hasBlockSupport( blockType, 'className', true ) ? | ||
getBlockDefaultClassname( reusableBlock.type ) : | ||
null; | ||
const className = classnames( generatedClassName, reusableBlockAttributes.className ); | ||
return [ | ||
// We fake the block being read-only by wrapping it with an element that has pointer-events: none | ||
<div key="edit" style={ { pointerEvents: isEditing ? 'auto' : 'none' } }> | ||
<BlockEdit | ||
{ ...this.props } | ||
focus={ isEditing ? focus : null } | ||
attributes={ reusableBlockAttributes } | ||
setAttributes={ isEditing ? this.setAttributes : noop } | ||
className={ className } | ||
/> | ||
</div>, | ||
focus && ( | ||
<ReusableBlockEditPanel | ||
key="panel" | ||
isEditing={ isEditing } | ||
name={ name !== null ? name : reusableBlock.name } | ||
isSaving={ isSaving } | ||
onEdit={ this.startEditing } | ||
onDetach={ convertBlockToStatic } | ||
onChangeName={ this.setName } | ||
onSave={ this.updateReusableBlock } | ||
onCancel={ this.stopEditing } | ||
/> | ||
), | ||
]; | ||
} | ||
} | ||
|
||
const ConnectedReusableBlockEdit = connect( | ||
( state, ownProps ) => ( { | ||
reusableBlock: state.reusableBlocks.data[ ownProps.attributes.ref ], | ||
isSaving: state.reusableBlocks.isSaving[ ownProps.attributes.ref ], | ||
} ), | ||
( dispatch, ownProps ) => ( { | ||
fetchReusableBlock() { | ||
dispatch( { | ||
type: 'FETCH_REUSABLE_BLOCKS', | ||
id: ownProps.attributes.ref, | ||
} ); | ||
}, | ||
updateReusableBlock( reusableBlock ) { | ||
dispatch( { | ||
type: 'UPDATE_REUSABLE_BLOCK', | ||
id: ownProps.attributes.ref, | ||
reusableBlock, | ||
} ); | ||
}, | ||
saveReusableBlock() { | ||
dispatch( { | ||
type: 'SAVE_REUSABLE_BLOCK', | ||
id: ownProps.attributes.ref, | ||
} ); | ||
}, | ||
convertBlockToStatic() { | ||
dispatch( { | ||
type: 'CONVERT_BLOCK_TO_STATIC', | ||
uid: ownProps.id, | ||
} ); | ||
}, | ||
} ) | ||
)( ReusableBlockEdit ); | ||
|
||
registerBlockType( 'core/block', { | ||
title: __( 'Reusable Block' ), | ||
category: 'reusable-blocks', | ||
isPrivate: true, | ||
|
||
attributes: { | ||
ref: { | ||
type: 'string', | ||
}, | ||
}, | ||
|
||
edit: ConnectedReusableBlockEdit, | ||
save: () => null, | ||
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
/** | ||
* Server-side rendering of the `core/block` block. | ||
* | ||
* @package gutenberg | ||
*/ | ||
|
||
/** | ||
* Renders the `core/block` block on server. | ||
* | ||
* @param array $attributes The block attributes. | ||
* | ||
* @return string Rendered HTML of the referenced block. | ||
*/ | ||
function gutenberg_render_block_core_reusable_block( $attributes ) { | ||
$reusable_block = get_post( $attributes['ref'] ); | ||
if ( ! $reusable_block ) { | ||
return ''; | ||
} | ||
|
||
$blocks = gutenberg_parse_blocks( $reusable_block->post_content ); | ||
|
||
$block = array_shift( $blocks ); | ||
if ( ! $block ) { | ||
return ''; | ||
} | ||
|
||
return gutenberg_render_block( $block ); | ||
} | ||
|
||
register_block_type( 'core/block', array( | ||
'attributes' => array( | ||
'ref' => array( | ||
'type' => 'string', | ||
), | ||
), | ||
|
||
'render_callback' => 'gutenberg_render_block_core_reusable_block', | ||
) ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.