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)=>{ }).then((res)=>{
return res.json(); return res.json();
}).then(() => { }).then(() => {
const id = document.querySelector('[name="add-to-cart"]').value; const products = this.getSubscriptionProducts();
const products = [new Product(id, 1, null)];
fetch(this.config.ajax.change_cart.endpoint, { fetch(this.config.ajax.change_cart.endpoint, {
method: 'POST', 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() configuration()
{ {
return { return {

View file

@ -163,6 +163,13 @@ class SingleProductBootstap {
this.errorHandler, 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( (new SimulateCart(
this.gateway.ajax.simulate_cart.endpoint, this.gateway.ajax.simulate_cart.endpoint,
this.gateway.ajax.simulate_cart.nonce, this.gateway.ajax.simulate_cart.nonce,
@ -198,7 +205,7 @@ class SingleProductBootstap {
this.handleButtonStatus(false); this.handleButtonStatus(false);
}, actionHandler.getProducts()); }, products);
} }
} }

View file

@ -75,7 +75,7 @@ class Renderer {
renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) { renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) {
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) ) { 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. // 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; return;
} }
@ -99,14 +99,20 @@ class Renderer {
jQuery(document) jQuery(document)
.off(this.reloadEventName, wrapper) .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); const settings = merge(this.defaultSettings, settingsOverride);
let scriptOptions = keysToCamelCase(settings.url_params); let scriptOptions = keysToCamelCase(settings.url_params);
scriptOptions = merge(scriptOptions, settings.script_attributes); scriptOptions = merge(scriptOptions, settings.script_attributes);
loadScript(scriptOptions).then((paypal) => { loadScript(scriptOptions).then((paypal) => {
widgetBuilder.setPaypal(paypal); widgetBuilder.setPaypal(paypal);
widgetBuilder.registerButtons(wrapper, buttonsOptions()); widgetBuilder.registerButtons([wrapper, fundingSource], buttonsOptions());
widgetBuilder.renderAll(); widgetBuilder.renderAll();
}); });
}); });
@ -114,8 +120,8 @@ class Renderer {
this.renderedSources.add(wrapper + (fundingSource ?? '')); this.renderedSources.add(wrapper + (fundingSource ?? ''));
if (typeof paypal !== 'undefined' && typeof paypal.Buttons !== 'undefined') { if (typeof paypal !== 'undefined' && typeof paypal.Buttons !== 'undefined') {
widgetBuilder.registerButtons(wrapper, buttonsOptions()); widgetBuilder.registerButtons([wrapper, fundingSource], buttonsOptions());
widgetBuilder.renderButtons(wrapper); 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 { class WidgetBuilder {
constructor() { constructor() {
@ -19,14 +22,18 @@ class WidgetBuilder {
} }
registerButtons(wrapper, options) { registerButtons(wrapper, options) {
this.buttons.set(wrapper, { wrapper = this.sanitizeWrapper(wrapper);
this.buttons.set(this.toKey(wrapper), {
wrapper: wrapper, wrapper: wrapper,
options: options options: options,
}); });
} }
renderButtons(wrapper) { renderButtons(wrapper) {
if (!this.buttons.has(wrapper)) { wrapper = this.sanitizeWrapper(wrapper);
if (!this.buttons.has(this.toKey(wrapper))) {
return; return;
} }
@ -34,14 +41,21 @@ class WidgetBuilder {
return; return;
} }
const entry = this.buttons.get(wrapper); const entry = this.buttons.get(this.toKey(wrapper));
const btn = this.paypal.Buttons(entry.options); const btn = this.paypal.Buttons(entry.options);
if (!btn.isEligible()) { if (!btn.isEligible()) {
this.buttons.delete(this.toKey(wrapper));
return; return;
} }
btn.render(entry.wrapper); let target = this.buildWrapperTarget(wrapper);
if (!target) {
return;
}
btn.render(target);
} }
renderAllButtons() { renderAllButtons() {
@ -84,7 +98,64 @@ class WidgetBuilder {
} }
hasRendered(wrapper) { 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;
} }
} }