diff --git a/packages/block-editor/src/components/media-placeholder/hooks/use-files-upload.js b/packages/block-editor/src/components/media-placeholder/hooks/use-files-upload.js new file mode 100644 index 00000000000000..6948bae230879c --- /dev/null +++ b/packages/block-editor/src/components/media-placeholder/hooks/use-files-upload.js @@ -0,0 +1,88 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../../store'; + +export default function useFilesUpload( { + addToGallery, + handleUpload, + onSelect, + multiple, + onFilesPreUpload, + value, + allowedTypes, + onError, +} ) { + const mediaUpload = useSelect( ( select ) => { + const { getSettings } = select( blockEditorStore ); + return getSettings().mediaUpload; + }, [] ); + + return [ + mediaUpload, + ( files ) => { + if ( ! handleUpload ) { + return onSelect( files ); + } + onFilesPreUpload( files ); + let setMedia; + if ( multiple ) { + if ( addToGallery ) { + // Since the setMedia function runs multiple times per upload group + // and is passed newMedia containing every item in its group each time, we must + // filter out whatever this upload group had previously returned to the + // gallery before adding and returning the image array with replacement newMedia + // values. + + // Define an array to store urls from newMedia between subsequent function calls. + let lastMediaPassed = []; + setMedia = ( newMedia ) => { + // Remove any images this upload group is responsible for (lastMediaPassed). + // Their replacements are contained in newMedia. + const filteredMedia = ( value ?? [] ).filter( + ( item ) => { + // If Item has id, only remove it if lastMediaPassed has an item with that id. + if ( item.id ) { + return ! lastMediaPassed.some( + // Be sure to convert to number for comparison. + ( { id } ) => + Number( id ) === Number( item.id ) + ); + } + // Compare transient images via .includes since gallery may append extra info onto the url. + return ! lastMediaPassed.some( + ( { urlSlug } ) => + item.url.includes( urlSlug ) + ); + } + ); + // Return the filtered media array along with newMedia. + onSelect( filteredMedia.concat( newMedia ) ); + // Reset lastMediaPassed and set it with ids and urls from newMedia. + lastMediaPassed = newMedia.map( ( media ) => { + // Add everything up to '.fileType' to compare via .includes. + const cutOffIndex = media.url.lastIndexOf( '.' ); + const urlSlug = media.url.slice( 0, cutOffIndex ); + return { id: media.id, urlSlug }; + } ); + }; + } else { + setMedia = onSelect; + } + } else { + setMedia = ( [ media ] ) => onSelect( media ); + } + mediaUpload( { + allowedTypes, + filesList: files, + onFileChange: setMedia, + onError, + } ); + }, + ]; +} diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index 58bc1a86352481..9d4383284bbb1d 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -16,7 +16,6 @@ import { } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useState, useEffect } from '@wordpress/element'; -import { useSelect } from '@wordpress/data'; import deprecated from '@wordpress/deprecated'; import { keyboardReturn } from '@wordpress/icons'; @@ -26,7 +25,7 @@ import { keyboardReturn } from '@wordpress/icons'; import MediaUpload from '../media-upload'; import MediaUploadCheck from '../media-upload/check'; import URLPopover from '../url-popover'; -import { store as blockEditorStore } from '../../store'; +import useFilesUpload from './hooks/use-files-upload'; const InsertFromURLPopover = ( { src, onChange, onSubmit, onClose } ) => ( @@ -79,10 +78,16 @@ export function MediaPlaceholder( { mediaLibraryButton, placeholder, } ) { - const mediaUpload = useSelect( ( select ) => { - const { getSettings } = select( blockEditorStore ); - return getSettings().mediaUpload; - }, [] ); + const [ mediaUpload, onFilesUpload ] = useFilesUpload( { + addToGallery, + handleUpload, + onSelect, + multiple, + onFilesPreUpload, + value, + allowedTypes, + onError, + } ); const [ src, setSrc ] = useState( '' ); const [ isURLInputVisible, setIsURLInputVisible ] = useState( false ); @@ -120,62 +125,6 @@ export function MediaPlaceholder( { } }; - const onFilesUpload = ( files ) => { - if ( ! handleUpload ) { - return onSelect( files ); - } - onFilesPreUpload( files ); - let setMedia; - if ( multiple ) { - if ( addToGallery ) { - // Since the setMedia function runs multiple times per upload group - // and is passed newMedia containing every item in its group each time, we must - // filter out whatever this upload group had previously returned to the - // gallery before adding and returning the image array with replacement newMedia - // values. - - // Define an array to store urls from newMedia between subsequent function calls. - let lastMediaPassed = []; - setMedia = ( newMedia ) => { - // Remove any images this upload group is responsible for (lastMediaPassed). - // Their replacements are contained in newMedia. - const filteredMedia = ( value ?? [] ).filter( ( item ) => { - // If Item has id, only remove it if lastMediaPassed has an item with that id. - if ( item.id ) { - return ! lastMediaPassed.some( - // Be sure to convert to number for comparison. - ( { id } ) => Number( id ) === Number( item.id ) - ); - } - // Compare transient images via .includes since gallery may append extra info onto the url. - return ! lastMediaPassed.some( ( { urlSlug } ) => - item.url.includes( urlSlug ) - ); - } ); - // Return the filtered media array along with newMedia. - onSelect( filteredMedia.concat( newMedia ) ); - // Reset lastMediaPassed and set it with ids and urls from newMedia. - lastMediaPassed = newMedia.map( ( media ) => { - // Add everything up to '.fileType' to compare via .includes. - const cutOffIndex = media.url.lastIndexOf( '.' ); - const urlSlug = media.url.slice( 0, cutOffIndex ); - return { id: media.id, urlSlug }; - } ); - }; - } else { - setMedia = onSelect; - } - } else { - setMedia = ( [ media ] ) => onSelect( media ); - } - mediaUpload( { - allowedTypes, - filesList: files, - onFileChange: setMedia, - onError, - } ); - }; - const onUpload = ( event ) => { onFilesUpload( event.target.files ); };