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.