Skip to content

Commit

Permalink
Merge pull request #4139 from WordPress/add/reusable-block-deletion
Browse files Browse the repository at this point in the history
Add Reusable Block deletion
  • Loading branch information
noisysocks authored Jan 4, 2018
2 parents 55c5a79 + 78a9bb7 commit a6948bd
Show file tree
Hide file tree
Showing 19 changed files with 541 additions and 128 deletions.
2 changes: 1 addition & 1 deletion blocks/api/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export function switchToBlockType( blocks, name ) {
*/
export function createReusableBlock( type, attributes ) {
return {
id: +uniqueId(), // Temorary id replaced when the block is saved server side
id: -uniqueId(), // Temorary id replaced when the block is saved server side
isTemporary: true,
title: __( 'Untitled block' ),
type,
Expand Down
8 changes: 1 addition & 7 deletions blocks/library/block/edit-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import './style.scss';
const { ESCAPE } = keycodes;

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

return [
( ! isEditing && ! isSaving ) && (
Expand All @@ -27,12 +27,6 @@ function ReusableBlockEditPanel( props ) {
onClick={ onEdit }>
{ __( 'Edit' ) }
</Button>
<Button
isLarge
className="reusable-block-edit-panel__button"
onClick={ onDetach }>
{ __( 'Detach' ) }
</Button>
</div>
),
( isEditing || isSaving ) && (
Expand Down
18 changes: 8 additions & 10 deletions blocks/library/block/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,17 @@ class ReusableBlockEdit extends Component {
}

render() {
const { focus, reusableBlock, isSaving, convertBlockToStatic } = this.props;
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 @@ -103,9 +107,8 @@ class ReusableBlockEdit extends Component {
key="panel"
isEditing={ isEditing }
title={ title !== null ? title : reusableBlock.title }
isSaving={ isSaving }
isSaving={ isSaving && ! reusableBlock.isTemporary }
onEdit={ this.startEditing }
onDetach={ convertBlockToStatic }
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
86 changes: 86 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,86 @@
/**
* 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, getReusableBlock } from '../../store/selectors';
import { convertBlockToStatic, convertBlockToReusable, deleteReusableBlock } from '../../store/actions';

export function ReusableBlockSettings( { reusableBlock, onConvertToStatic, onConvertToReusable, onDelete } ) {
return (
<Fragment>
{ ! reusableBlock && (
<IconButton
className="editor-block-settings-menu__control"
icon="controls-repeat"
onClick={ onConvertToReusable }
>
{ __( 'Convert to Reusable Block' ) }
</IconButton>
) }
{ reusableBlock && (
<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"
disabled={ reusableBlock.isTemporary }
onClick={ () => onDelete( reusableBlock.id ) }
>
{ __( 'Delete Reusable Block' ) }
</IconButton>
</div>
) }
</Fragment>
);
}

export default connect(
( state, { uid } ) => {
const block = getBlock( state, uid );
return {
reusableBlock: isReusableBlock( block ) ? getReusableBlock( state, block.attributes.ref ) : null,
};
},
( 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
const hasConfirmed = window.confirm( __(
'Are you sure you want to delete this Reusable Block?\n\n' +
'It will be permanently removed from all posts and pages that use it.'
) );

if ( hasConfirmed ) {
dispatch( deleteReusableBlock( id ) );
onToggle();
}
},
} )
)( ReusableBlockSettings );
49 changes: 0 additions & 49 deletions editor/components/block-settings-menu/reusable-block-toggle.js

This file was deleted.

2 changes: 1 addition & 1 deletion editor/components/block-settings-menu/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
}
}

.editor-block-settings-menu__block-transformations {
.editor-block-settings-menu__section {
margin-top: $item-spacing;
padding-top: $item-spacing;
border-top: 1px solid $light-gray-500;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* External dependencies
*/
import { shallow } from 'enzyme';

/**
* Internal dependencies
*/
import { ReusableBlockSettings } from '../reusable-block-settings';

describe( 'ReusableBlockSettings', () => {
it( 'should allow converting a static block to reusable', () => {
const onConvert = jest.fn();
const wrapper = shallow(
<ReusableBlockSettings
reusableBlock={ null }
onConvertToReusable={ onConvert }
/>
);

const text = wrapper.find( 'IconButton' ).children().text();
expect( text ).toEqual( 'Convert to Reusable Block' );

wrapper.find( 'IconButton' ).simulate( 'click' );
expect( onConvert ).toHaveBeenCalled();
} );

it( 'should allow converting a reusable block to static', () => {
const onConvert = jest.fn();
const wrapper = shallow(
<ReusableBlockSettings
reusableBlock={ {} }
onConvertToStatic={ onConvert }
/>
);

const text = wrapper.find( 'IconButton' ).first().children().text();
expect( text ).toEqual( 'Detach from Reusable Block' );

wrapper.find( 'IconButton' ).first().simulate( 'click' );
expect( onConvert ).toHaveBeenCalled();
} );

it( 'should allow deleting a reusable block', () => {
const onDelete = jest.fn();
const wrapper = shallow(
<ReusableBlockSettings
reusableBlock={ { id: 123 } }
onDelete={ onDelete }
/>
);

const text = wrapper.find( 'IconButton' ).last().children().text();
expect( text ).toEqual( 'Delete Reusable Block' );

wrapper.find( 'IconButton' ).last().simulate( 'click' );
expect( onDelete ).toHaveBeenCalledWith( 123 );
} );
} );
Loading

0 comments on commit a6948bd

Please sign in to comment.