wp/wp-admin/js/customize-nav-menus.js
changeset 21 48c4eec2b7e6
parent 18 be944660c56a
child 22 8c2e4d02f4ef
--- a/wp/wp-admin/js/customize-nav-menus.js	Thu Sep 29 08:06:27 2022 +0200
+++ b/wp/wp-admin/js/customize-nav-menus.js	Fri Sep 05 18:40:08 2025 +0200
@@ -2,7 +2,7 @@
  * @output wp-admin/js/customize-nav-menus.js
  */
 
-/* global _wpCustomizeNavMenusSettings, wpNavMenu, console */
+/* global menus, _wpCustomizeNavMenusSettings, wpNavMenu, console */
 ( function( api, wp, $ ) {
 	'use strict';
 
@@ -1132,6 +1132,8 @@
 				$( '#menu-to-edit' ).removeAttr( 'id' );
 				wpNavMenu.menuList.attr( 'id', 'menu-to-edit' ).addClass( 'menu' );
 
+				api.Menus.MenuItemControl.prototype.initAccessibility();
+
 				_.each( api.section( section.id ).controls(), function( control ) {
 					if ( 'nav_menu_item' === control.params.type ) {
 						control.actuallyEmbed();
@@ -1575,6 +1577,80 @@
 		},
 
 		/**
+		 * Set up the initial state of the screen reader accessibility information for menu items.
+		 *
+		 * @since 6.6.0
+		 */
+		initAccessibility: function() {
+			var control = this,
+				menu = $( '#menu-to-edit' );
+
+			// Refresh the accessibility when the user comes close to the item in any way.
+			menu.on( 'mouseenter.refreshAccessibility focus.refreshAccessibility touchstart.refreshAccessibility', '.menu-item', function(){
+				control.refreshAdvancedAccessibilityOfItem( $( this ).find( 'button.item-edit' ) );
+			} );
+
+			// We have to update on click as well because we might hover first, change the item, and then click.
+			menu.on( 'click', 'button.item-edit', function() {
+				control.refreshAdvancedAccessibilityOfItem( $( this ) );
+			} );
+		},
+
+		/**
+		 * refreshAdvancedAccessibilityOfItem( [itemToRefresh] )
+		 *
+		 * Refreshes advanced accessibility buttons for one menu item.
+		 * Shows or hides buttons based on the location of the menu item.
+		 *
+		 * @param {Object} itemToRefresh The menu item that might need its advanced accessibility buttons refreshed
+		 * 
+		 * @since 6.6.0
+		 */
+		refreshAdvancedAccessibilityOfItem: function( itemToRefresh ) {
+			// Only refresh accessibility when necessary.
+			if ( true !== $( itemToRefresh ).data( 'needs_accessibility_refresh' ) ) {
+				return;
+			}
+
+			var primaryItems, itemPosition, title,
+				parentItem, parentItemId, parentItemName, subItems, totalSubItems,
+				$this = $( itemToRefresh ),
+				menuItem = $this.closest( 'li.menu-item' ).first(),
+				depth = menuItem.menuItemDepth(),
+				isPrimaryMenuItem = ( 0 === depth ),
+				itemName = $this.closest( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
+				menuItemType = $this.closest( '.menu-item-handle' ).find( '.item-type' ).text(),
+				totalMenuItems = $( '#menu-to-edit li' ).length;
+
+			if ( isPrimaryMenuItem ) {
+				primaryItems = $( '.menu-item-depth-0' ),
+				itemPosition = primaryItems.index( menuItem ) + 1,
+				totalMenuItems = primaryItems.length,
+				// String together help text for primary menu items.
+				title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$s', menuItemType ).replace( '%3$d', itemPosition ).replace( '%4$d', totalMenuItems );
+			} else {
+				parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1, 10 ) ).first(),
+				parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(),
+				parentItemName = parentItem.find( '.menu-item-title' ).text(),
+				subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
+				totalSubItems = subItems.length,
+				itemPosition = $( subItems.parents( '.menu-item' ).get().reverse() ).index( menuItem ) + 1;
+
+				// String together help text for sub menu items.
+				if ( depth < 2 ) {
+					title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$s', menuItemType ).replace( '%3$d', itemPosition ).replace( '%4$d', totalSubItems ).replace( '%5$s', parentItemName );
+				} else {
+					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 );
+				}
+			}
+
+			$this.find( '.screen-reader-text' ).text( title );
+
+			// Mark this item's accessibility as refreshed.
+			$this.data( 'needs_accessibility_refresh', false );
+		},
+
+		/**
 		 * Override the embed() method to do nothing,
 		 * so that the control isn't embedded on load,
 		 * unless the containing section is already expanded.
@@ -1607,6 +1683,9 @@
 			}
 			control.renderContent();
 			control.deferred.embedded.resolve(); // This triggers control.ready().
+			
+			// Mark all menu items as unprocessed.
+			$( 'button.item-edit' ).data( 'needs_accessibility_refresh', true );
 		},
 
 		/**
@@ -1664,6 +1743,8 @@
 			$reorderNav = control.container.find( '.menu-item-reorder-nav' );
 			$reorderNav.find( '.menus-move-up, .menus-move-down, .menus-move-left, .menus-move-right' ).on( 'click', function() {
 				var moveBtn = $( this );
+				control.params.depth = control.getDepth();
+
 				moveBtn.focus();
 
 				var isMoveUp = moveBtn.is( '.menus-move-up' ),
@@ -1679,9 +1760,13 @@
 					control.moveLeft();
 				} else if ( isMoveRight ) {
 					control.moveRight();
+					control.params.depth += 1;
 				}
-
+				
 				moveBtn.focus(); // Re-focus after the container was moved.
+
+				// Mark all menu items as unprocessed.
+				$( 'button.item-edit' ).data( 'needs_accessibility_refresh', true );
 			} );
 		},
 
@@ -2713,6 +2798,9 @@
 
 						menuItemControl.setting.set( setting );
 					});
+
+					// Mark all menu items as unprocessed.
+					$( 'button.item-edit' ).data( 'needs_accessibility_refresh', true );
 				});
 
 			});