Make WordPress Core

Changeset 41803


Ignore:
Timestamp:
10/10/2017 03:33:57 AM (9 years ago)
Author:
westonruter
Message:

Customize: Constrain focus when overlay notification is displayed.

  • Restore previously-focused element when overlay notifications are dismissed.
  • Allow notifications to be dismissed via keyboard.

Amends [41667].
See #42110, #35210, #39896.

Location:
trunk/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/customize-controls.js

    r41799 r41803  
    7878
    7979                        api.Values.prototype.initialize.call( collection, options );
     80
     81                        _.bindAll( collection, 'constrainFocus' );
    8082
    8183                        // Keep track of the order in which the notifications were added for sorting purposes.
    … …  
    189191                render: function() {
    190192                        var collection = this,
    191                                 notifications, hadOverlayNotification = false, hasOverlayNotification,
     193                                notifications, hadOverlayNotification = false, hasOverlayNotification, overlayNotifications = [],
    192194                                previousNotificationsByCode = {},
    193                                 listElement;
     195                                listElement, focusableElements;
    194196
    195197                        // Short-circuit if there are no container to render into.
    … …  
    227229                                }
    228230                                notificationContainer = $( notification.render() );
     231                                notification.container = notificationContainer;
    229232                                listElement.append( notificationContainer ); // @todo Consider slideDown() as enhancement.
    230233
    231                                 // @todo Constraing focus in notificationContainer if notification.extended( api.OverlayNotification ).
    232                         });
    233 
    234                         hasOverlayNotification = Boolean( _.find( notifications, function( notification ) {
    235                                 return notification.extended( api.OverlayNotification );
    236                         } ) );
     234                                if ( notification.extended( api.OverlayNotification ) ) {
     235                                        overlayNotifications.push( notification );
     236                                }
     237                        });
     238                        hasOverlayNotification = Boolean( overlayNotifications.length );
     239
    237240                        if ( collection.previousNotifications ) {
    238241                                hadOverlayNotification = Boolean( _.find( collection.previousNotifications, function( notification ) {
    … …  
    244247                                $( document.body ).toggleClass( 'customize-loading', hasOverlayNotification );
    245248                                collection.container.toggleClass( 'has-overlay-notifications', hasOverlayNotification );
     249                                if ( hasOverlayNotification ) {
     250                                        collection.previousActiveElement = document.activeElement;
     251                                        $( document ).on( 'keydown', collection.constrainFocus );
     252                                } else {
     253                                        $( document ).off( 'keydown', collection.constrainFocus );
     254                                }
     255                        }
     256
     257                        if ( hasOverlayNotification ) {
     258                                collection.focusContainer = overlayNotifications[ overlayNotifications.length - 1 ].container;
     259                                collection.focusContainer.prop( 'tabIndex', -1 );
     260                                focusableElements = collection.focusContainer.find( ':focusable' );
     261                                if ( focusableElements.length ) {
     262                                        focusableElements.first().focus();
     263                                } else {
     264                                        collection.focusContainer.focus();
     265                                }
     266                        } else if ( collection.previousActiveElement ) {
     267                                $( collection.previousActiveElement ).focus();
     268                                collection.previousActiveElement = null;
    246269                        }
    247270
    … …  
    249272                        collection.previousContainer = collection.container;
    250273                        collection.trigger( 'rendered' );
     274                },
     275
     276                /**
     277                 * Constrain focus on focus container.
     278                 *
     279                 * @since 4.9.0
     280                 *
     281                 * @param {jQuery.Event} event - Event.
     282                 * @returns {void}
     283                 */
     284                constrainFocus: function constrainFocus( event ) {
     285                        var collection = this;
     286                        if ( ! collection.focusContainer || collection.focusContainer.is( event.target ) || $.contains( collection.focusContainer[0], event.target[0] ) ) {
     287                                return;
     288                        }
     289                        collection.focusContainer.focus();
    251290                }
    252291        });
  • trunk/src/wp-includes/js/customize-base.js

    r41726 r41803  
    886886
    887887                        if ( notification.dismissible ) {
    888                                 container.find( '.notice-dismiss' ).on( 'click', function() {
     888                                container.find( '.notice-dismiss' ).on( 'click keydown', function( event ) {
     889                                        if ( 'keydown' === event.type && 13 !== event.which ) {
     890                                                return;
     891                                        }
     892
    889893                                        if ( notification.parent ) {
    890894                                                notification.parent.remove( notification.code );
Note: See TracChangeset for help on using the changeset viewer.