Make WordPress Core

Changeset 58306


Ignore:
Timestamp:
06/03/2024 08:33:03 PM (2 years ago)
Author:
joedolson
Message:

Menus: Accessibility: Improve screen reader text for edit button.

Change the edit menu item toggle to communicate more context about the item to be edited. Make edit text consistent between Customizer menu editor and admin menu editor.

The menu position is conveyed only visually, using indentation, because there are no organizational semantics in either editor. This change helps provide screen reader users with consistent contextual information about the order, position, and parent of the current item.

Props joedolson, rcreators, afercia, mohonchandra.
Fixes #60673, See #60672.

Location:
trunk/src
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/js/_enqueues/lib/nav-menu.js

    r54855 r58306  
    450450
    451451                        var thisLink, thisLinkText, primaryItems, itemPosition, title,
    452                                 parentItem, parentItemId, parentItemName, subItems,
     452                                parentItem, parentItemId, parentItemName, subItems, totalSubItems,
    453453                                $this = $( itemToRefresh ),
    454454                                menuItem = $this.closest( 'li.menu-item' ).first(),
    … …  
    456456                                isPrimaryMenuItem = ( 0 === depth ),
    457457                                itemName = $this.closest( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
     458                                menuItemType = $this.closest( '.menu-item-handle' ).find( '.item-controls' ).find( '.item-type' ).text(),
    458459                                position = parseInt( menuItem.index(), 10 ),
    459460                                prevItemDepth = ( isPrimaryMenuItem ) ? depth : parseInt( depth - 1, 10 ),
    … …  
    504505                                itemPosition = primaryItems.index( menuItem ) + 1,
    505506                                totalMenuItems = primaryItems.length,
    506 
    507507                                // String together help text for primary menu items.
    508                                 title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$d', totalMenuItems );
     508                                title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$s', menuItemType ).replace( '%3$d', itemPosition ).replace( '%4$d', totalMenuItems );
    509509                        } else {
    510510                                parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1, 10 ) ).first(),
    … …  
    512512                                parentItemName = parentItem.find( '.menu-item-title' ).text(),
    513513                                subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
     514                                totalSubItems = subItems.length,
    514515                                itemPosition = $( subItems.parents('.menu-item').get().reverse() ).index( menuItem ) + 1;
    515516
    516517                                // String together help text for sub menu items.
    517                                 title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$s', parentItemName );
     518                                if ( depth < 2 ) {
     519                                        title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$s', menuItemType ).replace( '%3$d', itemPosition ).replace( '%4$d', totalSubItems ).replace( '%5$s', parentItemName );
     520                                } else {
     521                                        title = menus.subMenuMoreDepthFocus.replace( '%1$s', itemName ).replace( '%2$s', menuItemType ).replace( '%3$d', itemPosition ).replace( '%4$d', totalSubItems ).replace( '%5$s', parentItemName ).replace( '%6$d', depth );
     522                                }
    518523                        }
    519524
    … …  
    733738                                        api.refreshKeyboardAccessibility();
    734739                                        api.refreshAdvancedAccessibility();
     740                                        api.refreshAdvancedAccessibilityOfItem( ui.item.find( 'a.item-edit' ) );
    735741                                },
    736742                                change: function(e, ui) {
  • trunk/src/js/_enqueues/wp/customize/nav-menus.js

    r57746 r58306  
    33 */
    44
    5 /* global _wpCustomizeNavMenusSettings, wpNavMenu, console */
     5/* global menus, _wpCustomizeNavMenusSettings, wpNavMenu, console */
    66( function( api, wp, $ ) {
    77        'use strict';
    … …  
    11331133                                wpNavMenu.menuList.attr( 'id', 'menu-to-edit' ).addClass( 'menu' );
    11341134
     1135                                api.Menus.MenuItemControl.prototype.initAccessibility();
     1136
    11351137                                _.each( api.section( section.id ).controls(), function( control ) {
    11361138                                        if ( 'nav_menu_item' === control.params.type ) {
    … …  
    15761578
    15771579                /**
     1580                 * Set up the initial state of the screen reader accessibility information for menu items.
     1581                 *
     1582                 * @since 6.6.0
     1583                 */
     1584                initAccessibility: function() {
     1585                        var control = this,
     1586                                menu = $( '#menu-to-edit' );
     1587
     1588                        // Refresh the accessibility when the user comes close to the item in any way.
     1589                        menu.on( 'mouseenter.refreshAccessibility focus.refreshAccessibility touchstart.refreshAccessibility', '.menu-item', function(){
     1590                                control.refreshAdvancedAccessibilityOfItem( $( this ).find( 'button.item-edit' ) );
     1591                        } );
     1592
     1593                        // We have to update on click as well because we might hover first, change the item, and then click.
     1594                        menu.on( 'click', 'button.item-edit', function() {
     1595                                control.refreshAdvancedAccessibilityOfItem( $( this ) );
     1596                        } );
     1597                },
     1598
     1599                /**
     1600                 * refreshAdvancedAccessibilityOfItem( [itemToRefresh] )
     1601                 *
     1602                 * Refreshes advanced accessibility buttons for one menu item.
     1603                 * Shows or hides buttons based on the location of the menu item.
     1604                 *
     1605                 * @param {Object} itemToRefresh The menu item that might need its advanced accessibility buttons refreshed
     1606                 *
     1607                 * @since 6.6.0
     1608                 */
     1609                refreshAdvancedAccessibilityOfItem: function( itemToRefresh ) {
     1610                        // Only refresh accessibility when necessary.
     1611                        if ( true !== $( itemToRefresh ).data( 'needs_accessibility_refresh' ) ) {
     1612                                return;
     1613                        }
     1614
     1615                        var primaryItems, itemPosition, title,
     1616                                parentItem, parentItemId, parentItemName, subItems, totalSubItems,
     1617                                $this = $( itemToRefresh ),
     1618                                menuItem = $this.closest( 'li.menu-item' ).first(),
     1619                                depth = menuItem.menuItemDepth(),
     1620                                isPrimaryMenuItem = ( 0 === depth ),
     1621                                itemName = $this.closest( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
     1622                                menuItemType = $this.closest( '.menu-item-handle' ).find( '.item-type' ).text(),
     1623                                totalMenuItems = $( '#menu-to-edit li' ).length;
     1624
     1625                        if ( isPrimaryMenuItem ) {
     1626                                primaryItems = $( '.menu-item-depth-0' ),
     1627                                itemPosition = primaryItems.index( menuItem ) + 1,
     1628                                totalMenuItems = primaryItems.length,
     1629                                // String together help text for primary menu items.
     1630                                title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$s', menuItemType ).replace( '%3$d', itemPosition ).replace( '%4$d', totalMenuItems );
     1631                        } else {
     1632                                parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1, 10 ) ).first(),
     1633                                parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(),
     1634                                parentItemName = parentItem.find( '.menu-item-title' ).text(),
     1635                                subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
     1636                                totalSubItems = subItems.length,
     1637                                itemPosition = $( subItems.parents( '.menu-item' ).get().reverse() ).index( menuItem ) + 1;
     1638
     1639                                // String together help text for sub menu items.
     1640                                if ( depth < 2 ) {
     1641                                        title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$s', menuItemType ).replace( '%3$d', itemPosition ).replace( '%4$d', totalSubItems ).replace( '%5$s', parentItemName );
     1642                                } else {
     1643                                        title = menus.subMenuMoreDepthFocus.replace( '%1$s', itemName ).replace( '%2$s', menuItemType ).replace( '%3$d', itemPosition ).replace( '%4$d', totalSubItems ).replace( '%5$s', parentItemName ).replace( '%6$d', depth );
     1644                                }
     1645                        }
     1646
     1647                        $this.find( '.screen-reader-text' ).text( title );
     1648
     1649                        // Mark this item's accessibility as refreshed.
     1650                        $this.data( 'needs_accessibility_refresh', false );
     1651                },
     1652
     1653                /**
    15781654                 * Override the embed() method to do nothing,
    15791655                 * so that the control isn't embedded on load,
    … …  
    16081684                        control.renderContent();
    16091685                        control.deferred.embedded.resolve(); // This triggers control.ready().
     1686                       
     1687                        // Mark all menu items as unprocessed.
     1688                        $( 'button.item-edit' ).data( 'needs_accessibility_refresh', true );
    16101689                },
    16111690
    … …  
    16801759                                } else if ( isMoveLeft ) {
    16811760                                        control.moveLeft();
    1682                                         if ( 1 === control.params.depth ) {
    1683                                                 control.container.find( '.is-submenu' ).hide();
    1684                                         } else {
    1685                                                 control.container.find( '.is-submenu' ).show();
    1686                                         }
    16871761                                } else if ( isMoveRight ) {
    16881762                                        control.moveRight();
    16891763                                        control.params.depth += 1;
    1690                                         if ( 0 === control.params.depth ) {
    1691                                                 control.container.find( '.is-submenu' ).hide();
    1692                                         } else {
    1693                                                 control.container.find( '.is-submenu' ).show();
    1694                                         }
    1695                                 }
    1696 
     1764                                }
     1765                               
    16971766                                moveBtn.focus(); // Re-focus after the container was moved.
     1767
     1768                                // Mark all menu items as unprocessed.
     1769                                $( 'button.item-edit' ).data( 'needs_accessibility_refresh', true );
    16981770                        } );
    16991771                },
    … …  
    27272799                                                menuItemControl.setting.set( setting );
    27282800                                        });
     2801
     2802                                        // Mark all menu items as unprocessed.
     2803                                        $( 'button.item-edit' ).data( 'needs_accessibility_refresh', true );
    27292804                                });
    27302805
  • trunk/src/wp-admin/nav-menus.php

    r56600 r58306  
    581581        /* translators: %s: Previous item name. */
    582582        'outFrom'                 => __( 'Out from under %s' ),
    583         /* translators: 1: Item name, 2: Item position, 3: Total number of items. */
    584         'menuFocus'               => __( '%1$s. Menu item %2$d of %3$d.' ),
    585         /* translators: 1: Item name, 2: Item position, 3: Parent item name. */
    586         'subMenuFocus'            => __( '%1$s. Sub item number %2$d under %3$s.' ),
     583        /* translators: 1: Item name, 2: Item type, 3: Item index, 4: Total items. */
     584        'menuFocus'               => __( 'Edit %1$s (%2$s, %3$d of %4$d)' ),
     585        /* translators: 1: Item name, 2: Item type, 3: Item index, 4: Total items, 5: Item parent. */
     586        'subMenuFocus'            => __( 'Edit %1$s (%2$s, sub-item %3$d of %4$d under %5$s)' ),
     587        /* translators: 1: Item name, 2: Item type, 3: Item index, 4: Total items, 5: Item parent, 6: Item depth. */
     588        'subMenuMoreDepthFocus'   => __( 'Edit %1$s (%2$s, sub-item %3$d of %4$d under %5$s, level %6$d)' ),
    587589        /* translators: %s: Item name. */
    588590        'menuItemDeletion'        => __( 'item %s' ),
  • trunk/src/wp-includes/class-wp-customize-nav-menus.php

    r58146 r58306  
    563563                        /* translators: %s: Previous item name. */
    564564                        'outFrom'                 => __( 'Out from under %s' ),
    565                         /* translators: 1: Item name, 2: Item position, 3: Total number of items. */
    566                         'menuFocus'               => __( '%1$s. Menu item %2$d of %3$d.' ),
    567                         /* translators: 1: Item name, 2: Item position, 3: Parent item name. */
    568                         'subMenuFocus'            => __( '%1$s. Sub item number %2$d under %3$s.' ),
     565                        /* translators: 1: Item name, 2: Item type, 3: Item index, 4: Total items. */
     566                        'menuFocus'               => __( 'Edit %1$s (%2$s, %3$d of %4$d)' ),
     567                        /* translators: 1: Item name, 2: Item type, 3: Item index, 4: Total items, 5: Item parent. */
     568                        'subMenuFocus'            => __( 'Edit %1$s (%2$s, sub-item %3$d of %4$d under %5$s)' ),
     569                        /* translators: 1: Item name, 2: Item type, 3: Item index, 4: Total items, 5: Item parent, 6: Item depth. */
     570                        'subMenuMoreDepthFocus'   => __( 'Edit %1$s (%2$s, sub-item %3$d of %4$d under %5$s, level %6$d)' ),
    569571                );
    570572                wp_localize_script( 'nav-menu', 'menus', $nav_menus_l10n );
  • trunk/src/wp-includes/customize/class-wp-customize-nav-menu-item-control.php

    r57746 r58306  
    7878                                <span class="item-controls">
    7979                                        <button type="button" class="button-link item-edit" aria-expanded="false"><span class="screen-reader-text">
    80                                         <?php
    81                                                 /* translators: 1: Title of a menu item, 2: Type of a menu item. */
    82                                                 printf( __( 'Edit menu item: %1$s (%2$s)' ), '{{ data.title || data.original_title || wp.customize.Menus.data.l10n.untitled }}', '{{ data.item_type_label }}' );
    83                                         ?>
     80                                        <# if ( 0 === data.depth ) { #>
     81                                                <?php
     82                                                /* translators: 1: Title of a menu item, 2: Type of a menu item. 3: Item index, 4: Total items. */
     83                                                printf( __( 'Edit %1$s (%2$s, %3$d of %4$d)' ), '{{ data.title || data.original_title || wp.customize.Menus.data.l10n.untitled }}', '{{ data.item_type_label }}', '', '' );
     84                                                ?>
     85                                        <# } else if ( 1 === data.depth ) { #>
     86                                                <?php
     87                                                        /* translators: 1: Title of a menu item, 2: Type of a menu item, 3, Item index, 4, Total items, 5: Item parent. */
     88                                                        printf( __( 'Edit %1$s (%2$s, sub-item %3$d of %4$d under %5$s)' ), '{{ data.title || data.original_title || wp.customize.Menus.data.l10n.untitled }}', '{{ data.item_type_label }}', '', '', '' );
     89                                                ?>
     90                                        <# } else { #>
     91                                                <?php
     92                                                        /* translators: 1: Title of a menu item, 2: Type of a menu item, 3, Item index, 4, Total items, 5: Item parent, 6: Item depth. */
     93                                                        printf( __( 'Edit %1$s (%2$s, sub-item %3$d of %4$d under %5$s, level %6$s)' ), '{{ data.title || data.original_title || wp.customize.Menus.data.l10n.untitled }}', '{{ data.item_type_label }}', '', '', '', '{{data.depth}}' );
     94                                                ?>
     95                                        <# } #>
    8496                                        </span><span class="toggle-indicator" aria-hidden="true"></span></button>
    8597                                        <button type="button" class="button-link item-delete submitdelete deletion"><span class="screen-reader-text">
Note: See TracChangeset for help on using the changeset viewer.