PageSourceSearch

https://www.schwarzdorn.de/Mailorder/GXModules/Gambio/Hub/Shop/Javascript/PayPalLoader.js?v=1773246820

js schwarzdorn.de collected 2026-09-25 20:22:14 UTC 43,074 bytes, 1,015 lines download raw bytes

1/* --------------------------------------------------------------
2   PayPalLoader.js 2023-04-12
3   Gambio GmbH
4   http://www.gambio.de
5   Copyright (c) 2023 Gambio GmbH
6   Released under the GNU General Public License (Version 2)
7   [http://www.gnu.org/licenses/gpl-2.0.html]
8   --------------------------------------------------------------
9*/
10
11
12(function() {
13	if (window.NodeList && !NodeList.prototype.forEach) {
14		NodeList.prototype.forEach = Array.prototype.forEach;
15	}
16
17	let currentScript = document.currentScript;
18	
19	let consoleInfo = function(...params) {
20		if (typeof payPalButtonSettings.developmentMode !== 'boolean' || payPalButtonSettings.developmentMode === false) {
21			return;
22		}
23		console.info('PayPalLoader', ...params);
24	}
25
26	let handleAntiqueBrowser = function() {
27		consoleInfo('Sorry, antique browser not supported.');
28		
29		let pppay = document.querySelector('li.gambio_hub-PayPal2Hub');
30		if (pppay) {
31			pppay.remove();
32		}
33	}
34	
35	let initDisplayModeECS_ButtonReplace = function() {
36		let paypalButtonContainer = document.querySelector('#paypal-button-container'),
37			footerTotalRow = document.querySelector('table.order-total tr.footer.total'),
38			newTotalRow = document.createElement('tr'),
39			newTotalRowCell = document.createElement('td');
40		newTotalRowCell.colSpan = '2';
41		newTotalRowCell.style.width = '100%';
42		newTotalRowCell.style.borderTop = 'none';
43		newTotalRowCell.appendChild(paypalButtonContainer);
44		newTotalRow.appendChild(newTotalRowCell);
45		footerTotalRow.parentNode.appendChild(newTotalRow);
46		footerTotalRow.querySelectorAll('td').forEach(function(td) {
47			td.style.paddingBottom = '15px';
48		});
49	};
50
51	let initDisplayModeECS = function() {
52		if(window.location.search.match(/(\?|&)display_mode=ecs($|&)/)) {
53			let checkoutButtons = document.querySelector('div.checkout-buttons');
54			if(checkoutButtons) {
55				checkoutButtons.style.display = 'none';
56			}
57			let checkoutSubmitButton = document.querySelector('div.shopping-cart-button a.button-submit');
58			if(checkoutSubmitButton === null) {
59				checkoutSubmitButton = document.querySelector('tr.checkout-button');
60			}
61			if(checkoutSubmitButton) {
62				checkoutSubmitButton.style.display = 'none';
63			}
64			let shoppingCartButton = document.querySelector('div.shopping-cart-button');
65			if(shoppingCartButton) {
66				shoppingCartButton.classList.add('paypal-ecs-mode');
67			}
68			let ppiContainer = document.querySelector('div.paypalinstallmentcontainer');
69			if(ppiContainer) {
70				ppiContainer.style.display = 'none';
71			}
72			initDisplayModeECS_ButtonReplace();
73		}
74	}
75
76	let initJSSDKPayPalButtonECS = function(amount) {
77        if (amount === undefined) {
78            amount = payPalButtonSettings.cartAmount;
79        } 
80        consoleInfo('initJSSDKPayPalButtonECS cart amount: ' + amount);
81        if (amount < 0.01) {
82            consoleInfo('ECS: not showing, cart amount too low');
83            return;
84        }
85		let buttonContainer = document.querySelector('#paypal-button-container');
86		if (!buttonContainer) {
87			return;
88		}
89        let ecsIntro = document.querySelector('div.ecs_intro');
90        if (document.querySelector('tr.checkout-button .button-disabled') !== null) {
91            if (ecsIntro) {
92                ecsIntro.style.display = 'none';
93            }
94            buttonContainer.style.display = 'none';
95        } else {
96            if (ecsIntro) {
97                ecsIntro.style.display = 'block';
98            }
99            buttonContainer.style.display = 'block';
100            initDisplayModeECS();
101        }
102
103		paypal.Buttons({
104			style: payPalButtonSettings.style,
105            createOrder: async function(data, actions) {
106                return await createOrderWithOrWithoutVault()
107            },
108			onApprove: function(data, actions) {
109				consoleInfo('Approved data:', data);
110				return fetch(payPalButtonSettings.approvedOrderUrl + '&orderId=' + data.orderID, {
111					method: 'post',
112					headers: {
113						'Content-Type': 'application/json'
114					},
115					body: JSON.stringify(data)
116				})
117					.then((res) => { return res.json(); })
118					.then((responsedata) => {
119						consoleInfo('response data:', responsedata);
120						document.location = payPalButtonSettings.checkoutUrl;
121					});
122			},
123			onError: function(err) {
124				let ppButtonContainer = document.querySelector('#paypal-button-container');
125				let ecsIntro = document.querySelector('div.ecs_intro');
126				if(ppButtonContainer) {
127					let errorMessage = document.querySelector('div.paypal-error');
128					if(!errorMessage) {
129						errorMessage = document.createElement('div');
130						errorMessage.classList.add('paypal-error');
131						errorMessage.classList.add('alert');
132						errorMessage.classList.add('alert-warning');
133						errorMessage.style.textAlign = 'left';
134						errorMessage.style.color = '#555';
135					}
136					errorMessage.innerText = payPalText.paypalUnavailable + ' ';
137					let shoppingCartButton = document.querySelector('div.shopping-cart-button');
138					if(shoppingCartButton && shoppingCartButton.classList.contains('paypal-ecs-mode')) {
139						let linkUrl = window.location.toString().replace('display_mode=ecs', 'display_mode=normal');
140						let continueLink = document.createElement('a');
141						continueLink.setAttribute('href', linkUrl);
142						continueLink.innerText = payPalText.errorContinue;
143						errorMessage.append(continueLink);
144					}
145					ppButtonContainer.parentNode.append(errorMessage);
146					ppButtonContainer.style.display = 'none';
147				}
148				if(ecsIntro) {
149					ecsIntro.style.display = 'none';
150				}
151			}
152		}).render('#paypal-button-container');
153
154		let observerTarget = document.querySelector('#paypal-button-container');
155		let observer = new MutationObserver(function(mutations, observer) {
156			mutations.forEach(function(mutation) {
157				if(mutation.removedNodes.length > 0) {
158					consoleInfo('re-init PayPal buttons');
159                    let totalSumCell = document.querySelector('tr.total.sum td:nth-child(2)');
160                    if (totalSumCell) {
161                        let amount = parseFloat(totalSumCell.textContent.replace(/[^0-9]/g, '')) / 100;
162                        initJSSDKPayPalButtonECS(amount);
163                        initInstallmentBanners(amount);
164                    } else {
165                        initJSSDKPayPalButtonECS();
166                        initInstallmentBanners();
167                    }
168				}
169			});
170		});
171		observer.observe(observerTarget, {childList: true});
172        appendVaultCheckbox(buttonContainer)
173	};
174
175    
176    let addButtonContainerDecoration = function(buttonContainer, continueButtonBlock)
177    {
178        buttonContainer.style.width = 'auto';
179        buttonContainer.style.textAlign = 'center';
180        buttonContainer.style.fontStyle = 'italic';
181        if (payPalText.continueToPayPal) {
182            let labelToButtonDistance = 3;
183            let lineHeight = '-' + window.getComputedStyle(continueButtonBlock).lineHeight;
184            buttonContainer.style.marginTop = 'calc(' + lineHeight + ' - ' + labelToButtonDistance + 'px)';
185            let continueLabel = document.createElement('span');
186            continueLabel.classList.add('paypal-continue-label');
187            continueLabel.textContent = payPalText.continueToPayPal
188            continueLabel.style.paddingBottom = labelToButtonDistance + 'px'; 
189            buttonContainer.appendChild(continueLabel) ;
190        }
191    }
192    
193    
194	let initJSSDKPayPalButtonECM = function(continueButtonBlock)
195	{
196        let paypalButtonContainer = document.createElement('div');
197        
198        paypalButtonContainer.id = 'paypal-button-container';
199        paypalButtonContainer.style.display = 'none';
200        addButtonContainerDecoration(paypalButtonContainer, continueButtonBlock);
201        continueButtonBlock.appendChild(paypalButtonContainer);
202		paypal.Buttons({
203            fundingSource: 'paypal',
204			style: payPalButtonSettings.style,
205			createOrder: async function(data, actions) {
206                return await createOrderWithOrWithoutVault(payPalButtonSettings.usePayNow)
207			},
208			onApprove: function(data, actions) {
209				document.querySelector('#checkout_payment input[name="PayPal2HubOrderId"]').value = data.orderID;
210				document.querySelector('#checkout_payment input[name="PayPal2HubPayerId"]').value = data.payerID;
211                document.querySelector('#checkout_payment input[name="PayPal2HubPaymentInitiator"]').value = 'ecm';
212				document.querySelector('#checkout_payment').submit();
213			}
214		}).render('#paypal-button-container');
215        appendVaultCheckbox(paypalButtonContainer)
216        return paypalButtonContainer;
217	}
218
219    /**
220     * Show save payment option.
221     * @param paypalButtonContainer
222     * @returns {*}
223     */
224    function appendVaultCheckbox(paypalButtonContainer) {
225        if (payPalButtonSettings.useVault !== true) {
226            //no enable vault
227            return;
228        }
229        // only enable for shop enable vault and customer has'not using vault yet.
230        if (!isCustomerUsingVaultToken()) {
231            // Checkbox already exists in the container
232            if (paypalButtonContainer.querySelector('#paypal-vaulting-checkbox')) {
233                return;
234            }
235            const labelTexts = {
236                "en_US": "Save PayPal account for future payments",
237                "de_DE": "Für zukünftige Einkäufe speichern"
238            }
239            const divTag = document.createElement('div');
240            divTag.id = 'paypal-vaulting-div'
241            divTag.style.marginTop = '3px'  
242            const checkbox = document.createElement('input');
243            checkbox.type = 'checkbox';
244            checkbox.id = 'paypal-vaulting-checkbox';
245            checkbox.value = true;
246            // Create the label
247            const label = document.createElement('label');
248            label.htmlFor = 'paypal-vaulting-checkbox';
249            label.style.display = 'inline'
250            label.style.marginLeft = '3px'
251            label.textContent = labelTexts[payPalButtonSettings.locale] || labelTexts["de_DE"];
252        
253            // Append the checkbox and label to the DOM (e.g., to the body)
254            divTag.appendChild(checkbox);
255            divTag.appendChild(label);
256            paypalButtonContainer.appendChild(divTag)
257        } else {
258            appendCustomVaultCss()
259        }
260    }
261
262    /**
263     * Append some customer css class for vault
264     */
265    function appendCustomVaultCss() {
266        try {
267            const paypalContainer = document.getElementById('paypal-button-container');
268            if (!paypalContainer) return;
269
270            const isShoppingCart = document.querySelector('.shopping-cart-button');
271            const isCheckout = document.querySelector('.continue_button');
272
273            if (isShoppingCart) {
274                paypalContainer.classList.add('paypal-shopping-cart-vault');
275            } else if (isCheckout) {
276                paypalContainer.classList.add('paypal-checkout-vault');
277
278                const continueButton = document.querySelector('.continue_button');
279                const backButton = document.querySelector('.back_button');
280                if (continueButton) {
281                    continueButton.classList.add('continue_button_vault');
282                }
283                if (backButton) {
284                    backButton.classList.add('back_button_vault');
285                }
286            }
287        } catch (error) {
288            console.error('Error appending custom vault CSS:', error);
289        }
290    }
291
292
293    /**
294     * Check customer is using vault token
295     * @returns {boolean}
296     */
297    function isCustomerUsingVaultToken() {
298        const vaultToken = payPalButtonSettings.vaultToken;
299        
300        return vaultToken !== null && typeof vaultToken !== 'undefined' && vaultToken !== "";
301    }
302
303
304    /**
305     * Separate a function create order with or without vault for paypal button
306     * @returns {Promise<*>}
307     */
308    async function createOrderWithOrWithoutVault(payNow = false) {
309        const url = new URL(payPalButtonSettings.createOrderUrl);
310        if (payNow === true || payNow === 'true') {
311            url.searchParams.set('payNow', 'true');
312        }
313        const vaultCheckbox = document.getElementById('paypal-vaulting-checkbox');
314        let shouldVault = ((vaultCheckbox && vaultCheckbox.checked) || isCustomerUsingVaultToken());
315        if (payPalButtonSettings.useVault === true && shouldVault === true) {
316            url.searchParams.set('vault', 'true');
317            url.searchParams.set('payment_method', 'paypal');
318        }
319        const response = await fetch(url.toString(), {
320            method: 'POST',
321            headers: {
322                'Content-Type': 'application/json'
323            }
324        });
325        const data = await response.json();
326        return data.id;
327    }
328
329    
330    let initPayLaterButton = function(continueButtonBlock)
331    {
332        let payLaterItem = document.querySelector('li.gambio_hub-PayPal2Hub-paylater');
333        if (payLaterItem === null) {
334            return null;
335        }
336    
337        let paylaterButton = paypal.Buttons({
338            fundingSource: 'paylater',
339            style: payPalButtonSettings.style,
340            createOrder: function(data, actions) {
341                return fetch(payPalButtonSettings.createOrderUrl, {
342                    method: 'post',
343                    headers: {
344                        'Content-Type': 'application/json'
345                    }
346                })
347                    .then((res) => { return res.json() })
348                    .then((orderdata) => {
349                        consoleInfo('order created: ' + orderdata.id, orderdata);
350                        return orderdata.id;
351                    });
352            },
353            onApprove: function(data, actions) {
354                document.querySelector('#checkout_payment input[name="PayPal2HubOrderId"]').value = data.orderID;
355                document.querySelector('#checkout_payment input[name="PayPal2HubPayerId"]').value = data.payerID;
356                document.querySelector('#checkout_payment').submit();
357            }
358        });
359    
360        if (paylaterButton.isEligible()) {
361            let paylaterButtonId = 'paypal-paylater-button-container',
362                paylaterButtonContainer = document.createElement('div');
363            paylaterButtonContainer.id = paylaterButtonId;
364            paylaterButtonContainer.style.display = 'none';
365            addButtonContainerDecoration(paylaterButtonContainer, continueButtonBlock);
366            continueButtonBlock.appendChild(paylaterButtonContainer);
367            paylaterButton.render('#' + paylaterButtonId);
368            consoleInfo('PayPal Paylater: eligible and initialized');
369            return paylaterButtonContainer;
370        } else {
371            consoleInfo('PayPal Paylater: not eligible');
372            payLaterItem.remove();
373        }
374        
375        return null;
376    }
377    
378    
379    let initSepaButton = function(continueButtonBlock)
380    {
381        let sepaItem = document.querySelector('li.gambio_hub-PayPal2Hub-sepa');
382        if (sepaItem === null) {
383            return null;
384        }
385        let sepaButtonStyle = payPalButtonSettings.style;
386        if (sepaButtonStyle.color === 'gold' || sepaButtonStyle.color === 'blue') {
387            sepaButtonStyle.color = 'silver';
388        }
389        
390        let sepaButton = paypal.Buttons({
391            fundingSource: 'sepa',
392            style: payPalButtonSettings.style,
393            createOrder: function(data, actions) {
394                return fetch(payPalButtonSettings.createOrderUrl, {
395                    method: 'post',
396                    headers: {
397                        'Content-Type': 'application/json'
398                    }
399                })
400                    .then((res) => { return res.json() })
401                    .then((orderdata) => {
402                        consoleInfo('order created: ' + orderdata.id, orderdata);
403                        return orderdata.id;
404                    });
405            },
406            onApprove: function(data, actions) {
407                document.querySelector('#checkout_payment input[name="PayPal2HubOrderId"]').value = data.orderID;
408                document.querySelector('#checkout_payment input[name="PayPal2HubPayerId"]').value = data.payerID;
409                document.querySelector('#checkout_payment').submit();
410            }
411        });
412        
413        if (sepaButton.isEligible()) {
414            let sepaButtonId = 'paypal-sepa-button-container',
415                sepaButtonContainer = document.createElement('div');
416            sepaButtonContainer.id = sepaButtonId;
417            sepaButtonContainer.style.display = 'none';
418            addButtonContainerDecoration(sepaButtonContainer, continueButtonBlock);
419            continueButtonBlock.appendChild(sepaButtonContainer);
420            sepaButton.render('#' + sepaButtonId);
421            consoleInfo('PayPal SEPA: eligible and initialized');
422            return sepaButtonContainer;
423        } else {
424            consoleInfo('PayPal SEPA: not eligible');
425            sepaItem.remove();
426        }
427        
428        return null;
429    }
430    
431    
432    let initCreditCardButton = function(continueButtonBlock)
433    {
434        let brandedCreditCardsItem = document.querySelector('li.gambio_hub-PayPal2Hub-creditcardbutton');
435        if (brandedCreditCardsItem === null) {
436            return null;
437        }
438        
439        let cardButtonStyle = payPalButtonSettings.style;
440        cardButtonStyle.color = 'black';
441        cardButtonStyle.shape = 'pill';
442
443        let creditCardButton = paypal.Buttons({
444            fundingSource: 'card',
445            style: cardButtonStyle,
446            createOrder: function(data, actions) {
447                return fetch(payPalButtonSettings.createOrderUrl, {
448                    method: 'post',
449                    headers: {
450                        'Content-Type': 'application/json'
451                    }
452                })
453                    .then((res) => { return res.json() })
454                    .then((orderdata) => {
455                        consoleInfo('order created: ' + orderdata.id, orderdata);
456                        return orderdata.id;
457                    });
458            },
459            onApprove: function(data, actions) {
460                document.querySelector('#checkout_payment input[name="PayPal2HubOrderId"]').value = data.orderID;
461                document.querySelector('#checkout_payment input[name="PayPal2HubPayerId"]').value = data.payerID;
462                document.querySelector('#checkout_payment').submit();
463            }
464        });
465        
466        consoleInfo(creditCardButton);
467        
468        if (creditCardButton.isEligible()) {
469            consoleInfo('Eligible for branded cc payments');
470            let creditCardButtonId = 'paypal-creditcard-button-container',
471                creditCardButtonContainer = document.createElement('div');
472            creditCardButtonContainer.id = creditCardButtonId;
473            creditCardButtonContainer.style.display = 'none';
474            addButtonContainerDecoration(creditCardButtonContainer, continueButtonBlock);
475            continueButtonBlock.appendChild(creditCardButtonContainer);
476            creditCardButton.render('#' + creditCardButtonId);
477            return creditCardButtonContainer;
478        } else {
479            consoleInfo('NOT eligible for branded cc payments');
480            brandedCreditCardsItem.remove();
481        }
482        
483        return null;
484    }
485    
486
487    let initHostedCreditCard = function() {
488        let theLabel = document.querySelector('#ppcc-card-holder-field').closest('label'),
489            theDiv = document.createElement('div');
490    
491        theDiv.classList.add('payment-module-container');
492        theLabel.parentNode.appendChild(theDiv);
493        while(theLabel.hasChildNodes()) {
494            theDiv.appendChild(theLabel.firstChild);
495        }
496        theLabel.remove();
497        
498        let theListItem = document.querySelector('li.gambio_hub-PayPal2Hub-creditcard');
499        theListItem.style.cursor = 'pointer';
500        theListItem.addEventListener('click', function() {
501            $(this).find('input:radio:not(:disabled):not(.placeholder-radio)').first().prop('checked', true).trigger('change');
502        });
503    
504        let cardHolderField = document.querySelector('#ppcc-card-holder-field'),
505            fieldStyle = getComputedStyle(cardHolderField),
506            orderIdElement = document.querySelector('#checkout_payment input[name="PayPal2HubOrderId"]');
507    
508        paypal.HostedFields.render({
509            createOrder: function() {
510                return fetch(payPalButtonSettings.createOrderUrl, {
511                    method: 'post',
512                    headers: {
513                        'Content-Type': 'application/json'
514                    }
515                })
516                    .then((res) => {
517                        return res.json()
518                    })
519                    .then((orderdata) => {
520                        orderIdElement.value = orderdata.id;
521                        consoleInfo('credit card order created: ' + orderdata.id, orderdata);
522                        return orderdata.id;
523                    });
524            },
525            styles: {
526                'input': {
527                    'color': fieldStyle.color,
528                    'font-size': fieldStyle.fontSize,
529                    'font-family': fieldStyle.fontFamily,
530                    'padding': fieldStyle.padding,
531                    'line-height': fieldStyle.lineHeight
532                },
533                '.valid': {
534                    'color': 'green'
535                },
536                '.invalid': {
537                    'color': 'red'
538                }
539            },
540            fields: {
541                number: {
542                    'selector': '#ppcc-card-number',
543                    'placeholder': '4111111111111111',
544                },
545                cvv: {
546                    'selector': '#ppcc-cvv',
547                    'placeholder': '123',
548                },
549                expirationDate: {
550                    'selector': '#ppcc-expiration-date',
551                    'placeholder': 'MM/YY',
552                }
553            }
554        }).then(function(cardFields) {
555            consoleInfo('PayPal: CC fields initialized', cardFields);
556            let paymentForm = document.querySelector('#checkout_payment');
557            let cardFieldsSubmitted = false;
558            paymentForm.addEventListener('submit', function(event) {
559                if (cardFieldsSubmitted === false && paymentForm.payment.value === 'gambio_hub-PayPal2Hub-creditcard') {
560                    event.preventDefault();
561                    let billingAddressData = JSON.parse(document.querySelector('#ppcc-billingaddress').textContent);
562                    cardFields.submit({
563                        cardholderName: paymentForm.ppcc_card_holder.value,
564                        billingAddress: billingAddressData,
565                        contingencies: ['SCA_WHEN_REQUIRED']
566                    }).then(function() {
567                        // OK
568                        consoleInfo('cardFields submitted');
569                        cardFieldsSubmitted = true;
570                        paymentForm.submit();
571                    }).catch(function(err) {
572                        orderIdElement.value = '';
573                        consoleInfo(err);
574                        alert(payPalText.errorCheckData);
575                        document.querySelector('input[name="payment"]:checked').scrollIntoView(false);
576                    });
577                }
578            });
579        });
580    }
581    let initLoadingButton = function (continueButtonBlock) {
582        const loadingButtonId = 'loading-button-container'
583        let loadingButtonContainer = document.createElement('div');
584        loadingButtonContainer.id = loadingButtonId;
585        loadingButtonContainer.style.display = 'none';
586        loadingButtonContainer.style.width = 'auto';
587        loadingButtonContainer.style.verticalAlign = 'inherit'
588        loadingButtonContainer.style.backgroundImage = "url(https://cdn.gambiohub.com/sdk/images/loading.gif)"
589        loadingButtonContainer.style.backgroundSize = "contain"
590        loadingButtonContainer.style.backgroundRepeat = "no-repeat"
591        loadingButtonContainer.style.backgroundPosition = "center"
592        let parentHeight = continueButtonBlock.clientHeight;
593        loadingButtonContainer.style.height = parentHeight + 'px';
594        window.addEventListener('showLoadingButton', evt => {
595            loadingButtonContainer.style.display = 'block';
596        });
597        window.addEventListener('hideLoadingButton', evt => {
598            loadingButtonContainer.style.display = 'none';
599        });
600        continueButtonBlock.appendChild(loadingButtonContainer);
601    }
602
603    let initAlternativePaymentMethod =  function ()  {
604        try {
605            let loader = new PayPalAlternativePaymentMethodLoader.PayPalAlternativePaymentMethodLoader();
606            return loader.load();
607        } catch (err) {
608            consoleInfo(err)
609            return [];
610        }
611
612    }
613    
614	let initCheckoutPayment = function() {
615		let continueButtonBlock = document.querySelector('#checkout_payment div.continue_button'),
616			continueButton = continueButtonBlock.querySelector('input[type="submit"]'),
617			continueButtonDisplay = continueButton.style.display,
618			paypalButtonContainer = document.createElement('div'),
619			plusContainer = document.querySelector('#gambiohub-ppplus'),
620            ccForm = document.querySelector('div.paypal-cc-form'),
621            orderIdElement = document.querySelector('#checkout_payment input[name="PayPal2HubOrderId"]'),
622            ccCardHolderFieldForm = document.querySelector('#paypal-cardfields-form-container');
623        
624        if (plusContainer === null && ccForm !== null && ccCardHolderFieldForm === null) {
625            consoleInfo('PayPal: Credit Card form found on page.');
626            let hostedFieldsEligible = paypal.HostedFields.isEligible();
627            let brandedCreditCardsOption = document.querySelector('li.gambio_hub-PayPal2Hub-creditcardbutton');
628            if (hostedFieldsEligible) {
629                consoleInfo('PayPal: eligible for hosted fields');
630                if (brandedCreditCardsOption) {
631                    brandedCreditCardsOption.remove();
632                }
633                
634                initHostedCreditCard();
635            }
636            else {
637                consoleInfo('PayPal: NOT eligible for hosted fields');
638                let ccListItem = document.querySelector('li.gambio_hub-PayPal2Hub-creditcard');
639                if (ccListItem) {
640                    ccListItem.remove();
641                }
642            }
643        }
644
645		if (plusContainer === null && !payPalButtonSettings.paymentApproved) {
646            let backButtonBlock = continueButtonBlock.parentElement.querySelector('div.back_button');
647            if (backButtonBlock !== null && backButtonBlock.classList.contains('col-xs-6')) {
648                backButtonBlock.classList.remove('col-xs-6');
649                backButtonBlock.classList.add('col-xs-4');
650                continueButtonBlock.classList.remove('col-xs-6');
651                continueButtonBlock.classList.add('col-xs-8');
652                let backButton = backButtonBlock.querySelector('a.btn');
653                let height = parseInt(getComputedStyle(backButton).height);
654                if (isNaN(height)) {
655                    height = 25; // fallback
656                }
657
658                if (height < 25) height = 25;
659                if (height > 50) height = 50;
660                payPalButtonSettings.style.height = height;
661            }
662            let promises = initAlternativePaymentMethod();
663            initJSSDKPayPalButtonECM(continueButtonBlock);
664            initPayLaterButton(continueButtonBlock);
665            initCreditCardButton(continueButtonBlock);
666            initSepaButton(continueButtonBlock);
667            initLoadingButton(continueButtonBlock);
668            let payPalContainerButtonConfig = [
669                {
670                    'value' : 'gambio_hub-PayPal2Hub',
671                    'container' : 'paypal-button-container'
672                },
673                {
674                    'value' : 'gambio_hub-PayPal2Hub-paylater',
675                    'container' : 'paypal-paylater-button-container'
676                },
677                {
678                    'value' : 'gambio_hub-PayPal2Hub-sepa',
679                    'container' : 'paypal-sepa-button-container'
680                },
681                {
682                    'value' : 'gambio_hub-PayPal2Hub-creditcardbutton',
683                    'container' : 'paypal-creditcard-button-container'
684                },
685                {
686                    'value' : 'loading-button-container',
687                    'container' : 'loading-button-container'
688                },
689            ];
690            
691			let paymentItemClickListener = function() {
692				let selected_payment = this.querySelector('input[name="payment"]');
693                if (null !== selected_payment) {
694                    let showDefaultButton = true;
695                    let selectedPaymentValue = selected_payment.value;
696                    if (selectedPaymentValue === 'gambio_hub' && selected_payment.dataset.module_code === 'PayPal2Hub') {
697                        selectedPaymentValue = 'gambio_hub-PayPal2Hub'
698                    }
699                    payPalContainerButtonConfig.forEach((item) => {
700                        let button =  document.getElementById(item.container);
701                        if (button) {
702                            if (item.value === selectedPaymentValue) {
703                                showDefaultButton = false;
704                                button.style.display = 'block'
705                                continueButton.style.display = 'none';
706                            } else  {
707                                button.style.display = 'none'
708                            }
709                        }
710                    });
711                    if (showDefaultButton === true) {
712                        continueButton.style.display = continueButtonDisplay;
713                    }
714                }
715			};
716
717            Promise.allSettled(promises).then((results) => {
718                results.forEach((result) => {
719                    if (result.status === 'fulfilled' && result.value) {
720                        payPalContainerButtonConfig.push(result.value)
721                    }
722                })
723                let paymentItems = document.querySelectorAll('#checkout_payment input[name="payment"], #checkout_payment li.list-group-item');
724                paymentItems.forEach(function(paymentItem) {
725                    paymentItem.addEventListener('click', paymentItemClickListener)
726                });
727
728                let paymentListEntries = document.querySelectorAll('#checkout_payment li');
729                paymentListEntries.forEach(function(paymentOption) {
730                    if (paymentOption.querySelector('input[name="payment"]:checked') || paymentListEntries.length === 1) {
731                        paymentOption.dispatchEvent(new Event('click'));
732                    }
733                });
734            });
735		}
736	}
737
738	/****
739	 ****  Installment Banners
740 	 */
741
742	let initInstallmentBanners = function(amount) {
743		consoleInfo('Initialising PayPal Installments banners', 'CartAmount = ' + payPalBannerSettings.cartAmount);
744		let banners = document.querySelectorAll('.paypal-installments');
745		banners.forEach(function(bannerElement) {
746			let position = bannerElement.dataset.ppinstPos;
747			consoleInfo('found banner on position ' + position);
748			if (payPalBannerSettings.positions && payPalBannerSettings.positions[position]) {
749				consoleInfo('settings found for position ' + position, payPalBannerSettings.positions[position]);
750				if (payPalBannerSettings.positions[position].style.layout === 'none') {
751					consoleInfo('position disabled: ' + position);
752					return;
753				}
754
755				if (amount === undefined) {
756                    amount = 0.00;
757                }
758				if (payPalBannerSettings.cartAmount) {
759					amount += payPalBannerSettings.cartAmount;
760				}
761                if (payPalBannerSettings.productsPrice) {
762                    amount += payPalBannerSettings.productsPrice;
763                } else {
764					let p = document.querySelector('div.current-price-container');
765					if(p) {
766						let priceText = p.innerText;
767						priceText = priceText.replace(/.*?[\d,.]+\s+\D{1,3}.*?([\d,.]+\s+\D{1,3})/s, '$1');
768						amount += 0.01 * parseFloat(priceText.replace(/.*?(((\d{1,3}[.,])+)(\d{2})).*/, '$1').replace(/[.,]/g, ''));
769						consoleInfo('Product amount for banner: ' + amount);
770					}
771                }
772				if (amount < 99) {
773					consoleInfo('Not showing PayPal Installments banner for amount ' + amount);
774                    return;
775				}
776
777				if(bannerElement.classList.contains('paypal-installments-cartbottom')) {
778					let observerTarget = document.querySelector('div.shopping-cart-button');
779					if (observerTarget) {
780						let cartSumElement = document.querySelector('tr.total.sum td:nth-child(2)');
781						let amountString = '0';
782						if(cartSumElement) {
783							amountString = cartSumElement.textContent.trim();
784						} else {
785							cartSumElement = document.querySelector('tr.footer.total td:nth-child(2)');
786							if(cartSumElement) {
787								amountString = cartSumElement.textContent.trim()
788									.replace(/(\n|\t|\.|\,)/g, '')
789									.replace(/.*?([0-9.,]+)\s+EUR.*/, '$1');
790							}
791						}
792                        amount = 0.01 * parseInt(amountString.replace(/[^0-9]/g, ''));
793						consoleInfo('cart amount ' + amount);
794
795						let observer = new MutationObserver(function(mutations, observer) {
796							mutations.forEach(function(mutation) {
797								if(mutation.removedNodes.length > 0) {
798									consoleInfo('re-init PayPal installments banner');
799									initInstallmentBanners();
800								}
801							});
802						});
803						observer.observe(observerTarget, {childList: true});
804					}
805				}
806
807				paypal.Messages({
808					amount: amount,
809					currency: payPalBannerSettings.currency,
810					style: payPalBannerSettings.positions[position].style,
811					placement: payPalBannerSettings.positions[position].placement
812				}).render(bannerElement)
813                    .then(function() {
814                        let legacyInstallmentContainer = document.querySelector('.paypalinstallmentcontainer');
815                        if(legacyInstallmentContainer) {
816                            legacyInstallmentContainer.remove();
817                        }
818                    });
819			}
820		});
821	};
822
823	let paypalSdkLoaded = function() {
824		consoleInfo('PayPalSDK loaded');
825		if(window.location.pathname.match(/shopping_cart.php/)) {
826			consoleInfo('Initializing ECS button');
827			initJSSDKPayPalButtonECS();
828		}
829		if(window.location.pathname.match(/checkout_payment.php/)) {
830			consoleInfo('Initializing PayPal on payment page');
831			initCheckoutPayment();
832		}
833		initInstallmentBanners();
834	};
835
836    let disableJavascriptFeatures = function(disable = true) {
837        /*
838        let pppay = document.querySelector('ul:not(.paypal3-plus-checkout) li.gambio_hub-PayPal2Hub');
839        if (pppay) {
840            consoleInfo('Removing PayPal payment option');
841            pppay.remove();
842        }
843        */
844
845        let newStyle = disable ? 'none' : 'block';
846        
847        let ecsButton = document.querySelector('div#paypal-newbutton');
848        if (ecsButton) {
849            ecsButton.style.display = newStyle;
850        }
851
852        let ccPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub-creditcard');
853        if (ccPaymentOption) {
854            ccPaymentOption.style.display = newStyle;
855        }
856        
857        let puiPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub-pui');
858        if (puiPaymentOption) {
859            puiPaymentOption.style.display = newStyle;
860        }
861        
862        let paylaterPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub-paylater');
863        if (paylaterPaymentOption) {
864            paylaterPaymentOption.style.display = newStyle;
865        }
866    
867        let sepaPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub-sepa');
868        if (sepaPaymentOption) {
869            sepaPaymentOption.style.display = newStyle;
870        }
871    
872        let ecmPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub');
873        if (ecmPaymentOption && disable) {
874            let paypalModeInput = document.createElement('input');
875            paypalModeInput.type = 'hidden';
876            paypalModeInput.name = 'PayPalMode';
877            paypalModeInput.value = 'sdkless';
878            ecmPaymentOption.appendChild(paypalModeInput);
879        }
880    }
881    
882    let disablePayPalOptions = function(disable = true) {
883        let paymentOptions = document.querySelectorAll('#checkout_payment li.list-group-item');
884        paymentOptions.forEach((paymentOption, key, parent) => {
885            paymentOption.classList.forEach((className) => {
886                if (className.match(/.*PayPal2Hub.*/)) {
887                    if (disable) {
888                        paymentOption.querySelector('input[name="payment"]').setAttribute('disabled', 'disabled');
889                        paymentOption.style.opacity = '0.5';
890                    } else {
891                        paymentOption.querySelector('input[name="payment"]').removeAttribute('disabled');
892                        paymentOption.style.opacity = '1';
893                    }
894                }
895            });
896        });
897    };
898    
899    let enablePayPalOptions = function() {
900        disablePayPalOptions(false);
901    }
902    
903    
904	let readyCallback = function() {
905        consoleInfo('readyCallback start');
906		let jssrc = '';
907        if (typeof (payPalButtonSettings) !== 'undefined' && payPalButtonSettings.jssrc) {
908            jssrc = payPalButtonSettings.jssrc;
909        } else if (typeof (payPalBannerSettings) !== 'undefined' && payPalBannerSettings.jssrc) {
910            jssrc = payPalBannerSettings.jssrc;
911        }
912        let pageHasBanners = document.querySelectorAll('.paypal-installments').length > 0;
913        let isCheckoutPage = window.location.pathname.match(/shopping_cart.php/) ||
914            window.location.pathname.match(/checkout_payment.php/);
915        
916        let consentGiven = undefined;
917        let purposeId = null;
918        let consentDataElement = document.getElementById('paypalconsent');
919        if (consentDataElement !== null) {
920            let consentData = JSON.parse(consentDataElement.textContent);
921            purposeId = consentData.purpose_id;
922            let gxConsentsString = document.cookie.split('; ').find((row) => row.startsWith('GXConsents='));
923            let gxConsents = gxConsentsString ? gxConsentsString.split('=')[1] : null;
924            if (gxConsents) {
925                let gxConsentsData = JSON.parse(gxConsents);
926                consentGiven = gxConsentsData.purposeConsents[''+purposeId];
927            }
928        }
929        
930        if (jssrc && (pageHasBanners || isCheckoutPage) && typeof(window.paypal) === 'undefined') {
931            let loadTimeout = null;
932            
933            let onPayPalSdkLoad = function() {
934                clearTimeout(loadTimeout);
935                paypalSdkLoaded();
936                disableJavascriptFeatures(false);
937                enablePayPalOptions();
938            };
939            let onPayPalSdkError = function() {
940                consoleInfo('ERROR loading PayPal Javascript - blocked?');
941                consoleInfo('PayPal JSSDK unavailable, disabling features');
942                disableJavascriptFeatures();
943                enablePayPalOptions();
944            };
945            window.initPayPalJSSDK = function() {
946                if (typeof(window.paypal) !== 'undefined') {
947                    return;
948                }
949                let jssdk = document.createElement('script');
950                jssdk.src = payPalButtonSettings.jssrc ? payPalButtonSettings.jssrc : payPalBannerSettings.jssrc;
951                if (payPalButtonSettings.useVault === true && isCustomerUsingVaultToken()) {
952                    jssdk.setAttribute('data-user-id-token', payPalButtonSettings.vaultToken);
953                }
954                if (
955                    payPalButtonSettings.partnerAttributionId !== null &&
956                    payPalButtonSettings.partnerAttributionId !== undefined) {
957                    jssdk.setAttribute('data-partner-attribution-id', payPalButtonSettings.partnerAttributionId);
958                }
959                let acdcIdentity = document.querySelector('#paypal_cc_i
959dentity');
960                if (acdcIdentity !== null) {
961                    let clientIdentity = JSON.parse(acdcIdentity.textContent);
962                    if (typeof clientIdentity.client_token !== 'undefined') {
963                        jssdk.dataset.clientToken = clientIdentity.client_token;
964                    }
965                }
966                jssdk.onerror = onPayPalSdkError;
967                jssdk.onload = onPayPalSdkLoad;
968    
969                if(document.currentScript) {
970                    document.currentScript.parentNode.insertBefore(jssdk, document.currentScript);
971                } else {
972                    document.querySelector('script:last-of-type').parentNode.appendChild(jssdk);
973                }
974            }
975            
976            disablePayPalOptions();
977            if (purposeId !== null) {
978                consoleInfo("External PayPal Javascript is managed by CookieConsent, purpose " + purposeId);
979                if (window.PayPalAsOilClearToLoad) {
980                    consoleInfo('OIL has cleared PayPal to load');
981                    window.initPayPalJSSDK();
982                } else {
983                    consoleInfo('OIL has not yet cleared PayPal to load');
984                    disableJavascriptFeatures();
985                    window.addEventListener('PayPalClearedToLoad', evt => {
986                        consoleInfo('OIL has cleared PayPal to load (Event)');
987                        window.initPayPalJSSDK();
988                    });
989                    if (isCheckoutPage) {
990                        consoleInfo('on checkout page; waiting 5s for OIL')
991                        loadTimeout = setTimeout(onPayPalSdkError, 5000);
992                    }
993                }
994            } else {
995                console.info("Not using CookieConsent integration for PayPal, loading directly");
996                window.initPayPalJSSDK();
997            }
998		} else {
999			consoleInfo('PayPal JSSDK unavailable or not required, disabling features');
1000            disableJavascriptFeatures();
1001		}
1002        consoleInfo('readyCallback end');
1003	};
1004
1005	let mainCallback = ("fetch" in window) ? readyCallback : handleAntiqueBrowser;
1006	
1007	if(document.readyState === 'complete' || (document.readyState !== 'loading' && !document.documentElement.doScroll)) {
1008        consoleInfo('Readystate complete');
1009		mainCallback();
1010	} else {
1011        consoleInfo('Adding EventListener for DOMContentLoaded');
1012		document.addEventListener('DOMContentLoaded', mainCallback);
1013	}
1014	
1015}());

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.