Accessibility: improve the "URL" and "Alt text" fields in the media modals.

Many users found the attachment URL field confusing: it says "URL" so it may appear like a field meant to paste a URL into.
Also, the Alt text field is the most important one in terms of content, while the Title field needs to be de-emphasized.

- changes the URL field label to "Copy link"
- moves the alt text field to the top as first field 
- avoids to set initial focus on the alt text field 
- adds an explanatory text with a link pointing to the W3C "alt decision tree" tutorial 
- adds `aria-describedby` to target the explanatory text
- adjusts the CSS accordingly
- updates the QUnit index.html file

Props melchoyce, audrasjb, afercia.
Fixes #41612.


git-svn-id: https://develop.svn.wordpress.org/trunk@44900 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Andrea Fercia 2019-03-15 10:42:35 +00:00
parent d52e37ea5e
commit 026abd4bc6
4 changed files with 125 additions and 88 deletions

View File

@ -42,23 +42,10 @@ Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototyp
rerenderOnModelChange: false
});
this.on( 'ready', this.initialFocus );
// Call 'initialize' directly on the parent class.
Attachment.prototype.initialize.apply( this, arguments );
},
initialFocus: function() {
if ( ! wp.media.isTouchDevice ) {
/*
Previously focused the first ':input' (the readonly URL text field).
Since the first ':input' is now a button (delete/trash): when pressing
spacebar on an attachment, Firefox fires deleteAttachment/trashAttachment
as soon as focus is moved. Explicitly target the first text field for now.
@todo change initial focus logic, also for accessibility.
*/
this.$( 'input[type="text"]' ).eq( 0 ).focus();
}
},
/**
* @param {Object} event
*/

View File

@ -431,7 +431,8 @@
.attachment-details .setting input[type="tel"],
.attachment-details .setting input[type="url"],
.attachment-details .setting textarea,
.attachment-details .setting .value {
.attachment-details .setting .value,
.attachment-details .setting + .description {
box-sizing: border-box;
margin: 1px;
width: 65%;
@ -439,11 +440,18 @@
}
.media-sidebar .setting .value,
.attachment-details .setting .value {
.attachment-details .setting .value,
.attachment-details .setting + .description {
margin: 0 1px;
text-align: left;
}
.attachment-details .setting + .description {
font-size: 12px;
font-style: normal;
margin-bottom: 0.5em;
}
.media-sidebar .setting textarea,
.attachment-details .setting textarea,
.compat-item .field textarea {
@ -2040,6 +2048,15 @@
clear: both;
}
.media-embed .setting.has-description {
margin-bottom: 5px;
}
.media-embed .description {
clear: both;
font-style: normal;
}
.image-details .embed-media-settings .setting {
float: none;
width: auto;
@ -2069,11 +2086,17 @@
.image-details .embed-media-settings .setting input.link-to-custom,
.image-details .embed-media-settings .link-target,
.image-details .embed-media-settings .custom-size {
.image-details .embed-media-settings .custom-size,
.image-details .description {
margin-left: 27%;
width: 70%;
}
.image-details .description {
font-style: normal;
margin-top: 0;
}
.image-details .embed-media-settings .link-target {
margin-top: 24px;
}

View File

@ -161,6 +161,18 @@ function wp_print_media_templates() {
if ( $is_IE && strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 7' ) !== false ) {
$class .= ' ie7';
}
$alt_text_description = sprintf(
/* translators: 1: link start tag, 2: accessibility text, 3: link end tag */
__( 'Describe %1$sthe purpose of the image%2$s%3$s. Leave empty if the image is purely decorative.' ),
'<a href="' . esc_url( 'https://www.w3.org/WAI/tutorials/images/decision-tree' ) . '" target="_blank" rel="noopener noreferrer">',
sprintf(
'<span class="screen-reader-text"> %s</span>',
/* translators: accessibility text */
__( '(opens in a new tab)' )
),
'</a>'
);
?>
<!--[if lte IE 8]>
<style>
@ -404,11 +416,14 @@ function wp_print_media_templates() {
</div>
<div class="settings">
<label class="setting" data-setting="url">
<span class="name"><?php _e( 'URL' ); ?></span>
<input type="text" value="{{ data.url }}" readonly />
</label>
<# var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; #>
<# if ( 'image' === data.type ) { #>
<label class="setting" data-setting="alt">
<span class="name"><?php _e( 'Alternative Text' ); ?></span>
<input type="text" value="{{ data.alt }}" aria-describedby="alt-text-description" {{ maybeReadOnly }} />
</label>
<p class="description" id="alt-text-description"><?php echo $alt_text_description; ?></p>
<# } #>
<?php if ( post_type_supports( 'attachment', 'title' ) ) : ?>
<label class="setting" data-setting="title">
<span class="name"><?php _e( 'Title' ); ?></span>
@ -432,12 +447,6 @@ function wp_print_media_templates() {
<span class="name"><?php _e( 'Caption' ); ?></span>
<textarea {{ maybeReadOnly }}>{{ data.caption }}</textarea>
</label>
<# if ( 'image' === data.type ) { #>
<label class="setting" data-setting="alt">
<span class="name"><?php _e( 'Alt Text' ); ?></span>
<input type="text" value="{{ data.alt }}" {{ maybeReadOnly }} />
</label>
<# } #>
<label class="setting" data-setting="description">
<span class="name"><?php _e( 'Description' ); ?></span>
<textarea {{ maybeReadOnly }}>{{ data.description }}</textarea>
@ -456,6 +465,10 @@ function wp_print_media_templates() {
<# } #>
</div>
<# } #>
<label class="setting" data-setting="url">
<span class="name"><?php _e( 'Copy Link' ); ?></span>
<input type="text" value="{{ data.url }}" readonly />
</label>
<div class="attachment-compat"></div>
</div>
@ -595,11 +608,14 @@ function wp_print_media_templates() {
</div>
</div>
<label class="setting" data-setting="url">
<span class="name"><?php _e( 'URL' ); ?></span>
<input type="text" value="{{ data.url }}" readonly />
</label>
<# var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; #>
<# if ( 'image' === data.type ) { #>
<label class="setting" data-setting="alt">
<span class="name"><?php _e( 'Alt Text' ); ?></span>
<input type="text" value="{{ data.alt }}" aria-describedby="alt-text-description" {{ maybeReadOnly }} />
</label>
<p class="description" id="alt-text-description"><?php echo $alt_text_description; ?></p>
<# } #>
<?php if ( post_type_supports( 'attachment', 'title' ) ) : ?>
<label class="setting" data-setting="title">
<span class="name"><?php _e( 'Title' ); ?></span>
@ -623,16 +639,14 @@ function wp_print_media_templates() {
<span class="name"><?php _e( 'Caption' ); ?></span>
<textarea {{ maybeReadOnly }}>{{ data.caption }}</textarea>
</label>
<# if ( 'image' === data.type ) { #>
<label class="setting" data-setting="alt">
<span class="name"><?php _e( 'Alt Text' ); ?></span>
<input type="text" value="{{ data.alt }}" {{ maybeReadOnly }} />
</label>
<# } #>
<label class="setting" data-setting="description">
<span class="name"><?php _e( 'Description' ); ?></span>
<textarea {{ maybeReadOnly }}>{{ data.description }}</textarea>
</label>
<label class="setting" data-setting="url">
<span class="name"><?php _e( 'Copy Link' ); ?></span>
<input type="text" value="{{ data.url }}" readonly />
</label>
</script>
<script type="text/html" id="tmpl-media-selection">
@ -882,6 +896,12 @@ function wp_print_media_templates() {
<img src="{{ data.model.url }}" draggable="false" alt="" />
</div>
<label class="setting alt-text has-description">
<span><?php _e( 'Alternative Text' ); ?></span>
<input type="text" data-setting="alt" aria-describedby="alt-text-description" />
</label>
<p class="description" id="alt-text-description"><?php echo $alt_text_description; ?></p>
<?php
/** This filter is documented in wp-admin/includes/media.php */
if ( ! apply_filters( 'disable_captions', '' ) ) :
@ -892,11 +912,6 @@ function wp_print_media_templates() {
</label>
<?php endif; ?>
<label class="setting alt-text">
<span><?php _e( 'Alt Text' ); ?></span>
<input type="text" data-setting="alt" />
</label>
<div class="setting align">
<span><?php _e( 'Align' ); ?></span>
<div class="button-group button-large" data-setting="align">
@ -948,6 +963,12 @@ function wp_print_media_templates() {
</div>
</div>
<div class="column-settings">
<label class="setting alt-text has-description">
<span><?php _e( 'Alternative Text' ); ?></span>
<input type="text" data-setting="alt" value="{{ data.model.alt }}" aria-describedby="alt-text-description" />
</label>
<p class="description" id="alt-text-description"><?php echo $alt_text_description; ?></p>
<?php
/** This filter is documented in wp-admin/includes/media.php */
if ( ! apply_filters( 'disable_captions', '' ) ) :
@ -958,11 +979,6 @@ function wp_print_media_templates() {
</label>
<?php endif; ?>
<label class="setting alt-text">
<span><?php _e( 'Alternative Text' ); ?></span>
<input type="text" data-setting="alt" value="{{ data.model.alt }}" />
</label>
<h2><?php _e( 'Display Settings' ); ?></h2>
<div class="setting align">
<span><?php _e( 'Align' ); ?></span>

View File

@ -1118,12 +1118,16 @@
<div class="file-size"><strong>File size:</strong> {{ data.filesizeHumanReadable }}</div>
<# if ( 'image' === data.type && ! data.uploading ) { #>
<# if ( data.width && data.height ) { #>
<div class="dimensions"><strong>Dimensions:</strong> {{ data.width }} &times; {{ data.height }}</div>
<div class="dimensions"><strong>Dimensions:</strong>
{{ data.width }} by {{ data.height }} pixels </div>
<# } #>
<# } #>
<# if ( data.fileLength ) { #>
<div class="file-length"><strong>Length:</strong> {{ data.fileLength }}</div>
<# if ( data.fileLength && data.fileLengthHumanReadable ) { #>
<div class="file-length"><strong>Length:</strong>
<span aria-hidden="true">{{ data.fileLength }}</span>
<span class="screen-reader-text">{{ data.fileLengthHumanReadable }}</span>
</div>
<# } #>
<# if ( 'audio' === data.type && data.meta.bitrate ) { #>
@ -1143,11 +1147,14 @@
</div>
<div class="settings">
<label class="setting" data-setting="url">
<span class="name">URL</span>
<input type="text" value="{{ data.url }}" readonly />
</label>
<# var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; #>
<# if ( 'image' === data.type ) { #>
<label class="setting" data-setting="alt">
<span class="name">Alternative Text</span>
<input type="text" value="{{ data.alt }}" aria-describedby="alt-text-description" {{ maybeReadOnly }} />
</label>
<p class="description" id="alt-text-description">Describe <a href="https://www.w3.org/WAI/tutorials/images/decision-tree" target="_blank" rel="noopener noreferrer">the purpose of the image<span class="screen-reader-text"> (opens in a new tab)</span></a>. Leave empty if the image is purely decorative.</p>
<# } #>
<label class="setting" data-setting="title">
<span class="name">Title</span>
<input type="text" value="{{ data.title }}" {{ maybeReadOnly }} />
@ -1166,37 +1173,35 @@
<span class="name">Caption</span>
<textarea {{ maybeReadOnly }}>{{ data.caption }}</textarea>
</label>
<# if ( 'image' === data.type ) { #>
<label class="setting" data-setting="alt">
<span class="name">Alt Text</span>
<input type="text" value="{{ data.alt }}" {{ maybeReadOnly }} />
</label>
<# } #>
<label class="setting" data-setting="description">
<span class="name">Description</span>
<textarea {{ maybeReadOnly }}>{{ data.description }}</textarea>
</label>
<label class="setting">
<div class="setting">
<span class="name">Uploaded By</span>
<span class="value">{{ data.authorName }}</span>
</label>
</div>
<# if ( data.uploadedToTitle ) { #>
<label class="setting">
<div class="setting">
<span class="name">Uploaded To</span>
<# if ( data.uploadedToLink ) { #>
<span class="value"><a href="{{ data.uploadedToLink }}">{{ data.uploadedToTitle }}</a></span>
<# } else { #>
<span class="value">{{ data.uploadedToTitle }}</span>
<# } #>
</label>
</div>
<# } #>
<label class="setting" data-setting="url">
<span class="name">Copy Link</span>
<input type="text" value="{{ data.url }}" readonly />
</label>
<div class="attachment-compat"></div>
</div>
<div class="actions">
<a class="view-attachment" href="{{ data.link }}">View attachment page</a>
<# if ( data.can.save ) { #> |
<a href="post.php?post={{ data.id }}&action=edit">Edit more details</a>
<a href="{{ data.editLink }}">Edit more details</a>
<# } #>
<# if ( ! data.uploading && data.can.remove ) { #> |
<button type="button" class="button-link delete-attachment">Delete Permanently</button>
@ -1280,7 +1285,8 @@
<div class="file-size">{{ data.filesizeHumanReadable }}</div>
<# if ( 'image' === data.type && ! data.uploading ) { #>
<# if ( data.width && data.height ) { #>
<div class="dimensions">{{ data.width }} &times; {{ data.height }}</div>
<div class="dimensions">
{{ data.width }} by {{ data.height }} pixels </div>
<# } #>
<# if ( data.can.save && data.sizes ) { #>
@ -1288,8 +1294,10 @@
<# } #>
<# } #>
<# if ( data.fileLength ) { #>
<div class="file-length">Length: {{ data.fileLength }}</div>
<# if ( data.fileLength && data.fileLengthHumanReadable ) { #>
<div class="file-length">Length: <span aria-hidden="true">{{ data.fileLength }}</span>
<span class="screen-reader-text">{{ data.fileLengthHumanReadable }}</span>
</div>
<# } #>
<# if ( ! data.uploading && data.can.remove ) { #>
@ -1304,11 +1312,14 @@
</div>
</div>
<label class="setting" data-setting="url">
<span class="name">URL</span>
<input type="text" value="{{ data.url }}" readonly />
</label>
<# var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; #>
<# if ( 'image' === data.type ) { #>
<label class="setting" data-setting="alt">
<span class="name">Alt Text</span>
<input type="text" value="{{ data.alt }}" aria-describedby="alt-text-description" {{ maybeReadOnly }} />
</label>
<p class="description" id="alt-text-description">Describe <a href="https://www.w3.org/WAI/tutorials/images/decision-tree" target="_blank" rel="noopener noreferrer">the purpose of the image<span class="screen-reader-text"> (opens in a new tab)</span></a>. Leave empty if the image is purely decorative.</p>
<# } #>
<label class="setting" data-setting="title">
<span class="name">Title</span>
<input type="text" value="{{ data.title }}" {{ maybeReadOnly }} />
@ -1327,16 +1338,14 @@
<span class="name">Caption</span>
<textarea {{ maybeReadOnly }}>{{ data.caption }}</textarea>
</label>
<# if ( 'image' === data.type ) { #>
<label class="setting" data-setting="alt">
<span class="name">Alt Text</span>
<input type="text" value="{{ data.alt }}" {{ maybeReadOnly }} />
</label>
<# } #>
<label class="setting" data-setting="description">
<span class="name">Description</span>
<textarea {{ maybeReadOnly }}>{{ data.description }}</textarea>
</label>
<label class="setting" data-setting="url">
<span class="name">Copy Link</span>
<input type="text" value="{{ data.url }}" readonly />
</label>
</script>
<script type="text/html" id="tmpl-media-selection">
@ -1597,16 +1606,17 @@
<img src="{{ data.model.url }}" draggable="false" alt="" />
</div>
<label class="setting alt-text has-description">
<span>Alternative Text</span>
<input type="text" data-setting="alt" aria-describedby="alt-text-description" />
</label>
<p class="description" id="alt-text-description">Describe <a href="https://www.w3.org/WAI/tutorials/images/decision-tree" target="_blank" rel="noopener noreferrer">the purpose of the image<span class="screen-reader-text"> (opens in a new tab)</span></a>. Leave empty if the image is purely decorative.</p>
<label class="setting caption">
<span>Caption</span>
<textarea data-setting="caption" />
</label>
<label class="setting alt-text">
<span>Alt Text</span>
<input type="text" data-setting="alt" />
</label>
<div class="setting align">
<span>Align</span>
<div class="button-group button-large" data-setting="align">
@ -1651,16 +1661,17 @@
</div>
</div>
<div class="column-settings">
<label class="setting alt-text has-description">
<span>Alternative Text</span>
<input type="text" data-setting="alt" value="{{ data.model.alt }}" aria-describedby="alt-text-description" />
</label>
<p class="description" id="alt-text-description">Describe <a href="https://www.w3.org/WAI/tutorials/images/decision-tree" target="_blank" rel="noopener noreferrer">the purpose of the image<span class="screen-reader-text"> (opens in a new tab)</span></a>. Leave empty if the image is purely decorative.</p>
<label class="setting caption">
<span>Caption</span>
<textarea data-setting="caption">{{ data.model.caption }}</textarea>
</label>
<label class="setting alt-text">
<span>Alternative Text</span>
<input type="text" data-setting="alt" value="{{ data.model.alt }}" />
</label>
<h2>Display Settings</h2>
<div class="setting align">
<span>Align</span>
@ -1761,7 +1772,7 @@
</div>
<label class="setting link-rel">
<span>Link Rel</span>
<input type="text" data-setting="linkRel" value="{{ data.model.linkClassName }}" />
<input type="text" data-setting="linkRel" value="{{ data.model.linkRel }}" />
</label>
<label class="setting link-class-name">
<span>Link CSS Class</span>