diff --git a/src/js/_enqueues/admin/post.js b/src/js/_enqueues/admin/post.js index f6da847f9c..127757ede5 100644 --- a/src/js/_enqueues/admin/post.js +++ b/src/js/_enqueues/admin/post.js @@ -4,7 +4,7 @@ * @output wp-admin/js/post.js */ - /* global postL10n, ajaxurl, wpAjax, setPostThumbnailL10n, postboxes, pagenow, tinymce, alert, deleteUserSetting */ + /* global postL10n, ajaxurl, wpAjax, setPostThumbnailL10n, postboxes, pagenow, tinymce, alert, deleteUserSetting, ClipboardJS */ /* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply, commentsBox */ /* global WPSetThumbnailHTML, wptitlehint */ @@ -297,7 +297,10 @@ jQuery(document).ready( function($) { $postVisibilitySelect = $('#post-visibility-select'), $timestampdiv = $('#timestampdiv'), $postStatusSelect = $('#post-status-select'), - isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false; + isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false, + copyAttachmentURLClipboard = new ClipboardJS( '.copy-attachment-url.edit-media' ), + copyAttachmentURLSuccessTimeout, + __ = wp.i18n.__; postboxes.add_postbox_toggles(pagenow); @@ -1217,7 +1220,38 @@ jQuery(document).ready( function($) { window.history.replaceState( null, null, location ); }); } -}); + + /** + * Copies the attachment URL in the Edit Media page to the clipboard. + * + * @since 5.5.0 + * + * @param {MouseEvent} event A click event. + * + * @returns {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.focus(); + + // Show success visual feedback. + clearTimeout( copyAttachmentURLSuccessTimeout ); + successElement.removeClass( 'hidden' ); + + // Hide success visual feedback after 3 seconds since last success. + copyAttachmentURLSuccessTimeout = setTimeout( function() { + successElement.addClass( 'hidden' ); + }, 3000 ); + + // Handle success audible feedback. + wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) ); + } ); +} ); /** * TinyMCE word count display diff --git a/src/js/media/views/attachment/details.js b/src/js/media/views/attachment/details.js index b9cf51445e..f6c2726351 100644 --- a/src/js/media/views/attachment/details.js +++ b/src/js/media/views/attachment/details.js @@ -1,7 +1,9 @@ +/* global ClipboardJS */ var Attachment = wp.media.view.Attachment, l10n = wp.media.view.l10n, $ = jQuery, - Details; + Details, + __ = wp.i18n.__; Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototype */{ tagName: 'div', @@ -26,6 +28,42 @@ Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototyp 'keydown': 'toggleSelectionHandler' }, + /** + * Copies the attachment URL to the clipboard. + * + * @since 5.5.0 + * + * @param {MouseEvent} event A click event. + * + * @returns {void} + */ + copyAttachmentDetailsURLClipboard: function() { + var clipboard = new ClipboardJS( '.copy-attachment-url' ), + successTimeout; + + clipboard.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.focus(); + + // Show success visual feedback. + clearTimeout( successTimeout ); + successElement.removeClass( 'hidden' ); + + // Hide success visual feedback after 3 seconds since last success. + successTimeout = setTimeout( function() { + successElement.addClass( 'hidden' ); + }, 3000 ); + + // Handle success audible feedback. + wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) ); + } ); + }, + /** * Shows the details of an attachment. * @@ -43,6 +81,8 @@ Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototyp // Call 'initialize' directly on the parent class. Attachment.prototype.initialize.apply( this, arguments ); + + this.copyAttachmentDetailsURLClipboard(); }, /** diff --git a/src/wp-admin/css/media.css b/src/wp-admin/css/media.css index 3857baaf01..59fd90477a 100644 --- a/src/wp-admin/css/media.css +++ b/src/wp-admin/css/media.css @@ -797,6 +797,16 @@ border color while dragging a file over the uploader drop area */ text-decoration: none; } +.copy-to-clipboard-container { + display: flex; + align-items: center; + margin-top: 8px; + clear: both; +} + +.copy-to-clipboard-container .success { + margin-left: 8px; +} /*------------------------------------------------------------------------------ 14.2 - Image Editor @@ -1215,6 +1225,10 @@ audio, video { width: auto; max-width: none; } + + .copy-to-clipboard-container .success { + font-size: 14px; + } } /** diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index 24f65818e4..622b24b214 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -3268,6 +3268,10 @@ function attachment_submitbox_metadata() {
+ + + +
diff --git a/src/wp-includes/css/buttons.css b/src/wp-includes/css/buttons.css index c20927ee64..f955c9f9f5 100644 --- a/src/wp-includes/css/buttons.css +++ b/src/wp-includes/css/buttons.css @@ -354,6 +354,11 @@ TABLE OF CONTENTS: margin-bottom: 4px; } + /* Copy attachment URL button in the legacy edit media page. */ + .wp-core-ui .copy-to-clipboard-container .copy-attachment-url { + margin-bottom: 0; + } + #media-upload.wp-core-ui .button { padding: 0 10px 1px; min-height: 24px; diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css index d782905798..00fb52b519 100644 --- a/src/wp-includes/css/media-views.css +++ b/src/wp-includes/css/media-views.css @@ -457,6 +457,26 @@ font-size: 12px; } +.media-sidebar .copy-to-clipboard-container, +.attachment-details .copy-to-clipboard-container { + flex-wrap: wrap; + margin-top: 10px; + margin-left: calc( 35% - 1px ); + padding-top: 10px; +} + +/* Needs high specificity. */ +.attachment-details .attachment-info .copy-to-clipboard-container { + float: none; +} + +.media-sidebar .copy-to-clipboard-container .success, +.attachment-details .copy-to-clipboard-container .success { + padding: 0; + min-height: 0; + text-align: left; +} + .compat-item label span { text-align: right; } @@ -2539,6 +2559,18 @@ padding: 8px 2px 2px; } + /* Needs high specificity. */ + .media-sidebar .setting .copy-to-clipboard-container, + .attachment-details .attachment-info .copy-to-clipboard-container { + margin-left: 0; + padding-top: 0; + } + + .media-sidebar .setting .copy-attachment-url, + .attachment-details .attachment-info .copy-attachment-url { + margin: 0 1px; + } + .media-sidebar .setting .value, .attachment-details .setting .value { float: none; @@ -2712,12 +2744,16 @@ .media-frame-toolbar .media-toolbar { bottom: -54px; } -} -@media screen and (max-width: 782px) { .mode-grid .attachments-browser .media-toolbar-primary { display: block; } + + .media-sidebar .copy-to-clipboard-container .success, + .attachment-details .copy-to-clipboard-container .success { + font-size: 14px; + line-height: 2.71428571; + } } /* Responsive on portrait and landscape */ diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php index 7742f73883..43053edfa9 100644 --- a/src/wp-includes/media-template.php +++ b/src/wp-includes/media-template.php @@ -500,8 +500,12 @@ function wp_print_media_templates() { <# } #> - - + + + + + +
@@ -687,8 +691,12 @@ function wp_print_media_templates() { - - + + +
+ + +
diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index ec7290cea3..3083692405 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -1232,7 +1232,7 @@ function wp_default_scripts( $scripts ) { // To enqueue media-views or media-editor, call wp_enqueue_media(). // Both rely on numerous settings, styles, and templates to operate correctly. - $scripts->add( 'media-views', "/wp-includes/js/media-views$suffix.js", array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement', 'wp-api-request', 'wp-a11y', 'wp-i18n' ), false, 1 ); + $scripts->add( 'media-views', "/wp-includes/js/media-views$suffix.js", array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement', 'wp-api-request', 'wp-a11y', 'wp-i18n', 'clipboard' ), false, 1 ); $scripts->set_translations( 'media-views' ); $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 ); $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor' ), false, 1 ); @@ -1294,7 +1294,7 @@ function wp_default_scripts( $scripts ) { ) ); - $scripts->add( 'post', "/wp-admin/js/post$suffix.js", array( 'suggest', 'wp-lists', 'postbox', 'tags-box', 'underscore', 'word-count', 'wp-a11y', 'wp-sanitize' ), false, 1 ); + $scripts->add( 'post', "/wp-admin/js/post$suffix.js", array( 'suggest', 'wp-lists', 'postbox', 'tags-box', 'underscore', 'word-count', 'wp-a11y', 'wp-sanitize', 'clipboard', 'wp-i18n' ), false, 1 ); did_action( 'init' ) && $scripts->localize( 'post', 'postL10n',