Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import { store as coreStore } from '@wordpress/core-data';
import { createBlock } from '@wordpress/blocks';
import { useDispatch, useSelect } from '@wordpress/data';
import { video as videoIcon } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';

/**
Expand Down Expand Up @@ -53,16 +52,13 @@ export default function AnimatedGifConvertControl( { attributes, clientId } ) {
if ( ! urlPath?.toLowerCase().endsWith( '.gif' ) ) {
return null;
}
// A gallery only accepts `core/image` children, so swapping the
// image for a video block there would be rejected. Hide the
// control inside a gallery; the converted video is still
// sideloaded and stored for use elsewhere.
const { getBlockRootClientId, getBlockName } =
const { getBlockRootClientId, canInsertBlockType } =
select( blockEditorStore );
const rootClientId = getBlockRootClientId( clientId );
if (
rootClientId &&
getBlockName( rootClientId ) === 'core/gallery'
! canInsertBlockType(
'core/video',
getBlockRootClientId( clientId )
)
Comment on lines +58 to +61

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Eventually, the gallery might support the Video block, so this is a better way to assert.

) {
return null;
}
Expand Down Expand Up @@ -126,7 +122,7 @@ export default function AnimatedGifConvertControl( { attributes, clientId } ) {
return (
<BlockControls group="other">
<ToolbarGroup>
<ToolbarButton icon={ videoIcon } onClick={ convertToVideo }>
<ToolbarButton onClick={ convertToVideo }>
{ __( 'Display as video' ) }
</ToolbarButton>
</ToolbarGroup>
Expand Down
44 changes: 22 additions & 22 deletions packages/block-library/src/image/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -854,21 +854,27 @@ export default function Image( {

const showBlockControls = showUrlInput || allowCrop || showCoverControls;

const mediaReplaceFlow = isSingleSelected && ! lockUrlControls && (
// For contentOnly mode, put this button in its own area so it has borders around it.
<BlockControls group={ isContentOnlyMode ? 'inline' : 'other' }>
<MediaReplaceFlow
mediaId={ id }
mediaURL={ url }
allowedTypes={ ALLOWED_MEDIA_TYPES }
onSelect={ onSelectImage }
onSelectURL={ onSelectURL }
onError={ onUploadError }
name={ ! url ? __( 'Add image' ) : __( 'Replace' ) }
onReset={ () => onSelectImage( undefined ) }
variant="toolbar"
const mediaControls = isSingleSelected && ! lockUrlControls && (
<>
{ /* For contentOnly mode, put this button in its own area so it has borders around it. */ }
<BlockControls group={ isContentOnlyMode ? 'inline' : 'other' }>
<MediaReplaceFlow
mediaId={ id }
mediaURL={ url }
allowedTypes={ ALLOWED_MEDIA_TYPES }
onSelect={ onSelectImage }
onSelectURL={ onSelectURL }
onError={ onUploadError }
name={ ! url ? __( 'Add image' ) : __( 'Replace' ) }
onReset={ () => onSelectImage( undefined ) }
variant="toolbar"
/>
</BlockControls>
<AnimatedGifConvertControl
attributes={ attributes }
clientId={ clientId }
/>
</BlockControls>
</>
);

const hasDataFormBlockFields =
Expand Down Expand Up @@ -1355,7 +1361,7 @@ export default function Image( {
if ( ! url && ! temporaryURL ) {
return (
<>
{ mediaReplaceFlow }
{ mediaControls }
{ controls }
</>
);
Expand Down Expand Up @@ -1390,13 +1396,7 @@ export default function Image( {

return (
<>
{ isSingleSelected && ! lockUrlControls && (
<AnimatedGifConvertControl
attributes={ attributes }
clientId={ clientId }
/>
) }
{ mediaReplaceFlow }
{ mediaControls }
{ controls }
{ featuredImageControl }
{ img }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,16 @@ jest.mock( '@wordpress/blocks', () => ( {
* whether the attachment record was requested.
*
* @param {Object} options Options.
* @param {string} [options.rootBlockName] Block name of the block's root (e.g. 'core/gallery').
* @param {boolean} [options.canInsert] Whether a `core/video` block can be inserted in the parent.
* @param {Function} options.getEntityRecord Spy used for getEntityRecord.
* @return {Function} A select() implementation.
*/
function makeSelect( { rootBlockName = undefined, getEntityRecord } ) {
function makeSelect( { canInsert = true, getEntityRecord } ) {
return ( storeName ) => {
if ( storeName === 'core/block-editor' ) {
return {
getBlockRootClientId: () =>
rootBlockName ? 'root-client-id' : undefined,
getBlockName: () => rootBlockName,
getBlockRootClientId: () => undefined,
canInsertBlockType: () => canInsert,
};
}
// core-data store.
Expand Down Expand Up @@ -180,14 +179,14 @@ describe( 'AnimatedGifConvertControl', () => {
expect( container ).toBeEmptyDOMElement();
} );

it( 'hides the control inside a gallery without fetching', () => {
it( 'hides the control when a video block cannot be inserted in the parent (e.g. a gallery) without fetching', () => {
const { container } = renderControl( {
attributes: {
id: 7,
url: 'https://example.com/wp-content/uploads/cat.gif',
},
select: makeSelect( {
rootBlockName: 'core/gallery',
canInsert: false,
getEntityRecord,
} ),
} );
Expand Down
39 changes: 21 additions & 18 deletions packages/block-library/src/video/gif-restore-control.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import { store as coreStore } from '@wordpress/core-data';
import { createBlock } from '@wordpress/blocks';
import { useDispatch, useSelect } from '@wordpress/data';
import { image as imageIcon } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';

/**
Expand Down Expand Up @@ -44,26 +43,30 @@ export default function GifRestoreControl( { attributes, clientId } ) {
// The original GIF is the underlying image attachment. Only offer the
// restore when the media resolves to an image (an editor-converted GIF),
// not when a regular video has simply been set to loop/autoplay/mute.
const gif = useSelect(
const { gif, canRestoreToImage } = useSelect(
( select ) => {
if ( ! id ) {
return null;
}
const record = select( coreStore ).getEntityRecord(
'postType',
'attachment',
id,
{ context: 'view' }
);
if ( ! record?.mime_type?.startsWith( 'image/' ) ) {
return null;
}
return record;
const { getEntityRecord } = select( coreStore );
const { canInsertBlockType, getBlockRootClientId } =
select( blockEditorStore );

const record = id
? getEntityRecord( 'postType', 'attachment', id, {
context: 'view',
} )
: null;

return {
gif: record?.mime_type?.startsWith( 'image/' ) ? record : null,
canRestoreToImage: canInsertBlockType(
'core/image',
getBlockRootClientId( clientId )
),
};
},
[ id ]
[ id, clientId ]
);

if ( ! gif?.source_url ) {
if ( ! gif?.source_url || ! canRestoreToImage ) {
return null;
}

Expand All @@ -83,7 +86,7 @@ export default function GifRestoreControl( { attributes, clientId } ) {
return (
<BlockControls group="other">
<ToolbarGroup>
<ToolbarButton icon={ imageIcon } onClick={ restoreToImage }>
<ToolbarButton onClick={ restoreToImage }>
{ __( 'Display as GIF' ) }
</ToolbarButton>
</ToolbarGroup>
Expand Down
Loading