1// Timer per il debouncing dell'aggiornamento checkout 2let checkoutUpdateTimer = null; 3let isCheckoutUpdating = false; 4 5// Funzione di debouncing per l'aggiornamento del checkout 6function debounceCheckoutUpdate(delay = 800) { 7 if (checkoutUpdateTimer) { 8 clearTimeout(checkoutUpdateTimer); 9 } 10 11 // Evita chiamate multiple sovrapposte 12 if (isCheckoutUpdating) { 13 return; 14 } 15 16 checkoutUpdateTimer = setTimeout(function () { 17 isCheckoutUpdating = true; 18 jQuery(document.body).trigger("update_checkout", { 19 update_shipping_method: true, 20 }); 21 22 // Reset del flag dopo un breve delay e trigger auto-click degli updatePudo 23 setTimeout(function() { 24 isCheckoutUpdating = false; 25 }, 1000); 26 }, delay); 27} 28 29function ensureShippingContainer() { 30 let shippingContainer = document.querySelector("app-shipping-container ul"); 31 if (shippingContainer) { 32 return shippingContainer; 33 } 34 35 const appShipping = document.querySelector("app-shipping-container"); 36 if (!appShipping) { 37 return null; 38 } 39 40 shippingContainer = document.createElement("ul"); 41 shippingContainer.id = "shipping_method"; 42 shippingContainer.className = 43 "woocommerce-shipping-methods Shipping__Methods"; 44 appShipping.appendChild(shippingContainer); 45 return shippingContainer; 46} 47 48document.addEventListener("DOMContentLoaded", function () { 49 // Aspetta che WooCommerce sia completamente caricato 50 setTimeout(function () { 51 syncBillingForm(); 52 // Forza un aggiornamento iniziale per calcolare le spedizioni al primo load 53 if (!document.body.dataset.checkoutInitialUpdate) { 54 document.body.dataset.checkoutInitialUpdate = "1"; 55 if (window.wc_checkout_form && document.querySelector("form.checkout")) { 56 debounceCheckoutUpdate(0); 57 } 58 } 59 }, 1000); 60 61 // Ri-inizializza dopo gli aggiornamenti del checkout 62 jQuery(document.body).on("updated_checkout", function (event, data) { 63 //console.log("Checkout updated, re-initializing sync"); 64 //console.log("Updated checkout data:", data); 65 66 setTimeout(function () { 67 syncBillingForm(); 68 handleShippingContainerUpdate(); 69 70 // Debug: verifica se ci sono frammenti aggiornati 71 if (data && data.fragments) { 72 //TODO: fix shipping methods update 73 /* console.log( 74 "Available fragments:", 75 Object.keys(data.fragments), 76 data.fragments 77 ); */ 78 let shippingContainer = ensureShippingContainer(); 79 //console.log("Shipping container:", shippingContainer); 80 if (shippingContainer) { 81 //empty and repopulate the shipping container 82 shippingContainer.innerHTML = ""; 83 Object.keys(data.fragments).forEach(function (key) { 84 if (key.includes("available-shipping-methods")) { 85 let fragment = data.fragments[key]; 86 shippingContainer.insertAdjacentHTML("beforeend", fragment); 87 } else if (key.includes("sumo-points")) { 88 // Prima rimuovi TUTTI gli elementi sumo-points esistenti con diversi selettori 89 let selectors = [ 90 ".sumo_reward_points_checkout_apply_discount", 91 ".EcommerceRecap__Content.sumo_reward_points_checkout_apply_discount", 92 ".EcommerceRecap__Content .sumo_reward_points_checkout_apply_discount", 93 "[class*='sumo_reward_points_checkout']", 94 "[class*='sumo-points']" 95 ]; 96 97 selectors.forEach(function(selector) { 98 let existingElements = document.querySelectorAll(selector); 99 existingElements.forEach(function (el) { 100 console.log("Removing sumo element:", el); 101 el.remove(); 102 }); 103 }); 104 105 // Inserisci il nuovo elemento dopo l'info element 106 let infoElement = document.querySelector( 107 ".EcommerceRecap__Content .woocommerce-info.sumo_available_points.rs_checkout_messages" 108 ); 109 if (infoElement) { 110 infoElement.insertAdjacentHTML( 111 "afterend", 112 data.fragments[key] 113 ); 114 console.log("Inserted new Sumo Points element after info element"); 115 } else { 116 // Fallback: inserisci nell'EcommerceRecap__Content se l'info element non esiste 117 let recapContent = document.querySelector(".EcommerceRecap__Content"); 118 if (recapContent) { 119 recapContent.insertAdjacentHTML( 120 "beforeend", 121 data.fragments[key] 122 ); 123 console.log("Inserted new Sumo Points element in recap content"); 124 } else { 125 console.warn( 126 "Info element and EcommerceRecap__Content not found for Sumo Points" 127 ); 128 } 129 } 130 } 131 }); 132 } else { 133 console.warn("Shipping container not found"); 134 } 135 } 136 }, 250); 137 }); 138 139 // Listener specifico per l'aggiornamento dei metodi di spedizione 140 jQuery(document.body).on("updated_shipping_method", function () { 141 handleShippingContainerUpdate(); 142 }); 143}); 144 145function checkFermoPointSection() { 146 // Deve controllare se il valore della select del paese è IT 147 let countrySelect = document.querySelector("#shipping_country"); 148 if (!countrySelect) { 149 console.error("Country select not found"); 150 return; 151 } 152 153 let countryValue = countrySelect.value; 154 const pudoAlert = document.querySelectorAll(".wc_brt_div_alert"); 155 156 if (countryValue !== "IT") { 157 pudoAlert.forEach((alert) => { 158 alert.style.display = "none"; 159 }); 160 } 161} 162 163function syncBillingForm() { 164 let body = document.querySelector("body"); 165 if (!body.classList.contains("woocommerce-checkout")) { 166 return; 167 } 168 let shippingFormWrapper = document.querySelector( 169 ".woocommerce-shipping-fields" 170 ); 171 let billingFormWrapper = document.querySelector( 172 ".woocommerce-billing-fields" 173 ); 174 175 //early return if no billing form found 176 if (!billingFormWrapper) { 177 console.error("No billing form found"); 178 return; 179 } 180 if (!shippingFormWrapper) { 181 console.error("No shipping form found"); 182 return; 183 } 184 185 // Rimuovi event listeners precedenti per evitare duplicati 186 shippingFormWrapper.removeAttribute("data-sync-initialized"); 187 188 // Controlla se già inizializzato 189 if (shippingFormWrapper.getAttribute("data-sync-initialized") === "true") { 190 return; 191 } 192 193 //select all input, select, textarea fields in billing form 194 let shippingFields = shippingFormWrapper.querySelectorAll( 195 "input, select, textarea" 196 ); 197 //loop through all fields in shipping form 198 shippingFields.forEach((shippingField) => { 199 // Funzione per sincronizzare il campo 200 function syncField() { 201 if (!isSyncActive()) { 202 return; 203 } 204 205 checkFermoPointSection(); 206 207 if (shippingField.id === "shipping_phone" || shippingField.id === "shipping_email") { 208 autoClickUpdatePudo(); 209 } 210 211 //since the field name is like shipping_first_name, we need to extract the field name, and look for billing field with the same name 212 let fieldName = shippingField.getAttribute("name"); 213 /* console.log( 214 "Syncing field:", 215 fieldName, 216 "with billing form", 217 `[name="${fieldName.replace("shipping_", "billing_")}"]` 218 ); */ 219 let billingField = billingFormWrapper.querySelector( 220 `[name="${fieldName.replace("shipping_", "billing_")}"]` 221 ); 222 /* console.log( 223 "Syncing field:", 224 fieldName, 225 "with billing field:", 226 billingField 227 ); */ 228 229 // SINCRONIZZAZIONE: Avviene SEMPRE per TUTTI i campi se esiste il campo billing corrispondente 230 if (billingField) { 231 // Evita di aggiornare se il valore è già uguale 232 if (billingField.value === shippingField.value) { 233 // Il valore è già sincronizzato, ma controlla comunque se serve aggiornare il checkout 234 } else { 235 // Sincronizza il valore dal campo shipping a quello billing 236 billingField.value = shippingField.value; 237 238 // Se il campo billing è anche un Select2, aggiorna anche quello 239 if (jQuery(billingField).hasClass("select2-hidden-accessible")) { 240 jQuery(billingField).val(shippingField.value).trigger("change"); 241 } 242 } 243 } 244 245 // AGGIORNAMENTO CHECKOUT: Triggera solo per campi che influenzano la spedizione 246 const shippingRelevantFields = [ 247 "shipping_country", 248 "shipping_state", 249 "shipping_postcode", 250 "shipping_city", 251 ]; 252 if (shippingRelevantFields.includes(fieldName)) { 253 /* console.log( 254 "Triggering debounced checkout update for shipping field:", 255 fieldName 256 ); */ 257 258 // Usa il debouncing per evitare troppe chiamate AJAX 259 debounceCheckoutUpdate(); 260 } 261 } 262 263 // Event listeners per campi normali 264 // Usa solo eventi significativi per ridurre il numero di chiamate 265 const fieldType = shippingField.type || shippingField.tagName.toLowerCase(); 266 let events = ["change"]; 267 268 // Per i campi di testo, aggiungi anche blur per catturare quando l'utente finisce di editare 269 if (fieldType === "text" || fieldType === "email" || fieldType === "tel" || shippingField.tagName.toLowerCase() === "textarea") { 270 events.push("blur"); 271 } 272
273 events.forEach((event) => { 274 shippingField.addEventListener(event, syncField); 275 }); 276 277 // Event listener specifico per Select2 - usa jQuery direttamente 278 if (jQuery(shippingField).hasClass("select2-hidden-accessible")) { 279 /* console.log("Found Select2 field:", shippingField.getAttribute("name")); */ 280 281 // Rimuovi event listeners precedenti 282 jQuery(shippingField).off( 283 "select2:select.syncBilling select2:unselect.syncBilling change.syncBilling" 284 ); 285 286 // Aggiungi nuovi event listeners con namespace 287 jQuery(shippingField).on("select2:select.syncBilling", function (e) { 288 /* console.log("Select2 select event triggered for:", this.name); */ 289 syncField(); 290 }); 291 292 jQuery(shippingField).on("select2:unselect.syncBilling", function (e) { 293 /* console.log("Select2 unselect event triggered for:", this.name); */ 294 syncField(); 295 }); 296 297 // Fallback con change normale 298 jQuery(shippingField).on("change.syncBilling", function (e) { 299 /* console.log("Change event triggered for:", this.name); */ 300 syncField(); 301 }); 302 } 303 }); 304 305 // Marca come inizializzato 306 shippingFormWrapper.setAttribute("data-sync-initialized", "true"); 307} 308 309// Gestione specifica per il componente app-shipping-container 310function handleShippingContainerUpdate() { 311 //console.log("Handling shipping container update"); 312 313 // Assicurati che i nuovi elementi shipping siano gestiti correttamente 314 const shippingContainer = document.querySelector("app-shipping-container"); 315 if (shippingContainer) { 316 //console.log("Shipping container found and updated"); 317 318 // Forza un refresh della sezione shipping se necessario 319 // Cerca elementi con classi WooCommerce standard che potrebbero essere stati aggiornati 320 const shippingMethods = shippingContainer.querySelectorAll( 321 ".woocommerce-shipping-methods" 322 ); 323 //console.log("Found shipping methods containers:", shippingMethods.length); 324 325 // Se non ci sono metodi di spedizione visibili, prova a forzare un altro aggiornamento 326 if (shippingMethods.length === 0) { 327 //console.log("No shipping methods found, forcing another update"); 328 setTimeout(function () { 329 jQuery(document.body).trigger("wc_update_cart"); 330 }, 200); 331 } 332 } else { 333 //console.log("Shipping container not found"); 334 335 // Se il container non esiste, potrebbe essere stato rimosso durante l'aggiornamento 336 // Prova a forzare un refresh completo 337 setTimeout(function () { 338 jQuery(document.body).trigger("wc_update_cart"); 339 }, 200); 340 } 341} 342 343function isSyncActive() { 344 let radio = document.querySelector("#shipping-invoice_yes, #shipping-invoice_si"); 345 if (radio && radio.checked) { 346 return true; 347 } 348 return false; 349} 350 351// Funzione per cliccare automaticamente tutti gli elementi .updatePudo 352function autoClickUpdatePudo() { 353 const updatePudoElements = document.querySelectorAll('.updatePudo'); 354 355 if (updatePudoElements.length > 0) { 356 //console.log(`Trovati ${updatePudoElements.length} elementi .updatePudo, esecuzione click automatico...`); 357 358 updatePudoElements.forEach((element, index) => { 359 // Aggiungi un piccolo delay tra i click per evitare problemi di concorrenza 360 setTimeout(() => { 361 if (element && typeof element.click === 'function') { 362 element.click(); 363 //console.log(`Clicked .updatePudo elemento ${index + 1}/${updatePudoElements.length}`); 364 } 365 }, index * 50); // 50ms di delay tra ogni click 366 }); 367 } else { 368 // Log solo se siamo in modalità debug (rimuovi in produzione se vuoi) 369 // console.log('Nessun elemento .updatePudo trovato per l\'auto-click'); 370 } 371} 372 373/* global wc_checkout_params */ 374jQuery(function ($) { 375 // wc_checkout_params is required to continue, ensure the object exists 376 if (typeof wc_checkout_params === "undefined") { 377 return false; 378 } 379 380 $.blockUI.defaults.overlayCSS.cursor = "default"; 381 382 var wc_checkout_form = { 383 updateTimer: false, 384 dirtyInput: false, 385 selectedPaymentMethod: false, 386 xhr: false, 387 $order_review: $("#order_review"), 388 $checkout_form: $("form.checkout"), 389 init: function () { 390 $(document.body).on("update_checkout", this.update_checkout); 391 $(document.body).on("init_checkout", this.init_checkout); 392 393 // Payment methods 394 this.$checkout_form.on( 395 "click", 396 'input[name="payment_method"]', 397 this.payment_method_selected 398 ); 399 400 if ($(document.body).hasClass("woocommerce-order-pay")) { 401 this.$order_review.on( 402 "click", 403 'input[name="payment_method"]', 404 this.payment_method_selected 405 ); 406 this.$order_review.on("submit", this.submitOrder); 407 this.$order_review.attr("novalidate", "novalidate"); 408 } 409 410 // Prevent HTML5 validation which can conflict. 411 this.$checkout_form.attr("novalidate", "novalidate"); 412 413 // Form submission 414 this.$checkout_form.on("submit", this.submit); 415 416 // Inline validation 417 this.$checkout_form.on( 418 "input validate change focusout", 419 ".input-text, select, input:checkbox", 420 this.validate_field 421 ); 422 423 // Manual trigger 424 this.$checkout_form.on("update", this.trigger_update_checkout); 425
426 // Inputs/selects which update totals 427 this.$checkout_form.on( 428 "change", 429 'select.shipping_method, input[name^="shipping_method"], #ship-to-different-address input, .update_totals_on_change select, .update_totals_on_change input[type="radio"], .update_totals_on_change input[type="checkbox"]', 430 this.trigger_update_checkout 431 ); 432 this.$checkout_form.on( 433 "change", 434 ".address-field select", 435 this.input_changed 436 ); 437 this.$checkout_form.on( 438 "change", 439 ".address-field input.input-text, .update_totals_on_change input.input-text", 440 this.maybe_input_changed 441 ); 442 this.$checkout_form.on( 443 "keydown", 444 ".address-field input.input-text, .update_totals_on_change input.input-text", 445 this.queue_update_checkout 446 ); 447 448 // Address fields 449 this.$checkout_form.on( 450 "change", 451 "#ship-to-different-address input", 452 this.ship_to_different_address 453 ); 454 455 // Trigger events 456 this.$checkout_form 457 .find("#ship-to-different-address input") 458 .trigger("change"); 459 this.init_payment_methods(); 460 461 // Update on page load 462 if (wc_checkout_params.is_checkout === "1") { 463 $(document.body).trigger("init_checkout"); 464 } 465 466 // Make sure the create account checkbox is visible and functional 467 if (wc_checkout_params.option_guest_checkout === "yes") { 468 $("input#createaccount") 469 .on("change", this.toggle_create_account) 470 .trigger("change"); 471 // Make sure the checkbox is visible 472 $("input#createaccount").closest(".form-row").show(); 473 } 474 }, 475 init_payment_methods: function () { 476 var $payment_methods = $(".woocommerce-checkout").find( 477 'input[name="payment_method"]' 478 ); 479 480 // If there is one method, we can hide the radio input 481 if (1 === $payment_methods.length) { 482 $payment_methods.eq(0).hide(); 483 } 484 485 // If there was a previously selected method, check that one. 486 if (wc_checkout_form.selectedPaymentMethod) { 487 $("#" + wc_checkout_form.selectedPaymentMethod).prop("checked", true); 488 } 489 490 // If there are none selected, select the first. 491 if (0 === $payment_methods.filter(":checked").length) { 492 $payment_methods.eq(0).prop("checked", true); 493 } 494 495 // Get name of new selected method. 496 var checkedPaymentMethod = $payment_methods 497 .filter(":checked") 498 .eq(0) 499 .prop("id"); 500 501 if ($payment_methods.length > 1) { 502 // Hide open descriptions. 503 $('div.payment_box:not(".' + checkedPaymentMethod + '")') 504 .filter(":visible") 505 .slideUp(0); 506 } 507 508 // Trigger click event for selected method 509 $payment_methods.filter(":checked").eq(0).trigger("click"); 510 }, 511 get_payment_method: function () { 512 return wc_checkout_form.$checkout_form 513 .find('input[name="payment_method"]:checked') 514 .val(); 515 }, 516 payment_method_selected: function (e) { 517 e.stopPropagation(); 518 519 if ($(".payment_methods input.input-radio").length > 1) { 520 var target_payment_box = $("div.payment_box." + $(this).attr("ID")), 521 is_checked = $(this).is(":checked"); 522 523 if (is_checked && !target_payment_box.is(":visible")) { 524 $("div.payment_box").filter(":visible").slideUp(230); 525 526 if (is_checked) { 527 target_payment_box.slideDown(230); 528 } 529 } 530 } else { 531 $("div.payment_box").show(); 532 } 533 534 if ($(this).data("order_button_text")) { 535 $("#place_order").text($(this).data("order_button_text")); 536 } else { 537 $("#place_order").text($("#place_order").data("value")); 538 } 539 540 var selectedPaymentMethod = $( 541 '.woocommerce-checkout input[name="payment_method"]:checked' 542 ).attr("id"); 543 544 if (selectedPaymentMethod !== wc_checkout_form.selectedPaymentMethod) { 545 $(document.body).trigger("payment_method_selected"); 546 } 547 548 wc_checkout_form.selectedPaymentMethod = selectedPaymentMethod; 549 }, 550 toggle_create_account: function () { 551 $("div.create-account").hide(); 552 553 if ($(this).is(":checked")) { 554 // Ensure password is not pre-populated. 555 $("#account_password").val("").trigger("change"); 556 $("div.create-account").slideDown(); 557 } 558 }, 559 init_checkout: function () { 560 $(document.body).trigger("update_checkout"); 561 }, 562 maybe_input_changed: function (e) { 563 if (wc_checkout_form.dirtyInput) { 564 wc_checkout_form.input_changed(e); 565 } 566 }, 567 input_changed: function (e) { 568 wc_checkout_form.dirtyInput = e.target; 569 wc_checkout_form.maybe_update_checkout(); 570 }, 571 queue_update_checkout: function (e) { 572 var code = e.keyCode || e.which || 0; 573 574 if (code === 9) { 575 return true; 576 } 577 578 wc_checkout_form.dirtyInput = this; 579 wc_checkout_form.reset_update_checkout_timer(); 580 wc_checkout_form.updateTimer = setTimeout( 581 wc_checkout_form.maybe_update_checkout, 582 "1000" 583 ); 584 }, 585 trigger_update_checkout: function (event) { 586 wc_checkout_form.reset_update_checkout_timer(); 587 wc_checkout_form.dirtyInput = false;
588 $(document.body).trigger("update_checkout", { 589 current_target: event ? event.currentTarget : null, 590 }); 591 }, 592 maybe_update_checkout: function () { 593 var update_totals = true; 594 595 if ($(wc_checkout_form.dirtyInput).length) { 596 var $required_inputs = $(wc_checkout_form.dirtyInput) 597 .closest("div") 598 .find(".address-field.validate-required"); 599 600 if ($required_inputs.length) { 601 $required_inputs.each(function () { 602 if ($(this).find("input.input-text").val() === "") { 603 update_totals = false; 604 } 605 }); 606 } 607 } 608 if (update_totals) { 609 wc_checkout_form.trigger_update_checkout(); 610 } 611 }, 612 ship_to_different_address: function () { 613 $("div.shipping_address").hide(); 614 if ($(this).is(":checked")) { 615 $("div.shipping_address").slideDown(); 616 } 617 }, 618 reset_update_checkout_timer: function () { 619 clearTimeout(wc_checkout_form.updateTimer); 620 }, 621 is_valid_json: function (raw_json) { 622 try { 623 var json = JSON.parse(raw_json); 624 625 return json && "object" === typeof json; 626 } catch (e) { 627 return false; 628 } 629 }, 630 validate_field: function (e) { 631 var $this = $(this), 632 $parent = $this.closest(".form-row"), 633 validated = true, 634 validate_required = $parent.is(".validate-required"), 635 validate_email = $parent.is(".validate-email"), 636 validate_cf = $parent.is(".validate-cf"), 637 validate_phone = $parent.is(".validate-phone"), 638 pattern = "", 639 event_type = e.type; 640 641 if ("input" === event_type) { 642 $parent.removeClass( 643 "woocommerce-invalid woocommerce-invalid-required-field woocommerce-invalid-email woocommerce-invalid-cf woocommerce-invalid-phone woocommerce-validated" 644 ); 645 } 646 647 if ("validate" === event_type || "change" === event_type) { 648 if (validate_required) { 649 if ("checkbox" === $this.attr("type") && !$this.is(":checked")) { 650 $parent 651 .removeClass("woocommerce-validated") 652 .addClass( 653 "woocommerce-invalid woocommerce-invalid-required-field" 654 ); 655 validated = false; 656 } else if ($this.val() === "") { 657 $parent 658 .removeClass("woocommerce-validated") 659 .addClass( 660 "woocommerce-invalid woocommerce-invalid-required-field" 661 ); 662 validated = false; 663 } 664 } 665 666 if (validate_email) { 667 if ($this.val()) { 668 /* https://stackoverflow.com/questions/2855865/jquery-validate-e-mail-address-regex */ 669 pattern = new RegExp( 670 /^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([ \t]*\r\n)?[ \t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\u7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([ \t]*\r\n)?[ \t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i 671 ); // eslint-disable-line max-len 672 673 if (!pattern.test($this.val())) { 674 $parent 675 .removeClass("woocommerce-validated") 676 .addClass("woocommerce-invalid woocommerce-invalid-email"); 677 validated = false; 678 } 679 } 680 } 681 682 if (validate_cf) { 683 // Check if the field is empty 684 if ($this.val() != "") { 685 pattern = new RegExp(/^[A-Za-z]{6}[0-9]{2}[A-Za-z]{1}[0-9]{2}[A-Za-z]{1}[0-9]{3}[A-Za-z]{1}$/); 686 if (!pattern.test($this.val())) { 687 $parent 688 .removeClass("woocommerce-validated") 689 .addClass("woocommerce-invalid woocommerce-invalid-cf"); 690 validated = false;
691 } 692 } 693 } 694 695 if (validate_phone) { 696 pattern = new RegExp(/[\s\#0-9_\-\+\/\(\)\.]/g); 697 698 if (0 < $this.val().replace(pattern, "").length) { 699 $parent 700 .removeClass("woocommerce-validated") 701 .addClass("woocommerce-invalid woocommerce-invalid-phone"); 702 validated = false; 703 } 704 } 705 706 if (validated) { 707 $parent 708 .removeClass( 709 "woocommerce-invalid woocommerce-invalid-required-field woocommerce-invalid-email woocommerce-invalid-phone woocommerce-invalid-cf" 710 ) 711 .addClass("woocommerce-validated"); 712 } 713 } 714 }, 715 update_checkout: function (event, args) { 716 // Small timeout to prevent multiple requests when several fields update at the same time 717 wc_checkout_form.reset_update_checkout_timer(); 718 wc_checkout_form.updateTimer = setTimeout( 719 wc_checkout_form.update_checkout_action, 720 "5", 721 args 722 ); 723 }, 724 update_checkout_action: function (args) { 725 if (wc_checkout_form.xhr) { 726 wc_checkout_form.xhr.abort(); 727 } 728 729 if ($("form.checkout").length === 0) { 730 return; 731 } 732 733 args = 734 typeof args !== "undefined" 735 ? args 736 : { 737 update_shipping_method: true, 738 }; 739 740 var country = $("#billing_country").val(), 741 state = $("#billing_state").val(), 742 postcode = $(":input#billing_postcode").val(), 743 city = $("#billing_city").val(), 744 address = $(":input#billing_address_1").val(), 745 address_2 = $(":input#billing_address_2").val(), 746 s_country = country, 747 s_state = state, 748 s_postcode = postcode, 749 s_city = city, 750 s_address = address, 751 s_address_2 = address_2, 752 $required_inputs = $(wc_checkout_form.$checkout_form).find( 753 ".address-field.validate-required:visible" 754 ), 755 has_full_address = true; 756 757 if ($required_inputs.length) { 758 $required_inputs.each(function () { 759 if ($(this).find(":input").val() === "") { 760 has_full_address = false; 761 } 762 }); 763 } 764 765 if ($("#ship-to-different-address").find("input").is(":checked")) { 766 s_country = $("#shipping_country").val(); 767 s_state = $("#shipping_state").val(); 768 s_postcode = $(":input#shipping_postcode").val(); 769 s_city = $("#shipping_city").val(); 770 s_address = $(":input#shipping_address_1").val(); 771 s_address_2 = $(":input#shipping_address_2").val(); 772 } 773 774 var data = { 775 security: wc_checkout_params.update_order_review_nonce, 776 payment_method: wc_checkout_form.get_payment_method(), 777 country: country, 778 state: state, 779 postcode: postcode, 780 city: city, 781 address: address, 782 address_2: address_2, 783 s_country: s_country, 784 s_state: s_state, 785 s_postcode: s_postcode, 786 s_city: s_city, 787 s_address: s_address, 788 s_address_2: s_address_2, 789 has_full_address: has_full_address, 790 post_data: $("form.checkout").serialize(), 791 }; 792 793 if (false !== args.update_shipping_method) { 794 var shipping_methods = {}; 795 796 // eslint-disable-next-line max-len 797 $( 798 'select.shipping_method, input[name^="shipping_method"][type="radio"]:checked, input[name^="shipping_method"][type="hidden"]' 799 ).each(function () { 800 shipping_methods[$(this).data("index")] = $(this).val(); 801 }); 802 803 data.shipping_method = shipping_methods; 804 } 805 806 $( 807 ".woocommerce-checkout-payment, .woocommerce-checkout-review-order-table" 808 ).block({ 809 message: null, 810 overlayCSS: { 811 background: "#fff", 812 opacity: 0.6, 813 }, 814 }); 815 816 wc_checkout_form.xhr = $.ajax({ 817 type: "POST", 818 url: wc_checkout_params.wc_ajax_url 819 .toString() 820 .replace("%%endpoint%%", "update_order_review"), 821 data: data, 822 success: function (data) { 823 // Reload the page if requested 824 if (data && true === data.reload) { 825 window.location.reload(); 826 return; 827 } 828 829 // Remove any notices added previously 830 $(".woocommerce-NoticeGroup-updateOrderReview").remove(); 831 832 var termsCheckBoxChecked = $("#terms").prop("checked"); 833 834 // Save payment details to a temporary object 835 var paymentDetails = {}; 836 $(".payment_box :input").each(function () { 837 var ID = $(this).attr("id"); 838 839 if (ID) { 840 if ( 841 $.inArray($(this).attr("type"), ["checkbox", "radio"]) !== -1 842 ) { 843 paymentDetails[ID] = $(this).prop("checked"); 844 } else { 845 paymentDetails[ID] = $(this).val(); 846 } 847 } 848 }); 849 850 // Always update the fragments 851 if (data && data.fragments) { 852 $.each(data.fragments, function (key, value) { 853 if ( 854 !wc_checkout_form.fragments || 855 wc_checkout_form.fragments[key] !== value 856 ) { 857 $(key).replaceWith(value); 858 } 859 $(key).unblock(); 860 }); 861 wc_checkout_form.fragments = data.fragments; 862 } 863 864 // Recheck the terms and conditions box, if needed 865 if (termsCheckBoxChecked) { 866 $("#terms").prop("checked", true); 867 } 868 869 // Fill in the payment details if possible without overwriting data 870 if (!$.isEmptyObject(paymentDetails)) { 871 $(".payment_box :input").each(function () { 872 var ID = $(this).attr("id"); 873 if (ID) { 874 if ( 875 $.inArray($(this).attr("type"), ["checkbox", "radio"]) !== -1 876 ) { 877 $(this).prop("checked", paymentDetails[ID]).trigger("change"); 878 } else if ($.inArray($(this).attr("type"), ["select"]) !== -1) { 879 $(this).val(paymentDetails[ID]).trigger("change"); 880 } else if ( 881 null !== $(this).val() && 882 0 === $(this).val().length 883 ) { 884 $(this).val(paymentDetails[ID]).trigger("change"); 885 } 886 } 887 }); 888 } 889 890 // Check for error 891 if (data && "failure" === data.result) { 892 var $form = $("form.checkout"); 893 894 // Remove notices from all sources 895 $(".woocommerce-error, .woocommerce-message").remove(); 896 897 // Add new errors returned by this event 898 if (data.messages) { 899 $form.prepend( 900 '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-updateOrderReview">' + 901 data.messages + 902 "</div>" 903 ); // eslint-disable-line max-len 904 } else { 905 $form.prepend(data); 906 } 907 908 // Lose focus for all fields 909 $form
910 .find(".input-text, select, input:checkbox") 911 .trigger("validate") 912 .trigger("blur"); 913 914 wc_checkout_form.scroll_to_notices(); 915 } 916 917 // Re-init methods 918 wc_checkout_form.init_payment_methods(); 919 920 // Fire updated_checkout event. 921 $(document.body).trigger("updated_checkout", [data]); 922 }, 923 }); 924 }, 925 submit: function () { 926 wc_checkout_form.reset_update_checkout_timer(); 927 var $form = $(this); 928 929 if ($form.is(".processing")) { 930 return false; 931 } 932 933 // Trigger a handler to let gateways manipulate the checkout if needed 934 // eslint-disable-next-line max-len 935 if ( 936 $form.triggerHandler("checkout_place_order") !== false && 937 $form.triggerHandler( 938 "checkout_place_order_" + wc_checkout_form.get_payment_method() 939 ) !== false 940 ) { 941 $form.addClass("processing"); 942 943 wc_checkout_form.blockOnSubmit($form); 944 945 // Attach event to block reloading the page when the form has been submitted 946 wc_checkout_form.attachUnloadEventsOnSubmit(); 947 948 // ajaxSetup is global, but we use it to ensure JSON is valid once returned. 949 $.ajaxSetup({ 950 dataFilter: function (raw_response, dataType) { 951 // We only want to work with JSON 952 if ("json" !== dataType) { 953 return raw_response; 954 } 955 956 if (wc_checkout_form.is_valid_json(raw_response)) { 957 return raw_response; 958 } else { 959 // Attempt to fix the malformed JSON 960 var maybe_valid_json = raw_response.match(/{"result.*}/); 961 962 if (null === maybe_valid_json) { 963 //console.log("Unable to fix malformed JSON"); 964 } else if (wc_checkout_form.is_valid_json(maybe_valid_json[0])) { 965 //console.log("Fixed malformed JSON. Original:"); 966 //console.log(raw_response); 967 raw_response = maybe_valid_json[0]; 968 } else { 969 //console.log("Unable to fix malformed JSON"); 970 } 971 } 972 973 return raw_response; 974 }, 975 }); 976 977 $.ajax({ 978 type: "POST", 979 url: wc_checkout_params.checkout_url, 980 data: $form.serialize(), 981 dataType: "json", 982 success: function (result) { 983 wc_checkout_form.detachUnloadEventsOnSubmit(); 984 985 try { 986 if ( 987 "success" === result.result && 988 $form.triggerHandler("checkout_place_order_success", result) !== 989 false 990 ) { 991 if ( 992 -1 === result.redirect.indexOf("https://") || 993 -1 === result.redirect.indexOf("http://") 994 ) { 995 window.location = result.redirect; 996 } else { 997 window.location = decodeURI(result.redirect); 998 } 999 } else if ("failure" === result.result) { 1000 throw "Result failure"; 1001 } else { 1002 throw "Invalid response"; 1003 } 1004 } catch (err) { 1005 // Reload page 1006 if (true === result.reload) { 1007 window.location.reload(); 1008 return; 1009 } 1010 1011 // Trigger update in case we need a fresh nonce 1012 if (true === result.refresh) { 1013 $(document.body).trigger("update_checkout"); 1014 } 1015 1016 // Add new errors 1017 if (result.messages) { 1018 wc_checkout_form.submit_error(result.messages); 1019 } else { 1020 wc_checkout_form.submit_error( 1021 '<div class="woocommerce-error">' + 1022 wc_checkout_params.i18n_checkout_error + 1023 "</div>" 1024 ); // eslint-disable-line max-len 1025 } 1026 } 1027 }, 1028 error: function (jqXHR, textStatus, errorThrown) { 1029 wc_checkout_form.detachUnloadEventsOnSubmit(); 1030 wc_checkout_form.submit_error( 1031 '<div class="woocommerce-error">' + errorThrown + "</div>" 1032 ); 1033 }, 1034 }); 1035 } 1036 1037 return false;
1038 }, 1039 scroll_to_notices: function () { 1040 const headerMain = document.querySelector('.Header--Main'); 1041 var scrollElement = $( 1042 ".woocommerce-NoticeGroup-updateOrderReview, .woocommerce-NoticeGroup-checkout" 1043 ); 1044 1045 if (!scrollElement.length) { 1046 scrollElement = $("form.checkout"); 1047 } 1048 1049 // Calcola l'altezza dell'headerMain se presente 1050 let headerOffset = 0; 1051 if (headerMain) { 1052 headerOffset = headerMain.offsetHeight || 0; 1053 } 1054 1055 // Scroll con offset per evitare che l'header copra l'elemento 1056 $("html, body").animate( 1057 { 1058 scrollTop: scrollElement.offset().top - headerOffset - 20, 1059 }, 1060 500 1061 ); 1062 }, 1063 attach_listener_for_add_new_card_option: function () { 1064 // This ensures the checkout is re-rendered when a new payment method is added. 1065 if (wc_checkout_form.is_form_ready) { 1066 $(document.body).on("payment_method_selected", function () { 1067 $(document.body).trigger("update_checkout"); 1068 }); 1069 wc_checkout_form.is_form_ready = false; 1070 } 1071 }, 1072 attach_listener_for_checkout_credentials_input: function () { 1073 // Listen for changes to the checkout credentials (e.g. username and password) 1074 // and make sure the user is warned if they're already logged in. 1075 if (wc_checkout_form.is_logged_in) { 1076 const $username_field = $("#username"); 1077 const $password_field = $("#password"); 1078 const on_input_change = function () { 1079 if ($username_field.length && $username_field.val()) { 1080 $(".woocommerce-checkout").on("checkout_place_order", function () { 1081 return confirm( 1082 wc_checkout_params.i18n_checkout_logged_in_message 1083 ); 1084 }); 1085 } 1086 }; 1087 $username_field.on("change", on_input_change); 1088 $password_field.on("change", on_input_change); 1089 } 1090 }, 1091 submit_error: function (error_message) { 1092 $( 1093 ".woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message" 1094 ).remove(); 1095 wc_checkout_form.$checkout_form.prepend( 1096 '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">' + 1097 error_message + 1098 "</div>" 1099 ); // eslint-disable-line max-len 1100 wc_checkout_form.$checkout_form.removeClass("processing").unblock(); 1101 wc_checkout_form.$checkout_form 1102 .find(".input-text, select, input:checkbox") 1103 .trigger("validate") 1104 .trigger("blur"); 1105 wc_checkout_form.scroll_to_notices(); 1106 $(document.body).trigger("checkout_error", [error_message]); 1107 }, 1108 blockOnSubmit: function ($form) { 1109 var form_data = $form.data(); 1110 1111 if (1 !== form_data["blockUI.isBlocked"]) { 1112 $form.block({ 1113 message: null, 1114 overlayCSS: { 1115 background: "#fff", 1116 opacity: 0.6, 1117 }, 1118 }); 1119 } 1120 }, 1121 attachUnloadEventsOnSubmit: function () { 1122 $(window).on("beforeunload", this.handleUnloadEvent); 1123 }, 1124 detachUnloadEventsOnSubmit: function () { 1125 $(window).off("beforeunload", this.handleUnloadEvent); 1126 }, 1127 handleUnloadEvent: function (e) { 1128 // Modern browsers have their own standard generic messages that they will display. 1129 // Confirm, alert, prompt or custom message are not allowed during the unload event 1130 // Browsers will display their own standard messages 1131 1132 // Check if the browser is Internet Explorer 1133 if ( 1134 navigator.userAgent.indexOf("MSIE") !== -1 || 1135 !!document.documentMode 1136 ) { 1137 // IE handles unload events differently than modern browsers 1138 e.preventDefault(); 1139 return undefined; 1140 } 1141 1142 return true; 1143 }, 1144 }; 1145 1146 var wc_checkout_coupons = { 1147 init: function () { 1148 $(document.body).on("click", "a.showcoupon", this.show_coupon_form); 1149 $(document.body).on( 1150 "click", 1151 ".woocommerce-remove-coupon", 1152 this.remove_coupon 1153 ); 1154 $("form.checkout_coupon").hide().on("submit", this.submit); 1155 }, 1156 show_coupon_form: function () { 1157 $(".checkout_coupon").slideToggle(400, function () { 1158 $(".checkout_coupon").find(":input:eq(0)").trigger("focus"); 1159 }); 1160 return false;
1161 }, 1162 submit: function () { 1163 var $form = $(this); 1164 1165 if ($form.is(".processing")) { 1166 return false; 1167 } 1168 1169 $form.addClass("processing").block({ 1170 message: null, 1171 overlayCSS: { 1172 background: "#fff", 1173 opacity: 0.6, 1174 }, 1175 }); 1176 1177 var data = { 1178 security: wc_checkout_params.apply_coupon_nonce, 1179 coupon_code: $form.find('input[name="coupon_code"]').val(), 1180 }; 1181 1182 $.ajax({ 1183 type: "POST", 1184 url: wc_checkout_params.wc_ajax_url 1185 .toString() 1186 .replace("%%endpoint%%", "apply_coupon"), 1187 data: data, 1188 success: function (code) { 1189 $(".woocommerce-error, .woocommerce-message").remove(); 1190 $form.removeClass("processing").unblock(); 1191 1192 if (code) { 1193 $form.before(code); 1194 $form.slideUp(); 1195 1196 $(document.body).trigger("applied_coupon_in_checkout", [ 1197 data.coupon_code, 1198 ]); 1199 $(document.body).trigger("update_checkout", { 1200 update_shipping_method: false, 1201 }); 1202 } 1203 }, 1204 dataType: "html", 1205 }); 1206 1207 return false; 1208 }, 1209 remove_coupon: function (e) { 1210 e.preventDefault(); 1211 1212 var container = $(this).parents(".woocommerce-checkout-review-order"), 1213 coupon = $(this).data("coupon"); 1214 1215 container.addClass("processing").block({ 1216 message: null, 1217 overlayCSS: { 1218 background: "#fff", 1219 opacity: 0.6, 1220 }, 1221 }); 1222 1223 var data = { 1224 security: wc_checkout_params.remove_coupon_nonce, 1225 coupon: coupon, 1226 }; 1227 1228 $.ajax({ 1229 type: "POST", 1230 url: wc_checkout_params.wc_ajax_url 1231 .toString() 1232 .replace("%%endpoint%%", "remove_coupon"), 1233 data: data, 1234 success: function (code) { 1235 $(".woocommerce-error, .woocommerce-message").remove(); 1236 container.removeClass("processing").unblock(); 1237 1238 if (code) { 1239 $("form.woocommerce-checkout").before(code); 1240 1241 $(document.body).trigger("removed_coupon_in_checkout", [ 1242 data.coupon, 1243 ]); 1244 $(document.body).trigger("update_checkout", { 1245 update_shipping_method: false, 1246 }); 1247 1248 // Remove coupon code from coupon field 1249 $("form.checkout_coupon").find('input[name="coupon_code"]').val(""); 1250 } 1251 }, 1252 error: function (jqXHR) { 1253 if (wc_checkout_params.debug_mode) { 1254 /* jshint devel: true */ 1255 //console.log(jqXHR.responseText); 1256 } 1257 }, 1258 dataType: "html", 1259 }); 1260 }, 1261 }; 1262 1263 var wc_checkout_login_form = { 1264 init: function () { 1265 $(document.body).on("click", "a.showlogin", this.show_login_form); 1266 }, 1267 show_login_form: function () { 1268 $("form.login, form.woocommerce-form--login").slideToggle(); 1269 return false; 1270 }, 1271 }; 1272 1273 var wc_terms_toggle = { 1274 init: function () { 1275 $(document.body).on( 1276 "click", 1277 "a.woocommerce-terms-and-conditions-link", 1278 this.toggle_terms 1279 ); 1280 }, 1281 1282 toggle_terms: function () { 1283 if ($(".woocommerce-terms-and-conditions").length) { 1284 $(".woocommerce-terms-and-conditions").slideToggle(function () { 1285 var link_toggle = $(".woocommerce-terms-and-conditions-link"); 1286 1287 if ($(".woocommerce-terms-and-conditions").is(":visible")) { 1288 link_toggle.addClass("woocommerce-terms-and-conditions-link--open"); 1289 link_toggle.removeClass( 1290 "woocommerce-terms-and-conditions-link--closed" 1291 ); 1292 } else { 1293 link_toggle.removeClass( 1294 "woocommerce-terms-and-conditions-link--open" 1295 ); 1296 link_toggle.addClass( 1297 "woocommerce-terms-and-conditions-link--closed" 1298 ); 1299 } 1300 }); 1301 1302 return false; 1303 } 1304 }, 1305 }; 1306 1307 wc_checkout_form.init(); 1308 wc_checkout_coupons.init(); 1309 wc_checkout_login_form.init(); 1310 wc_terms_toggle.init(); 1311});
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.