Add ability in WidgetBuilder to have multiple buttons rendered per wrapper.

This commit is contained in:
Pedro Silva 2023-07-25 16:33:56 +01:00
parent cc79f62cab
commit 0fed872c13
No known key found for this signature in database
GPG key ID: E2EE20C0669D24B3
4 changed files with 104 additions and 15 deletions

View file

@ -40,8 +40,7 @@ class SingleProductActionHandler {
}).then((res)=>{
return res.json();
}).then(() => {
const id = document.querySelector('[name="add-to-cart"]').value;
const products = [new Product(id, 1, null)];
const products = this.getSubscriptionProducts();
fetch(this.config.ajax.change_cart.endpoint, {
method: 'POST',
@ -71,6 +70,12 @@ class SingleProductActionHandler {
}
}
getSubscriptionProducts()
{
const id = document.querySelector('[name="add-to-cart"]').value;
return [new Product(id, 1, null)];
}
configuration()
{
return {

View file

@ -163,6 +163,13 @@ class SingleProductBootstap {
this.errorHandler,
);
const hasSubscriptions = PayPalCommerceGateway.data_client_id.has_subscriptions
&& PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled;
const products = hasSubscriptions
? actionHandler.getSubscriptionProducts()
: actionHandler.getProducts();
(new SimulateCart(
this.gateway.ajax.simulate_cart.endpoint,
this.gateway.ajax.simulate_cart.nonce,
@ -198,7 +205,7 @@ class SingleProductBootstap {
this.handleButtonStatus(false);
}, actionHandler.getProducts());
}, products);
}
}

View file

@ -75,7 +75,7 @@ class Renderer {
renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) {
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) ) {
// Try to render registered buttons again in case they were removed from the DOM by an external source.
widgetBuilder.renderButtons(wrapper);
widgetBuilder.renderButtons([wrapper, fundingSource]);
return;
}
@ -99,14 +99,20 @@ class Renderer {
jQuery(document)
.off(this.reloadEventName, wrapper)
.on(this.reloadEventName, wrapper, (event, settingsOverride = {}) => {
.on(this.reloadEventName, wrapper, (event, settingsOverride = {}, triggeredFundingSource) => {
// Only accept events from the matching funding source
if (fundingSource && triggeredFundingSource && (triggeredFundingSource !== fundingSource)) {
return;
}
const settings = merge(this.defaultSettings, settingsOverride);
let scriptOptions = keysToCamelCase(settings.url_params);
scriptOptions = merge(scriptOptions, settings.script_attributes);
loadScript(scriptOptions).then((paypal) => {
widgetBuilder.setPaypal(paypal);
widgetBuilder.registerButtons(wrapper, buttonsOptions());
widgetBuilder.registerButtons([wrapper, fundingSource], buttonsOptions());
widgetBuilder.renderAll();
});
});
@ -114,8 +120,8 @@ class Renderer {
this.renderedSources.add(wrapper + (fundingSource ?? ''));
if (typeof paypal !== 'undefined' && typeof paypal.Buttons !== 'undefined') {
widgetBuilder.registerButtons(wrapper, buttonsOptions());
widgetBuilder.renderButtons(wrapper);
widgetBuilder.registerButtons([wrapper, fundingSource], buttonsOptions());
widgetBuilder.renderButtons([wrapper, fundingSource]);
}
}

View file

@ -1,4 +1,7 @@
/**
* Handles the registration and rendering of PayPal widgets: Buttons and Messages.
* To have several Buttons per wrapper, an array should be provided, ex: [wrapper, fundingSource].
*/
class WidgetBuilder {
constructor() {
@ -19,14 +22,18 @@ class WidgetBuilder {
}
registerButtons(wrapper, options) {
this.buttons.set(wrapper, {
wrapper = this.sanitizeWrapper(wrapper);
this.buttons.set(this.toKey(wrapper), {
wrapper: wrapper,
options: options
options: options,
});
}
renderButtons(wrapper) {
if (!this.buttons.has(wrapper)) {
wrapper = this.sanitizeWrapper(wrapper);
if (!this.buttons.has(this.toKey(wrapper))) {
return;
}
@ -34,14 +41,21 @@ class WidgetBuilder {
return;
}
const entry = this.buttons.get(wrapper);
const entry = this.buttons.get(this.toKey(wrapper));
const btn = this.paypal.Buttons(entry.options);
if (!btn.isEligible()) {
this.buttons.delete(this.toKey(wrapper));
return;
}
btn.render(entry.wrapper);
let target = this.buildWrapperTarget(wrapper);
if (!target) {
return;
}
btn.render(target);
}
renderAllButtons() {
@ -84,7 +98,64 @@ class WidgetBuilder {
}
hasRendered(wrapper) {
return document.querySelector(wrapper).hasChildNodes();
let selector = wrapper;
if (Array.isArray(wrapper)) {
selector = wrapper[0];
for (const item of wrapper.slice(1)) {
selector += ' .item-' + item;
}
}
const element = document.querySelector(selector);
return element && element.hasChildNodes();
}
sanitizeWrapper(wrapper) {
if (Array.isArray(wrapper)) {
wrapper = wrapper.filter(item => !!item);
if (wrapper.length === 1) {
wrapper = wrapper[0];
}
}
return wrapper;
}
buildWrapperTarget(wrapper) {
let target = wrapper;
if (Array.isArray(wrapper)) {
const $wrapper = jQuery(wrapper[0]);
if (!$wrapper.length) {
return;
}
const itemClass = 'item-' + wrapper[1];
// Check if the parent element exists and it doesn't already have the div with the class
let $item = $wrapper.find('.' + itemClass);
if (!$item.length) {
$item = jQuery(`<div class="${itemClass}"></div>`);
$wrapper.append($item);
}
target = $item.get(0);
}
if (!jQuery(target).length) {
return null;
}
return target;
}
toKey(wrapper) {
if (Array.isArray(wrapper)) {
return JSON.stringify(wrapper);
}
return wrapper;
}
}