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

[WIP] Add ability to delete a reusable block #4031

Closed
wants to merge 5 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
2 changes: 1 addition & 1 deletion blocks/api/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export function createReusableBlock( type, attributes ) {
return {
id: +uniqueId(), // Temorary id replaced when the block is saved server side
isTemporary: true,
name: __( 'Untitled block' ),
title: __( 'Untitled block' ),
type,
attributes,
};
Expand Down
2 changes: 1 addition & 1 deletion blocks/api/test/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ describe( 'block factory', () => {

expect( createReusableBlock( type, attributes ) ).toMatchObject( {
id: expect.any( Number ),
name: 'Untitled block',
title: 'Untitled block',
type,
attributes,
} );
Expand Down
21 changes: 7 additions & 14 deletions blocks/library/block/edit-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import { __ } from '@wordpress/i18n';
import './style.scss';

function ReusableBlockEditPanel( props ) {
const { isEditing, name, isSaving, onEdit, onDetach, onChangeName, onSave, onCancel } = props;
const { isEditing, title, isSaving, onEdit, onChangeTitle, onSave, onCancel } = props;

return (
<div className="reusable-block-edit-panel">
{ ! isEditing && ! isSaving && [
<span key="info" className="reusable-block-edit-panel__info">
<b>{ name }</b>
<b>{ title }</b>
</span>,
<Button
key="edit"
Expand All @@ -25,28 +25,21 @@ function ReusableBlockEditPanel( props ) {
onClick={ onEdit }>
{ __( 'Edit' ) }
</Button>,
<Button
key="detach"
isLarge
className="reusable-block-edit-panel__button"
onClick={ onDetach }>
{ __( 'Detach' ) }
</Button>,
] }
{ ( isEditing || isSaving ) && [
<input
key="name"
key="title"
type="text"
disabled={ isSaving }
className="reusable-block-edit-panel__name"
value={ name }
onChange={ ( event ) => onChangeName( event.target.value ) } />,
className="reusable-block-edit-panel__title"
value={ title }
onChange={ ( event ) => onChangeTitle( event.target.value ) } />,
<Button
key="save"
isPrimary
isLarge
isBusy={ isSaving }
disabled={ ! name || isSaving }
disabled={ ! title || isSaving }
className="reusable-block-edit-panel__button"
onClick={ onSave }>
{ __( 'Save' ) }
Expand Down
2 changes: 1 addition & 1 deletion blocks/library/block/edit-panel/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
margin-right: auto;
}

.reusable-block-edit-panel__name {
.reusable-block-edit-panel__title {
flex-grow: 1;
font-size: 14px;
height: 30px;
Expand Down
38 changes: 18 additions & 20 deletions blocks/library/block/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ class ReusableBlockEdit extends Component {
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.setTitle = this.setTitle.bind( this );
this.updateReusableBlock = this.updateReusableBlock.bind( this );

this.state = {
isEditing: false,
name: null,
title: null,
attributes: null,
};
}
Expand All @@ -48,7 +48,7 @@ class ReusableBlockEdit extends Component {
stopEditing() {
this.setState( {
isEditing: false,
name: null,
title: null,
attributes: null,
} );
}
Expand All @@ -59,16 +59,16 @@ class ReusableBlockEdit extends Component {
} ) );
}

setName( name ) {
this.setState( { name } );
setTitle( title ) {
this.setState( { title } );
}

updateReusableBlock() {
const { name, attributes } = this.state;
const { title, attributes } = this.state;

// Use pickBy to include only changed (assigned) values in payload
const payload = pickBy( {
name,
title,
attributes,
} );

Expand All @@ -78,13 +78,17 @@ class ReusableBlockEdit extends Component {
}

render() {
const { focus, reusableBlock, isSaving, convertBlockToStatic } = this.props;
const { isEditing, name, attributes } = this.state;
const { focus, reusableBlock, isFetching, isSaving } = this.props;
const { isEditing, title, attributes } = this.state;

if ( ! reusableBlock ) {
if ( ! reusableBlock && isFetching ) {
return <Placeholder><Spinner /></Placeholder>;
}

if ( ! reusableBlock ) {
return <Placeholder>{ __( 'Block has been deleted or is unavailable.' ) }</Placeholder>;
}

const reusableBlockAttributes = { ...reusableBlock.attributes, ...attributes };

return [
Expand All @@ -102,11 +106,10 @@ class ReusableBlockEdit extends Component {
<ReusableBlockEditPanel
key="panel"
isEditing={ isEditing }
name={ name !== null ? name : reusableBlock.name }
isSaving={ isSaving }
title={ title !== null ? title : reusableBlock.title }
isSaving={ isSaving && ! reusableBlock.isTemporary }
onEdit={ this.startEditing }
onDetach={ convertBlockToStatic }
onChangeName={ this.setName }
onChangeTitle={ this.setTitle }
onSave={ this.updateReusableBlock }
onCancel={ this.stopEditing }
/>
Expand All @@ -118,6 +121,7 @@ class ReusableBlockEdit extends Component {
const ConnectedReusableBlockEdit = connect(
( state, ownProps ) => ( {
reusableBlock: state.reusableBlocks.data[ ownProps.attributes.ref ],
isFetching: state.reusableBlocks.isFetching[ ownProps.attributes.ref ],
isSaving: state.reusableBlocks.isSaving[ ownProps.attributes.ref ],
} ),
( dispatch, ownProps ) => ( {
Expand All @@ -140,12 +144,6 @@ const ConnectedReusableBlockEdit = connect(
id: ownProps.attributes.ref,
} );
},
convertBlockToStatic() {
dispatch( {
type: 'CONVERT_BLOCK_TO_STATIC',
uid: ownProps.id,
} );
},
} )
)( ReusableBlockEdit );

Expand Down
4 changes: 2 additions & 2 deletions editor/components/block-list/block-mobile-toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
* Internal dependencies
*/
import BlockMover from '../block-mover';
import BlockDeleteButton from '../block-settings-menu/block-delete-button';
import BlockRemoveButton from '../block-settings-menu/block-remove-button';
import BlockSettingsMenu from '../block-settings-menu';

function BlockMobileToolbar( { uid } ) {
return (
<div className="editor-block-list__block-mobile-toolbar">
<BlockMover uids={ [ uid ] } />
<BlockDeleteButton uids={ [ uid ] } small />
<BlockRemoveButton uids={ [ uid ] } small />
<BlockSettingsMenu uids={ [ uid ] } />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ import { compose } from '@wordpress/element';
*/
import { removeBlocks } from '../../store/actions';

export function BlockDeleteButton( { onDelete, onClick = noop, isLocked, small = false } ) {
export function BlockRemoveButton( { onRemove, onClick = noop, isLocked, small = false } ) {
if ( isLocked ) {
return null;
}

const label = __( 'Delete' );
const label = __( 'Remove' );

return (
<IconButton
className="editor-block-settings-menu__control"
onClick={ flow( onDelete, onClick ) }
onClick={ flow( onRemove, onClick ) }
icon="trash"
label={ small ? label : undefined }
>
Expand All @@ -39,7 +39,7 @@ export default compose(
connect(
undefined,
( dispatch, ownProps ) => ( {
onDelete() {
onRemove() {
dispatch( removeBlocks( ownProps.uids ) );
},
} )
Expand All @@ -51,4 +51,4 @@ export default compose(
isLocked: !! templateLock,
};
} ),
)( BlockDeleteButton );
)( BlockRemoveButton );
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function BlockTransformations( { blocks, small = false, onTransform, onClick = n
return null;
}
return (
<div className="editor-block-settings-menu__block-transformations">
<div className="editor-block-settings-menu__section">
{ possibleBlockTransformations.map( ( { name, title, icon } ) => {
/* translators: label indicating the transformation of a block into another block */
const shownText = sprintf( __( 'Turn into %s' ), title );
Expand Down
8 changes: 4 additions & 4 deletions editor/components/block-settings-menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import { IconButton, Dropdown, NavigableMenu } from '@wordpress/components';
import './style.scss';
import BlockInspectorButton from './block-inspector-button';
import BlockModeToggle from './block-mode-toggle';
import BlockDeleteButton from './block-delete-button';
import BlockRemoveButton from './block-remove-button';
import BlockTransformations from './block-transformations';
import ReusableBlockToggle from './reusable-block-toggle';
import ReusableBlockSettings from './reusable-block-settings';
import UnknownConverter from './unknown-converter';
import { selectBlock } from '../../store/actions';

Expand Down Expand Up @@ -57,8 +57,8 @@ function BlockSettingsMenu( { uids, onSelect, focus } ) {
<BlockInspectorButton onClick={ onClose } />
{ count === 1 && <BlockModeToggle uid={ uids[ 0 ] } onToggle={ onClose } /> }
{ count === 1 && <UnknownConverter uid={ uids[ 0 ] } /> }
<BlockDeleteButton uids={ uids } />
{ count === 1 && <ReusableBlockToggle uid={ uids[ 0 ] } onToggle={ onClose } /> }
<BlockRemoveButton uids={ uids } />
{ count === 1 && <ReusableBlockSettings uid={ uids[ 0 ] } onToggle={ onClose } /> }
<BlockTransformations uids={ uids } onClick={ onClose } />
</NavigableMenu>
) }
Expand Down
81 changes: 81 additions & 0 deletions editor/components/block-settings-menu/reusable-block-settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* External dependencies
*/
import { connect } from 'react-redux';
import { noop } from 'lodash';

/**
* WordPress dependencies
*/
import { Fragment } from '@wordpress/element';
import { IconButton } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { isReusableBlock } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { getBlock } from '../../store/selectors';
import { convertBlockToStatic, convertBlockToReusable, deleteReusableBlock } from '../../store/actions';

export function ReusableBlockSettings( { block, onConvertToStatic, onConvertToReusable, onDelete } ) {
const isReusable = isReusableBlock( block );

return (
<Fragment>
{ ! isReusable && (
<IconButton
className="editor-block-settings-menu__control"
icon="controls-repeat"
onClick={ onConvertToReusable }
>
{ __( 'Convert to Reusable Block' ) }
</IconButton>
) }
{ isReusable && (
<div className="editor-block-settings-menu__section">
<IconButton
className="editor-block-settings-menu__control"
icon="controls-repeat"
onClick={ onConvertToStatic }
>
{ __( 'Detach from Reusable Block' ) }
</IconButton>
<IconButton
className="editor-block-settings-menu__control"
icon="no"
onClick={ () => onDelete( block.attributes.ref ) }
>
{ __( 'Delete Reusable Block' ) }
</IconButton>
</div>
) }
</Fragment>
);
}

export default connect(
( state, { uid } ) => {
return {
block: getBlock( state, uid ),
};
},
( dispatch, { uid, onToggle = noop } ) => ( {
onConvertToStatic() {
dispatch( convertBlockToStatic( uid ) );
onToggle();
},
onConvertToReusable() {
dispatch( convertBlockToReusable( uid ) );
onToggle();
},
onDelete( id ) {
// TODO: Make this a <Confirm /> component or similar
// eslint-disable-next-line no-alert
if ( window.confirm( __( 'Are you sure you want to permanently delete this Reusable Block?' ) ) ) {
dispatch( deleteReusableBlock( id ) );
onToggle();
}
},
} )
)( ReusableBlockSettings );
49 changes: 0 additions & 49 deletions editor/components/block-settings-menu/reusable-block-toggle.js

This file was deleted.

Loading