Skip to content
This repository has been archived by the owner on Aug 24, 2018. It is now read-only.

Fix accessibility issues with image widget #50

Merged
merged 5 commits into from
Apr 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions wp-admin/js/widgets/media-image-widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@
*/
renderPreview: function renderPreview() {
var control = this, previewContainer, previewTemplate;
previewContainer = control.$el.find( '.media-widget-preview .rendered' );
previewContainer = control.$el.find( '.media-widget-preview' );
previewTemplate = wp.template( 'wp-media-widget-image-preview' );
previewContainer.html( previewTemplate( { attachment: control.selectedAttachment.attributes } ) );
previewContainer.html( previewTemplate( _.extend(
control.model.toJSON(),
{ attachment: control.selectedAttachment.toJSON() }
) ) );
},

/**
Expand Down
4 changes: 3 additions & 1 deletion wp-admin/js/widgets/media-widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ wp.mediaWidgets = ( function( $ ) {

// Re-render the preview when the attachment changes.
control.selectedAttachment = new wp.media.model.Attachment( { id: 0 } );
control.renderPreview = _.debounce( control.renderPreview );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe, though I could be wrong, that renderPreview is only called when the media modal is closed when the 'Update' button is clicked... if the dialog is closed with the 'x' or hitting the escape key, the model is not updated and renderPreview is not called. So not sure if we need to debounce this or not...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I added the debounce is because the preview is also now re-rendering in due to changes to control.model. So when you change the media, it will result the model being changed (the attachment_id and url props) as well as the selectedAttachment model, resulting in renderPreview being called twice. So this was intended to be a minor DOM performance improvement to not waste cycles.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, so this saves one render in instances where you are changing media/url. Looks like the preview is rendered twice upon initial load as well when the model is being updated. While playing with this I noticed renderPreview is called on each keystroke when editing the widget title currently so perhaps that is a good candidate for a _.throttle if we are concerned about too many renders.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preview rendering is separate. It actually already has throttling via the Customizer in two places. If you type quickly you'll note that the preview doesn't update until you slow down. Debouncing the updates to the widget instance settings is currently handled here: https://github.com/WordPress/wordpress-develop/blob/4.7.3/src/wp-admin/js/customize-widgets.js#L887-L889

The selective refresh of the widget in the preview also gets debounced here: https://github.com/WordPress/wordpress-develop/blob/4.7.3/src/wp-includes/js/customize-selective-refresh.js#L684-L712

And full refreshes are debounced here: https://github.com/WordPress/wordpress-develop/blob/4.7.3/src/wp-admin/js/customize-controls.js#L3655-L3677

For the core fix to reduce the number of preview refreshes in rapid succession, such as with implementing a decay, see https://core.trac.wordpress.org/ticket/38954

Copy link
Contributor

@timmyc timmyc Apr 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff, thanks for those links... so much to learn here. So here is the renderPreview bit in action in the widget itself. I've hacked the alt attribute in the renderPreview method to show how many times it is called. Note that the number increments with each keystroke of the title which is triggering the change on control.model. This is happening in master here too, mis-spoke there, it is the addition of control.listenTo( control.model, 'change', control.renderPreview ); that causes the preview to re-render whenever the title changes.

refresh

control.listenTo( control.selectedAttachment, 'change', control.renderPreview );
control.listenTo( control.model, 'change', control.renderPreview );

// Make sure a copy of the selected attachment is always fetched.
control.model.on( 'change', control.fetchSelectedAttachment );
Expand Down Expand Up @@ -370,7 +372,7 @@ wp.mediaWidgets = ( function( $ ) {
var control = this, titleInput;

if ( ! control.templateRendered ) {
control.$el.html( control.template()( control.model.attributes ) );
control.$el.html( control.template()( control.model.toJSON() ) );
control.renderPreview(); // Hereafter it will re-render when control.selectedAttachment changes.
control.templateRendered = true;
}
Expand Down
22 changes: 20 additions & 2 deletions wp-includes/widgets/class-wp-widget-image.php
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,9 @@ public function render_control_template_scripts() {

?>
<script type="text/html" id="tmpl-wp-media-widget-image-preview">
<#
var describedById = 'describedBy-' + String( Math.random() );
#>
<# if ( data.attachment.error && 'missing_attachment' === data.attachment.error ) { #>
<div class="notice notice-error notice-alt notice-missing-attachment">
<p><?php echo $this->l10n['missing_attachment']; ?></p>
Expand All @@ -292,8 +295,23 @@ public function render_control_template_scripts() {
<div class="notice notice-error notice-alt">
<p><?php _e( 'Unable to preview media due to an unknown error.' ); ?></p>
</div>
<# } else if ( data.attachment.url ) { #>
<img class="attachment-thumb" src="{{ data.attachment.url }}" draggable="false" alt="" />
<# } else if ( data.attachment.url || data.url ) { #>
<img class="attachment-thumb" src="{{ data.attachment.url || data.url }}" draggable="false" alt="{{ data.alt }}" <# if ( ! data.alt ) { #> aria-describedby="{{ describedById }}" <# } #> />
<# if ( ! data.alt ) { #>
<#
var alt = ( data.attachment.url || data.url );
alt = alt.replace( /\?.*$/, '' );
alt = alt.replace( /^.+\//, '' );
#>
<p class="hidden" id="{{ describedById }}"><?php
/* translators: placeholder is image filename */
echo sprintf( __( 'Current image: %s' ), '{{ alt }}' );
?></p>
<# } #>
<# } else { #>
<div class="attachment-media-view">
<p class="placeholder"><?php echo esc_html( $this->l10n['no_media_selected'] ); ?></p>
</div>
<# } #>
</script>
<?php
Expand Down
5 changes: 1 addition & 4 deletions wp-includes/widgets/class-wp-widget-media.php
Original file line number Diff line number Diff line change
Expand Up @@ -341,10 +341,7 @@ public function render_control_template_scripts() {
<input id="{{ elementIdPrefix }}title" type="text" class="widefat title">
</p>
<div class="media-widget-preview">
<div class="selected rendered">
<!-- Media rendering goes here. -->
</div>
<div class="attachment-media-view not-selected">
<div class="attachment-media-view">
<p class="placeholder"><?php echo esc_html( $this->l10n['no_media_selected'] ); ?></p>
</div>
</div>
Expand Down