New helper to monitor multistep checkout forms

The new script adds an interval to monitor the visibility of the “woocommerce-checkout-payment” element to initialize payment buttons with a delay, if needed.
This commit is contained in:
Philipp Stracker 2024-06-26 17:56:48 +02:00
parent 167c2c6883
commit 25c5ef2e9e
No known key found for this signature in database
2 changed files with 124 additions and 0 deletions

View file

@ -17,6 +17,7 @@ import {
import {setVisibleByClass} from "./modules/Helper/Hiding";
import {isChangePaymentPage} from "./modules/Helper/Subscriptions";
import FreeTrialHandler from "./modules/ActionHandler/FreeTrialHandler";
import MultistepCheckoutHelper from "./modules/Helper/MultistepCheckoutHelper";
import FormSaver from './modules/Helper/FormSaver';
import FormValidator from "./modules/Helper/FormValidator";
import {loadPaypalScript} from "./modules/Helper/ScriptLoading";
@ -53,6 +54,8 @@ const bootstrap = () => {
const freeTrialHandler = new FreeTrialHandler(PayPalCommerceGateway, checkoutFormSelector, formSaver, formValidator, spinner, errorHandler);
new MultistepCheckoutHelper(checkoutFormSelector);
jQuery('form.woocommerce-checkout input').on('keydown', e => {
if (e.key === 'Enter' && [
PaymentMethods.PAYPAL,

View file

@ -0,0 +1,121 @@
/**
* The MultistepCheckoutHelper class ensures the initialization of payment buttons
* on websites using a multistep checkout plugin. These plugins usually hide the
* payment button on page load up and reveal it later using JS. During the
* invisibility period of wrappers, some payment buttons fail to initialize,
* so we wait for the payment element to be visible.
*
* @property {HTMLElement} form - Checkout form element.
* @property {HTMLElement} triggerElement - Element, which visibility we need to detect.
* @property {boolean} isVisible - Whether the triggerElement is visible.
*/
class MultistepCheckoutHelper {
/**
* Configuration that defines the HTML selector for the component we are waiting to be visible.
* @type {string}
*/
#triggerElementSelector = '.woocommerce-checkout-payment';
/**
* Interval (in milliseconds) in which the visibility of the trigger element is checked.
* @type {number}
*/
#intervalTime = 150;
/**
* The interval ID returned by the setInterval() method.
* @type {number|false}
*/
#intervalId;
/**
* Selector passed to the constructor that identifies the checkout form
* @type {string}
*/
#formSelector;
/**
* @param {string} formSelector - Selector of the checkout form
*/
constructor(formSelector) {
this.#formSelector = formSelector;
this.#intervalId = false;
/*
Start the visibility checker after a brief delay. This allows eventual multistep plugins to
dynamically prepare the checkout page, so we can decide whether this helper is needed.
*/
setTimeout(() => {
if (this.form && !this.isVisible) {
this.start();
}
}, 250);
}
/**
* The checkout form element.
* @returns {Element|null} - Form element or null.
*/
get form() {
return document.querySelector(this.#formSelector);
}
/**
* The element which must be visible before payment buttons should be initialized.
* @returns {Element|null} - Trigger element or null.
*/
get triggerElement() {
return this.form?.querySelector(this.#triggerElementSelector);
}
/**
* Checks the visibility of the payment button wrapper.
* @returns {boolean} - returns boolean value on the basis of visibility of element.
*/
get isVisible() {
const box = this.triggerElement?.getBoundingClientRect();
return !!(box && box.width && box.height);
}
/**
* Starts the observation of the DOM, initiates monitoring the checkout form.
* To ensure multiple calls to start don't create multiple intervals, we first call stop.
*/
start() {
this.stop();
this.#intervalId = setInterval(() => this.checkElement(), this.#intervalTime);
}
/**
* Stops the observation of the checkout form.
* Multiple calls to stop are safe as clearInterval doesn't throw if provided ID doesn't exist.
*/
stop() {
if (this.#intervalId) {
clearInterval(this.#intervalId);
this.#intervalId = false;
}
}
/**
* Checks if the trigger element is visible.
* If visible, it initialises the payment buttons and stops the observation.
*/
checkElement() {
if (this.isVisible) {
this.refreshButtons();
this.stop();
}
}
/**
* Initializes the payment buttons on the visibility of wrapper.
*/
refreshButtons() {
document.dispatchEvent(new Event('ppcp_refresh_payment_buttons'));
}
}
export default MultistepCheckoutHelper;