wp/wp-admin/js/customize-controls.js
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
--- a/wp/wp-admin/js/customize-controls.js	Fri Sep 05 18:40:08 2025 +0200
+++ b/wp/wp-admin/js/customize-controls.js	Fri Sep 05 18:52:52 2025 +0200
@@ -1530,7 +1530,7 @@
 			}
 
 			// Expand/Collapse accordion sections on click.
-			section.container.find( '.accordion-section-title, .customize-section-back' ).on( 'click keydown', function( event ) {
+			section.container.find( '.accordion-section-title button, .customize-section-back, .accordion-section-title[tabindex]' ).on( 'click keydown', function( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -1605,7 +1605,7 @@
 				content = section.contentContainer,
 				overlay = section.headContainer.closest( '.wp-full-overlay' ),
 				backBtn = content.find( '.customize-section-back' ),
-				sectionTitle = section.headContainer.find( '.accordion-section-title' ).first(),
+				sectionTitle = section.headContainer.find( '.accordion-section-title button, .accordion-section-title[tabindex]' ).first(),
 				expand, panel;
 
 			if ( expanded && ! content.hasClass( 'open' ) ) {
@@ -1615,9 +1615,6 @@
 				} else {
 					expand = function() {
 						section._animateChangeExpanded( function() {
-							sectionTitle.attr( 'tabindex', '-1' );
-							backBtn.attr( 'tabindex', '0' );
-
 							backBtn.trigger( 'focus' );
 							content.css( 'top', '' );
 							container.scrollTop( 0 );
@@ -1663,8 +1660,6 @@
 					}
 				}
 				section._animateChangeExpanded( function() {
-					backBtn.attr( 'tabindex', '-1' );
-					sectionTitle.attr( 'tabindex', '0' );
 
 					sectionTitle.trigger( 'focus' );
 					content.css( 'top', '' );
@@ -2699,7 +2694,7 @@
 				container = section.headContainer.closest( '.wp-full-overlay-sidebar-content' ),
 				content = section.contentContainer,
 				backBtn = content.find( '.customize-section-back' ),
-				sectionTitle = section.headContainer.find( '.accordion-section-title' ).first(),
+				sectionTitle = section.headContainer.find( '.accordion-section-title button, .accordion-section-title[tabindex]' ).first(),
 				body = $( document.body ),
 				expand, panel;
 
@@ -2719,9 +2714,6 @@
 				} else {
 					expand = function() {
 						section._animateChangeExpanded( function() {
-							sectionTitle.attr( 'tabindex', '-1' );
-							backBtn.attr( 'tabindex', '0' );
-
 							backBtn.trigger( 'focus' );
 							content.css( 'top', '' );
 							container.scrollTop( 0 );
@@ -2752,8 +2744,6 @@
 					}
 				}
 				section._animateChangeExpanded( function() {
-					backBtn.attr( 'tabindex', '-1' );
-					sectionTitle.attr( 'tabindex', '0' );
 
 					sectionTitle.trigger( 'focus' );
 					content.css( 'top', '' );
@@ -2843,7 +2833,7 @@
 			var meta, panel = this;
 
 			// Expand/Collapse accordion sections on click.
-			panel.headContainer.find( '.accordion-section-title' ).on( 'click keydown', function( event ) {
+			panel.headContainer.find( '.accordion-section-title button, .accordion-section-title[tabindex]' ).on( 'click keydown', function( event ) {
 				if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
 					return;
 				}
@@ -2947,7 +2937,7 @@
 				accordionSection = panel.contentContainer,
 				overlay = accordionSection.closest( '.wp-full-overlay' ),
 				container = accordionSection.closest( '.wp-full-overlay-sidebar-content' ),
-				topPanel = panel.headContainer.find( '.accordion-section-title' ),
+				topPanel = panel.headContainer.find( '.accordion-section-title button, .accordion-section-title[tabindex]' ),
 				backBtn = accordionSection.find( '.customize-panel-back' ),
 				childSections = panel.sections(),
 				skipTransition;
@@ -2974,9 +2964,6 @@
 					} );
 				} else {
 					panel._animateChangeExpanded( function() {
-						topPanel.attr( 'tabindex', '-1' );
-						backBtn.attr( 'tabindex', '0' );
-
 						backBtn.trigger( 'focus' );
 						accordionSection.css( 'top', '' );
 						container.scrollTop( 0 );
@@ -2996,8 +2983,6 @@
 				skipTransition = accordionSection.hasClass( 'skip-transition' );
 				if ( ! skipTransition ) {
 					panel._animateChangeExpanded( function() {
-						topPanel.attr( 'tabindex', '0' );
-						backBtn.attr( 'tabindex', '-1' );
 
 						topPanel.focus();
 						accordionSection.css( 'top', '' );
@@ -4602,26 +4587,29 @@
 		 * @return {Object} Options
 		 */
 		calculateImageSelectOptions: function( attachment, controller ) {
-			var control    = controller.get( 'control' ),
-				flexWidth  = !! parseInt( control.params.flex_width, 10 ),
-				flexHeight = !! parseInt( control.params.flex_height, 10 ),
-				realWidth  = attachment.get( 'width' ),
-				realHeight = attachment.get( 'height' ),
-				xInit = parseInt( control.params.width, 10 ),
-				yInit = parseInt( control.params.height, 10 ),
-				ratio = xInit / yInit,
-				xImg  = xInit,
-				yImg  = yInit,
+			var control       = controller.get( 'control' ),
+				flexWidth     = !! parseInt( control.params.flex_width, 10 ),
+				flexHeight    = !! parseInt( control.params.flex_height, 10 ),
+				realWidth     = attachment.get( 'width' ),
+				realHeight    = attachment.get( 'height' ),
+				xInit         = parseInt( control.params.width, 10 ),
+				yInit         = parseInt( control.params.height, 10 ),
+				requiredRatio = xInit / yInit,
+				realRatio     = realWidth / realHeight,
+				xImg          = xInit,
+				yImg          = yInit,
 				x1, y1, imgSelectOptions;
 
+			controller.set( 'hasRequiredAspectRatio', control.hasRequiredAspectRatio( requiredRatio, realRatio ) );
+			controller.set( 'suggestedCropSize', { width: realWidth, height: realHeight, x1: 0, y1: 0, x2: xInit, y2: yInit } );
 			controller.set( 'canSkipCrop', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) );
 
-			if ( realWidth / realHeight > ratio ) {
+			if ( realRatio > requiredRatio ) {
 				yInit = realHeight;
-				xInit = yInit * ratio;
+				xInit = yInit * requiredRatio;
 			} else {
 				xInit = realWidth;
-				yInit = xInit / ratio;
+				yInit = xInit / requiredRatio;
 			}
 
 			x1 = ( realWidth - xInit ) / 2;
@@ -4662,13 +4650,13 @@
 		/**
 		 * Return whether the image must be cropped, based on required dimensions.
 		 *
-		 * @param {boolean} flexW
-		 * @param {boolean} flexH
-		 * @param {number}  dstW
-		 * @param {number}  dstH
-		 * @param {number}  imgW
-		 * @param {number}  imgH
-		 * @return {boolean}
+		 * @param {boolean} flexW Width is flexible.
+		 * @param {boolean} flexH Height is flexible.
+		 * @param {number}  dstW  Required width.
+		 * @param {number}  dstH  Required height.
+		 * @param {number}  imgW  Provided image's width.
+		 * @param {number}  imgH  Provided image's height.
+		 * @return {boolean} Whether cropping is required.
 		 */
 		mustBeCropped: function( flexW, flexH, dstW, dstH, imgW, imgH ) {
 			if ( true === flexW && true === flexH ) {
@@ -4695,6 +4683,25 @@
 		},
 
 		/**
+		 * Check if the image's aspect ratio essentially matches the required aspect ratio.
+		 *
+		 * Floating point precision is low, so this allows a small tolerance. This
+		 * tolerance allows for images over 100,000 px on either side to still trigger
+		 * the cropping flow.
+		 *
+		 * @param {number} requiredRatio Required image ratio.
+		 * @param {number} realRatio     Provided image ratio.
+		 * @return {boolean} Whether the image has the required aspect ratio.
+		 */
+		hasRequiredAspectRatio: function ( requiredRatio, realRatio ) {
+			if ( Math.abs( requiredRatio - realRatio ) < 0.000001 ) {
+				return true;
+			}
+
+			return false;
+		},
+
+		/**
 		 * If cropping was skipped, apply the image data directly to the setting.
 		 */
 		onSkippedCrop: function() {