Skip to content

Commit

Permalink
Allow dropping multiple images to the image block (#65030)
Browse files Browse the repository at this point in the history
co-authored-by: kevin940726 <kevin940726@git.wordpress.org>Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>Co-authored-by: andrewserong <andrewserong@git.wordpress.org>Co-authored-by: swissspidy <swissspidy@git.wordpress.org>Co-authored-by: richtabor <richtabor@git.wordpress.org>
* Allow dropping multiple images to the image block

* Check for canInsert and file type

* Separate the list callback
  • Loading branch information
kevin940726 authored Sep 5, 2024
1 parent 29e344c commit 90a7c7e
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@ Callback called when urls can be configured. No media insertion from url will be

### handleUpload

When set to false the handling of the upload is left to the calling component.
When the value is set to `false` or returned as `false`, the handling of the upload is left to the consumer component. The function signature accepts an array containing the files to be uploaded.

- Type: `Boolean`
- Type: `Boolean|Function`
- Required: No
- Default: `true`
- Platform: Web
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,10 @@ export function MediaPlaceholder( {
};

const onFilesUpload = ( files ) => {
if ( ! handleUpload ) {
if (
! handleUpload ||
( typeof handleUpload === 'function' && ! handleUpload( files ) )
) {
return onSelect( files );
}
onFilesPreUpload( files );
Expand Down
63 changes: 58 additions & 5 deletions packages/block-library/src/image/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import clsx from 'clsx';
/**
* WordPress dependencies
*/
import { isBlobURL } from '@wordpress/blob';
import { store as blocksStore } from '@wordpress/blocks';
import { isBlobURL, createBlobURL } from '@wordpress/blob';
import { store as blocksStore, createBlock } from '@wordpress/blocks';
import { Placeholder } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import {
Expand All @@ -31,6 +31,7 @@ import { useResizeObserver } from '@wordpress/compose';
import { unlock } from '../lock-unlock';
import { useUploadMediaFromBlobURL } from '../utils/hooks';
import Image from './image';
import { isValidFileType } from './utils';

/**
* Module constants
Expand Down Expand Up @@ -109,6 +110,7 @@ export function ImageEdit( {
metadata,
} = attributes;
const [ temporaryURL, setTemporaryURL ] = useState( attributes.blob );
const figureRef = useRef();

const [ contentResizeListener, { width: containerWidth } ] =
useResizeObserver();
Expand All @@ -123,7 +125,7 @@ export function ImageEdit( {
captionRef.current = caption;
}, [ caption ] );

const { __unstableMarkNextChangeAsNotPersistent } =
const { __unstableMarkNextChangeAsNotPersistent, replaceBlock } =
useDispatch( blockEditorStore );

useEffect( () => {
Expand All @@ -138,7 +140,12 @@ export function ImageEdit( {
}
}, [ __unstableMarkNextChangeAsNotPersistent, align, setAttributes ] );

const { getSettings } = useSelect( blockEditorStore );
const {
getSettings,
getBlockRootClientId,
getBlockName,
canInsertBlockType,
} = useSelect( blockEditorStore );
const blockEditingMode = useBlockEditingMode();

const { createErrorNotice } = useDispatch( noticesStore );
Expand All @@ -152,7 +159,52 @@ export function ImageEdit( {
} );
}

function onSelectImagesList( images ) {
const win = figureRef.current?.ownerDocument.defaultView;

if ( images.every( ( file ) => file instanceof win.File ) ) {
/** @type {File[]} */
const files = images;
const rootClientId = getBlockRootClientId( clientId );

if ( files.some( ( file ) => ! isValidFileType( file ) ) ) {
// Copied from the same notice in the gallery block.
createErrorNotice(
__(
'If uploading to a gallery all files need to be image formats'
),
{ id: 'gallery-upload-invalid-file', type: 'snackbar' }
);
}

const imageBlocks = files
.filter( ( file ) => isValidFileType( file ) )
.map( ( file ) =>
createBlock( 'core/image', {
blob: createBlobURL( file ),
} )
);

if ( getBlockName( rootClientId ) === 'core/gallery' ) {
replaceBlock( clientId, imageBlocks );
} else if ( canInsertBlockType( 'core/gallery', rootClientId ) ) {
const galleryBlock = createBlock(
'core/gallery',
{},
imageBlocks
);

replaceBlock( clientId, galleryBlock );
}
}
}

function onSelectImage( media ) {
if ( Array.isArray( media ) ) {
onSelectImagesList( media );
return;
}

if ( ! media || ! media.url ) {
setAttributes( {
url: undefined,
Expand Down Expand Up @@ -296,7 +348,7 @@ export function ImageEdit( {
Object.keys( borderProps.style ).length > 0 ),
} );

const blockProps = useBlockProps( { className: classes } );
const blockProps = useBlockProps( { ref: figureRef, className: classes } );

// Much of this description is duplicated from MediaPlaceholder.
const { lockUrlControls = false, lockUrlControlsMessage } = useSelect(
Expand Down Expand Up @@ -394,6 +446,7 @@ export function ImageEdit( {
placeholder={ placeholder }
accept="image/*"
allowedTypes={ ALLOWED_MEDIA_TYPES }
handleUpload={ ( files ) => files.length === 1 }
value={ { id, src } }
mediaPreview={ mediaPreview }
disableMediaButtons={ temporaryURL || url }
Expand Down
14 changes: 13 additions & 1 deletion packages/block-library/src/image/utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
import { NEW_TAB_REL } from './constants';
import { NEW_TAB_REL, ALLOWED_MEDIA_TYPES } from './constants';

/**
* Evaluates a CSS aspect-ratio property value as a number.
Expand Down Expand Up @@ -81,3 +81,15 @@ export function getImageSizeAttributes( image, size ) {

return {};
}

/**
* Checks if the file has a valid file type.
*
* @param {File} file - The file to check.
* @return {boolean} - Returns true if the file has a valid file type, otherwise false.
*/
export function isValidFileType( file ) {
return ALLOWED_MEDIA_TYPES.some(
( mediaType ) => file.type.indexOf( mediaType ) === 0
);
}

1 comment on commit 90a7c7e

@github-actions
Copy link

Choose a reason for hiding this comment

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

Flaky tests detected in 90a7c7e.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/10716182520
📝 Reported issues:

Please sign in to comment.