mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 12:25:15 +08:00
Merge trunk
This commit is contained in:
commit
96e434d4b0
77 changed files with 1571 additions and 831 deletions
|
@ -28,6 +28,8 @@ const cardsSpinner = new Spinner('#ppcp-hosted-fields');
|
|||
const bootstrap = () => {
|
||||
const checkoutFormSelector = 'form.woocommerce-checkout';
|
||||
|
||||
const context = PayPalCommerceGateway.context;
|
||||
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
document.querySelector(checkoutFormSelector) ?? document.querySelector('.woocommerce-notices-wrapper')
|
||||
|
@ -58,7 +60,7 @@ const bootstrap = () => {
|
|||
}
|
||||
});
|
||||
|
||||
const onSmartButtonClick = (data, actions) => {
|
||||
const onSmartButtonClick = async (data, actions) => {
|
||||
window.ppcpFundingSource = data.fundingSource;
|
||||
const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
|
||||
requiredFields.each((i, input) => {
|
||||
|
@ -120,13 +122,21 @@ const bootstrap = () => {
|
|||
freeTrialHandler.handle();
|
||||
return actions.reject();
|
||||
}
|
||||
|
||||
if (context === 'checkout' && !PayPalCommerceGateway.funding_sources_without_redirect.includes(data.fundingSource)) {
|
||||
try {
|
||||
await formSaver.save(form);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onSmartButtonsInit = () => {
|
||||
buttonsSpinner.unblock();
|
||||
};
|
||||
const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit);
|
||||
const messageRenderer = new MessageRenderer(PayPalCommerceGateway.messages);
|
||||
const context = PayPalCommerceGateway.context;
|
||||
if (context === 'mini-cart' || context === 'product') {
|
||||
if (PayPalCommerceGateway.mini_cart_buttons_enabled === '1') {
|
||||
const miniCartBootstrap = new MiniCartBootstap(
|
||||
|
|
|
@ -102,6 +102,9 @@ class CheckoutActionHandler {
|
|||
} else {
|
||||
errorHandler.message(data.data.message);
|
||||
}
|
||||
|
||||
// fire WC event for other plugins
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ errorHandler.currentHtml() ] );
|
||||
}
|
||||
|
||||
throw {type: 'create-order-error', data: data.data};
|
||||
|
|
|
@ -40,6 +40,10 @@ class FreeTrialHandler {
|
|||
if (errors.length > 0) {
|
||||
this.spinner.unblock();
|
||||
this.errorHandler.messages(errors);
|
||||
|
||||
// fire WC event for other plugins
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ this.errorHandler.currentHtml() ] );
|
||||
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import ButtonsToggleListener from '../Helper/ButtonsToggleListener';
|
||||
import Product from '../Entity/Product';
|
||||
import onApprove from '../OnApproveHandler/onApproveForContinue';
|
||||
import {payerData} from "../Helper/PayerData";
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import CartActionHandler from '../ActionHandler/CartActionHandler';
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
import {setVisible} from "../Helper/Hiding";
|
||||
import {subscriptionHasPlan} from "../Helper/Subscriptions";
|
||||
|
||||
|
@ -7,6 +8,10 @@ class CartBootstrap {
|
|||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.errorHandler = errorHandler;
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||
this.handleButtonStatus();
|
||||
}, true);
|
||||
}
|
||||
|
||||
init() {
|
||||
|
@ -15,9 +20,11 @@ class CartBootstrap {
|
|||
}
|
||||
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
|
||||
jQuery(document.body).on('updated_cart_totals updated_checkout', () => {
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
|
||||
fetch(
|
||||
this.gateway.ajax.cart_script_params.endpoint,
|
||||
|
@ -41,10 +48,18 @@ class CartBootstrap {
|
|||
});
|
||||
}
|
||||
|
||||
handleButtonStatus() {
|
||||
BootstrapHelper.handleButtonStatus(this);
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
return document.querySelector(this.gateway.button.wrapper) !== null && subscriptionHasPlan();
|
||||
}
|
||||
|
||||
shouldEnable() {
|
||||
return BootstrapHelper.shouldEnable(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
const actionHandler = new CartActionHandler(
|
||||
PayPalCommerceGateway,
|
||||
|
|
|
@ -5,6 +5,8 @@ import {
|
|||
isSavedCardSelected, ORDER_BUTTON_SELECTOR,
|
||||
PaymentMethods
|
||||
} from "../Helper/CheckoutMethodState";
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
import {disable, enable} from "../Helper/ButtonDisabler";
|
||||
|
||||
class CheckoutBootstap {
|
||||
constructor(gateway, renderer, messages, spinner, errorHandler) {
|
||||
|
@ -15,10 +17,15 @@ class CheckoutBootstap {
|
|||
this.errorHandler = errorHandler;
|
||||
|
||||
this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR;
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||
this.handleButtonStatus();
|
||||
}, true);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
|
||||
// Unselect saved card.
|
||||
// WC saves form values, so with our current UI it would be a bit weird
|
||||
|
@ -28,6 +35,7 @@ class CheckoutBootstap {
|
|||
|
||||
jQuery(document.body).on('updated_checkout', () => {
|
||||
this.render()
|
||||
this.handleButtonStatus();
|
||||
});
|
||||
|
||||
jQuery(document.body).on('updated_checkout payment_method_selected', () => {
|
||||
|
@ -43,6 +51,10 @@ class CheckoutBootstap {
|
|||
this.updateUi();
|
||||
}
|
||||
|
||||
handleButtonStatus() {
|
||||
BootstrapHelper.handleButtonStatus(this);
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
if (document.querySelector(this.gateway.button.cancel_wrapper)) {
|
||||
return false;
|
||||
|
@ -51,6 +63,10 @@ class CheckoutBootstap {
|
|||
return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null;
|
||||
}
|
||||
|
||||
shouldEnable() {
|
||||
return BootstrapHelper.shouldEnable(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldRender()) {
|
||||
return;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import CartActionHandler from '../ActionHandler/CartActionHandler';
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
|
||||
class MiniCartBootstap {
|
||||
constructor(gateway, renderer, errorHandler) {
|
||||
|
@ -15,9 +16,22 @@ class MiniCartBootstap {
|
|||
this.errorHandler,
|
||||
);
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
|
||||
jQuery(document.body).on('wc_fragments_loaded wc_fragments_refreshed', () => {
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
});
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.mini_cart_wrapper, () => {
|
||||
this.handleButtonStatus();
|
||||
}, true);
|
||||
}
|
||||
|
||||
handleButtonStatus() {
|
||||
BootstrapHelper.handleButtonStatus(this, {
|
||||
wrapper: this.gateway.button.mini_cart_wrapper,
|
||||
skipMessages: true
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -26,6 +40,12 @@ class MiniCartBootstap {
|
|||
|| document.querySelector(this.gateway.hosted_fields.mini_cart_wrapper) !== null;
|
||||
}
|
||||
|
||||
shouldEnable() {
|
||||
return BootstrapHelper.shouldEnable(this, {
|
||||
isDisabled: !!this.gateway.button.is_mini_cart_disabled
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldRender()) {
|
||||
return;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import UpdateCart from "../Helper/UpdateCart";
|
||||
import SingleProductActionHandler from "../ActionHandler/SingleProductActionHandler";
|
||||
import {hide, show, setVisible} from "../Helper/Hiding";
|
||||
import ButtonsToggleListener from "../Helper/ButtonsToggleListener";
|
||||
import {hide, show} from "../Helper/Hiding";
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
import {subscriptionHasPlan} from "../Helper/Subscriptions";
|
||||
|
||||
class SingleProductBootstap {
|
||||
|
@ -11,78 +11,88 @@ class SingleProductBootstap {
|
|||
this.messages = messages;
|
||||
this.errorHandler = errorHandler;
|
||||
this.mutationObserver = new MutationObserver(this.handleChange.bind(this));
|
||||
this.formSelector = 'form.cart';
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||
this.handleChange();
|
||||
}, true);
|
||||
}
|
||||
|
||||
variations() {
|
||||
if (!this.hasVariations()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const attributes = [...document.querySelector('form.cart')?.querySelectorAll("[name^='attribute_']")].map(
|
||||
(element) => {
|
||||
return {
|
||||
value: element.value,
|
||||
name: element.name
|
||||
}
|
||||
}
|
||||
);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
hasVariations() {
|
||||
return document.querySelector('form.cart')?.classList.contains('variations_form');
|
||||
form() {
|
||||
return document.querySelector(this.formSelector);
|
||||
}
|
||||
|
||||
handleChange() {
|
||||
const shouldRender = this.shouldRender();
|
||||
setVisible(this.gateway.button.wrapper, shouldRender);
|
||||
setVisible(this.gateway.messages.wrapper, shouldRender);
|
||||
if (!shouldRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
init() {
|
||||
const form = document.querySelector('form.cart');
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
|
||||
form.addEventListener('change', this.handleChange.bind(this));
|
||||
this.mutationObserver.observe(form, {childList: true, subtree: true});
|
||||
|
||||
const buttonObserver = new ButtonsToggleListener(
|
||||
form.querySelector('.single_add_to_cart_button'),
|
||||
() => {
|
||||
show(this.gateway.button.wrapper);
|
||||
show(this.gateway.messages.wrapper);
|
||||
this.messages.renderWithAmount(this.priceAmount())
|
||||
},
|
||||
() => {
|
||||
hide(this.gateway.button.wrapper);
|
||||
hide(this.gateway.messages.wrapper);
|
||||
},
|
||||
);
|
||||
buttonObserver.init();
|
||||
|
||||
if (!this.shouldRender()) {
|
||||
hide(this.gateway.button.wrapper);
|
||||
this.renderer.disableSmartButtons(this.gateway.button.wrapper);
|
||||
hide(this.gateway.button.wrapper, this.formSelector);
|
||||
hide(this.gateway.messages.wrapper);
|
||||
return;
|
||||
}
|
||||
|
||||
this.render();
|
||||
|
||||
this.renderer.enableSmartButtons(this.gateway.button.wrapper);
|
||||
show(this.gateway.button.wrapper);
|
||||
show(this.gateway.messages.wrapper);
|
||||
|
||||
this.handleButtonStatus();
|
||||
}
|
||||
|
||||
handleButtonStatus() {
|
||||
BootstrapHelper.handleButtonStatus(this, {
|
||||
formSelector: this.formSelector
|
||||
});
|
||||
}
|
||||
|
||||
init() {
|
||||
const form = this.form();
|
||||
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
|
||||
form.addEventListener('change', () => {
|
||||
this.handleChange();
|
||||
|
||||
setTimeout(() => { // Wait for the DOM to be fully updated
|
||||
// For the moment renderWithAmount should only be done here to prevent undesired side effects due to priceAmount()
|
||||
// not being correctly formatted in some cases, can be moved to handleButtonStatus() once this issue is fixed
|
||||
this.messages.renderWithAmount(this.priceAmount());
|
||||
}, 100);
|
||||
});
|
||||
this.mutationObserver.observe(form, { childList: true, subtree: true });
|
||||
|
||||
const addToCartButton = form.querySelector('.single_add_to_cart_button');
|
||||
|
||||
if (addToCartButton) {
|
||||
(new MutationObserver(this.handleButtonStatus.bind(this)))
|
||||
.observe(addToCartButton, { attributes : true });
|
||||
}
|
||||
|
||||
if (!this.shouldRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.render();
|
||||
this.handleChange();
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
return document.querySelector('form.cart') !== null
|
||||
&& !this.priceAmountIsZero()
|
||||
&& !this.isSubscriptionMode()
|
||||
return this.form() !== null
|
||||
&& !this.isWcsattSubscriptionMode()
|
||||
&& subscriptionHasPlan();
|
||||
}
|
||||
|
||||
shouldEnable() {
|
||||
const form = this.form();
|
||||
const addToCartButton = form ? form.querySelector('.single_add_to_cart_button') : null;
|
||||
|
||||
return BootstrapHelper.shouldEnable(this)
|
||||
&& !this.priceAmountIsZero()
|
||||
&& ((null === addToCartButton) || !addToCartButton.classList.contains('disabled'));
|
||||
}
|
||||
|
||||
priceAmount() {
|
||||
const priceText = [
|
||||
() => document.querySelector('form.cart ins .woocommerce-Price-amount')?.innerText,
|
||||
|
@ -113,16 +123,36 @@ class SingleProductBootstap {
|
|||
if(subscriptionHasPlan()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const price = this.priceAmount();
|
||||
return !price || price === 0;
|
||||
}
|
||||
|
||||
isSubscriptionMode() {
|
||||
isWcsattSubscriptionMode() {
|
||||
// Check "All products for subscriptions" plugin.
|
||||
return document.querySelector('.wcsatt-options-product:not(.wcsatt-options-product--hidden) .subscription-option input[type="radio"]:checked') !== null
|
||||
|| document.querySelector('.wcsatt-options-prompt-label-subscription input[type="radio"]:checked') !== null; // grouped
|
||||
}
|
||||
|
||||
variations() {
|
||||
if (!this.hasVariations()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [...document.querySelector('form.cart')?.querySelectorAll("[name^='attribute_']")].map(
|
||||
(element) => {
|
||||
return {
|
||||
value: element.value,
|
||||
name: element.name
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
hasVariations() {
|
||||
return document.querySelector('form.cart')?.classList.contains('variations_form');
|
||||
}
|
||||
|
||||
render() {
|
||||
const actionHandler = new SingleProductActionHandler(
|
||||
this.gateway,
|
||||
|
@ -130,7 +160,7 @@ class SingleProductBootstap {
|
|||
this.gateway.ajax.change_cart.endpoint,
|
||||
this.gateway.ajax.change_cart.nonce,
|
||||
),
|
||||
document.querySelector('form.cart'),
|
||||
this.form(),
|
||||
this.errorHandler,
|
||||
);
|
||||
|
||||
|
|
|
@ -40,6 +40,15 @@ class ErrorHandler {
|
|||
this._scrollToMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {String}
|
||||
*/
|
||||
currentHtml()
|
||||
{
|
||||
const messageContainer = this._getMessageContainer();
|
||||
return messageContainer.outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {String} text
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import {disable, enable} from "./ButtonDisabler";
|
||||
|
||||
/**
|
||||
* Common Bootstrap methods to avoid code repetition.
|
||||
*/
|
||||
export default class BootstrapHelper {
|
||||
|
||||
static handleButtonStatus(bs, options) {
|
||||
options = options || {};
|
||||
options.wrapper = options.wrapper || bs.gateway.button.wrapper;
|
||||
options.messagesWrapper = options.messagesWrapper || bs.gateway.messages.wrapper;
|
||||
options.skipMessages = options.skipMessages || false;
|
||||
|
||||
if (!bs.shouldEnable()) {
|
||||
bs.renderer.disableSmartButtons(options.wrapper);
|
||||
disable(options.wrapper, options.formSelector || null);
|
||||
|
||||
if (!options.skipMessages) {
|
||||
disable(options.messagesWrapper);
|
||||
}
|
||||
return;
|
||||
}
|
||||
bs.renderer.enableSmartButtons(options.wrapper);
|
||||
enable(options.wrapper);
|
||||
|
||||
if (!options.skipMessages) {
|
||||
enable(options.messagesWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
static shouldEnable(bs, options) {
|
||||
options = options || {};
|
||||
if (typeof options.isDisabled === 'undefined') {
|
||||
options.isDisabled = bs.gateway.button.is_disabled;
|
||||
}
|
||||
|
||||
return bs.shouldRender()
|
||||
&& options.isDisabled !== true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* @param selectorOrElement
|
||||
* @returns {Element}
|
||||
*/
|
||||
const getElement = (selectorOrElement) => {
|
||||
if (typeof selectorOrElement === 'string') {
|
||||
return document.querySelector(selectorOrElement);
|
||||
}
|
||||
return selectorOrElement;
|
||||
}
|
||||
|
||||
export const setEnabled = (selectorOrElement, enable, form = null) => {
|
||||
const element = getElement(selectorOrElement);
|
||||
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
jQuery(element).css({
|
||||
'cursor': '',
|
||||
'-webkit-filter': '',
|
||||
'filter': '',
|
||||
} )
|
||||
.off('mouseup')
|
||||
.find('> *')
|
||||
.css('pointer-events', '');
|
||||
} else {
|
||||
jQuery(element).css({
|
||||
'cursor': 'not-allowed',
|
||||
'-webkit-filter': 'grayscale(100%)',
|
||||
'filter': 'grayscale(100%)',
|
||||
})
|
||||
.on('mouseup', function(event) {
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
if (form) {
|
||||
// Trigger form submit to show the error message
|
||||
let $form = jQuery(form);
|
||||
if ($form.find('.single_add_to_cart_button').hasClass('disabled')) {
|
||||
$form.find(':submit').trigger('click');
|
||||
}
|
||||
}
|
||||
})
|
||||
.find('> *')
|
||||
.css('pointer-events', 'none');
|
||||
}
|
||||
};
|
||||
|
||||
export const disable = (selectorOrElement, form = null) => {
|
||||
setEnabled(selectorOrElement, false, form);
|
||||
};
|
||||
|
||||
export const enable = (selectorOrElement) => {
|
||||
setEnabled(selectorOrElement, true);
|
||||
};
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
* When you can't add something to the cart, the PayPal buttons should not show.
|
||||
* Therefore we listen for changes on the add to cart button and show/hide the buttons accordingly.
|
||||
*/
|
||||
|
||||
class ButtonsToggleListener {
|
||||
constructor(element, showCallback, hideCallback)
|
||||
{
|
||||
this.element = element;
|
||||
this.showCallback = showCallback;
|
||||
this.hideCallback = hideCallback;
|
||||
this.observer = null;
|
||||
}
|
||||
|
||||
init()
|
||||
{
|
||||
if (!this.element) {
|
||||
return;
|
||||
}
|
||||
const config = { attributes : true };
|
||||
const callback = () => {
|
||||
if (this.element.classList.contains('disabled')) {
|
||||
this.hideCallback();
|
||||
return;
|
||||
}
|
||||
this.showCallback();
|
||||
}
|
||||
this.observer = new MutationObserver(callback);
|
||||
this.observer.observe(this.element, config);
|
||||
callback();
|
||||
}
|
||||
|
||||
disconnect()
|
||||
{
|
||||
this.observer.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
export default ButtonsToggleListener;
|
|
@ -4,7 +4,6 @@ export const isChangePaymentPage = () => {
|
|||
}
|
||||
|
||||
export const subscriptionHasPlan = () => {
|
||||
return true;
|
||||
if (PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled && PayPalCommerceGateway.data_client_id.has_subscriptions) {
|
||||
if (PayPalCommerceGateway.subscription_plan_id !== '') {
|
||||
return true;
|
||||
|
|
|
@ -10,6 +10,7 @@ class CreditCardRenderer {
|
|||
this.spinner = spinner;
|
||||
this.cardValid = false;
|
||||
this.formValid = false;
|
||||
this.emptyFields = new Set(['number', 'cvv', 'expirationDate']);
|
||||
this.currentHostedFieldsInstance = null;
|
||||
}
|
||||
|
||||
|
@ -130,7 +131,7 @@ class CreditCardRenderer {
|
|||
return event.fields[key].isValid;
|
||||
});
|
||||
|
||||
const className = this._cardNumberFiledCLassNameByCardType(event.cards[0].type);
|
||||
const className = event.cards.length ? this._cardNumberFiledCLassNameByCardType(event.cards[0].type) : '';
|
||||
event.fields.number.isValid
|
||||
? cardNumber.classList.add(className)
|
||||
: this._recreateElementClassAttribute(cardNumber, cardNumberField.className);
|
||||
|
@ -138,6 +139,12 @@ class CreditCardRenderer {
|
|||
this.formValid = formValid;
|
||||
|
||||
});
|
||||
hostedFields.on('empty', (event) => {
|
||||
this.emptyFields.add(event.emittedBy);
|
||||
});
|
||||
hostedFields.on('notEmpty', (event) => {
|
||||
this.emptyFields.delete(event.emittedBy);
|
||||
});
|
||||
|
||||
show(buttonSelector);
|
||||
|
||||
|
@ -249,7 +256,16 @@ class CreditCardRenderer {
|
|||
});
|
||||
} else {
|
||||
this.spinner.unblock();
|
||||
const message = ! this.cardValid ? this.defaultConfig.hosted_fields.labels.card_not_supported : this.defaultConfig.hosted_fields.labels.fields_not_valid;
|
||||
|
||||
let message = this.defaultConfig.labels.error.generic;
|
||||
if (this.emptyFields.size > 0) {
|
||||
message = this.defaultConfig.hosted_fields.labels.fields_empty;
|
||||
} else if (!this.cardValid) {
|
||||
message = this.defaultConfig.hosted_fields.labels.card_not_supported;
|
||||
} else if (!this.formValid) {
|
||||
message = this.defaultConfig.hosted_fields.labels.fields_not_valid;
|
||||
}
|
||||
|
||||
this.errorHandler.message(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ class MessageRenderer {
|
|||
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.optionsFingerprint = null;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -9,38 +10,58 @@ class MessageRenderer {
|
|||
return;
|
||||
}
|
||||
|
||||
paypal.Messages({
|
||||
const options = {
|
||||
amount: this.config.amount,
|
||||
placement: this.config.placement,
|
||||
style: this.config.style
|
||||
}).render(this.config.wrapper);
|
||||
};
|
||||
|
||||
if (this.optionsEqual(options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
paypal.Messages(options).render(this.config.wrapper);
|
||||
|
||||
jQuery(document.body).on('updated_cart_totals', () => {
|
||||
paypal.Messages({
|
||||
amount: this.config.amount,
|
||||
placement: this.config.placement,
|
||||
style: this.config.style
|
||||
}).render(this.config.wrapper);
|
||||
paypal.Messages(options).render(this.config.wrapper);
|
||||
});
|
||||
}
|
||||
|
||||
renderWithAmount(amount) {
|
||||
|
||||
if (! this.shouldRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
amount,
|
||||
placement: this.config.placement,
|
||||
style: this.config.style
|
||||
};
|
||||
|
||||
if (this.optionsEqual(options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newWrapper = document.createElement('div');
|
||||
newWrapper.setAttribute('id', this.config.wrapper.replace('#', ''));
|
||||
|
||||
const sibling = document.querySelector(this.config.wrapper).nextSibling;
|
||||
document.querySelector(this.config.wrapper).parentElement.removeChild(document.querySelector(this.config.wrapper));
|
||||
const oldWrapper = document.querySelector(this.config.wrapper);
|
||||
const sibling = oldWrapper.nextSibling;
|
||||
oldWrapper.parentElement.removeChild(oldWrapper);
|
||||
sibling.parentElement.insertBefore(newWrapper, sibling);
|
||||
paypal.Messages({
|
||||
amount,
|
||||
placement: this.config.placement,
|
||||
style: this.config.style
|
||||
}).render(this.config.wrapper);
|
||||
|
||||
paypal.Messages(options).render(this.config.wrapper);
|
||||
}
|
||||
|
||||
optionsEqual(options) {
|
||||
const fingerprint = JSON.stringify(options);
|
||||
|
||||
if (this.optionsFingerprint === fingerprint) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.optionsFingerprint = fingerprint;
|
||||
return false;
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
|
|
|
@ -7,6 +7,9 @@ class Renderer {
|
|||
this.onSmartButtonClick = onSmartButtonClick;
|
||||
this.onSmartButtonsInit = onSmartButtonsInit;
|
||||
|
||||
this.buttonsOptions = {};
|
||||
this.onButtonsInitListeners = {};
|
||||
|
||||
this.renderedSources = new Set();
|
||||
}
|
||||
|
||||
|
@ -77,7 +80,12 @@ class Renderer {
|
|||
style,
|
||||
...contextConfig,
|
||||
onClick: this.onSmartButtonClick,
|
||||
onInit: this.onSmartButtonsInit,
|
||||
onInit: (data, actions) => {
|
||||
if (this.onSmartButtonsInit) {
|
||||
this.onSmartButtonsInit(data, actions);
|
||||
}
|
||||
this.handleOnButtonsInit(wrapper, data, actions);
|
||||
},
|
||||
});
|
||||
if (!btn.isEligible()) {
|
||||
return;
|
||||
|
@ -106,6 +114,44 @@ class Renderer {
|
|||
enableCreditCardFields() {
|
||||
this.creditCardRenderer.enableFields();
|
||||
}
|
||||
|
||||
onButtonsInit(wrapper, handler, reset) {
|
||||
this.onButtonsInitListeners[wrapper] = reset ? [] : (this.onButtonsInitListeners[wrapper] || []);
|
||||
this.onButtonsInitListeners[wrapper].push(handler);
|
||||
}
|
||||
|
||||
handleOnButtonsInit(wrapper, data, actions) {
|
||||
|
||||
this.buttonsOptions[wrapper] = {
|
||||
data: data,
|
||||
actions: actions
|
||||
}
|
||||
|
||||
if (this.onButtonsInitListeners[wrapper]) {
|
||||
for (let handler of this.onButtonsInitListeners[wrapper]) {
|
||||
if (typeof handler === 'function') {
|
||||
handler({
|
||||
wrapper: wrapper,
|
||||
...this.buttonsOptions[wrapper]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disableSmartButtons(wrapper) {
|
||||
if (!this.buttonsOptions[wrapper]) {
|
||||
return;
|
||||
}
|
||||
this.buttonsOptions[wrapper].actions.disable();
|
||||
}
|
||||
|
||||
enableSmartButtons(wrapper) {
|
||||
if (!this.buttonsOptions[wrapper]) {
|
||||
return;
|
||||
}
|
||||
this.buttonsOptions[wrapper].actions.enable();
|
||||
}
|
||||
}
|
||||
|
||||
export default Renderer;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue