diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js
index 8ef7ebeee71532..c155f6cf66a38a 100644
--- a/packages/block-library/src/image/edit.native.js
+++ b/packages/block-library/src/image/edit.native.js
@@ -428,6 +428,7 @@ export class ImageEdit extends Component {
id: media.id,
url: media.url,
caption: media.caption,
+ alt: media.alt,
};
let additionalAttributes;
diff --git a/packages/block-library/src/image/test/edit.native.js b/packages/block-library/src/image/test/edit.native.js
index 214c953be323b2..2803060847bb92 100644
--- a/packages/block-library/src/image/test/edit.native.js
+++ b/packages/block-library/src/image/test/edit.native.js
@@ -16,6 +16,7 @@ import Clipboard from '@react-native-clipboard/clipboard';
*/
import { getBlockTypes, unregisterBlockType } from '@wordpress/blocks';
import {
+ requestMediaPicker,
setFeaturedImage,
sendMediaUpload,
subscribeMediaUpload,
@@ -49,6 +50,10 @@ jest.mock( 'lodash', () => {
return { ...actual, delay: ( cb ) => cb() };
} );
+function mockGetMedia( media ) {
+ jest.spyOn( select( coreStore ), 'getMedia' ).mockReturnValue( media );
+}
+
const apiFetchPromise = Promise.resolve( {} );
const clipboardPromise = Promise.resolve( '' );
@@ -292,12 +297,6 @@ describe( 'Image Block', () => {
);
}
- function mockGetMedia( media ) {
- jest.spyOn( select( coreStore ), 'getMedia' ).mockReturnValueOnce(
- media
- );
- }
-
it( 'does not prompt to replace featured image during a new image upload', () => {
// Arrange
const INITIAL_IMAGE = { id: 1, url: 'mock-url-1' };
@@ -406,4 +405,37 @@ describe( 'Image Block', () => {
);
} );
} );
+
+ it( 'sets src and alt attributes when selecting media', async () => {
+ const IMAGE = { id: 1, url: 'mock-image', alt: 'A beautiful mountain' };
+ requestMediaPicker.mockImplementationOnce(
+ ( source, filter, multiple, callback ) => {
+ callback( {
+ id: IMAGE.id,
+ url: IMAGE.url,
+ alt: IMAGE.alt,
+ } );
+ }
+ );
+ mockGetMedia( {
+ id: IMAGE.id,
+ source_url: IMAGE.url,
+ } );
+
+ const initialHtml = `
+
+
+
+
+ `;
+ const screen = await initializeEditor( { initialHtml } );
+
+ fireEvent.press( screen.getByText( 'ADD IMAGE' ) );
+ fireEvent.press( screen.getByText( 'WordPress Media Library' ) );
+
+ const expectedHtml = `
+
+`;
+ expect( getEditorHtml() ).toBe( expectedHtml );
+ } );
} );
diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNMedia.kt b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNMedia.kt
index 8f1b3bb367e86c..9c3a25a5ed0762 100644
--- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNMedia.kt
+++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNMedia.kt
@@ -8,5 +8,6 @@ interface RNMedia {
val type: String
val caption: String
val title: String
+ val alt: String
fun toMap(): WritableMap
}
diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/WPAndroidGlue/Media.kt b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/WPAndroidGlue/Media.kt
index fc835284805ae2..d225593d8eef4d 100644
--- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/WPAndroidGlue/Media.kt
+++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/WPAndroidGlue/Media.kt
@@ -14,7 +14,8 @@ data class Media(
override val url: String,
override val type: String,
override val caption: String = "",
- override val title: String = ""
+ override val title: String = "",
+ override val alt: String = ""
) : RNMedia {
override fun toMap(): WritableMap = WritableNativeMap().apply {
putInt("id", id)
@@ -22,17 +23,11 @@ data class Media(
putString("type", type)
putString("caption", caption)
putString("title", title)
+ putString("alt", alt)
}
companion object {
- @JvmStatic
- fun createRNMediaUsingMimeType(
- id: Int,
- url: String,
- mimeType: String?,
- caption: String?,
- title: String?
- ): Media {
+ private fun convertToType(mimeType: String?): String {
val isMediaType = { mediaType: MediaType ->
mimeType?.startsWith(mediaType.name.toLowerCase(Locale.ROOT)) == true
}
@@ -41,6 +36,30 @@ data class Media(
isMediaType(VIDEO) -> VIDEO
else -> OTHER
}.name.toLowerCase(Locale.ROOT)
+ return type;
+ }
+
+ @JvmStatic
+ fun createRNMediaUsingMimeType(
+ id: Int,
+ url: String,
+ mimeType: String?,
+ caption: String?,
+ title: String?,
+ alt: String?,
+ ): Media {
+ val type = convertToType(mimeType)
+ return Media(id, url, type, caption ?: "", title ?: "", alt ?: "")
+ }
+ @JvmStatic
+ fun createRNMediaUsingMimeType(
+ id: Int,
+ url: String,
+ mimeType: String?,
+ caption: String?,
+ title: String?,
+ ): Media {
+ val type = convertToType(mimeType)
return Media(id, url, type, caption ?: "", title ?: "")
}
}
diff --git a/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift b/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift
index 98b4c721caff1b..ae03570d6f038a 100644
--- a/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift
+++ b/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift
@@ -4,13 +4,15 @@ public struct MediaInfo: Encodable {
public let type: String?
public let title: String?
public let caption: String?
+ public let alt: String?
- public init(id: Int32?, url: String?, type: String?, caption: String? = nil, title: String? = nil) {
+ public init(id: Int32?, url: String?, type: String?, caption: String? = nil, title: String? = nil, alt: String? = nil) {
self.id = id
self.url = url
self.type = type
self.caption = caption
self.title = title
+ self.alt = alt
}
}
diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md
index 577348dd63bd0a..cd464e5021adf3 100644
--- a/packages/react-native-editor/CHANGELOG.md
+++ b/packages/react-native-editor/CHANGELOG.md
@@ -12,6 +12,7 @@ For each user feature we should also add a importance categorization label to i
## Unreleased
- [*] Add 'Insert from URL' option to Video block [#41493]
+- [*] Image block copies the alt text from the media library when selecting an item [#41839]
## 1.78.1
diff --git a/packages/react-native-editor/__device-tests__/helpers/test-data.js b/packages/react-native-editor/__device-tests__/helpers/test-data.js
index ac225a02403215..9f9a3c4214c976 100644
--- a/packages/react-native-editor/__device-tests__/helpers/test-data.js
+++ b/packages/react-native-editor/__device-tests__/helpers/test-data.js
@@ -96,7 +96,7 @@ exports.imageCompletehtml = `
`;
exports.imageShorteHtml = `
-
C'est la vie my friends
+
C'est la vie my friends
diff --git a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java
index b94e581a736cbe..354cb09e953ecd 100644
--- a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java
+++ b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java
@@ -1,5 +1,7 @@
package com.gutenberg;
+import static org.wordpress.mobile.WPAndroidGlue.Media.createRNMediaUsingMimeType;
+
import android.app.Application;
import android.content.Intent;
import android.content.res.Configuration;
@@ -83,17 +85,17 @@ public void requestMediaPickFromMediaLibrary(MediaSelectedCallback mediaSelected
switch (mediaType) {
case IMAGE:
- rnMediaList.add(new Media(1, "https://cldup.com/cXyG__fTLN.jpg", "image", "Mountain", ""));
+ rnMediaList.add(createRNMediaUsingMimeType(1, "https://cldup.com/cXyG__fTLN.jpg", "image", "Mountain", "", "A snow-capped mountain top in a cloudy sky with red-leafed trees in the foreground"));
break;
case VIDEO:
- rnMediaList.add(new Media(2, "https://i.cloudup.com/YtZFJbuQCE.mov", "video", "Cloudup", ""));
+ rnMediaList.add(createRNMediaUsingMimeType(2, "https://i.cloudup.com/YtZFJbuQCE.mov", "video", "Cloudup", ""));
break;
case ANY:
case OTHER:
- rnMediaList.add(new Media(3, "https://wordpress.org/latest.zip", "zip", "WordPress latest version", "WordPress.zip"));
+ rnMediaList.add(createRNMediaUsingMimeType(3, "https://wordpress.org/latest.zip", "zip", "WordPress latest version", "WordPress.zip"));
break;
case AUDIO:
- rnMediaList.add(new Media(5, "https://cldup.com/59IrU0WJtq.mp3", "audio", "Summer presto", ""));
+ rnMediaList.add(createRNMediaUsingMimeType(5, "https://cldup.com/59IrU0WJtq.mp3", "audio", "Summer presto", ""));
break;
}
mediaSelectedCallback.onMediaFileSelected(rnMediaList);
@@ -145,7 +147,7 @@ public void getOtherMediaPickerOptions(OtherMediaOptionsReceivedCallback otherMe
public void requestMediaPickFrom(String mediaSource, MediaSelectedCallback mediaSelectedCallback, Boolean allowMultipleSelection) {
if (mediaSource.equals("1")) {
List rnMediaList = new ArrayList<>();
- rnMediaList.add(new Media(1, "https://grad.illinois.edu/sites/default/files/pdfs/cvsamples.pdf", "other", "","cvsamples.pdf"));
+ rnMediaList.add(createRNMediaUsingMimeType(1, "https://grad.illinois.edu/sites/default/files/pdfs/cvsamples.pdf", "other", "","cvsamples.pdf"));
mediaSelectedCallback.onMediaFileSelected(rnMediaList);
}
}
diff --git a/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift b/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift
index 9c722452c19d9b..928310f3f76439 100644
--- a/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift
+++ b/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift
@@ -88,9 +88,9 @@ extension GutenbergViewController: GutenbergBridgeDelegate {
case .image:
if(allowMultipleSelection) {
callback([MediaInfo(id: 1, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image"),
- MediaInfo(id: 3, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image", caption: "Mountain")])
+ MediaInfo(id: 3, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image", caption: "Mountain", alt: "A snow-capped mountain top in a cloudy sky with red-leafed trees in the foreground")])
} else {
- callback([MediaInfo(id: 1, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image", caption: "Mountain")])
+ callback([MediaInfo(id: 1, url: "https://cldup.com/cXyG__fTLN.jpg", type: "image", caption: "Mountain", alt: "A snow-capped mountain top in a cloudy sky with red-leafed trees in the foreground")])
}
case .video:
if(allowMultipleSelection) {