woocommerce-subscriptions/assets/js/modal.js

132 lines
3.5 KiB
JavaScript

jQuery( function ( $ ) {
const $modals = $( '.wcs-modal' );
let $currentModal;
let $triggerElement;
// Resize all open modals on window resize.
$( window ).on( 'resize', resizeModals );
// Initialize modals
$( $modals ).each( function () {
trigger = $( this ).data( 'modal-trigger' );
$( trigger ).on( 'click', { modal: this }, show_modal );
} );
/**
* Displays the modal linked to a click event.
*
* Attaches all close callbacks and resizes to fit.
*
* @param {JQuery event} event
*/
function show_modal( event ) {
$triggerElement = $( event.target );
$currentModal = $( event.data.modal );
if ( ! should_show_modal( $currentModal ) ) {
return;
}
// Prevent the trigger element event being triggered.
event.preventDefault();
const $contentWrapper = $currentModal.find( '.content-wrapper' );
const $close = $currentModal.find( '.close' );
$currentModal.addClass( 'open' );
resizeModal( $currentModal );
$( document.body ).toggleClass( 'wcs-modal-open', true );
$currentModal.focus();
document.addEventListener( 'focusin', keepFocusInModal );
// Attach callbacks to handle closing the modal.
$close.on( 'click', () => close_modal( $currentModal ) );
$currentModal.on( 'click', () => close_modal( $currentModal ) );
$contentWrapper.on( 'click', ( e ) => e.stopPropagation() );
// Close the modal if the escape key is pressed.
$currentModal.on( 'keyup', function ( e ) {
if ( 27 === e.keyCode ) {
close_modal( $currentModal );
}
} );
}
/**
* Closes a modal and resets any forced height styles.
*
* @param {JQuery Object} $modal
*/
function close_modal( $modal ) {
$modal.removeClass( 'open' );
$( $modal ).find( '.content-wrapper' ).css( 'height', '' );
if ( 0 === $modals.filter( '.open' ).length ) {
$( document.body ).removeClass( 'wcs-modal-open' );
$currentModal = false;
document.removeEventListener( 'focusin', keepFocusInModal );
$triggerElement.focus();
}
}
/**
* Determines if a modal should be displayed.
*
* A custom trigger is called to allow third-parties to filter whether the modal should be displayed or not.
*
* @param {JQuery Object} modal
*/
function should_show_modal( modal ) {
// Allow third-parties to filter whether the modal should be displayed.
var event = jQuery.Event( 'wcs_show_modal' );
event.modal = modal;
$( document ).trigger( event );
// Fallback to true (show modal) if the result is undefined.
return undefined === event.result ? true : event.result;
}
/**
* Resize all open modals to fit the display.
*/
function resizeModals() {
$( $modals ).each( function () {
if ( ! $( this ).hasClass( 'open' ) ) {
return;
}
resizeModal( this );
} );
}
/**
* Resize a modal to fit the display.
*
* @param {JQuery Object} $modal
*/
function resizeModal( $modal ) {
const $modal_container = $( $modal ).find( '.content-wrapper' );
// On smaller displays the height is already forced to be 100% in CSS. We just clear any height we might set previously.
if ( $( window ).width() <= 414 ) {
$modal_container.css( 'height', '' );
} else if ( $modal_container.height() > $( window ).height() ) {
// Force the container height to trigger scroll etc if it doesn't fit on the screen.
$modal_container.css( 'height', '90%' );
}
}
/**
* If focus moves out of the open modal, return focus to it.
*
* @param event
*/
function keepFocusInModal( event ) {
if ( $currentModal && ! $currentModal[0].contains( event.target ) ) {
$currentModal.focus();
}
}
} );