[Accessibility] Trap focus inside the product gallery modal (#50730)

* Add i18n_open_product_gallery prop to wc_single_product_params

* Trap focus inside the product gallery modal

* Ensure the product gallery controls are always visible

* Add changelog file

* Add space before parameter

* Early return if there is no elements enough to trap focus

* Revert changes on the gallery trigger link

* Remove unnecessary white sopace

* Fix trap focus when the arrow buttons are hidden

* Remove usage of the Photoswipe destroy event
This commit is contained in:
Gabriel Manussakis 2024-08-30 05:14:22 -03:00 committed by GitHub
parent ff197207ef
commit 0f1634d6da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 70 additions and 3 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Trap focus inside the product gallery modal.

View File

@ -127,6 +127,8 @@ jQuery( function( $ ) {
this.onResetSlidePosition = this.onResetSlidePosition.bind( this );
this.getGalleryItems = this.getGalleryItems.bind( this );
this.openPhotoswipe = this.openPhotoswipe.bind( this );
this.trapFocusPhotoswipe = this.trapFocusPhotoswipe.bind( this );
this.handlePswpTrapFocus = this.handlePswpTrapFocus.bind( this );
if ( this.flexslider_enabled ) {
this.initFlexslider( args.flexslider );
@ -309,6 +311,8 @@ jQuery( function( $ ) {
var pswpElement = $( '.pswp' )[0],
items = this.getGalleryItems(),
eventTarget = $( e.target ),
currentTarget = e.currentTarget,
self = this,
clicked;
if ( 0 < eventTarget.closest( '.woocommerce-product-gallery__trigger' ).length ) {
@ -326,14 +330,73 @@ jQuery( function( $ ) {
}
captionEl.children[0].textContent = item.title;
return true;
}
},
timeToIdle: 0, // Ensure the gallery controls are always visible to avoid keyboard navigation issues.
}, wc_single_product_params.photoswipe_options );
// Initializes and opens PhotoSwipe.
var photoswipe = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options );
photoswipe.listen( 'afterInit', function() {
self.trapFocusPhotoswipe( true );
});
photoswipe.listen( 'close', function() {
self.trapFocusPhotoswipe( false );
currentTarget.focus();
});
photoswipe.init();
};
/**
* Control focus in photoswipe modal.
*
* @param {boolean} trapFocus - Whether to trap focus or not.
*/
ProductGallery.prototype.trapFocusPhotoswipe = function( trapFocus ) {
var pswp = document.querySelector( '.pswp' );
if ( ! pswp ) {
return;
}
if ( trapFocus ) {
pswp.addEventListener( 'keydown', this.handlePswpTrapFocus );
} else {
pswp.removeEventListener( 'keydown', this.handlePswpTrapFocus );
}
};
/**
* Handle keydown event in photoswipe modal.
*/
ProductGallery.prototype.handlePswpTrapFocus = function( e ) {
var allFocusablesEls = e.currentTarget.querySelectorAll( 'button:not([disabled])' );
var filteredFocusablesEls = Array.from( allFocusablesEls ).filter( function( btn ) {
return btn.style.display !== 'none' && window.getComputedStyle( btn ).display !== 'none';
} );
if ( 1 >= filteredFocusablesEls.length ) {
return;
}
var firstTabStop = filteredFocusablesEls[0];
var lastTabStop = filteredFocusablesEls[filteredFocusablesEls.length - 1];
if ( e.key === 'Tab' ) {
if ( e.shiftKey ) {
if ( document.activeElement === firstTabStop ) {
e.preventDefault();
lastTabStop.focus();
}
} else if ( document.activeElement === lastTabStop ) {
e.preventDefault();
firstTabStop.focus();
}
}
};
/**
* Function to call wc_product_gallery on jquery selector.
*/