From d519284b5c4b4fa5d073498c0d88b77a4b6b8540 Mon Sep 17 00:00:00 2001 From: Timothy Jacobs Date: Mon, 9 Nov 2020 18:03:57 +0000 Subject: [PATCH] App Passwords: Further accessibility improvements. - Add a label to the readonly password input. - Handle focus loss after revoking app passwords. - Handle focus loss after dismissing notices. - Mark app name as `aria-required`. - Use `aria-label` for detailed revoke button text instead of `title`. - Use `-1` for `tabindex` instead of `0`. Props alexstine, afercia, sabernhardt, audrasjb, joedolson, TimothyBlynJacobs. Fixes #51580. git-svn-id: https://develop.svn.wordpress.org/trunk@49549 602fd350-edb4-49c9-b593-d223f7449a82 --- .../_enqueues/admin/application-passwords.js | 41 ++++++++++++------- src/js/_enqueues/admin/auth-app.js | 13 +++--- src/wp-admin/authorize-application.php | 21 ++++++---- src/wp-admin/css/forms.css | 6 ++- ...ss-wp-application-passwords-list-table.php | 4 +- src/wp-admin/user-edit.php | 26 ++++++------ src/wp-includes/script-loader.php | 2 +- 7 files changed, 68 insertions(+), 45 deletions(-) diff --git a/src/js/_enqueues/admin/application-passwords.js b/src/js/_enqueues/admin/application-passwords.js index 4ff58afddb..09e4434e2f 100644 --- a/src/js/_enqueues/admin/application-passwords.js +++ b/src/js/_enqueues/admin/application-passwords.js @@ -29,7 +29,7 @@ return; } - clearErrors(); + clearNotices(); $newAppPassButton.prop( 'aria-disabled', true ).addClass( 'disabled' ); var request = { @@ -90,7 +90,7 @@ $tr = $submitButton.closest( 'tr' ), uuid = $tr.data( 'uuid' ); - clearErrors(); + clearNotices(); $submitButton.prop( 'disabled', true ); wp.apiRequest( { @@ -105,7 +105,7 @@ } $tr.remove(); - wp.a11y.speak( wp.i18n.__( 'Application password revoked.' ) ); + addNotice( wp.i18n.__( 'Application password revoked.' ), 'success' ).focus(); } } ).fail( handleErrorResponse ); } ); @@ -119,7 +119,7 @@ var $submitButton = $( this ); - clearErrors(); + clearNotices(); $submitButton.prop( 'disabled', true ); wp.apiRequest( { @@ -133,17 +133,19 @@ $appPassSection.children( '.new-application-password' ).remove(); $appPassTwrapper.hide(); - wp.a11y.speak( wp.i18n.__( 'All application passwords revoked.' ) ); + addNotice( wp.i18n.__( 'All application passwords revoked.' ), 'success' ).focus(); } } ).fail( handleErrorResponse ); } ); - $( document ).on( 'click', '.new-application-password-notice .notice-dismiss', function( e ) { + $appPassSection.on( 'click', '.notice-dismiss', function( e ) { e.preventDefault(); var $el = $( this ).parent(); + $el.removeAttr( 'role' ); $el.fadeTo( 100, 0, function () { $el.slideUp( 100, function () { $el.remove(); + $newAppPassField.focus(); } ); } ); } ); @@ -169,31 +171,42 @@ errorMessage = xhr.responseJSON.message; } - addError( errorMessage ); + addNotice( errorMessage, 'error' ); } /** - * Displays an error message in the Application Passwords section. + * Displays a message in the Application Passwords section. * * @since 5.6.0 * - * @param {string} message The error message to display. + * @param {string} message The message to display. + * @param {string} type The notice type. Either 'success' or 'error'. + * @returns {jQuery} The notice element. */ - function addError( message ) { + function addNotice( message, type ) { var $notice = $( '
' ) .attr( 'role', 'alert' ) - .addClass( 'notice notice-error' ) - .append( $( '

' ).text( message ) ); + .attr( 'tabindex', '-1' ) + .addClass( 'is-dismissible notice notice-' + type ) + .append( $( '

' ).text( message ) ) + .append( + $( '' ) + .attr( 'type', 'button' ) + .addClass( 'notice-dismiss' ) + .append( $( '' ).addClass( 'screen-reader-text' ).text( wp.i18n.__( 'Dismiss this notice.' ) ) ) + ); $newAppPassForm.after( $notice ); + + return $notice; } /** - * Clears error messages from the Application Passwords section. + * Clears notice messages from the Application Passwords section. * * @since 5.6.0 */ - function clearErrors() { + function clearNotices() { $( '.notice', $appPassSection ).remove(); } }( jQuery ) ); diff --git a/src/js/_enqueues/admin/auth-app.js b/src/js/_enqueues/admin/auth-app.js index bd7fd5ac1a..8401da8c6f 100644 --- a/src/js/_enqueues/admin/auth-app.js +++ b/src/js/_enqueues/admin/auth-app.js @@ -83,15 +83,16 @@ window.location = url; } else { message = wp.i18n.sprintf( - wp.i18n.__( 'Your new password for %1$s is: %2$s.' ), - '', - '' - ); + /* translators: %s: Application name */ + '', + '' + ) + ' '; $notice = $( '
' ) .attr( 'role', 'alert' ) - .attr( 'tabindex', 0 ) + .attr( 'tabindex', -1 ) .addClass( 'notice notice-success notice-alt' ) - .append( $( '

' ).addClass( 'application-password-display' ).html( message ) ); + .append( $( '

' ).addClass( 'application-password-display' ).html( message ) ) + .append( '

' + wp.i18n.__( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ) + '

' ); // We're using .text() to write the variables to avoid any chance of XSS. $( 'strong', $notice ).text( name ); diff --git a/src/wp-admin/authorize-application.php b/src/wp-admin/authorize-application.php index ea09b0486a..ebf3d862d7 100644 --- a/src/wp-admin/authorize-application.php +++ b/src/wp-admin/authorize-application.php @@ -171,15 +171,18 @@ require_once ABSPATH . 'wp-admin/admin-header.php';

- ' . esc_html( $app_name ) . '', - sprintf( '', esc_attr( WP_Application_Passwords::chunk_password( $new_password ) ) ) - ); - ?> + +

+

- + sprintf( __( 'Revoke "%s"' ), $item['name'] ), + 'aria-label' => sprintf( __( 'Revoke "%s"' ), $item['name'] ), ) ); } @@ -234,7 +234,7 @@ class WP_Application_Passwords_List_Table extends WP_List_Table { break; case 'revoke': printf( - '', + '', esc_attr( __( 'Revoke' ) ), /* translators: %s: the application password's given name. */ esc_attr( sprintf( __( 'Revoke "%s"' ), '{{ data.name }}' ) ) diff --git a/src/wp-admin/user-edit.php b/src/wp-admin/user-edit.php index 7dc87869b4..70be9ffc05 100644 --- a/src/wp-admin/user-edit.php +++ b/src/wp-admin/user-edit.php @@ -742,7 +742,7 @@ endif;
- +
- +
@@ -857,18 +857,20 @@ endif;