woocommerce-paypal-payments/modules/ppcp-settings/resources/js/utils/Helper/MultistepCheckoutHelper.js

124 lines
3.4 KiB
JavaScript
Raw Normal View History

import { refreshButtons } from './ButtonRefreshHelper';
const DEFAULT_TRIGGER_ELEMENT_SELECTOR = '.woocommerce-checkout-payment';
/**
* 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 {
/**
* Selector that defines the HTML element we are waiting to become visible.
* @type {string}
*/
#triggerElementSelector;
/**
* 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
* @param {string} triggerElementSelector - Optional. Selector of the dependant element.
*/
constructor( formSelector, triggerElementSelector = '' ) {
this.#formSelector = formSelector;
this.#triggerElementSelector =
triggerElementSelector || DEFAULT_TRIGGER_ELEMENT_SELECTOR;
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.
* @return {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.
* @return {Element|null} - Trigger element or null.
*/
get triggerElement() {
return this.form?.querySelector( this.#triggerElementSelector );
}
/**
* Checks the visibility of the payment button wrapper.
* @return {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 ) {
refreshButtons();
this.stop();
}
}
}
export default MultistepCheckoutHelper;