Keyboard navigation friendliness for themes.php.

props matveb, azaozz, jorbin.
see #26527.


git-svn-id: https://develop.svn.wordpress.org/trunk@26922 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Andrew Nacin 2014-01-08 21:34:03 +00:00
parent 5447a6ab72
commit 972b6ef466
3 changed files with 83 additions and 15 deletions

View File

@ -6465,6 +6465,24 @@ span.imgedit-scale-warn {
-webkit-transition: opacity 0.1s ease-in-out;
transition: opacity 0.1s ease-in-out;
}
.theme-browser .theme:focus {
outline: 1px dotted #222;
}
/* Hide shortcut actions and hover feedback when using tab navigation */
.theme-browser .theme:focus .theme-actions {
display: none;
}
/* Restore display of theme controls if you hover a focused theme */
.theme-browser .theme:focus:hover .theme-actions {
display: block;
}
.theme-browser .theme:focus .more-details {
opacity: 1;
}
/* Current theme needs to have its action always on view */
.theme-browser .theme.active:focus .theme-actions {
display: block;
}
.theme-browser.rendered .theme:hover .more-details {
opacity: 1;
@ -6690,10 +6708,13 @@ body.theme-overlay-open {
width: 50px;
text-align: center;
float: right;
border: 0;
border-left: 1px solid #ddd;
background-color: transparent;
}
.theme-overlay .theme-header .close:hover:before {
.theme-overlay .theme-header .close:hover:before,
.theme-overlay .theme-header .close:focus:before {
color: #fff;
}
@ -6710,20 +6731,21 @@ body.theme-overlay-open {
.theme-overlay .theme-header .left {
cursor: pointer;
color: #777;
background-color: transparent;
height: 48px;
width: 54px;
float: left;
text-align: center;
border: 0;
border-right: 1px solid #ddd;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.theme-overlay .theme-header .close:hover,
.theme-overlay .theme-header .right:hover,
.theme-overlay .theme-header .left:hover {
.theme-overlay .theme-header .left:hover,
.theme-overlay .theme-header .close:focus,
.theme-overlay .theme-header .right:focus,
.theme-overlay .theme-header .left:focus {
background: #0074a2;
color: #fff;
}
@ -6832,7 +6854,8 @@ body.folded .theme-overlay .theme-wrap {
background: transparent;
}
.theme-overlay .theme-actions .delete-theme:hover {
.theme-overlay .theme-actions .delete-theme:hover,
.theme-overlay .theme-actions .delete-theme:focus {
background: #d54e21;
color: #fff;
border-color: #d54e21;

View File

@ -188,6 +188,7 @@ themes.view.Theme = wp.Backbone.View.extend({
events: {
'click': 'expand',
'keydown': 'expand',
'touchend': 'expand',
'touchmove': 'preventExpand'
},
@ -197,7 +198,8 @@ themes.view.Theme = wp.Backbone.View.extend({
render: function() {
var data = this.model.toJSON();
// Render themes using the html template
this.$el.html( this.html( data ) );
this.$el.html( this.html( data ) ).attr( 'tabindex', 0 );
// Renders active theme styles
this.activeTheme();
@ -219,19 +221,27 @@ themes.view.Theme = wp.Backbone.View.extend({
expand: function( event ) {
var self = this;
event = event || window.event;
// 'enter' and 'space' keys expand the details view when a theme is :focused
if ( event.type === 'keydown' && ( event.which !== 13 && event.which !== 32 ) ) {
return;
}
// Bail if the user scrolled on a touch device
if ( this.touchDrag === true ) {
return this.touchDrag = false;
}
event = event || window.event;
// Prevent the modal from showing when the user clicks
// one of the direct action buttons
if ( $( event.target ).is( '.theme-actions a' ) ) {
return;
}
// Set focused theme to current element
themes.focusedTheme = this.$el;
this.trigger( 'theme:expand', self.model.cid );
},
@ -266,6 +276,8 @@ themes.view.Details = wp.Backbone.View.extend({
this.navigation();
// Checks screenshot size
this.screenshotCheck( this.$el );
// Contain "tabbing" inside the overlay
this.containFocus( this.$el );
},
// Adds a class to the currently active theme
@ -275,6 +287,34 @@ themes.view.Details = wp.Backbone.View.extend({
this.$el.toggleClass( 'active', this.model.get( 'active' ) );
},
// Keeps :focus within the theme details elements
containFocus: function( $el ) {
var $target;
// Move focus to the primary action
_.delay( function() {
$( '.theme-wrap a.button-primary:visible' ).focus();
}, 500 );
$el.on( 'keydown.wp-themes', function( event ) {
// Tab key
if ( event.which === 9 ) {
$target = $( event.target );
// Keep focus within the overlay by making the last link on theme actions
// switch focus to button.left on tabbing and vice versa
if ( $target.is( 'button.left' ) && event.shiftKey ) {
$el.find( '.theme-actions a:last-child' ).focus();
event.preventDefault();
} else if ( $target.is( '.theme-actions a:last-child' ) ) {
$el.find( 'button.left' ).focus();
event.preventDefault();
}
}
});
},
// Single theme overlay screen
// It's shown when clicking a theme
collapse: function( event ) {
@ -291,7 +331,7 @@ themes.view.Details = wp.Backbone.View.extend({
// Detect if the click is inside the overlay
// and don't close it unless the target was
// the div.back button
if ( $( event.target ).is( '.theme-backdrop' ) || $( event.target ).is( 'div.close' ) || event.keyCode === 27 ) {
if ( $( event.target ).is( '.theme-backdrop' ) || $( event.target ).is( '.close' ) || event.keyCode === 27 ) {
// Add a temporary closing class while overlay fades out
$( 'body' ).addClass( 'closing-overlay' );
@ -311,6 +351,11 @@ themes.view.Details = wp.Backbone.View.extend({
// Restore scroll position
document.body.scrollTop = scroll;
// Return focus to the theme div
if ( themes.focusedTheme ) {
themes.focusedTheme.focus();
}
});
}
},

View File

@ -192,7 +192,7 @@ if ( ! $ct->errors() || ( 1 == count( $ct->errors()->get_error_codes() )
*/
foreach ( $themes as $theme ) : ?>
<div class="theme<?php if ( $theme['active'] ) echo ' active'; ?>">
<div class="theme<?php if ( $theme['active'] ) echo ' active'; ?>" tabindex="0">
<?php if ( ! empty( $theme['screenshot'][0] ) ) { ?>
<div class="theme-screenshot">
<img src="<?php echo $theme['screenshot'][0]; ?>" alt="" />
@ -309,9 +309,9 @@ if ( ! is_multisite() && current_user_can('edit_themes') && $broken_themes = wp_
<div class="theme-backdrop"></div>
<div class="theme-wrap">
<div class="theme-header">
<div alt="<?php _e( 'Close overlay' ); ?>" class="close dashicons dashicons-no"></div>
<div alt="<?php _e( 'Show previous theme' ); ?>" class="left dashicons dashicons-no"></div>
<div alt="<?php _e( 'Show next theme' ); ?>" class="right dashicons dashicons-no"></div>
<button alt="<?php _e( 'Show previous theme' ); ?>" class="left dashicons dashicons-no"></button>
<button alt="<?php _e( 'Show next theme' ); ?>" class="right dashicons dashicons-no"></button>
<button alt="<?php _e( 'Close overlay' ); ?>" class="close dashicons dashicons-no"></button>
</div>
<div class="theme-about">
<div class="theme-screenshots">