Make WordPress Core

Changeset 48232


Ignore:
Timestamp:
06/30/2020 01:14:05 PM (4 years ago)
Author:
afercia
Message:

Accessibility: Media: Add a "Copy URL" button to the attachment File URL fields.

For a number of years, various screens in the WordPress admin provided users with a readonly input field to copy the attachment file URL. Manually copying from a readonly field is an annoying task at best even for mouser users. It's a usability and accessibility issue at the same time.
These fields now have a new "Copy URL" button that is easy to use and accessible to everyone.

Props theolg, markdubois, vabrashev, sajjad67, xkon, nrqsnchz, melchoyce, audrasjb, afercia.
See #41612, #50322, #50335.
Fixes #48463.

Location:
trunk/src
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/js/_enqueues/admin/post.js

    r48168 r48232  
    55 */
    66
    7  /* global postL10n, ajaxurl, wpAjax, setPostThumbnailL10n, postboxes, pagenow, tinymce, alert, deleteUserSetting */
     7 /* global postL10n, ajaxurl, wpAjax, setPostThumbnailL10n, postboxes, pagenow, tinymce, alert, deleteUserSetting, ClipboardJS */
    88 /* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply, commentsBox */
    99 /* global WPSetThumbnailHTML, wptitlehint */
     
    298298        $timestampdiv = $('#timestampdiv'),
    299299        $postStatusSelect = $('#post-status-select'),
    300         isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false;
     300        isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false,
     301        copyAttachmentURLClipboard = new ClipboardJS( '.copy-attachment-url.edit-media' ),
     302        copyAttachmentURLSuccessTimeout,
     303        __ = wp.i18n.__;
    301304
    302305    postboxes.add_postbox_toggles(pagenow);
     
    12181221        });
    12191222    }
    1220 });
     1223
     1224    /**
     1225     * Copies the attachment URL in the Edit Media page to the clipboard.
     1226     *
     1227     * @since 5.5.0
     1228     *
     1229     * @param {MouseEvent} event A click event.
     1230     *
     1231     * @returns {void}
     1232     */
     1233    copyAttachmentURLClipboard.on( 'success', function( event ) {
     1234        var triggerElement = $( event.trigger ),
     1235            successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
     1236
     1237        // Clear the selection and move focus back to the trigger.
     1238        event.clearSelection();
     1239        // Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
     1240        triggerElement.focus();
     1241
     1242        // Show success visual feedback.
     1243        clearTimeout( copyAttachmentURLSuccessTimeout );
     1244        successElement.removeClass( 'hidden' );
     1245
     1246        // Hide success visual feedback after 3 seconds since last success.
     1247        copyAttachmentURLSuccessTimeout = setTimeout( function() {
     1248            successElement.addClass( 'hidden' );
     1249        }, 3000 );
     1250
     1251        // Handle success audible feedback.
     1252        wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
     1253    } );
     1254} );
    12211255
    12221256/**
  • trunk/src/js/media/views/attachment/details.js

    r47233 r48232  
     1/* global ClipboardJS */
    12var Attachment = wp.media.view.Attachment,
    23    l10n = wp.media.view.l10n,
    34    $ = jQuery,
    4     Details;
     5    Details,
     6    __ = wp.i18n.__;
    57
    68Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototype */{
     
    2830
    2931    /**
     32     * Copies the attachment URL to the clipboard.
     33     *
     34     * @since 5.5.0
     35     *
     36     * @param {MouseEvent} event A click event.
     37     *
     38     * @returns {void}
     39     */
     40     copyAttachmentDetailsURLClipboard: function() {
     41        var clipboard = new ClipboardJS( '.copy-attachment-url' ),
     42            successTimeout;
     43
     44        clipboard.on( 'success', function( event ) {
     45            var triggerElement = $( event.trigger ),
     46                successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
     47
     48            // Clear the selection and move focus back to the trigger.
     49            event.clearSelection();
     50            // Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
     51            triggerElement.focus();
     52
     53            // Show success visual feedback.
     54            clearTimeout( successTimeout );
     55            successElement.removeClass( 'hidden' );
     56
     57            // Hide success visual feedback after 3 seconds since last success.
     58            successTimeout = setTimeout( function() {
     59                successElement.addClass( 'hidden' );
     60            }, 3000 );
     61
     62            // Handle success audible feedback.
     63            wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
     64        } );
     65     },
     66
     67    /**
    3068     * Shows the details of an attachment.
    3169     *
     
    4482        // Call 'initialize' directly on the parent class.
    4583        Attachment.prototype.initialize.apply( this, arguments );
     84
     85        this.copyAttachmentDetailsURLClipboard();
    4686    },
    4787
  • trunk/src/wp-admin/css/media.css

    r47418 r48232  
    798798}
    799799
     800.copy-to-clipboard-container {
     801    display: flex;
     802    align-items: center;
     803    margin-top: 8px;
     804    clear: both;
     805}
     806
     807.copy-to-clipboard-container .success {
     808    margin-left: 8px;
     809}
    800810
    801811/*------------------------------------------------------------------------------
     
    12161226        max-width: none;
    12171227    }
     1228
     1229    .copy-to-clipboard-container .success {
     1230        font-size: 14px;
     1231    }
    12181232}
    12191233
  • trunk/src/wp-admin/includes/media.php

    r48199 r48232  
    32693269        <label for="attachment_url"><?php _e( 'File URL:' ); ?></label>
    32703270        <input type="text" class="widefat urlfield" readonly="readonly" name="attachment_url" id="attachment_url" value="<?php echo esc_attr( $att_url ); ?>" />
     3271        <span class="copy-to-clipboard-container">
     3272            <button type="button" class="button copy-attachment-url edit-media" data-clipboard-target="#attachment_url"><?php _e( 'Copy URL' ); ?></button>
     3273            <span class="success hidden" aria-hidden="true"><?php _e( 'Copied!' ); ?></span>
     3274        </span>
    32713275    </div>
    32723276    <div class="misc-pub-section misc-pub-filename">
  • trunk/src/wp-includes/css/buttons.css

    r47771 r48232  
    355355    }
    356356
     357    /* Copy attachment URL button in the legacy edit media page. */
     358    .wp-core-ui .copy-to-clipboard-container .copy-attachment-url {
     359        margin-bottom: 0;
     360    }
     361
    357362    #media-upload.wp-core-ui .button {
    358363        padding: 0 10px 1px;
  • trunk/src/wp-includes/css/media-views.css

    r47549 r48232  
    458458}
    459459
     460.media-sidebar .copy-to-clipboard-container,
     461.attachment-details .copy-to-clipboard-container {
     462    flex-wrap: wrap;
     463    margin-top: 10px;
     464    margin-left: calc( 35% - 1px );
     465    padding-top: 10px;
     466}
     467
     468/* Needs high specificity. */
     469.attachment-details .attachment-info .copy-to-clipboard-container {
     470    float: none;
     471}
     472
     473.media-sidebar .copy-to-clipboard-container .success,
     474.attachment-details .copy-to-clipboard-container .success {
     475    padding: 0;
     476    min-height: 0;
     477    text-align: left;
     478}
     479
    460480.compat-item label span {
    461481    text-align: right;
     
    25402560    }
    25412561
     2562    /* Needs high specificity. */
     2563    .media-sidebar .setting .copy-to-clipboard-container,
     2564    .attachment-details .attachment-info .copy-to-clipboard-container {
     2565        margin-left: 0;
     2566        padding-top: 0;
     2567    }
     2568
     2569    .media-sidebar .setting .copy-attachment-url,
     2570    .attachment-details .attachment-info .copy-attachment-url {
     2571        margin: 0 1px;
     2572    }
     2573
    25422574    .media-sidebar .setting .value,
    25432575    .attachment-details .setting .value {
     
    27132745        bottom: -54px;
    27142746    }
    2715 }
    2716 
    2717 @media screen and (max-width: 782px) {
     2747
    27182748    .mode-grid .attachments-browser .media-toolbar-primary {
    27192749        display: block;
     2750    }
     2751
     2752    .media-sidebar .copy-to-clipboard-container .success,
     2753    .attachment-details .copy-to-clipboard-container .success {
     2754        font-size: 14px;
     2755        line-height: 2.71428571;
    27202756    }
    27212757}
  • trunk/src/wp-includes/media-template.php

    r47808 r48232  
    501501                <# } #>
    502502                <span class="setting" data-setting="url">
    503                     <label for="attachment-details-two-column-copy-link" class="name"><?php _e( 'Copy Link' ); ?></label>
    504                     <input type="text" id="attachment-details-two-column-copy-link" value="{{ data.url }}" readonly />
     503                    <label for="attachment-details-two-column-copy-link" class="name"><?php _e( 'File URL:' ); ?></label>
     504                    <input type="text" class="attachment-details-copy-link" id="attachment-details-two-column-copy-link" value="{{ data.url }}" readonly />
     505                    <span class="copy-to-clipboard-container">
     506                        <button type="button" class="button button-small copy-attachment-url" data-clipboard-target="#attachment-details-two-column-copy-link"><?php _e( 'Copy URL' ); ?></button>
     507                        <span class="success hidden" aria-hidden="true"><?php _e( 'Copied!' ); ?></span>
     508                    </span>
    505509                </span>
    506510                <div class="attachment-compat"></div>
     
    688692        </span>
    689693        <span class="setting" data-setting="url">
    690             <label for="attachment-details-copy-link" class="name"><?php _e( 'Copy Link' ); ?></label>
    691             <input type="text" id="attachment-details-copy-link" value="{{ data.url }}" readonly />
     694            <label for="attachment-details-copy-link" class="name"><?php _e( 'File URL:' ); ?></label>
     695            <input type="text" class="attachment-details-copy-link" id="attachment-details-copy-link" value="{{ data.url }}" readonly />
     696            <div class="copy-to-clipboard-container">
     697                <button type="button" class="button button-small copy-attachment-url" data-clipboard-target="#attachment-details-copy-link"><?php _e( 'Copy URL' ); ?></button>
     698                <span class="success hidden" aria-hidden="true"><?php _e( 'Copied!' ); ?></span>
     699            </div>
    692700        </span>
    693701    </script>
  • trunk/src/wp-includes/script-loader.php

    r48142 r48232  
    12331233    // To enqueue media-views or media-editor, call wp_enqueue_media().
    12341234    // Both rely on numerous settings, styles, and templates to operate correctly.
    1235     $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 );
     1235    $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 );
    12361236    $scripts->set_translations( 'media-views' );
    12371237    $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
     
    12951295        );
    12961296
    1297         $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 );
     1297        $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 );
    12981298        did_action( 'init' ) && $scripts->localize(
    12991299            'post',
Note: See TracChangeset for help on using the changeset viewer.