From 92fcdc69a977837827ef897fbfa8ca79343ca636 Mon Sep 17 00:00:00 2001
From: Paul Biron <paul@sparrowhawkcomputing.com>
Date: Sat, 4 Dec 2021 09:32:12 -0700
Subject: [PATCH] Add a "Copy URL to clipboard" row action in Media >
 Library...similar to the button on the Edit Media screen.

---
 src/js/_enqueues/admin/media.js               | 36 ++++++++++++++++++-
 .../includes/class-wp-media-list-table.php    |  9 +++++
 src/wp-includes/script-loader.php             |  2 +-
 3 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/src/js/_enqueues/admin/media.js b/src/js/_enqueues/admin/media.js
index 13d46e485b..feae563816 100644
--- a/src/js/_enqueues/admin/media.js
+++ b/src/js/_enqueues/admin/media.js
@@ -141,7 +141,10 @@
 	 * @return {void}
 	 */
 	$( function() {
-		var settings, $mediaGridWrap = $( '#wp-media-grid' );
+		var settings,
+			$mediaGridWrap             = $( '#wp-media-grid' ),
+			copyAttachmentURLClipboard = new ClipboardJS( '.copy-attachment-url.media-library' ),
+			copyAttachmentURLSuccessTimeout;
 
 		// Opens a manage media frame into the grid.
 		if ( $mediaGridWrap.length && window.wp && window.wp.media ) {
@@ -205,5 +208,36 @@
 		$( '.find-box-inside' ).on( 'click', 'tr', function() {
 			$( this ).find( '.found-radio input' ).prop( 'checked', true );
 		});
+
+		/**
+		 * Handles media list copy media URL button.
+		 *
+		 * @since 6.0
+		 *
+		 * @param {MouseEvent} event A click event.
+		 * @return {void}
+		 */
+		copyAttachmentURLClipboard.on( 'success', function( event ) {
+			var triggerElement = $( event.trigger ),
+				successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
+	
+			// Clear the selection and move focus back to the trigger.
+			event.clearSelection();
+			// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
+			triggerElement.trigger( 'focus' );
+	
+			// Show success visual feedback.
+			clearTimeout( copyAttachmentURLSuccessTimeout );
+			successElement.removeClass( 'hidden' );
+	
+			// Hide success visual feedback after 3 seconds since last success and unfocus the trigger.
+			copyAttachmentURLSuccessTimeout = setTimeout( function() {
+				successElement.addClass( 'hidden' );
+				triggerElement.trigger( 'blur' );
+			}, 3000 );
+	
+			// Handle success audible feedback.
+			wp.a11y.speak( wp.i18n.__( 'The file URL has been copied to your clipboard' ) );
+		} );
 	});
 })( jQuery );
diff --git a/src/wp-admin/includes/class-wp-media-list-table.php b/src/wp-admin/includes/class-wp-media-list-table.php
index d425bccfbf..030e2ada99 100644
--- a/src/wp-admin/includes/class-wp-media-list-table.php
+++ b/src/wp-admin/includes/class-wp-media-list-table.php
@@ -806,6 +806,15 @@ class WP_Media_List_Table extends WP_List_Table {
 					esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $att_title ) ),
 					__( 'View' )
 				);
+
+				$actions['copy'] = sprintf(
+					'<span class="copy-to-clipboard-container" style="display: inline;"><button type="button" class="button-link copy-attachment-url media-library" data-clipboard-text="%s" aria-label="%s">%s</button><span class="success hidden" aria-hidden="true">%s</span></span>',
+					esc_url( wp_get_attachment_url( $post->ID ) ),
+					/* translators: %s: Attachment title. */
+					esc_attr( sprintf( __( 'Copy &#8220;%s&#8221; URL to clipboard' ), $att_title ) ),
+					__( 'Copy URL to clipboard' ),
+					__( 'Copied!' )
+				);
 			}
 		}
 
diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
index 8313088e67..3322406d8c 100644
--- a/src/wp-includes/script-loader.php
+++ b/src/wp-includes/script-loader.php
@@ -1351,7 +1351,7 @@ function wp_default_scripts( $scripts ) {
 		$scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" );
 
 		$scripts->add( 'media-grid', "/wp-includes/js/media-grid$suffix.js", array( 'media-editor' ), false, 1 );
-		$scripts->add( 'media', "/wp-admin/js/media$suffix.js", array( 'jquery' ), false, 1 );
+		$scripts->add( 'media', "/wp-admin/js/media$suffix.js", array( 'jquery', 'clipboard', 'wp-i18n', 'wp-a11y' ), false, 1 );
 		$scripts->set_translations( 'media' );
 
 		$scripts->add( 'image-edit', "/wp-admin/js/image-edit$suffix.js", array( 'jquery', 'jquery-ui-core', 'json2', 'imgareaselect', 'wp-a11y' ), false, 1 );
-- 
2.30.2.windows.1

