@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
8 lines (7 loc) • 12.2 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/components/post-publish-panel/maybe-upload-media.js"],
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tPanelBody,\n\tButton,\n\tSpinner,\n\t__unstableMotion as motion,\n\t__unstableAnimatePresence as AnimatePresence,\n} from '@wordpress/components';\nimport { useSelect, useDispatch } from '@wordpress/data';\nimport { __, _x } from '@wordpress/i18n';\nimport { store as blockEditorStore } from '@wordpress/block-editor';\nimport { useState } from '@wordpress/element';\nimport { isBlobURL } from '@wordpress/blob';\n\n/**\n * Internal dependencies\n */\nimport { fetchMedia } from './media-util';\n\nfunction flattenBlocks( blocks ) {\n\tconst result = [];\n\n\tblocks.forEach( ( block ) => {\n\t\tresult.push( block );\n\t\tresult.push( ...flattenBlocks( block.innerBlocks ) );\n\t} );\n\n\treturn result;\n}\n\n/**\n * Determine whether a block has external media.\n *\n * Different blocks use different attribute names (and potentially\n * different logic as well) in determining whether the media is\n * present, and whether it's external.\n *\n * @param {{name: string, attributes: Object}} block The block.\n * @return {boolean?} Whether the block has external media\n */\nfunction hasExternalMedia( block ) {\n\tif ( block.name === 'core/image' || block.name === 'core/cover' ) {\n\t\treturn block.attributes.url && ! block.attributes.id;\n\t}\n\n\tif ( block.name === 'core/media-text' ) {\n\t\treturn block.attributes.mediaUrl && ! block.attributes.mediaId;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Retrieve media info from a block.\n *\n * Different blocks use different attribute names, so we need this\n * function to normalize things into a consistent naming scheme.\n *\n * @param {{name: string, attributes: Object}} block The block.\n * @return {{url: ?string, alt: ?string, id: ?number}} The media info for the block.\n */\nfunction getMediaInfo( block ) {\n\tif ( block.name === 'core/image' || block.name === 'core/cover' ) {\n\t\tconst { url, alt, id } = block.attributes;\n\t\treturn { url, alt, id };\n\t}\n\n\tif ( block.name === 'core/media-text' ) {\n\t\tconst { mediaUrl: url, mediaAlt: alt, mediaId: id } = block.attributes;\n\t\treturn { url, alt, id };\n\t}\n\n\treturn {};\n}\n\n// Image component to represent a single image in the upload dialog.\nfunction Image( { clientId, alt, url } ) {\n\tconst { selectBlock } = useDispatch( blockEditorStore );\n\treturn (\n\t\t<motion.img\n\t\t\ttabIndex={ 0 }\n\t\t\trole=\"button\"\n\t\t\taria-label={ __( 'Select image block.' ) }\n\t\t\tonClick={ () => {\n\t\t\t\tselectBlock( clientId );\n\t\t\t} }\n\t\t\tonKeyDown={ ( event ) => {\n\t\t\t\tif ( event.key === 'Enter' || event.key === ' ' ) {\n\t\t\t\t\tselectBlock( clientId );\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t} }\n\t\t\tkey={ clientId }\n\t\t\talt={ alt }\n\t\t\tsrc={ url }\n\t\t\tanimate={ { opacity: 1 } }\n\t\t\texit={ { opacity: 0, scale: 0 } }\n\t\t\tstyle={ {\n\t\t\t\twidth: '32px',\n\t\t\t\theight: '32px',\n\t\t\t\tobjectFit: 'cover',\n\t\t\t\tborderRadius: '2px',\n\t\t\t\tcursor: 'pointer',\n\t\t\t} }\n\t\t\twhileHover={ { scale: 1.08 } }\n\t\t/>\n\t);\n}\n\nexport default function MaybeUploadMediaPanel() {\n\tconst [ isUploading, setIsUploading ] = useState( false );\n\tconst [ isAnimating, setIsAnimating ] = useState( false );\n\tconst [ hadUploadError, setHadUploadError ] = useState( false );\n\tconst { editorBlocks, mediaUpload } = useSelect(\n\t\t( select ) => ( {\n\t\t\teditorBlocks: select( blockEditorStore ).getBlocks(),\n\t\t\tmediaUpload: select( blockEditorStore ).getSettings().mediaUpload,\n\t\t} ),\n\t\t[]\n\t);\n\n\t// Get a list of blocks with external media.\n\tconst blocksWithExternalMedia = flattenBlocks( editorBlocks ).filter(\n\t\t( block ) => hasExternalMedia( block )\n\t);\n\tconst { updateBlockAttributes } = useDispatch( blockEditorStore );\n\n\tif ( ! mediaUpload || ! blocksWithExternalMedia.length ) {\n\t\treturn null;\n\t}\n\n\tconst panelBodyTitle = [\n\t\t__( 'Suggestion:' ),\n\t\t<span className=\"editor-post-publish-panel__link\" key=\"label\">\n\t\t\t{ __( 'External media' ) }\n\t\t</span>,\n\t];\n\n\t/**\n\t * Update an individual block to point to newly-added library media.\n\t *\n\t * Different blocks use different attribute names, so we need this\n\t * function to ensure we modify the correct attributes for each type.\n\t *\n\t * @param {{name: string, attributes: Object}} block The block.\n\t * @param {{id: number, url: string}} media Media library file info.\n\t */\n\tfunction updateBlockWithUploadedMedia( block, media ) {\n\t\tif ( block.name === 'core/image' || block.name === 'core/cover' ) {\n\t\t\tupdateBlockAttributes( block.clientId, {\n\t\t\t\tid: media.id,\n\t\t\t\turl: media.url,\n\t\t\t} );\n\t\t}\n\n\t\tif ( block.name === 'core/media-text' ) {\n\t\t\tupdateBlockAttributes( block.clientId, {\n\t\t\t\tmediaId: media.id,\n\t\t\t\tmediaUrl: media.url,\n\t\t\t} );\n\t\t}\n\t}\n\n\t// Handle fetching and uploading all external media in the post.\n\tfunction uploadImages() {\n\t\tsetIsUploading( true );\n\t\tsetHadUploadError( false );\n\n\t\t// Multiple blocks can be using the same URL, so we\n\t\t// should ensure we only fetch and upload each of them once.\n\t\tconst mediaUrls = new Set(\n\t\t\tblocksWithExternalMedia.map( ( block ) => {\n\t\t\t\tconst { url } = getMediaInfo( block );\n\t\t\t\treturn url;\n\t\t\t} )\n\t\t);\n\n\t\t// Create an upload promise for each URL, that we can wait for in all\n\t\t// blocks that make use of that media.\n\t\tconst uploadPromises = Object.fromEntries(\n\t\t\tObject.entries( fetchMedia( [ ...mediaUrls ] ) ).map(\n\t\t\t\t( [ url, filePromise ] ) => {\n\t\t\t\t\tconst uploadPromise = filePromise.then(\n\t\t\t\t\t\t( blob ) =>\n\t\t\t\t\t\t\tnew Promise( ( resolve, reject ) => {\n\t\t\t\t\t\t\t\tmediaUpload( {\n\t\t\t\t\t\t\t\t\tfilesList: [ blob ],\n\t\t\t\t\t\t\t\t\tonFileChange: ( [ media ] ) => {\n\t\t\t\t\t\t\t\t\t\tif ( isBlobURL( media.url ) ) {\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tresolve( media );\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tonError() {\n\t\t\t\t\t\t\t\t\t\treject();\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\n\t\t\t\t\treturn [ url, uploadPromise ];\n\t\t\t\t}\n\t\t\t)\n\t\t);\n\n\t\t// Wait for all blocks to be updated with library media.\n\t\tPromise.allSettled(\n\t\t\tblocksWithExternalMedia.map( ( block ) => {\n\t\t\t\tconst { url } = getMediaInfo( block );\n\n\t\t\t\treturn uploadPromises[ url ]\n\t\t\t\t\t.then( ( media ) =>\n\t\t\t\t\t\tupdateBlockWithUploadedMedia( block, media )\n\t\t\t\t\t)\n\t\t\t\t\t.then( () => setIsAnimating( true ) )\n\t\t\t\t\t.catch( () => setHadUploadError( true ) );\n\t\t\t} )\n\t\t).finally( () => {\n\t\t\tsetIsUploading( false );\n\t\t} );\n\t}\n\n\treturn (\n\t\t<PanelBody initialOpen title={ panelBodyTitle }>\n\t\t\t<p>\n\t\t\t\t{ __(\n\t\t\t\t\t'Upload external images to the Media Library. Images from different domains may load slowly, display incorrectly, or be removed unexpectedly.'\n\t\t\t\t) }\n\t\t\t</p>\n\t\t\t<div\n\t\t\t\tstyle={ {\n\t\t\t\t\tdisplay: 'inline-flex',\n\t\t\t\t\tflexWrap: 'wrap',\n\t\t\t\t\tgap: '8px',\n\t\t\t\t} }\n\t\t\t>\n\t\t\t\t<AnimatePresence\n\t\t\t\t\tonExitComplete={ () => setIsAnimating( false ) }\n\t\t\t\t>\n\t\t\t\t\t{ blocksWithExternalMedia.map( ( block ) => {\n\t\t\t\t\t\tconst { url, alt } = getMediaInfo( block );\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Image\n\t\t\t\t\t\t\t\tkey={ block.clientId }\n\t\t\t\t\t\t\t\tclientId={ block.clientId }\n\t\t\t\t\t\t\t\turl={ url }\n\t\t\t\t\t\t\t\talt={ alt }\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t} ) }\n\t\t\t\t</AnimatePresence>\n\t\t\t\t{ isUploading || isAnimating ? (\n\t\t\t\t\t<Spinner />\n\t\t\t\t) : (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tsize=\"compact\"\n\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\tonClick={ uploadImages }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ _x( 'Upload', 'verb' ) }\n\t\t\t\t\t</Button>\n\t\t\t\t) }\n\t\t\t</div>\n\t\t\t{ hadUploadError && <p>{ __( 'Upload failed, try again.' ) }</p> }\n\t\t</PanelBody>\n\t);\n}\n"],
"mappings": "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",
"names": []
}