diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index afe8af17a8743..3100a3293e96c 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { isEmpty, concat, differenceBy, some, find } from 'lodash'; +import { isEmpty, concat, find } from 'lodash'; /** * WordPress dependencies @@ -23,7 +23,6 @@ import { InspectorControls, useBlockProps, } from '@wordpress/block-editor'; -import { store as coreStore } from '@wordpress/core-data'; import { Platform, useEffect, useMemo } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { useSelect, useDispatch } from '@wordpress/data'; @@ -51,6 +50,8 @@ import { } from './constants'; import useImageSizes from './use-image-sizes'; import useShortCodeTransform from './use-short-code-transform'; +import useGetNewImages from './use-get-new-images'; +import useGetMedia from './use-get-media'; const MAX_COLUMNS = 8; const linkOptions = [ @@ -122,35 +123,27 @@ function GalleryEdit( props ) { const images = useMemo( () => innerBlockImages?.map( ( block ) => ( { + clientId: block.clientId, id: block.attributes.id, url: block.attributes.url, attributes: block.attributes, + fromSavedContent: Boolean( block.originalContent ), } ) ), [ innerBlockImages ] ); - const imageData = useSelect( - ( select ) => { - if ( - ! innerBlockImages?.length || - some( - innerBlockImages, - ( imageBlock ) => ! imageBlock.attributes.id - ) - ) { - return imageData; - } + const imageData = useGetMedia( innerBlockImages ); - const imageIds = innerBlockImages.map( - ( imageBlock ) => imageBlock.attributes.id - ); + const newImages = useGetNewImages( images, imageData ); - const getMediaItems = select( coreStore ).getMediaItems; - - return getMediaItems( { include: imageIds } ); - }, - [ innerBlockImages ] - ); + useEffect( () => { + newImages?.forEach( ( newImage ) => { + updateBlockAttributes( newImage.clientId, { + ...buildImageAttributes( false, newImage ), + id: newImage.id, + } ); + } ); + }, [ newImages ] ); const shortCodeImages = useShortCodeTransform( shortCodeTransforms ); @@ -241,17 +234,22 @@ function GalleryEdit( props ) { const existingImageBlocks = ! newFileUploads ? innerBlockImages.filter( ( block ) => processedImages.find( - ( img ) => img.url === block.attributes.url + ( img ) => img.id === block.attributes.id ) ) : innerBlockImages; - const newImages = differenceBy( processedImages, images, 'url' ); + const newImageList = processedImages.filter( + ( img ) => + ! existingImageBlocks.find( + ( existingImg ) => img.id === existingImg.attributes.id + ) + ); - const newBlocks = newImages.map( ( image ) => { + const newBlocks = newImageList.map( ( image ) => { return createBlock( 'core/image', { - ...buildImageAttributes( false, image ), id: image.id, + url: image.url, } ); } ); diff --git a/packages/block-library/src/gallery/use-get-media.js b/packages/block-library/src/gallery/use-get-media.js new file mode 100644 index 0000000000000..fc04e070f9617 --- /dev/null +++ b/packages/block-library/src/gallery/use-get-media.js @@ -0,0 +1,55 @@ +/** + * External dependencies + */ +import { some } from 'lodash'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; + +export default function useGetMedia( innerBlockImages ) { + const [ currentImageMedia, setCurrentImageMedia ] = useState( [] ); + + const imageMedia = useSelect( + ( select ) => { + if ( + ! innerBlockImages?.length || + some( + innerBlockImages, + ( imageBlock ) => ! imageBlock.attributes.id + ) + ) { + return currentImageMedia; + } + + const imageIds = innerBlockImages.map( + ( imageBlock ) => imageBlock.attributes.id + ); + + if ( imageIds.length === 0 ) { + return currentImageMedia; + } + const getMedia = select( coreStore ).getMedia; + const newImageMedia = imageIds.map( ( img ) => { + return getMedia( img ); + } ); + + if ( newImageMedia.some( ( img ) => ! img ) ) { + return currentImageMedia; + } + + return newImageMedia; + }, + [ innerBlockImages ] + ); + + if ( imageMedia?.length !== currentImageMedia.length ) { + setCurrentImageMedia( imageMedia ); + return imageMedia; + } + + return currentImageMedia; +} diff --git a/packages/block-library/src/gallery/use-get-new-images.js b/packages/block-library/src/gallery/use-get-new-images.js new file mode 100644 index 0000000000000..25ac5a15560ee --- /dev/null +++ b/packages/block-library/src/gallery/use-get-new-images.js @@ -0,0 +1,56 @@ +/** + * WordPress dependencies + */ +import { useMemo, useState } from '@wordpress/element'; + +export default function useGetNewImages( images, imageData ) { + const [ currentImages, setCurrentImages ] = useState( [] ); + + return useMemo( () => getNewImages(), [ images, imageData ] ); + + function getNewImages() { + let imagesUpdated = false; + + // First lets check if any images have been deleted. + const newCurrentImages = currentImages.filter( ( currentImg ) => + images.find( ( img ) => { + return currentImg.clientId === img.clientId; + } ) + ); + + if ( newCurrentImages.length < currentImages.length ) { + imagesUpdated = true; + } + + // Now lets see if we have any images hydrated from saved content and if so + // add them to currentImages state. + images.forEach( ( image ) => { + if ( + image.fromSavedContent && + ! newCurrentImages.find( + ( currentImage ) => currentImage.id === image.id + ) + ) { + imagesUpdated = true; + newCurrentImages.push( image ); + } + } ); + + // Now check for any new images that have been added to InnerBlocks and for which + // we have the imageData we need for setting default block attributes. + const newImages = images.filter( + ( image ) => + ! newCurrentImages.find( + ( currentImage ) => image.id && currentImage.id === image.id + ) && + imageData?.find( ( img ) => img.id === image.id ) && + ! image.fromSavedConent + ); + + if ( imagesUpdated || newImages?.length > 0 ) { + setCurrentImages( [ ...newCurrentImages, ...newImages ] ); + } + + return newImages.length > 0 ? newImages : null; + } +}