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
This commit is contained in:
Timothy Jacobs
2020-11-09 18:03:57 +00:00
parent 63db886240
commit d519284b5c
7 changed files with 68 additions and 45 deletions

View File

@@ -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 = $( '<div></div>' )
.attr( 'role', 'alert' )
.addClass( 'notice notice-error' )
.append( $( '<p></p>' ).text( message ) );
.attr( 'tabindex', '-1' )
.addClass( 'is-dismissible notice notice-' + type )
.append( $( '<p></p>' ).text( message ) )
.append(
$( '<button></button>' )
.attr( 'type', 'button' )
.addClass( 'notice-dismiss' )
.append( $( '<span></span>' ).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 ) );

View File

@@ -83,15 +83,16 @@
window.location = url;
} else {
message = wp.i18n.sprintf(
wp.i18n.__( 'Your new password for %1$s is: %2$s.' ),
'<strong></strong>',
'<input type="text" class="code" readonly="readonly" value="" />'
);
/* translators: %s: Application name */
'<label for="new-application-password-value">' + wp.i18n.__( 'Your new password for %s is:' ) + '</label>',
'<strong></strong>'
) + ' <input id="new-application-password-value" type="text" class="code" readonly="readonly" value="" />';
$notice = $( '<div></div>' )
.attr( 'role', 'alert' )
.attr( 'tabindex', 0 )
.attr( 'tabindex', -1 )
.addClass( 'notice notice-success notice-alt' )
.append( $( '<p></p>' ).addClass( 'application-password-display' ).html( message ) );
.append( $( '<p></p>' ).addClass( 'application-password-display' ).html( message ) )
.append( '<p>' + wp.i18n.__( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ) + '</p>' );
// We're using .text() to write the variables to avoid any chance of XSS.
$( 'strong', $notice ).text( name );

View File

@@ -171,15 +171,18 @@ require_once ABSPATH . 'wp-admin/admin-header.php';
<?php if ( $new_password ) : ?>
<div class="notice notice-success notice-alt below-h2">
<p class="application-password-display">
<?php
printf(
/* translators: 1: Application name, 2: Generated password. */
__( 'Your new password for %1$s is %2$s.' ),
'<strong>' . esc_html( $app_name ) . '</strong>',
sprintf( '<input type="text" class="code" readonly="readonly" value="%s" />', esc_attr( WP_Application_Passwords::chunk_password( $new_password ) ) )
);
?>
<label for="new-application-password-value">
<?php
printf(
/* translators: %s: Application name */
esc_html__( 'Your new password for %s is:' ),
'<strong>' . esc_html( $app_name ) . '</strong>'
);
?>
</label>
<input id="new-application-password-value" type="text" class="code" readonly="readonly" value="<?php esc_attr( WP_Application_Passwords::chunk_password( $new_password ) ); ?>" />
</p>
<p><?php _e( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ); ?></p>
</div>
<?php
@@ -204,7 +207,7 @@ require_once ABSPATH . 'wp-admin/admin-header.php';
<div class="form-field">
<label for="app_name"><?php _e( 'New Application Password Name' ); ?></label>
<input type="text" id="app_name" name="app_name" value="<?php echo esc_attr( $app_name ); ?>" placeholder="<?php esc_attr_e( 'WordPress App on My Phone' ); ?>" required aria-required="true" />
<input type="text" id="app_name" name="app_name" value="<?php echo esc_attr( $app_name ); ?>" placeholder="<?php esc_attr_e( 'WordPress App on My Phone' ); ?>" required />
</div>
<?php

View File

@@ -864,7 +864,7 @@ table.form-table td .updated p {
padding-bottom: 0;
}
.new-application-password-notice.notice {
#application-passwords-section .notice {
margin-top: 20px;
margin-bottom: 0;
}
@@ -873,6 +873,10 @@ table.form-table td .updated p {
width: 19em;
}
.auth-app-card.card {
max-width: 768px;
}
/*------------------------------------------------------------------------------
19.0 - Tools
------------------------------------------------------------------------------*/

View File

@@ -117,7 +117,7 @@ class WP_Application_Passwords_List_Table extends WP_List_Table {
false,
array(
/* translators: %s: the application password's given name. */
'title' => 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(
'<input type="submit" class="button delete" value="%1$s" title="%2$s">',
'<input type="submit" class="button delete" value="%1$s" aria-label="%2$s">',
esc_attr( __( 'Revoke' ) ),
/* translators: %s: the application password's given name. */
esc_attr( sprintf( __( 'Revoke "%s"' ), '{{ data.name }}' ) )

View File

@@ -742,7 +742,7 @@ endif;
<div class="create-application-password form-wrap">
<div class="form-field">
<label for="new_application_password_name"><?php _e( 'New Application Password Name' ); ?></label>
<input type="text" size="30" id="new_application_password_name" name="new_application_password_name" placeholder="<?php esc_attr_e( 'WordPress App on My Phone' ); ?>" class="input" />
<input type="text" size="30" id="new_application_password_name" name="new_application_password_name" placeholder="<?php esc_attr_e( 'WordPress App on My Phone' ); ?>" class="input" aria-required="true" aria-describedby="<?php esc_attr_e( 'Required to create an Application Password, but not to update the user.' ); ?>" />
</div>
<?php
@@ -756,7 +756,7 @@ endif;
do_action( 'wp_create_application_password_form', $profileuser );
?>
<?php submit_button( __( 'Add New' ), 'secondary', 'do_new_application_password' ); ?>
<?php submit_button( __( 'Add New Application Password' ), 'secondary', 'do_new_application_password' ); ?>
</div>
<div class="application-passwords-list-table-wrapper">
@@ -857,18 +857,20 @@ endif;
<?php if ( isset( $application_passwords_list_table ) ) : ?>
<script type="text/html" id="tmpl-new-application-password">
<div class="notice notice-success is-dismissible new-application-password-notice" role="alert" tabindex="0">
<div class="notice notice-success is-dismissible new-application-password-notice" role="alert" tabindex="-1">
<p class="application-password-display">
<?php
printf(
/* translators: 1: Application name, 2: Generated password. */
esc_html__( 'Your new password for %1$s is: %2$s' ),
'<strong>{{ data.name }}</strong>',
'<input type="text" class="code" readonly="readonly" value="{{ data.password }}" />'
);
?>
<label for="new-application-password-value">
<?php
printf(
/* translators: %s: Application name */
__( 'Your new password for %s is:' ),
'<strong>{{ data.name }}</strong>'
);
?>
</label>
<input id="new-application-password-value" type="text" class="code" readonly="readonly" value="{{ data.password }}" />
</p>
<p><?php esc_attr_e( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ); ?></p>
<p><?php _e( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ); ?></p>
<button type="button" class="notice-dismiss">
<span class="screen-reader-text"><?php _e( 'Dismiss this notice.' ); ?></span>
</button>

View File

@@ -1067,7 +1067,7 @@ function wp_default_scripts( $scripts ) {
);
$scripts->set_translations( 'password-strength-meter' );
$scripts->add( 'application-passwords', "/wp-admin/js/application-passwords$suffix.js", array( 'jquery', 'wp-util', 'wp-api-request', 'wp-date', 'wp-i18n', 'wp-hooks', 'wp-a11y' ), false, 1 );
$scripts->add( 'application-passwords', "/wp-admin/js/application-passwords$suffix.js", array( 'jquery', 'wp-util', 'wp-api-request', 'wp-date', 'wp-i18n', 'wp-hooks' ), false, 1 );
$scripts->set_translations( 'application-passwords' );
$scripts->add( 'auth-app', "/wp-admin/js/auth-app$suffix.js", array( 'jquery', 'wp-api-request', 'wp-i18n', 'wp-hooks' ), false, 1 );