diff --git a/src/js/_enqueues/wp/customize/controls.js b/src/js/_enqueues/wp/customize/controls.js index 64bfd3fe754be..83d5a0c2f9897 100644 --- a/src/js/_enqueues/wp/customize/controls.js +++ b/src/js/_enqueues/wp/customize/controls.js @@ -2597,10 +2597,14 @@ */ updateLimits: function () { if ( ! this.getNextTheme() ) { - this.overlay.find( '.right' ).addClass( 'disabled' ); + this.overlay.find( '.right' ) + .addClass( 'disabled' ) + .attr( 'aria-disabled', true ); } if ( ! this.getPreviousTheme() ) { - this.overlay.find( '.left' ).addClass( 'disabled' ); + this.overlay.find( '.left' ) + .addClass( 'disabled' ) + .attr( 'aria-disabled', true ); } }, diff --git a/src/js/_enqueues/wp/theme.js b/src/js/_enqueues/wp/theme.js index ff5d72ad2801e..c495140302007 100644 --- a/src/js/_enqueues/wp/theme.js +++ b/src/js/_enqueues/wp/theme.js @@ -480,7 +480,7 @@ themes.view.Theme = wp.Backbone.View.extend({ return; } - // Set focused theme to current element. + // Store the theme that had focus when expand is called. themes.focusedTheme = this.$el; this.trigger( 'theme:expand', self.model.cid ); @@ -520,7 +520,7 @@ themes.view.Theme = wp.Backbone.View.extend({ event = event || window.event; - // Set focus to current theme. + // Store the theme that had focus when preview is called. themes.focusedTheme = this.$el; // Construct a new Preview view. @@ -620,18 +620,16 @@ themes.view.Theme = wp.Backbone.View.extend({ if ( 0 === this.model.collection.indexOf( current ) ) { previousThemeButton .addClass( 'disabled' ) - .prop( 'disabled', true ); - - nextThemeButton.trigger( 'focus' ); + .attr( 'aria-disabled', true ) + .trigger( 'focus' ); } // Disable next if the next model is undefined. if ( _.isUndefined( this.model.collection.at( this.model.collection.indexOf( current ) + 1 ) ) ) { nextThemeButton .addClass( 'disabled' ) - .prop( 'disabled', true ); - - previousThemeButton.trigger( 'focus' ); + .attr( 'aria-disabled', true ) + .trigger( 'focus' ); } }, @@ -725,11 +723,14 @@ themes.view.Details = wp.Backbone.View.extend({ // Set initial focus and constrain tabbing within the theme browser modal. containFocus: function( $el ) { + // Set initial focus on the theme overlay modal dialog, only on first render. + var $themeOverlay = $( '.theme-overlay' ); + if ( $themeOverlay.hasClass( 'theme-overlay-initial' ) ) { + _.delay( function() { + $themeOverlay.trigger( 'focus' ).removeClass( 'theme-overlay-initial' ); + }, 100 ); + } - // Set initial focus on the primary action control. - _.delay( function() { - $( '.theme-overlay' ).trigger( 'focus' ); - }, 100 ); // Constrain tabbing within the modal. $el.on( 'keydown.wp-themes', function( event ) { @@ -785,10 +786,13 @@ themes.view.Details = wp.Backbone.View.extend({ // Restore scroll position. document.body.scrollTop = scroll; - // Return focus to the theme div. + // Return focus to the opener theme 'more-details' button. if ( themes.focusedTheme ) { - themes.focusedTheme.find('.more-details').trigger( 'focus' ); + themes.focusedTheme.find( '.more-details' ).trigger( 'focus' ); } + + // Add back the `theme-overlay-initial` class for the theme overlay. + $( '.theme-overlay' ).addClass( 'theme-overlay-initial' ); }); } @@ -803,12 +807,12 @@ themes.view.Details = wp.Backbone.View.extend({ if ( this.model.cid === this.model.collection.at(0).cid ) { this.$el.find( '.left' ) .addClass( 'disabled' ) - .prop( 'disabled', true ); + .attr( 'aria-disabled', true ); } if ( this.model.cid === this.model.collection.at( this.model.collection.length - 1 ).cid ) { this.$el.find( '.right' ) .addClass( 'disabled' ) - .prop( 'disabled', true ); + .attr( 'aria-disabled', true ); } }, @@ -960,6 +964,8 @@ themes.view.Preview = themes.view.Details.extend({ this.$el.fadeIn( 200, function() { $body.addClass( 'theme-installer-active full-overlay-active' ); + // Set initial focus on the theme installer overlay modal dialog. + self.$el.trigger( 'focus' ); }); this.$el.find( 'iframe' ).one( 'load', function() { @@ -976,9 +982,9 @@ themes.view.Preview = themes.view.Details.extend({ this.$el.fadeOut( 200, function() { $( 'body' ).removeClass( 'theme-installer-active full-overlay-active' ); - // Return focus to the theme div. + // Return focus to the opener theme 'more-details' button. if ( themes.focusedTheme ) { - themes.focusedTheme.find('.more-details').trigger( 'focus' ); + themes.focusedTheme.find( '.more-details' ).trigger( 'focus' ); } }).removeClass( 'iframe-ready' ); @@ -1354,6 +1360,8 @@ themes.view.Themes = wp.Backbone.View.extend({ // Trigger a route update for the current model. self.theme.trigger( 'theme:expand', nextModel.cid ); + // Set focus again to the 'Next' navigation button after the view fully re-rendeers. + $( '.theme-header .right' ).trigger( 'focus' ); themes.announceThemeDebounced( nextModel ); } }, @@ -1389,6 +1397,8 @@ themes.view.Themes = wp.Backbone.View.extend({ // Trigger a route update for the current model. self.theme.trigger( 'theme:expand', previousModel.cid ); + // Set focus again to the 'Previous' navigation button after the view fully re-rendeers. + $( '.theme-header .left' ).trigger( 'focus' ); themes.announceThemeDebounced( previousModel ); } }, diff --git a/src/js/media/views/frame/edit-attachments.js b/src/js/media/views/frame/edit-attachments.js index e3bc0d09e643b..f55a2169b16cd 100644 --- a/src/js/media/views/frame/edit-attachments.js +++ b/src/js/media/views/frame/edit-attachments.js @@ -201,8 +201,8 @@ EditAttachments = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.EditAtta }, toggleNav: function() { - this.$( '.left' ).prop( 'disabled', ! this.hasPrevious() ); - this.$( '.right' ).prop( 'disabled', ! this.hasNext() ); + this.$( '.left' ).attr( 'aria-disabled', ! this.hasPrevious() ); + this.$( '.right' ).attr( 'aria-disabled', ! this.hasNext() ); }, /** @@ -238,8 +238,6 @@ EditAttachments = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.EditAtta model = this.library.at( this.getCurrentIndex() - 1 ); this.trigger( 'refresh', model ); - // Move focus to the Previous button. When there are no more items, to the Next button. - this.focusNavButton( this.hasPrevious() ? '.left' : '.right' ); this.announceMediaItemDebounced( model ); }, @@ -255,22 +253,9 @@ EditAttachments = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.EditAtta model = this.library.at( this.getCurrentIndex() + 1 ); this.trigger( 'refresh', model ); - // Move focus to the Next button. When there are no more items, to the Previous button. - this.focusNavButton( this.hasNext() ? '.right' : '.left' ); this.announceMediaItemDebounced( model ); }, - /** - * Set focus to the navigation buttons depending on the browsing direction. - * - * @since 5.3.0 - * - * @param {string} which A CSS selector to target the button to focus. - */ - focusNavButton: function( which ) { - $( which ).trigger( 'focus' ); - }, - getCurrentIndex: function() { return this.library.indexOf( this.model ); }, diff --git a/src/wp-admin/css/colors/_admin.scss b/src/wp-admin/css/colors/_admin.scss index 20704b3f525f0..2d014555a2c2f 100644 --- a/src/wp-admin/css/colors/_admin.scss +++ b/src/wp-admin/css/colors/_admin.scss @@ -773,10 +773,10 @@ div#wp-responsive-toggle a::before { &.wp-customizer .theme-overlay .theme-header .close:focus, &.wp-customizer .theme-overlay .theme-header .close:hover, - &.wp-customizer .theme-overlay .theme-header .right:focus, - &.wp-customizer .theme-overlay .theme-header .right:hover, - &.wp-customizer .theme-overlay .theme-header .left:focus, - &.wp-customizer .theme-overlay .theme-header .left:hover { + &.wp-customizer .theme-overlay .theme-header .right:focus:not(.disabled), + &.wp-customizer .theme-overlay .theme-header .right:hover:not(.disabled), + &.wp-customizer .theme-overlay .theme-header .left:focus:not(.disabled), + &.wp-customizer .theme-overlay .theme-header .left:hover:not(.disabled) { border-bottom-color: variables.$button-color; color: variables.$link; } diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css index 24de538114bad..7cdc6e97ae4d3 100644 --- a/src/wp-admin/css/customize-controls.css +++ b/src/wp-admin/css/customize-controls.css @@ -2455,10 +2455,10 @@ p.customize-section-description { .wp-customizer .theme-overlay .theme-header .close:focus, .wp-customizer .theme-overlay .theme-header .close:hover, -.wp-customizer .theme-overlay .theme-header .right:focus, -.wp-customizer .theme-overlay .theme-header .right:hover, -.wp-customizer .theme-overlay .theme-header .left:focus, -.wp-customizer .theme-overlay .theme-header .left:hover { +.wp-customizer .theme-overlay .theme-header .right:focus:not(.disabled), +.wp-customizer .theme-overlay .theme-header .right:hover:not(.disabled), +.wp-customizer .theme-overlay .theme-header .left:focus:not(.disabled), +.wp-customizer .theme-overlay .theme-header .left:hover:not(.disabled) { background: #fff; } diff --git a/src/wp-admin/css/media.css b/src/wp-admin/css/media.css index 5e67e429776ec..c4b48286a5a2b 100644 --- a/src/wp-admin/css/media.css +++ b/src/wp-admin/css/media.css @@ -725,9 +725,9 @@ border color while dragging a file over the uploader drop area */ .upload-php .media-modal-close:focus, .edit-attachment-frame .edit-media-header .left:focus, .edit-attachment-frame .edit-media-header .right:focus { - /* Only visible in Windows High Contrast mode */ - outline: 2px solid transparent; - outline-offset: -2px; + /* Always visible also in Windows High Contrast mode */ + outline: 1px solid #c3c4c7;; + outline-offset: -1px; } .upload-php .media-modal-close:focus .media-modal-icon::before, @@ -745,8 +745,9 @@ border color while dragging a file over the uploader drop area */ content: "\f345" / ""; } -.edit-attachment-frame .edit-media-header [disabled], -.edit-attachment-frame .edit-media-header [disabled]:hover { +.edit-attachment-frame .edit-media-header [aria-disabled="true"], +.edit-attachment-frame .edit-media-header [aria-disabled="true"]:hover, +.edit-attachment-frame .edit-media-header [aria-disabled="true"]:focus { color: #c3c4c7; background: inherit; cursor: default; diff --git a/src/wp-admin/css/themes.css b/src/wp-admin/css/themes.css index 5b71c223b6ce6..8f89f2c04fb6a 100644 --- a/src/wp-admin/css/themes.css +++ b/src/wp-admin/css/themes.css @@ -1406,6 +1406,12 @@ body.full-overlay-active { visibility: hidden; } +/* Make sure the ARIA live regions are visible, as they inherit the hidden visibility from the body. */ +.a11y-speak-intro-text, +.a11y-speak-region { + visibility: visible; +} + .wp-full-overlay { background: #1d2327; z-index: 500000; @@ -1561,6 +1567,14 @@ body.full-overlay-active { box-shadow: none; } +.theme-install-overlay .close-full-overlay:focus, +.theme-install-overlay .previous-theme:focus, +.theme-install-overlay .next-theme:focus { + /* Always visible also in Windows High Contrast mode */ + outline: 1px solid #c3c4c7;; + outline-offset: -1px; +} + .theme-install-overlay .close-full-overlay::before { font: 400 22px/1 dashicons; content: "\f335"; @@ -1597,7 +1611,6 @@ body.full-overlay-active { color: #c3c4c7; background: #f0f0f1; cursor: default; - pointer-events: none; } .theme-install-overlay .close-full-overlay::before, diff --git a/src/wp-admin/includes/theme.php b/src/wp-admin/includes/theme.php index 5ee488536ede2..7f92fed1b2625 100644 --- a/src/wp-admin/includes/theme.php +++ b/src/wp-admin/includes/theme.php @@ -828,13 +828,13 @@ function customize_themes_print_templates() { + <# } else { #> + <# } #>
<# if ( data.installed ) { #> diff --git a/src/wp-admin/themes.php b/src/wp-admin/themes.php index ac2cd4a9824cb..a0686c645766a 100644 --- a/src/wp-admin/themes.php +++ b/src/wp-admin/themes.php @@ -664,7 +664,7 @@
- +

@@ -1057,19 +1057,19 @@ function wp_theme_auto_update_setting_template() { diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php index 70e75e0d28567..ee9c6bc21a1c3 100644 --- a/src/wp-includes/media-template.php +++ b/src/wp-includes/media-template.php @@ -206,7 +206,7 @@ function wp_print_media_templates() { <# } #> @@ -369,9 +369,9 @@ function wp_print_media_templates() {