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 let paymentItemClickListener = function() { 691 let selected_payment = this.querySelector('input[name="payment"]'); 692 if (null !== selected_payment) { 693 let showDefaultButton = true; 694 let selectedPaymentValue = selected_payment.value; 695 if (selectedPaymentValue === 'gambio_hub' && selected_payment.dataset.module_code === 'PayPal2Hub') { 696 selectedPaymentValue = 'gambio_hub-PayPal2Hub' 697 } 698 payPalContainerButtonConfig.forEach((item) => { 699 let button = document.getElementById(item.container); 700 if (button) { 701 if (item.value === selectedPaymentValue) { 702 showDefaultButton = false;
703 button.style.display = 'block' 704 continueButton.style.display = 'none'; 705 } else { 706 button.style.display = 'none' 707 } 708 } 709 }); 710 if (showDefaultButton === true) { 711 continueButton.style.display = continueButtonDisplay; 712 } 713 } 714 }; 715 716 Promise.allSettled(promises).then((results) => { 717 results.forEach((result) => { 718 if (result.status === 'fulfilled' && result.value) { 719 payPalContainerButtonConfig.push(result.value) 720 } 721 }) 722 let paymentItems = document.querySelectorAll('#checkout_payment input[name="payment"], #checkout_payment li.list-group-item'); 723 paymentItems.forEach(function(paymentItem) { 724 paymentItem.addEventListener('click', paymentItemClickListener) 725 }); 726 727 let paymentListEntries = document.querySelectorAll('#checkout_payment li'); 728 paymentListEntries.forEach(function(paymentOption) { 729 if (paymentOption.querySelector('input[name="payment"]:checked') || paymentListEntries.length === 1) { 730 paymentOption.dispatchEvent(new Event('click')); 731 } 732 }); 733 }); 734 } 735 } 736 737 /**** 738 **** Installment Banners 739 */ 740 741 let initInstallmentBanners = function(amount) { 742 consoleInfo('Initialising PayPal Installments banners', 'CartAmount = ' + payPalBannerSettings.cartAmount); 743 let banners = document.querySelectorAll('.paypal-installments'); 744 banners.forEach(function(bannerElement) { 745 let position = bannerElement.dataset.ppinstPos; 746 consoleInfo('found banner on position ' + position); 747 if (payPalBannerSettings.positions && payPalBannerSettings.positions[position]) { 748 consoleInfo('settings found for position ' + position, payPalBannerSettings.positions[position]); 749 if (payPalBannerSettings.positions[position].style.layout === 'none') { 750 consoleInfo('position disabled: ' + position); 751 return; 752 } 753 754 if (amount === undefined) { 755 amount = 0.00; 756 } 757 if (payPalBannerSettings.cartAmount) { 758 amount += payPalBannerSettings.cartAmount; 759 } 760 if (payPalBannerSettings.productsPrice) { 761 amount += payPalBannerSettings.productsPrice; 762 } else { 763 let p = document.querySelector('div.current-price-container'); 764 if(p) { 765 let priceText = p.innerText; 766 priceText = priceText.replace(/.*?[\d,.]+\s+\D{1,3}.*?([\d,.]+\s+\D{1,3})/s, '$1'); 767 amount += 0.01 * parseFloat(priceText.replace(/.*?(((\d{1,3}[.,])+)(\d{2})).*/, '$1').replace(/[.,]/g, '')); 768 consoleInfo('Product amount for banner: ' + amount); 769 } 770 } 771 if (amount < 99) { 772 consoleInfo('Not showing PayPal Installments banner for amount ' + amount); 773 return; 774 } 775 776 if(bannerElement.classList.contains('paypal-installments-cartbottom')) { 777 let observerTarget = document.querySelector('div.shopping-cart-button'); 778 if (observerTarget) { 779 let cartSumElement = document.querySelector('tr.total.sum td:nth-child(2)'); 780 let amountString = '0'; 781 if(cartSumElement) { 782 amountString = cartSumElement.textContent.trim(); 783 } else { 784 cartSumElement = document.querySelector('tr.footer.total td:nth-child(2)'); 785 if(cartSumElement) { 786 amountString = cartSumElement.textContent.trim() 787 .replace(/(\n|\t|\.|\,)/g, '') 788 .replace(/.*?([0-9.,]+)\s+EUR.*/, '$1'); 789 } 790 } 791 amount = 0.01 * parseInt(amountString.replace(/[^0-9]/g, '')); 792 consoleInfo('cart amount ' + amount); 793 794 let observer = new MutationObserver(function(mutations, observer) { 795 mutations.forEach(function(mutation) { 796 if(mutation.removedNodes.length > 0) { 797 consoleInfo('re-init PayPal installments banner'); 798 initInstallmentBanners(); 799 } 800 }); 801 }); 802 observer.observe(observerTarget, {childList: true}); 803 } 804 } 805 806 paypal.Messages({ 807 amount: amount, 808 currency: payPalBannerSettings.currency, 809 style: payPalBannerSettings.positions[position].style, 810 placement: payPalBannerSettings.positions[position].placement 811 }).render(bannerElement) 812 .then(function() { 813 let legacyInstallmentContainer = document.querySelector('.paypalinstallmentcontainer'); 814 if(legacyInstallmentContainer) { 815 legacyInstallmentContainer.remove(); 816 } 817 }); 818 } 819 }); 820 }; 821 822 let paypalSdkLoaded = function() { 823 consoleInfo('PayPalSDK loaded'); 824 if(window.location.pathname.match(/shopping_cart.php/)) { 825 consoleInfo('Initializing ECS button'); 826 initJSSDKPayPalButtonECS(); 827 } 828 if(window.location.pathname.match(/checkout_payment.php/)) { 829 consoleInfo('Initializing PayPal on payment page'); 830 initCheckoutPayment(); 831 } 832 initInstallmentBanners(); 833 }; 834 835 let disableJavascriptFeatures = function(disable = true) { 836 /* 837 let pppay = document.querySelector('ul:not(.paypal3-plus-checkout) li.gambio_hub-PayPal2Hub'); 838 if (pppay) { 839 consoleInfo('Removing PayPal payment option'); 840 pppay.remove(); 841 } 842 */ 843 844 let newStyle = disable ? 'none' : 'block'; 845 846 let ecsButton = document.querySelector('div#paypal-newbutton'); 847 if (ecsButton) { 848 ecsButton.style.display = newStyle; 849 } 850 851 let ccPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub-creditcard'); 852 if (ccPaymentOption) { 853 ccPaymentOption.style.display = newStyle; 854 } 855 856 let puiPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub-pui'); 857 if (puiPaymentOption) { 858 puiPaymentOption.style.display = newStyle; 859 } 860 861 let paylaterPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub-paylater'); 862 if (paylaterPaymentOption) { 863 paylaterPaymentOption.style.display = newStyle; 864 } 865 866 let sepaPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub-sepa'); 867 if (sepaPaymentOption) { 868 sepaPaymentOption.style.display = newStyle; 869 } 870 871 let ecmPaymentOption = document.querySelector('#checkout_payment li.gambio_hub-PayPal2Hub'); 872 if (ecmPaymentOption && disable) { 873 let paypalModeInput = document.createElement('input'); 874 paypalModeInput.type = 'hidden'; 875 paypalModeInput.name = 'PayPalMode'; 876 paypalModeInput.value = 'sdkless'; 877 ecmPaymentOption.appendChild(paypalModeInput); 878 } 879 } 880 881 let disablePayPalOptions = function(disable = true) { 882 let paymentOptions = document.querySelectorAll('#checkout_payment li.list-group-item'); 883 paymentOptions.forEach((paymentOption, key, parent) => { 884 paymentOption.classList.forEach((className) => { 885 if (className.match(/.*PayPal2Hub.*/)) { 886 if (disable) { 887 paymentOption.querySelector('input[name="payment"]').setAttribute('disabled', 'disabled'); 888 paymentOption.style.opacity = '0.5'; 889 } else { 890 paymentOption.querySelector('input[name="payment"]').removeAttribute('disabled'); 891 paymentOption.style.opacity = '1'; 892 } 893 } 894 }); 895 }); 896 }; 897 898 let enablePayPalOptions = function() { 899 disablePayPalOptions(false); 900 } 901 902 903 let readyCallback = function() { 904 consoleInfo('readyCallback start'); 905 let jssrc = ''; 906 if (typeof (payPalButtonSettings) !== 'undefined' && payPalButtonSettings.jssrc) { 907 jssrc = payPalButtonSettings.jssrc; 908 } else if (typeof (payPalBannerSettings) !== 'undefined' && payPalBannerSettings.jssrc) { 909 jssrc = payPalBannerSettings.jssrc; 910 } 911 let pageHasBanners = document.querySelectorAll('.paypal-installments').length > 0; 912 let isCheckoutPage = window.location.pathname.match(/shopping_cart.php/) || 913 window.location.pathname.match(/checkout_payment.php/); 914 915 let consentGiven = undefined; 916 let purposeId = null; 917 let consentDataElement = document.getElementById('paypalconsent'); 918 if (consentDataElement !== null) { 919 let consentData = JSON.parse(consentDataElement.textContent); 920 purposeId = consentData.purpose_id; 921 let gxConsentsString = document.cookie.split('; ').find((row) => row.startsWith('GXConsents=')); 922 let gxConsents = gxConsentsString ? gxConsentsString.split('=')[1] : null; 923 if (gxConsents) { 924 let gxConsentsData = JSON.parse(gxConsents); 925 consentGiven = gxConsentsData.purposeConsents[''+purposeId]; 926 } 927 } 928 929 if (jssrc && (pageHasBanners || isCheckoutPage) && typeof(window.paypal) === 'undefined') { 930 let loadTimeout = null; 931 932 let onPayPalSdkLoad = function() { 933 clearTimeout(loadTimeout); 934 paypalSdkLoaded(); 935 disableJavascriptFeatures(false); 936 enablePayPalOptions(); 937 }; 938 let onPayPalSdkError = function() { 939 consoleInfo('ERROR loading PayPal Javascript - blocked?'); 940 consoleInfo('PayPal JSSDK unavailable, disabling features'); 941 disableJavascriptFeatures(); 942 enablePayPalOptions(); 943 }; 944 window.initPayPalJSSDK = function() { 945 if (typeof(window.paypal) !== 'undefined') { 946 return; 947 } 948 let jssdk = document.createElement('script'); 949 jssdk.src = payPalButtonSettings.jssrc ? payPalButtonSettings.jssrc : payPalBannerSettings.jssrc; 950 if (payPalButtonSettings.useVault === true && isCustomerUsingVaultToken()) { 951 jssdk.setAttribute('data-user-id-token', payPalButtonSettings.vaultToken); 952 } 953 if ( 954 payPalButtonSettings.partnerAttributionId !== null && 955 payPalButtonSettings.partnerAttributionId !== undefined) { 956 jssdk.setAttribute('data-partner-attribution-id', payPalButtonSettings.partnerAttributionId); 957 } 958 let acdcIdentity = document.querySelector('#paypal_cc_i
958dentity'); 959 if (acdcIdentity !== null) { 960 let clientIdentity = JSON.parse(acdcIdentity.textContent); 961 if (typeof clientIdentity.client_token !== 'undefined') { 962 jssdk.dataset.clientToken = clientIdentity.client_token; 963 } 964 } 965 jssdk.onerror = onPayPalSdkError; 966 jssdk.onload = onPayPalSdkLoad; 967 968 if(document.currentScript) { 969 document.currentScript.parentNode.insertBefore(jssdk, document.currentScript); 970 } else { 971 document.querySelector('script:last-of-type').parentNode.appendChild(jssdk); 972 } 973 } 974 975 disablePayPalOptions(); 976 if (purposeId !== null) { 977 consoleInfo("External PayPal Javascript is managed by CookieConsent, purpose " + purposeId); 978 if (window.PayPalAsOilClearToLoad) { 979 consoleInfo('OIL has cleared PayPal to load'); 980 window.initPayPalJSSDK(); 981 } else { 982 consoleInfo('OIL has not yet cleared PayPal to load'); 983 disableJavascriptFeatures(); 984 window.addEventListener('PayPalClearedToLoad', evt => { 985 consoleInfo('OIL has cleared PayPal to load (Event)'); 986 window.initPayPalJSSDK(); 987 }); 988 if (isCheckoutPage) { 989 consoleInfo('on checkout page; waiting 5s for OIL') 990 loadTimeout = setTimeout(onPayPalSdkError, 5000); 991 } 992 } 993 } else { 994 console.info("Not using CookieConsent integration for PayPal, loading directly"); 995 window.initPayPalJSSDK(); 996 } 997 } else { 998 consoleInfo('PayPal JSSDK unavailable or not required, disabling features'); 999 disableJavascriptFeatures(); 1000 } 1001 consoleInfo('readyCallback end'); 1002 }; 1003 1004 let mainCallback = ("fetch" in window) ? readyCallback : handleAntiqueBrowser; 1005 1006 if(document.readyState === 'complete' || (document.readyState !== 'loading' && !document.documentElement.doScroll)) { 1007 consoleInfo('Readystate complete'); 1008 mainCallback(); 1009 } else { 1010 consoleInfo('Adding EventListener for DOMContentLoaded'); 1011 document.addEventListener('DOMContentLoaded', mainCallback); 1012 } 1013 1014}());
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.