Make WordPress Core

Changeset 42794


Ignore:
Timestamp:
03/07/2018 10:26:39 PM (7 years ago)
Author:
afercia
Message:

Accessibility: Widgets: Make the "Available Widgets" section operable with a keyboard.

For a number of years, the "Available Widgets" section has been off-limits for
keyboard users. Now it can be used also with the keyboard. This change introduces
also some improvements for assistive technologies.

  • makes the widget toggles focusable and adds an aria-expanded attribute to indicate their state
  • improves the toggles labelling to clarify context (add/edit)
  • changes the controls to choose a sidebar from list items to buttons
  • adds an aria-label attribute to the buttons to clarify their purpose
  • adds an aria-pressed attribute to the buttons to indicate which one is selected
  • improves color contrast of the selected button
  • uses a wp.a11y.speak() message to announce to screen reader users when a widget has been added to a sidebar
  • moves focus back to the toggle button when closing a widget

See #40677.

Location:
trunk/src
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/common.css

    r42785 r42794  
    33693369#customize-info.open .accordion-section-title:after,
    33703370.nav-menus-php .menu-item-edit-active .item-edit:before,
    3371 .widget.open .widget-top .widget-action .toggle-indicator:before {
     3371.widget.open .widget-top .widget-action .toggle-indicator:before,
     3372.widget.widget-in-question .widget-top .widget-action .toggle-indicator:before  {
    33723373    content: "\f142";
    33733374}
  • trunk/src/wp-admin/css/widgets.css

    r42790 r42794  
    382382}
    383383
    384 #available-widgets .widget-action {
    385     display: none;
    386 }
    387 
    388384#available-widgets .widget {
    389385    margin: 0;
     
    517513
    518514#available-widgets .widget-control-edit .edit,
     515#available-widgets .widget-action .edit,
    519516#widgets-left .inactive-sidebar .widget-control-edit .add,
    520 #widgets-right .widget-control-edit .add {
     517#widgets-left .inactive-sidebar .widget-action .add,
     518#widgets-right .widget-control-edit .add,
     519#widgets-right .widget-action .add {
    521520    display: none;
    522521}
     
    665664
    666665.widgets-chooser li {
    667     padding: 10px 15px 10px 35px;
    668666    border-bottom: 1px solid #ccc;
    669667    background: #fff;
    670668    margin: 0;
     669    position: relative;
     670}
     671
     672.widgets-chooser .widgets-chooser-button {
     673    width: 100%;
     674    padding: 10px 15px 10px 35px;
     675    background: transparent;
     676    border: 0;
     677    box-sizing: border-box;
     678    text-align: left;
    671679    cursor: pointer;
     680    transition: background 0.2s ease-in-out;
     681}
     682
     683/* @todo looks like these hover/focus states are overridden by .widgets-chooser-selected */
     684.widgets-chooser .widgets-chooser-button:hover,
     685.widgets-chooser .widgets-chooser-button:focus {
    672686    outline: none;
    673     position: relative;
    674     transition: background 0.2s ease-in-out;
    675 }
    676 
    677  /* @todo looks like these hover/focus states are overridden by .widgets-chooser-selected */
    678 .widgets-chooser li:hover,
    679 .widgets-chooser li:focus {
    680     background: rgba(255,255,255,0.7);
    681 }
    682 
    683 .widgets-chooser li:focus:before {
    684     content: "\f147";
    685     display: block;
    686     -webkit-font-smoothing: antialiased;
    687     font: normal 26px/1 dashicons;
    688     color: #555d66;
    689     position: absolute;
    690     top: 7px;
    691     left: 5px;
     687    text-decoration: underline;
    692688}
    693689
     
    696692}
    697693
    698 .widgets-chooser li.widgets-chooser-selected {
    699     background: #00a0d2;
     694.widgets-chooser .widgets-chooser-selected .widgets-chooser-button {
     695    background: #0073aa;
    700696    color: #fff;
    701697}
    702698
    703 .widgets-chooser li.widgets-chooser-selected:before,
    704 .widgets-chooser li.widgets-chooser-selected:focus:before {
     699.widgets-chooser .widgets-chooser-selected:before {
    705700    content: "\f147";
    706701    display: block;
     
    718713}
    719714
    720 .widgets-chooser button {
    721     margin-right: 5px;
    722 }
    723 
    724715#available-widgets .widget .widget-top {
    725716    cursor: pointer;
  • trunk/src/wp-admin/includes/widgets.php

    r42343 r42794  
    9191
    9292    if ( $sidebar_name ) {
     93        $add_to = sprintf(
     94            /* translators: %s: widgets sidebar name. */
     95            __( 'Add to: %s' ),
     96            $sidebar_name
     97        );
    9398        ?>
    94         <div class="sidebar-name">
     99        <div class="sidebar-name" data-add-to="<?php echo esc_attr( $add_to ); ?>">
    95100            <button type="button" class="handlediv hide-if-no-js" aria-expanded="true">
    96101                <span class="screen-reader-text"><?php echo esc_html( $sidebar_name ); ?></span>
     
    240245    <div class="widget-title-action">
    241246        <button type="button" class="widget-action hide-if-no-js" aria-expanded="false">
    242             <span class="screen-reader-text"><?php printf( __( 'Edit widget: %s' ), $widget_title ); ?></span>
     247            <span class="screen-reader-text edit"><?php printf( __( 'Edit widget: %s' ), $widget_title ); ?></span>
     248            <span class="screen-reader-text add"><?php printf( __( 'Add widget: %s' ), $widget_title ); ?></span>
    243249            <span class="toggle-indicator" aria-hidden="true"></span>
    244250        </button>
  • trunk/src/wp-admin/js/widgets.js

    r42521 r42794  
    2222        save: '{save}',
    2323        saved: '{saved}',
    24         saveAlert: '{saveAlert}'
     24        saveAlert: '{saveAlert}',
     25        widgetAdded: '{widgetAdded}'
    2526    },
    2627
     
    177178                    });
    178179                }
    179                 e.preventDefault();
    180180            } else if ( target.hasClass('widget-control-save') ) {
    181181                wpWidgets.save( target.closest('div.widget'), 0, 1, 0 );
     
    183183            } else if ( target.hasClass('widget-control-remove') ) {
    184184                wpWidgets.save( target.closest('div.widget'), 1, 1, 0 );
    185                 e.preventDefault();
    186185            } else if ( target.hasClass('widget-control-close') ) {
    187186                widget = target.closest('div.widget');
     
    189188                toggleBtn.attr( 'aria-expanded', 'false' );
    190189                wpWidgets.close( widget );
    191                 e.preventDefault();
    192190            } else if ( target.attr( 'id' ) === 'inactive-widgets-control-remove' ) {
    193191                wpWidgets.removeInactiveWidgets();
     
    434432            var $element = $( element ),
    435433                name = $element.find( '.sidebar-name h2' ).text(),
     434                ariaLabel = $element.find( '.sidebar-name' ).data( 'add-to' ),
    436435                id = $element.find( '.widgets-sortables' ).attr( 'id' ),
    437                 li = $('<li tabindex="0">').text( $.trim( name ) );
     436                li = $( '<li>' ),
     437                button = $( '<button>', {
     438                    type: 'button',
     439                    'aria-pressed': 'false',
     440                    'class': 'widgets-chooser-button',
     441                    'aria-label': ariaLabel
     442                } ).text( $.trim( name ) );
     443
     444            li.append( button );
    438445
    439446            if ( index === 0 ) {
    440447                li.addClass( 'widgets-chooser-selected' );
     448                button.attr( 'aria-pressed', 'true' );
    441449            }
    442450
     
    445453        });
    446454
    447         $( '#available-widgets .widget .widget-title' ).on( 'click.widgets-chooser', function() {
    448             var $widget = $(this).closest( '.widget' );
     455        $( '#available-widgets .widget .widget-top' ).on( 'click.widgets-chooser', function() {
     456            var $widget = $( this ).closest( '.widget' ),
     457                toggleButton = $( this ).find( '.widget-action' ),
     458                chooserButtons = selectSidebar.find( '.widgets-chooser-button' );
    449459
    450460            if ( $widget.hasClass( 'widget-in-question' ) || $( '#widgets-left' ).hasClass( 'chooser' ) ) {
     461                toggleButton.attr( 'aria-expanded', 'false' );
    451462                self.closeChooser();
    452463            } else {
     
    454465                self.clearWidgetSelection();
    455466                $( '#widgets-left' ).addClass( 'chooser' );
     467                // Add CSS class and insert the chooser after the widget description.
    456468                $widget.addClass( 'widget-in-question' ).children( '.widget-description' ).after( chooser );
    457 
     469                // Open the chooser with a slide down animation.
    458470                chooser.slideDown( 300, function() {
    459                     selectSidebar.find('.widgets-chooser-selected').focus();
     471                    // Update the toggle button aria-expanded attribute after previous DOM manipulations.
     472                    toggleButton.attr( 'aria-expanded', 'true' );
    460473                });
    461474
    462                 selectSidebar.find( 'li' ).on( 'focusin.widgets-chooser', function() {
    463                     selectSidebar.find('.widgets-chooser-selected').removeClass( 'widgets-chooser-selected' );
    464                     $(this).addClass( 'widgets-chooser-selected' );
     475                chooserButtons.on( 'click.widgets-chooser', function() {
     476                    selectSidebar.find( '.widgets-chooser-selected' ).removeClass( 'widgets-chooser-selected' );
     477                    chooserButtons.attr( 'aria-pressed', 'false' );
     478                    $( this )
     479                        .attr( 'aria-pressed', 'true' )
     480                        .closest( 'li' ).addClass( 'widgets-chooser-selected' );
    465481                } );
    466482            }
     
    478494            }
    479495        }).on( 'keyup.widgets-chooser', function( event ) {
    480             if ( event.which === $.ui.keyCode.ENTER ) {
    481                 if ( $( event.target ).hasClass( 'widgets-chooser-cancel' ) ) {
    482                     // Close instead of adding when pressing Enter on the Cancel button
    483                     self.closeChooser();
    484                 } else {
    485                     self.addWidget( chooser );
    486                     self.closeChooser();
    487                 }
    488             } else if ( event.which === $.ui.keyCode.ESCAPE ) {
     496            if ( event.which === $.ui.keyCode.ESCAPE ) {
    489497                self.closeChooser();
    490498            }
     
    706714            // have to queue this "by hand".
    707715            widget.find( '.widget-title' ).trigger('click');
     716            // At the end of the animation, announce the widget has been added.
     717            window.wp.a11y.speak( wpWidgets.l10n.widgetAdded, 'assertive' );
    708718        }, 250 );
    709719    },
    710720
    711721    closeChooser: function() {
    712         var self = this;
     722        var self = this,
     723            widgetInQuestion = $( '#available-widgets .widget-in-question' );
    713724
    714725        $( '.widgets-chooser' ).slideUp( 200, function() {
    715726            $( '#wpbody-content' ).append( this );
    716727            self.clearWidgetSelection();
     728            // Move focus back to the toggle button.
     729            widgetInQuestion.find( '.widget-action' ).attr( 'aria-expanded', 'false' ).focus();
    717730        });
    718731    },
  • trunk/src/wp-includes/script-loader.php

    r42719 r42794  
    787787        $scripts->add( 'admin-gallery', "/wp-admin/js/gallery$suffix.js", array( 'jquery-ui-sortable' ) );
    788788
    789         $scripts->add( 'admin-widgets', "/wp-admin/js/widgets$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable' ), false, 1 );
     789        $scripts->add( 'admin-widgets', "/wp-admin/js/widgets$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable', 'wp-a11y' ), false, 1 );
    790790        did_action( 'init' ) && $scripts->add_inline_script(
    791791            'admin-widgets', sprintf(
    792792                'wpWidgets.l10n = %s;', wp_json_encode(
    793793                    array(
    794                         'save'      => __( 'Save' ),
    795                         'saved'     => __( 'Saved' ),
    796                         'saveAlert' => __( 'The changes you made will be lost if you navigate away from this page.' ),
     794                        'save'        => __( 'Save' ),
     795                        'saved'       => __( 'Saved' ),
     796                        'saveAlert'   => __( 'The changes you made will be lost if you navigate away from this page.' ),
     797                        'widgetAdded' => __( 'Widget has been added to the selected sidebar' ),
    797798                    )
    798799                )
Note: See TracChangeset for help on using the changeset viewer.