From a529520925c5b51d250768959c25c12d9da3df1d Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 3 Jul 2024 10:43:17 +0200 Subject: [PATCH 1/7] Block API: Introduce temporary attributes and use it for the image block --- docs/reference-guides/core-blocks.md | 2 +- packages/block-library/src/gallery/edit.js | 13 ++++--- .../block-library/src/gallery/transforms.js | 2 +- packages/block-library/src/image/block.json | 4 ++ packages/block-library/src/image/edit.js | 37 +++++++------------ .../block-library/src/image/transforms.js | 2 +- packages/block-library/src/utils/hooks.js | 14 +++---- packages/blocks/src/api/serializer.js | 5 +++ 8 files changed, 39 insertions(+), 40 deletions(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 77e466db8e1f9e..54d3763f407de0 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -388,7 +388,7 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media - **Supports:** align (center, full, left, right, wide), anchor, color (~~background~~, ~~text~~), filter (duotone), interactivity, shadow () -- **Attributes:** alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width +- **Attributes:** alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, temporaryUrl, title, url, width ## Latest Comments diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 0b0b378889070d..e30cd29e781c1c 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -249,9 +249,9 @@ function GalleryEdit( props ) { const imageArray = newFileUploads ? Array.from( selectedImages ).map( ( file ) => { if ( ! file.url ) { - return pickRelevantMediaFiles( { - url: createBlobURL( file ), - } ); + return { + temporaryUrl: createBlobURL( file ), + }; } return file; @@ -271,9 +271,9 @@ function GalleryEdit( props ) { .filter( ( file ) => file.url || isValidFileType( file ) ) .map( ( file ) => { if ( ! file.url ) { - return pickRelevantMediaFiles( { - url: createBlobURL( file ), - } ); + return { + temporaryUrl: createBlobURL( file ), + }; } return file; @@ -307,6 +307,7 @@ function GalleryEdit( props ) { const newBlocks = newImageList.map( ( image ) => { return createBlock( 'core/image', { id: image.id, + temporaryUrl: image.temporaryUrl, url: image.url, caption: image.caption, alt: image.alt, diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index bcb1dd016c5d90..622e10a49f7cb0 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -223,7 +223,7 @@ const transforms = { if ( isGalleryV2Enabled() ) { const innerBlocks = files.map( ( file ) => createBlock( 'core/image', { - url: createBlobURL( file ), + temporaryUrl: createBlobURL( file ), } ) ); diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 1076aad0f17982..2bf64b7855c51f 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -9,6 +9,10 @@ "keywords": [ "img", "photo", "picture" ], "textdomain": "default", "attributes": { + "temporaryUrl": { + "type": "string", + "isTemporary": true + }, "url": { "type": "string", "source": "attribute", diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 673ab44a8c28aa..7d391c74a8290d 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -19,7 +19,7 @@ import { __experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles, useBlockEditingMode, } from '@wordpress/block-editor'; -import { useEffect, useRef, useState } from '@wordpress/element'; +import { useEffect, useRef } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { image as icon, plugins as pluginsIcon } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; @@ -56,17 +56,6 @@ export const pickRelevantMediaFiles = ( image, size ) => { return imageProps; }; -/** - * Is the URL a temporary blob URL? A blob URL is one that is used temporarily - * while the image is being uploaded and will not have an id yet allocated. - * - * @param {number=} id The id of the image. - * @param {string=} url The url of the image. - * - * @return {boolean} Is the URL a Blob URL - */ -const isTemporaryImage = ( id, url ) => ! id && isBlobURL( url ); - /** * Is the url for the image hosted externally. An externally hosted image has no * id and is not a blob url. @@ -106,6 +95,7 @@ export function ImageEdit( { __unstableParentLayout: parentLayout, } ) { const { + temporaryUrl, url = '', alt, caption, @@ -118,9 +108,6 @@ export function ImageEdit( { align, metadata, } = attributes; - const [ temporaryURL, setTemporaryURL ] = useState( () => { - return isTemporaryImage( id, url ) ? url : undefined; - } ); const altRef = useRef(); useEffect( () => { @@ -157,8 +144,8 @@ export function ImageEdit( { src: undefined, id: undefined, url: undefined, + temporaryUrl: undefined, } ); - setTemporaryURL( undefined ); } function onSelectImage( media ) { @@ -169,18 +156,20 @@ export function ImageEdit( { id: undefined, title: undefined, caption: undefined, + temporaryUrl: undefined, } ); return; } if ( isBlobURL( media.url ) ) { - setTemporaryURL( media.url ); + setAttributes( { + temporaryUrl: media.url, + url: undefined, + } ); return; } - setTemporaryURL(); - const { imageDefaultSize } = getSettings(); // Try to use the previous selected image size if its available @@ -254,6 +243,7 @@ export function ImageEdit( { mediaAttributes.href = href; setAttributes( { + temporaryUrl: undefined, ...mediaAttributes, ...additionalAttributes, linkDestination, @@ -263,6 +253,7 @@ export function ImageEdit( { function onSelectURL( newURL ) { if ( newURL !== url ) { setAttributes( { + temporaryUrl: undefined, url: newURL, id: undefined, sizeSlug: getSettings().imageDefaultSize, @@ -271,7 +262,7 @@ export function ImageEdit( { } useUploadMediaFromBlobURL( { - url, + temporaryUrl, allowedTypes: ALLOWED_MEDIA_TYPES, onChange: onSelectImage, onError: onUploadError, @@ -292,7 +283,7 @@ export function ImageEdit( { const shadowProps = getShadowClassesAndStyles( attributes ); const classes = clsx( className, { - 'is-transient': temporaryURL, + 'is-transient': !! temporaryUrl, 'is-resized': !! width || !! height, [ `size-${ sizeSlug }` ]: sizeSlug, 'has-custom-border': @@ -375,7 +366,7 @@ export function ImageEdit( { return (
); diff --git a/packages/block-library/src/image/transforms.js b/packages/block-library/src/image/transforms.js index a96a93640292b5..96b9e659da5d67 100644 --- a/packages/block-library/src/image/transforms.js +++ b/packages/block-library/src/image/transforms.js @@ -159,7 +159,7 @@ const transforms = { transform( files ) { const blocks = files.map( ( file ) => { return createBlock( 'core/image', { - url: createBlobURL( file ), + temporaryUrl: createBlobURL( file ), } ); } ); return blocks; diff --git a/packages/block-library/src/utils/hooks.js b/packages/block-library/src/utils/hooks.js index 2d50ff986492fe..aec7b5f87f4f50 100644 --- a/packages/block-library/src/utils/hooks.js +++ b/packages/block-library/src/utils/hooks.js @@ -48,19 +48,17 @@ export function useUploadMediaFromBlobURL( args = {} ) { return; } - if ( - ! latestArgs.current.url || - ! isBlobURL( latestArgs.current.url ) - ) { + if ( ! latestArgs.current.temporaryUrl ) { return; } - const file = getBlobByURL( latestArgs.current.url ); + const file = getBlobByURL( latestArgs.current.temporaryUrl ); if ( ! file ) { return; } - const { url, allowedTypes, onChange, onError } = latestArgs.current; + const { temporaryUrl, allowedTypes, onChange, onError } = + latestArgs.current; const { mediaUpload } = getSettings(); hasUploadStarted.current = true; @@ -73,12 +71,12 @@ export function useUploadMediaFromBlobURL( args = {} ) { return; } - revokeBlobURL( url ); + revokeBlobURL( temporaryUrl ); onChange( media ); hasUploadStarted.current = false; }, onError: ( message ) => { - revokeBlobURL( url ); + revokeBlobURL( temporaryUrl ); onError( message ); hasUploadStarted.current = false; }, diff --git a/packages/blocks/src/api/serializer.js b/packages/blocks/src/api/serializer.js index 609e62fc7e84b2..b16f6dbaa8275b 100644 --- a/packages/blocks/src/api/serializer.js +++ b/packages/blocks/src/api/serializer.js @@ -237,6 +237,11 @@ export function getCommentAttributes( blockType, attributes ) { return accumulator; } + // Ignore all temporary attributes + if ( attributeSchema.isTemporary ) { + return accumulator; + } + // Ignore default value. if ( 'default' in attributeSchema && From 2acf12bfa3296b59aa8a9137a8211f4d0312f3fe Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 3 Jul 2024 17:06:22 +0200 Subject: [PATCH 2/7] Fix undo/redo --- packages/block-library/src/image/edit.js | 22 ++++++++++++---------- packages/block-library/src/utils/hooks.js | 11 +++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 7d391c74a8290d..2e1522778d56bf 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -19,7 +19,7 @@ import { __experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles, useBlockEditingMode, } from '@wordpress/block-editor'; -import { useEffect, useRef } from '@wordpress/element'; +import { useEffect, useRef, useState } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { image as icon, plugins as pluginsIcon } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; @@ -95,7 +95,6 @@ export function ImageEdit( { __unstableParentLayout: parentLayout, } ) { const { - temporaryUrl, url = '', alt, caption, @@ -108,6 +107,9 @@ export function ImageEdit( { align, metadata, } = attributes; + const [ temporaryURL, setTemporaryURL ] = useState( + attributes.temporaryUrl + ); const altRef = useRef(); useEffect( () => { @@ -158,15 +160,13 @@ export function ImageEdit( { caption: undefined, temporaryUrl: undefined, } ); + setTemporaryURL(); return; } if ( isBlobURL( media.url ) ) { - setAttributes( { - temporaryUrl: media.url, - url: undefined, - } ); + setTemporaryURL( media.url ); return; } @@ -248,6 +248,7 @@ export function ImageEdit( { ...additionalAttributes, linkDestination, } ); + setTemporaryURL(); } function onSelectURL( newURL ) { @@ -258,11 +259,12 @@ export function ImageEdit( { id: undefined, sizeSlug: getSettings().imageDefaultSize, } ); + setTemporaryURL(); } } useUploadMediaFromBlobURL( { - temporaryUrl, + url: temporaryURL, allowedTypes: ALLOWED_MEDIA_TYPES, onChange: onSelectImage, onError: onUploadError, @@ -283,7 +285,7 @@ export function ImageEdit( { const shadowProps = getShadowClassesAndStyles( attributes ); const classes = clsx( className, { - 'is-transient': !! temporaryUrl, + 'is-transient': !! temporaryURL, 'is-resized': !! width || !! height, [ `size-${ sizeSlug }` ]: sizeSlug, 'has-custom-border': @@ -366,7 +368,7 @@ export function ImageEdit( { return (
); diff --git a/packages/block-library/src/utils/hooks.js b/packages/block-library/src/utils/hooks.js index aec7b5f87f4f50..802f4c78932bc5 100644 --- a/packages/block-library/src/utils/hooks.js +++ b/packages/block-library/src/utils/hooks.js @@ -48,17 +48,16 @@ export function useUploadMediaFromBlobURL( args = {} ) { return; } - if ( ! latestArgs.current.temporaryUrl ) { + if ( ! latestArgs.current.url ) { return; } - const file = getBlobByURL( latestArgs.current.temporaryUrl ); + const file = getBlobByURL( latestArgs.current.url ); if ( ! file ) { return; } - const { temporaryUrl, allowedTypes, onChange, onError } = - latestArgs.current; + const { url, allowedTypes, onChange, onError } = latestArgs.current; const { mediaUpload } = getSettings(); hasUploadStarted.current = true; @@ -71,12 +70,12 @@ export function useUploadMediaFromBlobURL( args = {} ) { return; } - revokeBlobURL( temporaryUrl ); + revokeBlobURL( url ); onChange( media ); hasUploadStarted.current = false; }, onError: ( message ) => { - revokeBlobURL( temporaryUrl ); + revokeBlobURL( url ); onError( message ); hasUploadStarted.current = false; }, From f2734436651e07a49baea03356c70ba8166f5b59 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 3 Jul 2024 17:20:11 +0200 Subject: [PATCH 3/7] Rename temporaryUrl to blob --- docs/reference-guides/core-blocks.md | 2 +- packages/block-library/src/gallery/edit.js | 6 +++--- packages/block-library/src/gallery/transforms.js | 2 +- packages/block-library/src/image/block.json | 2 +- packages/block-library/src/image/edit.js | 12 +++++------- packages/block-library/src/image/transforms.js | 2 +- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 54d3763f407de0..528f5dac01681d 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -388,7 +388,7 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media - **Supports:** align (center, full, left, right, wide), anchor, color (~~background~~, ~~text~~), filter (duotone), interactivity, shadow () -- **Attributes:** alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, temporaryUrl, title, url, width +- **Attributes:** alt, aspectRatio, blob, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width ## Latest Comments diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index e30cd29e781c1c..e01128eb82067a 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -250,7 +250,7 @@ function GalleryEdit( props ) { ? Array.from( selectedImages ).map( ( file ) => { if ( ! file.url ) { return { - temporaryUrl: createBlobURL( file ), + blob: createBlobURL( file ), }; } @@ -272,7 +272,7 @@ function GalleryEdit( props ) { .map( ( file ) => { if ( ! file.url ) { return { - temporaryUrl: createBlobURL( file ), + blob: createBlobURL( file ), }; } @@ -307,7 +307,7 @@ function GalleryEdit( props ) { const newBlocks = newImageList.map( ( image ) => { return createBlock( 'core/image', { id: image.id, - temporaryUrl: image.temporaryUrl, + blob: image.blob, url: image.url, caption: image.caption, alt: image.alt, diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index 622e10a49f7cb0..6e76cd93ef560d 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -223,7 +223,7 @@ const transforms = { if ( isGalleryV2Enabled() ) { const innerBlocks = files.map( ( file ) => createBlock( 'core/image', { - temporaryUrl: createBlobURL( file ), + blob: createBlobURL( file ), } ) ); diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 2bf64b7855c51f..24c544b3feee07 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -9,7 +9,7 @@ "keywords": [ "img", "photo", "picture" ], "textdomain": "default", "attributes": { - "temporaryUrl": { + "blob": { "type": "string", "isTemporary": true }, diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 2e1522778d56bf..df07fd0474eff1 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -107,9 +107,7 @@ export function ImageEdit( { align, metadata, } = attributes; - const [ temporaryURL, setTemporaryURL ] = useState( - attributes.temporaryUrl - ); + const [ temporaryURL, setTemporaryURL ] = useState( attributes.blob ); const altRef = useRef(); useEffect( () => { @@ -146,7 +144,7 @@ export function ImageEdit( { src: undefined, id: undefined, url: undefined, - temporaryUrl: undefined, + blob: undefined, } ); } @@ -158,7 +156,7 @@ export function ImageEdit( { id: undefined, title: undefined, caption: undefined, - temporaryUrl: undefined, + blob: undefined, } ); setTemporaryURL(); @@ -243,7 +241,7 @@ export function ImageEdit( { mediaAttributes.href = href; setAttributes( { - temporaryUrl: undefined, + blob: undefined, ...mediaAttributes, ...additionalAttributes, linkDestination, @@ -254,7 +252,7 @@ export function ImageEdit( { function onSelectURL( newURL ) { if ( newURL !== url ) { setAttributes( { - temporaryUrl: undefined, + blob: undefined, url: newURL, id: undefined, sizeSlug: getSettings().imageDefaultSize, diff --git a/packages/block-library/src/image/transforms.js b/packages/block-library/src/image/transforms.js index 96b9e659da5d67..fda29a2ca2530a 100644 --- a/packages/block-library/src/image/transforms.js +++ b/packages/block-library/src/image/transforms.js @@ -159,7 +159,7 @@ const transforms = { transform( files ) { const blocks = files.map( ( file ) => { return createBlock( 'core/image', { - temporaryUrl: createBlobURL( file ), + blob: createBlobURL( file ), } ); } ); return blocks; From 473914c3a0d195ddd742679b351c453a9b4e9504 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 3 Jul 2024 17:49:06 +0200 Subject: [PATCH 4/7] Switch to using the role property in the attribute schema --- packages/block-library/src/image/block.json | 2 +- packages/blocks/src/api/serializer.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 24c544b3feee07..b9d269db674621 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -11,7 +11,7 @@ "attributes": { "blob": { "type": "string", - "isTemporary": true + "__experimentalRole": "local" }, "url": { "type": "string", diff --git a/packages/blocks/src/api/serializer.js b/packages/blocks/src/api/serializer.js index b16f6dbaa8275b..2e7246ce9584a9 100644 --- a/packages/blocks/src/api/serializer.js +++ b/packages/blocks/src/api/serializer.js @@ -237,8 +237,8 @@ export function getCommentAttributes( blockType, attributes ) { return accumulator; } - // Ignore all temporary attributes - if ( attributeSchema.isTemporary ) { + // Ignore all local attributes + if ( attributeSchema.__experimentalRole === 'local' ) { return accumulator; } From 5529d3f03401ec9d6f29e73ea7e4d04ee89de46a Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 3 Jul 2024 18:08:49 +0200 Subject: [PATCH 5/7] Restore hook --- packages/block-library/src/utils/hooks.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/utils/hooks.js b/packages/block-library/src/utils/hooks.js index 802f4c78932bc5..43733d7f49a046 100644 --- a/packages/block-library/src/utils/hooks.js +++ b/packages/block-library/src/utils/hooks.js @@ -47,8 +47,10 @@ export function useUploadMediaFromBlobURL( args = {} ) { if ( hasUploadStarted.current ) { return; } - - if ( ! latestArgs.current.url ) { + if ( + ! latestArgs.current.url || + ! isBlobURL( latestArgs.current.url ) + ) { return; } From 9d37f254e2840aa98a8fe30e46514233ed99f4c9 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 3 Jul 2024 18:58:55 +0200 Subject: [PATCH 6/7] Fix gallery upload --- packages/block-library/src/gallery/edit.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index e01128eb82067a..1191968032a7b5 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -237,7 +237,7 @@ function GalleryEdit( props ) { return ( ALLOWED_MEDIA_TYPES.some( ( mediaType ) => mediaTypeSelector?.indexOf( mediaType ) === 0 - ) || file.url?.indexOf( 'blob:' ) === 0 + ) || file.blob ); } @@ -272,7 +272,7 @@ function GalleryEdit( props ) { .map( ( file ) => { if ( ! file.url ) { return { - blob: createBlobURL( file ), + blob: file.blob || createBlobURL( file ), }; } From 51c66592bf6a1550b5626d69e3de1637a5bd9a46 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 4 Jul 2024 09:08:18 +0200 Subject: [PATCH 7/7] Add unit test --- packages/blocks/src/api/test/serializer.js | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/blocks/src/api/test/serializer.js b/packages/blocks/src/api/test/serializer.js index 6cb21470f9e1fa..7fed23041daaa6 100644 --- a/packages/blocks/src/api/test/serializer.js +++ b/packages/blocks/src/api/test/serializer.js @@ -148,6 +148,30 @@ describe( 'block serializer', () => { expect( attributes ).toEqual( { fruit: 'bananas' } ); } ); + + it( 'should ingore local attributes', () => { + const attributes = getCommentAttributes( + { + attributes: { + blob: { + type: 'string', + __experimentalRole: 'local', + }, + url: { + type: 'string', + }, + }, + }, + { + blob: 'blob://false-url.com', + url: 'http://real-url.com', + } + ); + + expect( attributes ).toEqual( { + url: 'http://real-url.com', + } ); + } ); } ); describe( 'serializeAttributes()', () => {