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;
|
border-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-router > a:active,
|
.media-router > a:active {
|
||||||
.media-router > a:focus {
|
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,6 +695,16 @@
|
||||||
user-select: none;
|
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 {
|
.selected.attachment {
|
||||||
-webkit-box-shadow:
|
-webkit-box-shadow:
|
||||||
0 0 0 1px #fff,
|
0 0 0 1px #fff,
|
||||||
|
@ -925,6 +934,7 @@
|
||||||
left: 300px;
|
left: 300px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attachments-browser .instructions {
|
.attachments-browser .instructions {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -478,8 +478,7 @@
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-router > a:active,
|
.media-router > a:active {
|
||||||
.media-router > a:focus {
|
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,6 +695,16 @@
|
||||||
user-select: none;
|
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 {
|
.selected.attachment {
|
||||||
-webkit-box-shadow:
|
-webkit-box-shadow:
|
||||||
0 0 0 1px #fff,
|
0 0 0 1px #fff,
|
||||||
|
@ -925,6 +934,7 @@
|
||||||
right: 300px;
|
right: 300px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attachments-browser .instructions {
|
.attachments-browser .instructions {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2313,6 +2313,12 @@
|
||||||
} else {
|
} else {
|
||||||
frame.close();
|
frame.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep focus inside media modal
|
||||||
|
// after canceling a gallery
|
||||||
|
new media.view.FocusManager({
|
||||||
|
el: this.el
|
||||||
|
}).focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
separateCancel: new media.View({
|
separateCancel: new media.View({
|
||||||
|
@ -2495,6 +2501,12 @@
|
||||||
}) );
|
}) );
|
||||||
|
|
||||||
this.controller.setState('gallery-edit');
|
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');
|
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');
|
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,
|
propagate: true,
|
||||||
freeze: true
|
freeze: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.focusManager = new media.view.FocusManager({
|
||||||
|
el: this.el
|
||||||
|
});
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
|
@ -3037,7 +3065,12 @@
|
||||||
return this;
|
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');
|
this.propagate('close');
|
||||||
|
|
||||||
// If the `freeze` option is set, restore the container's scroll position.
|
// If the `freeze` option is set, restore the container's scroll position.
|
||||||
|
@ -3098,6 +3131,9 @@
|
||||||
if ( 27 === event.which && this.$el.is(':visible') ) {
|
if ( 27 === event.which && this.$el.is(':visible') ) {
|
||||||
this.escape();
|
this.escape();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
|
} else {
|
||||||
|
// Keep focus inside the media modal
|
||||||
|
this.focusManager;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -3117,15 +3153,8 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
focus: function() {
|
focus: function() {
|
||||||
if ( _.isUndefined( this.index ) ) {
|
// Reset focus on first left menu item
|
||||||
return;
|
$('.media-menu-item').first().focus();
|
||||||
}
|
|
||||||
|
|
||||||
// Update our collection of `$tabbables`.
|
|
||||||
this.$tabbables = this.$(':tabbable');
|
|
||||||
|
|
||||||
// If tab is saved, focus it.
|
|
||||||
this.$tabbables.eq( this.index ).focus();
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param {Object} event
|
* @param {Object} event
|
||||||
|
@ -3136,37 +3165,23 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First try to update the index.
|
// Keep tab focus within media modal while it's open
|
||||||
if ( _.isUndefined( this.index ) ) {
|
if ( event.target === this.tabbableLast[0] && !event.shiftKey ) {
|
||||||
this.updateIndex( event );
|
this.tabbableFirst.focus();
|
||||||
}
|
return false;
|
||||||
|
} else if ( event.target === this.tabbableFirst[0] && event.shiftKey ) {
|
||||||
// If we still don't have an index, bail.
|
this.tabbableLast.focus();
|
||||||
if ( _.isUndefined( this.index ) ) {
|
return false;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = this.index + ( event.shiftKey ? -1 : 1 );
|
|
||||||
|
|
||||||
if ( index >= 0 && index < this.$tabbables.length ) {
|
|
||||||
this.index = index;
|
|
||||||
} else {
|
|
||||||
delete this.index;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param {Object} event
|
* @param {Object} event
|
||||||
*/
|
*/
|
||||||
updateIndex: function( event ) {
|
updateIndex: function( event ) {
|
||||||
this.$tabbables = this.$(':tabbable');
|
// Resets tabbable elements
|
||||||
|
this.tabbables = $( ':tabbable', this.$el );
|
||||||
var index = this.$tabbables.index( event.target );
|
this.tabbableFirst = this.tabbables.filter( ':first' );
|
||||||
|
this.tabbableLast = this.tabbables.filter( ':last' );
|
||||||
if ( -1 === index ) {
|
|
||||||
delete this.index;
|
|
||||||
} else {
|
|
||||||
this.index = index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4397,6 +4412,11 @@
|
||||||
className: 'attachment',
|
className: 'attachment',
|
||||||
template: media.template('attachment'),
|
template: media.template('attachment'),
|
||||||
|
|
||||||
|
attributes: {
|
||||||
|
tabIndex: 0,
|
||||||
|
role: 'checkbox'
|
||||||
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
'click .attachment-preview': 'toggleSelectionHandler',
|
'click .attachment-preview': 'toggleSelectionHandler',
|
||||||
'change [data-setting]': 'updateSetting',
|
'change [data-setting]': 'updateSetting',
|
||||||
|
@ -4405,7 +4425,8 @@
|
||||||
'change [data-setting] textarea': 'updateSetting',
|
'change [data-setting] textarea': 'updateSetting',
|
||||||
'click .close': 'removeFromLibrary',
|
'click .close': 'removeFromLibrary',
|
||||||
'click .check': 'removeFromSelection',
|
'click .check': 'removeFromSelection',
|
||||||
'click a': 'preventDefault'
|
'click a': 'preventDefault',
|
||||||
|
'keydown': 'toggleSelectionHandler'
|
||||||
},
|
},
|
||||||
|
|
||||||
buttons: {},
|
buttons: {},
|
||||||
|
@ -4413,6 +4434,7 @@
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
var selection = this.options.selection;
|
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:sizes change:uploading', this.render, this );
|
||||||
this.model.on( 'change:title', this._syncTitle, this );
|
this.model.on( 'change:title', this._syncTitle, this );
|
||||||
this.model.on( 'change:caption', this._syncCaption, this );
|
this.model.on( 'change:caption', this._syncCaption, this );
|
||||||
|
@ -4517,6 +4539,10 @@
|
||||||
toggleSelectionHandler: function( event ) {
|
toggleSelectionHandler: function( event ) {
|
||||||
var method;
|
var method;
|
||||||
|
|
||||||
|
// Catch enter and space events
|
||||||
|
if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ( event.shiftKey ) {
|
if ( event.shiftKey ) {
|
||||||
method = 'between';
|
method = 'between';
|
||||||
} else if ( event.ctrlKey || event.metaKey ) {
|
} else if ( event.ctrlKey || event.metaKey ) {
|
||||||
|
@ -4573,6 +4599,10 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fixes bug that loses focus when selecting a featured image
|
||||||
|
if ( !method ) {
|
||||||
|
method = 'add';
|
||||||
|
}
|
||||||
if ( method !== 'add' ) {
|
if ( method !== 'add' ) {
|
||||||
method = 'reset';
|
method = 'reset';
|
||||||
}
|
}
|
||||||
|
@ -4617,7 +4647,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$el.addClass('selected');
|
this.$el.addClass('selected').attr('aria-checked', true);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param {Backbone.Model} model
|
* @param {Backbone.Model} model
|
||||||
|
@ -4632,7 +4662,7 @@
|
||||||
if ( ! selection || ( collection && collection !== selection ) ) {
|
if ( ! selection || ( collection && collection !== selection ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$el.removeClass('selected');
|
this.$el.removeClass('selected').attr('aria-checked', false);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @param {Backbone.Model} model
|
* @param {Backbone.Model} model
|
||||||
|
@ -4865,6 +4895,10 @@
|
||||||
tagName: 'ul',
|
tagName: 'ul',
|
||||||
className: 'attachments',
|
className: 'attachments',
|
||||||
|
|
||||||
|
attributes: {
|
||||||
|
tabIndex: -1
|
||||||
|
},
|
||||||
|
|
||||||
cssTemplate: media.template('attachments-css'),
|
cssTemplate: media.template('attachments-css'),
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
|
@ -5579,6 +5613,12 @@
|
||||||
clear: function( event ) {
|
clear: function( event ) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.collection.reset();
|
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() {
|
initialize: function() {
|
||||||
/**
|
|
||||||
* @member {wp.media.view.FocusManager}
|
|
||||||
*/
|
|
||||||
this.focusManager = new media.view.FocusManager({
|
|
||||||
el: this.el
|
|
||||||
});
|
|
||||||
/**
|
/**
|
||||||
* call 'initialize' directly on the parent class
|
* call 'initialize' directly on the parent class
|
||||||
*/
|
*/
|
||||||
|
@ -5922,7 +5956,6 @@
|
||||||
* call 'render' directly on the parent class
|
* call 'render' directly on the parent class
|
||||||
*/
|
*/
|
||||||
media.view.Attachment.prototype.render.apply( this, arguments );
|
media.view.Attachment.prototype.render.apply( this, arguments );
|
||||||
this.focusManager.focus();
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -5933,6 +5966,11 @@
|
||||||
|
|
||||||
if ( confirm( l10n.warnDelete ) ) {
|
if ( confirm( l10n.warnDelete ) ) {
|
||||||
this.model.destroy();
|
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() {
|
initialize: function() {
|
||||||
/**
|
|
||||||
* @member {wp.media.view.FocusManager}
|
|
||||||
*/
|
|
||||||
this.focusManager = new media.view.FocusManager({
|
|
||||||
el: this.el
|
|
||||||
});
|
|
||||||
|
|
||||||
this.model.on( 'change:compat', this.render, this );
|
this.model.on( 'change:compat', this.render, this );
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
@ -6021,8 +6052,6 @@
|
||||||
this.views.detach();
|
this.views.detach();
|
||||||
this.$el.html( compat.item );
|
this.$el.html( compat.item );
|
||||||
this.views.render();
|
this.views.render();
|
||||||
|
|
||||||
this.focusManager.focus();
|
|
||||||
return this;
|
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 )
|
if ( $is_IE && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 7') !== false )
|
||||||
$class .= ' ie7';
|
$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">
|
<script type="text/html" id="tmpl-media-frame">
|
||||||
<div class="media-frame-menu"></div>
|
<div class="media-frame-menu"></div>
|
||||||
<div class="media-frame-title"></div>
|
<div class="media-frame-title"></div>
|
||||||
|
@ -238,7 +248,7 @@ function wp_print_media_templates() {
|
||||||
<# } else if ( 'image' === data.type ) { #>
|
<# } else if ( 'image' === data.type ) { #>
|
||||||
<div class="thumbnail">
|
<div class="thumbnail">
|
||||||
<div class="centered">
|
<div class="centered">
|
||||||
<img src="{{ data.size.url }}" draggable="false" />
|
<img src="{{ data.size.url }}" draggable="false" alt="" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<# } else { #>
|
<# } else { #>
|
||||||
|
@ -253,7 +263,7 @@ function wp_print_media_templates() {
|
||||||
<# } #>
|
<# } #>
|
||||||
|
|
||||||
<# if ( data.buttons.check ) { #>
|
<# 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>
|
</div>
|
||||||
<#
|
<#
|
||||||
|
|
Loading…
Reference in New Issue