At long last, improved keyboard accessibility for the media modal.
props lessbloat, grahamarmfield, sharonaustin, bramd. see #23560. Built from https://develop.svn.wordpress.org/trunk@28607 git-svn-id: http://core.svn.wordpress.org/trunk@28431 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
c4243e53d0
commit
78d90bd443
|
@ -478,8 +478,7 @@
|
|||
border-left: 0;
|
||||
}
|
||||
|
||||
.media-router > a:active,
|
||||
.media-router > a:focus {
|
||||
.media-router > a:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
@ -696,6 +695,16 @@
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
.attachment:focus {
|
||||
-webkit-box-shadow:
|
||||
0 0 0 1px #5b9dd9,
|
||||
0 0 2px 2px #5b9dd9;
|
||||
box-shadow:
|
||||
0 0 0 1px #5b9dd9,
|
||||
0 0 2px 2px #5b9dd9;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.selected.attachment {
|
||||
-webkit-box-shadow:
|
||||
0 0 0 1px #fff,
|
||||
|
@ -925,6 +934,7 @@
|
|||
left: 300px;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.attachments-browser .instructions {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -478,8 +478,7 @@
|
|||
border-right: 0;
|
||||
}
|
||||
|
||||
.media-router > a:active,
|
||||
.media-router > a:focus {
|
||||
.media-router > a:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
@ -696,6 +695,16 @@
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
.attachment:focus {
|
||||
-webkit-box-shadow:
|
||||
0 0 0 1px #5b9dd9,
|
||||
0 0 2px 2px #5b9dd9;
|
||||
box-shadow:
|
||||
0 0 0 1px #5b9dd9,
|
||||
0 0 2px 2px #5b9dd9;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.selected.attachment {
|
||||
-webkit-box-shadow:
|
||||
0 0 0 1px #fff,
|
||||
|
@ -925,6 +934,7 @@
|
|||
right: 300px;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.attachments-browser .instructions {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2313,6 +2313,12 @@
|
|||
} else {
|
||||
frame.close();
|
||||
}
|
||||
|
||||
// Keep focus inside media modal
|
||||
// after canceling a gallery
|
||||
new media.view.FocusManager({
|
||||
el: this.el
|
||||
}).focus();
|
||||
}
|
||||
},
|
||||
separateCancel: new media.View({
|
||||
|
@ -2495,6 +2501,12 @@
|
|||
}) );
|
||||
|
||||
this.controller.setState('gallery-edit');
|
||||
|
||||
// Keep focus inside media modal
|
||||
// after jumping to gallery view
|
||||
new media.view.FocusManager({
|
||||
el: this.el
|
||||
}).focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -2521,6 +2533,12 @@
|
|||
}) );
|
||||
|
||||
this.controller.setState('playlist-edit');
|
||||
|
||||
// Keep focus inside media modal
|
||||
// after jumping to playlist view
|
||||
new media.view.FocusManager({
|
||||
el: this.el
|
||||
}).focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -2547,6 +2565,12 @@
|
|||
}) );
|
||||
|
||||
this.controller.setState('video-playlist-edit');
|
||||
|
||||
// Keep focus inside media modal
|
||||
// after jumping to video playlist view
|
||||
new media.view.FocusManager({
|
||||
el: this.el
|
||||
}).focus();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -2956,6 +2980,10 @@
|
|||
propagate: true,
|
||||
freeze: true
|
||||
});
|
||||
|
||||
this.focusManager = new media.view.FocusManager({
|
||||
el: this.el
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @returns {Object}
|
||||
|
@ -3037,7 +3065,12 @@
|
|||
return this;
|
||||
}
|
||||
|
||||
this.$el.hide();
|
||||
// Hide modal and remove restricted media modal tab focus once it's closed
|
||||
this.$el.hide().undelegate( 'keydown' );
|
||||
|
||||
// Put focus back in useful location once modal is closed
|
||||
$('#wpbody-content').focus();
|
||||
|
||||
this.propagate('close');
|
||||
|
||||
// If the `freeze` option is set, restore the container's scroll position.
|
||||
|
@ -3098,6 +3131,9 @@
|
|||
if ( 27 === event.which && this.$el.is(':visible') ) {
|
||||
this.escape();
|
||||
event.stopImmediatePropagation();
|
||||
} else {
|
||||
// Keep focus inside the media modal
|
||||
this.focusManager;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -3117,15 +3153,8 @@
|
|||
},
|
||||
|
||||
focus: function() {
|
||||
if ( _.isUndefined( this.index ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update our collection of `$tabbables`.
|
||||
this.$tabbables = this.$(':tabbable');
|
||||
|
||||
// If tab is saved, focus it.
|
||||
this.$tabbables.eq( this.index ).focus();
|
||||
// Reset focus on first left menu item
|
||||
$('.media-menu-item').first().focus();
|
||||
},
|
||||
/**
|
||||
* @param {Object} event
|
||||
|
@ -3136,37 +3165,23 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// First try to update the index.
|
||||
if ( _.isUndefined( this.index ) ) {
|
||||
this.updateIndex( event );
|
||||
}
|
||||
|
||||
// If we still don't have an index, bail.
|
||||
if ( _.isUndefined( this.index ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = this.index + ( event.shiftKey ? -1 : 1 );
|
||||
|
||||
if ( index >= 0 && index < this.$tabbables.length ) {
|
||||
this.index = index;
|
||||
} else {
|
||||
delete this.index;
|
||||
// Keep tab focus within media modal while it's open
|
||||
if ( event.target === this.tabbableLast[0] && !event.shiftKey ) {
|
||||
this.tabbableFirst.focus();
|
||||
return false;
|
||||
} else if ( event.target === this.tabbableFirst[0] && event.shiftKey ) {
|
||||
this.tabbableLast.focus();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {Object} event
|
||||
*/
|
||||
updateIndex: function( event ) {
|
||||
this.$tabbables = this.$(':tabbable');
|
||||
|
||||
var index = this.$tabbables.index( event.target );
|
||||
|
||||
if ( -1 === index ) {
|
||||
delete this.index;
|
||||
} else {
|
||||
this.index = index;
|
||||
}
|
||||
// Resets tabbable elements
|
||||
this.tabbables = $( ':tabbable', this.$el );
|
||||
this.tabbableFirst = this.tabbables.filter( ':first' );
|
||||
this.tabbableLast = this.tabbables.filter( ':last' );
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -4397,6 +4412,11 @@
|
|||
className: 'attachment',
|
||||
template: media.template('attachment'),
|
||||
|
||||
attributes: {
|
||||
tabIndex: 0,
|
||||
role: 'checkbox'
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .attachment-preview': 'toggleSelectionHandler',
|
||||
'change [data-setting]': 'updateSetting',
|
||||
|
@ -4405,7 +4425,8 @@
|
|||
'change [data-setting] textarea': 'updateSetting',
|
||||
'click .close': 'removeFromLibrary',
|
||||
'click .check': 'removeFromSelection',
|
||||
'click a': 'preventDefault'
|
||||
'click a': 'preventDefault',
|
||||
'keydown': 'toggleSelectionHandler'
|
||||
},
|
||||
|
||||
buttons: {},
|
||||
|
@ -4413,6 +4434,7 @@
|
|||
initialize: function() {
|
||||
var selection = this.options.selection;
|
||||
|
||||
this.$el.attr('aria-label', this.model.attributes.title).attr('aria-checked', false);
|
||||
this.model.on( 'change:sizes change:uploading', this.render, this );
|
||||
this.model.on( 'change:title', this._syncTitle, this );
|
||||
this.model.on( 'change:caption', this._syncCaption, this );
|
||||
|
@ -4517,6 +4539,10 @@
|
|||
toggleSelectionHandler: function( event ) {
|
||||
var method;
|
||||
|
||||
// Catch enter and space events
|
||||
if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
|
||||
return;
|
||||
}
|
||||
if ( event.shiftKey ) {
|
||||
method = 'between';
|
||||
} else if ( event.ctrlKey || event.metaKey ) {
|
||||
|
@ -4573,6 +4599,10 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Fixes bug that loses focus when selecting a featured image
|
||||
if ( !method ) {
|
||||
method = 'add';
|
||||
}
|
||||
if ( method !== 'add' ) {
|
||||
method = 'reset';
|
||||
}
|
||||
|
@ -4617,7 +4647,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
this.$el.addClass('selected');
|
||||
this.$el.addClass('selected').attr('aria-checked', true);
|
||||
},
|
||||
/**
|
||||
* @param {Backbone.Model} model
|
||||
|
@ -4632,7 +4662,7 @@
|
|||
if ( ! selection || ( collection && collection !== selection ) ) {
|
||||
return;
|
||||
}
|
||||
this.$el.removeClass('selected');
|
||||
this.$el.removeClass('selected').attr('aria-checked', false);
|
||||
},
|
||||
/**
|
||||
* @param {Backbone.Model} model
|
||||
|
@ -4865,6 +4895,10 @@
|
|||
tagName: 'ul',
|
||||
className: 'attachments',
|
||||
|
||||
attributes: {
|
||||
tabIndex: -1
|
||||
},
|
||||
|
||||
cssTemplate: media.template('attachments-css'),
|
||||
|
||||
events: {
|
||||
|
@ -5579,6 +5613,12 @@
|
|||
clear: function( event ) {
|
||||
event.preventDefault();
|
||||
this.collection.reset();
|
||||
|
||||
// Keep focus inside media modal
|
||||
// after clear link is selected
|
||||
new media.view.FocusManager({
|
||||
el: this.el
|
||||
}).focus();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -5903,12 +5943,6 @@
|
|||
},
|
||||
|
||||
initialize: function() {
|
||||
/**
|
||||
* @member {wp.media.view.FocusManager}
|
||||
*/
|
||||
this.focusManager = new media.view.FocusManager({
|
||||
el: this.el
|
||||
});
|
||||
/**
|
||||
* call 'initialize' directly on the parent class
|
||||
*/
|
||||
|
@ -5922,7 +5956,6 @@
|
|||
* call 'render' directly on the parent class
|
||||
*/
|
||||
media.view.Attachment.prototype.render.apply( this, arguments );
|
||||
this.focusManager.focus();
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
|
@ -5933,6 +5966,11 @@
|
|||
|
||||
if ( confirm( l10n.warnDelete ) ) {
|
||||
this.model.destroy();
|
||||
// Keep focus inside media modal
|
||||
// after image is deleted
|
||||
new media.view.FocusManager({
|
||||
el: this.el
|
||||
}).focus();
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
@ -5988,13 +6026,6 @@
|
|||
},
|
||||
|
||||
initialize: function() {
|
||||
/**
|
||||
* @member {wp.media.view.FocusManager}
|
||||
*/
|
||||
this.focusManager = new media.view.FocusManager({
|
||||
el: this.el
|
||||
});
|
||||
|
||||
this.model.on( 'change:compat', this.render, this );
|
||||
},
|
||||
/**
|
||||
|
@ -6021,8 +6052,6 @@
|
|||
this.views.detach();
|
||||
this.$el.html( compat.item );
|
||||
this.views.render();
|
||||
|
||||
this.focusManager.focus();
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -119,6 +119,16 @@ function wp_print_media_templates() {
|
|||
if ( $is_IE && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 7') !== false )
|
||||
$class .= ' ie7';
|
||||
?>
|
||||
<!--[if lte IE 8]>
|
||||
<style>
|
||||
.attachment:focus {
|
||||
outline: #1e8cbe solid;
|
||||
}
|
||||
.selected.attachment {
|
||||
outline: #1e8cbe solid;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
<script type="text/html" id="tmpl-media-frame">
|
||||
<div class="media-frame-menu"></div>
|
||||
<div class="media-frame-title"></div>
|
||||
|
@ -238,7 +248,7 @@ function wp_print_media_templates() {
|
|||
<# } else if ( 'image' === data.type ) { #>
|
||||
<div class="thumbnail">
|
||||
<div class="centered">
|
||||
<img src="{{ data.size.url }}" draggable="false" />
|
||||
<img src="{{ data.size.url }}" draggable="false" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<# } else { #>
|
||||
|
@ -253,7 +263,7 @@ function wp_print_media_templates() {
|
|||
<# } #>
|
||||
|
||||
<# if ( data.buttons.check ) { #>
|
||||
<a class="check" href="#" title="<?php esc_attr_e('Deselect'); ?>"><div class="media-modal-icon"></div></a>
|
||||
<a class="check" href="#" title="<?php esc_attr_e('Deselect'); ?>" tabindex="-1"><div class="media-modal-icon"></div></a>
|
||||
<# } #>
|
||||
</div>
|
||||
<#
|
||||
|
|
Loading…
Reference in New Issue