1/** 2 * Jump Waiting List Popup JavaScript 3 * Handles the waiting list popup functionality with robust product detection 4 */ 5(function() { 6 'use strict'; 7 8 // Stato globale del popup 9 let popupState = { 10 isOpen: false, 11 currentProductData: null 12 }; 13 14 // Selettori DOM 15 const selectors = { 16 backdrop: '.jump-waiting-list__backdrop', 17 popup: '.jump-waiting-list__popup', 18 closeBtn: '.jump-waiting-list__close', 19 form: '.jump-waiting-list__form', 20 emailInput: '#jump-waiting-list-email', 21 termsCheckbox: '#jump-waiting-list-terms', 22 submitBtn: '.jump-waiting-list__submit', 23 productInfo: '.jump-waiting-list__product-info' 24 }; 25 26 /** 27 * Verifica se un elemento è un pulsante waiting list 28 * @param {Element} element - Elemento da verificare 29 * @returns {boolean} True se è un pulsante waiting list 30 */ 31 function isWaitingListButton(element) { 32 if (!element) return false; 33 34 const buttonText = element.textContent.toLowerCase().trim(); 35 const buttonHTML = element.innerHTML.toLowerCase(); 36 37 // Lista di parole chiave che indicano un pulsante waiting list 38 const waitingListKeywords = [ 39 'waiting', 40 'notifica', 41 'avvisa', 42 'avvisami', 43 'lista', 44 'attesa', 45 'disponibile', 46 'stock', 47 'esaurito' 48 ]; 49 50 // Controlla attributi/classi specifici 51 if (element.hasAttribute('data-waiting-list') || 52 element.classList.contains('waiting-list') || 53 element.classList.contains('notify-when-available') || 54 element.classList.contains('jump-waiting-list-btn')) { 55 return true; 56 } 57 58 // Controlla il testo del pulsante 59 const hasKeyword = waitingListKeywords.some(keyword => 60 buttonText.includes(keyword) || buttonHTML.includes(keyword) 61 ); 62 63 if (hasKeyword) { 64 return true; 65 } 66 67 return false; 68 } 69 70 /** 71 * Estrae i dati del prodotto dal componente jump-card-ecommerce 72 * @param {Element} clickedElement - Elemento che ha scatenato l'evento 73 * @returns {Object} Dati del prodotto/variazione 74 */ 75 function extractProductFromJumpCard(clickedElement = null) { 76 let productData = { 77 product_id: null, 78 variation_id: null, 79 product_name: '', 80 variation_name: '', 81 sku: '' 82 }; 83 84 let jumpCardElement = null; 85 86 // Se abbiamo un elemento cliccato, cerca il jump-card-ecommerce genitore 87 if (clickedElement) { 88 jumpCardElement = clickedElement.closest('jump-card-ecommerce'); 89 } 90 91 // Se non trovato, cerca il primo jump-card-ecommerce nella pagina 92 if (!jumpCardElement) { 93 jumpCardElement = document.querySelector('jump-card-ecommerce'); 94 } 95 96 if (jumpCardElement) { 97 98 // Estrai i dati dal componente jump-card-ecommerce 99 // Prova tutti i possibili modi per ottenere l'ID prodotto 100 const productId = jumpCardElement.getAttribute('product-id') || 101 jumpCardElement.getAttribute('productid') || 102 jumpCardElement.getAttribute('data-product-id') || 103 jumpCardElement.dataset.productId || 104 jumpCardElement.dataset.product || 105 jumpCardElement.productId || 106 jumpCardElement.product_id; 107 108 // Prova tutti i possibili modi per ottenere l'ID variazione 109 const variationId = jumpCardElement.getAttribute('variation-id') || 110 jumpCardElement.getAttribute('variationid') || 111 jumpCardElement.getAttribute('data-variation-id') || 112 jumpCardElement.dataset.variationId || 113 jumpCardElement.dataset.variation || 114 jumpCardElement.variationId || 115 jumpCardElement.variation_id; 116 117 // Prova tutti i possibili modi per ottenere il nome prodotto 118 const productName = jumpCardElement.getAttribute('product-name') || 119 jumpCardElement.getAttribute('productname') || 120 jumpCardElement.getAttribute('data-product-name') || 121 jumpCardElement.dataset.productName || 122 jumpCardElement.dataset.name || 123 jumpCardElement.productName || 124 jumpCardElement.product_name; 125 126 // Prova tutti i possibili modi per ottenere lo SKU 127 const sku = jumpCardElement.getAttribute('sku') || 128 jumpCardElement.getAttribute('data-sku') || 129 jumpCardElement.dataset.sku || 130 jumpCardElement.sku; 131 132 if (productId) { 133 productData.product_id = productId; 134 } 135 136 if (variationId && variationId !== '0') { 137 productData.variation_id = variationId; 138 } 139 140 if (productName) { 141 productData.product_name = productName; 142 } 143 144 if (sku) { 145 productData.sku = sku; 146 } 147 148 // Tentativo robusto: ricava la variante corrente dagli attributi "data-variation" e "variations" 149 // molti card espongono: data-variation='{"combined_variation":"{\"attribute_pa_x\":\"valore\"}"}' 150 // e variations='[{"variation_id":123, "raw_attributes":{"attribute_pa_x":"valore"}, ...}, ...]' 151 try { 152 // 1) leggi la variazione "corrente" dai dati del card 153 const dataVariationAttr = jumpCardElement.getAttribute('data-variation') || (jumpCardElement.dataset ? jumpCardElement.dataset.variation : null); 154 let selectedAttributes = null; 155 if (dataVariationAttr) { 156 const parsed = JSON.parse(dataVariationAttr); 157 if (parsed && parsed.combined_variation) {
158 // combined_variation è una stringa JSON: va riparsata 159 try { 160 selectedAttributes = JSON.parse(parsed.combined_variation); 161 } catch (e) { 162 // fallback: ignora 163 } 164 } 165 } 166 167 // 2) cerca nelle varianti esposte sul card quella che matcha gli attributi selezionati 168 const variationsAttr = jumpCardElement.getAttribute('variations'); 169 if (!productData.variation_id && variationsAttr) { 170 const variations = JSON.parse(variationsAttr); 171 if (Array.isArray(variations) && variations.length) { 172 let match = null; 173 if (selectedAttributes && Object.keys(selectedAttributes).length) { 174 match = variations.find(v => { 175 // prova raw_attributes prima 176 if (v && v.raw_attributes) { 177 // confronto chiave-valore 178 return Object.keys(selectedAttributes).every(k => { 179 return (v.raw_attributes && v.raw_attributes[k] === selectedAttributes[k]); 180 }); 181 } 182 return false; 183 }); 184 // ulteriore fallback su combined_attributes stringificati 185 if (!match && selectedAttributes) { 186 const selectedStr = JSON.stringify(selectedAttributes); 187 match = variations.find(v => v && v.combined_attributes && v.combined_attributes === selectedStr); 188 } 189 } 190 191 // ultimo fallback: se non abbiamo attributi, usa la variante marcata out-of-stock nel card, 192 // oppure semplicemente la prima variante 193 if (!match) { 194 match = variations[0]; 195 } 196 197 if (match && match.variation_id) { 198 productData.variation_id = match.variation_id; 199 } 200 } 201 } 202 } catch (e) { 203 // console.debug('Impossibile derivare variation_id da jump-card-ecommerce:', e); 204 } 205 206 // Prova a cercare attributi di variazione nel componente 207 const variationAttributes = jumpCardElement.querySelector('[data-variation-attributes]'); 208 if (variationAttributes) { 209 try { 210 const attributes = JSON.parse(variationAttributes.dataset.variationAttributes); 211 const attributeLabels = Object.entries(attributes).map(([key, value]) => { 212 return `${key.replace('attribute_pa_', '').replace('_', ' ')}: ${value}`; 213 }); 214 productData.variation_name = attributeLabels.join(', '); 215 } catch (e) { 216 // Errore nel parsing, ignora 217 } 218 } 219 } 220 221 // Se non abbiamo trovato dati dal jump-card, usa il fallback tradizionale 222 if (!productData.product_id) { 223 return extractProductFromDOM(); 224 } 225 226 return productData; 227 } 228 229 /** 230 * Estrae i dati del prodotto direttamente dall'elemento cliccato (data-attributes) 231 * @param {Element} clickedElement - Elemento che ha scatenato l'evento 232 * @returns {Object} Dati del prodotto/variazione 233 */ 234 function extractProductFromElement(clickedElement = null) { 235 let productData = { 236 product_id: null, 237 variation_id: null, 238 product_name: '', 239 variation_name: '', 240 sku: '' 241 }; 242 243 if (!clickedElement) { 244 return productData; 245 } 246 247 const el = clickedElement; 248 249 // Prova tutti i possibili modi per ottenere l'ID prodotto 250 const productId = el.getAttribute('data-product-id') || 251 (el.dataset ? el.dataset.productId : null) || 252 el.getAttribute('product-id') || 253 el.getAttribute('productid') || 254 (el.dataset ? el.dataset.product : null) || 255 el.productId || 256 el.product_id; 257 258 // Prova tutti i possibili modi per ottenere l'ID variazione 259 const variationId = el.getAttribute('data-variation-id') || 260 (el.dataset ? el.dataset.variationId : null) || 261 el.getAttribute('variation-id') || 262 el.getAttribute('variationid') || 263 (el.dataset ? el.dataset.variation : null) || 264 el.variationId || 265 el.variation_id; 266 267 // Prova tutti i possibili modi per ottenere il nome prodotto 268 const productName = el.getAttribute('data-product-name') || 269 (el.dataset ? el.dataset.productName : null) || 270 el.getAttribute('product-name') || 271 el.getAttribute('productname') || 272 (el.dataset ? el.dataset.name : null) || 273 el.productName || 274 el.product_name; 275 276 if (productId) { 277 productData.product_id = productId; 278 } 279 280 if (variationId && variationId !== '0') { 281 productData.variation_id = variationId; 282 } 283 284 if (productName) { 285 productData.product_name = productName; 286 } 287 288 return productData; 289 } 290 291 /** 292 * Verifica se i dati contengono un product_id valido 293 * @param {Object|null} data 294 * @returns {boolean} 295 */ 296 function hasValidProductId(data) { 297 return !!(data && data.product_id && data.product_id !== 0 && data.product_id !== '0'); 298 } 299 300 /** 301 * Estrae i dati del prodotto dal DOM come fallback 302 * @returns {Object} Dati del prodotto/variazione 303 */ 304 function extractProductFromDOM() { 305 let productData = { 306 product_id: null, 307 variation_id: null, 308 product_name: '', 309 variation_name: '', 310 sku: '' 311 }; 312 313 // Cerca l'ID del prodotto 314 const productIdInput = document.querySelector('input[name="product_id"]'); 315 const addToCartForm = document.querySelector('.cart'); 316 317 if (productIdInput) { 318 productData.product_id = productIdInput.value; 319 } else if (addToCartForm && addToCartForm.dataset.productId) { 320 productData.product_id = addToCartForm.dataset.productId; 321 } 322 323 // Cerca l'ID della variazione 324 const variationIdInput = document.querySelector('input[name="variation_id"]'); 325 const variationSelect = document.querySelector('.variations_form'); 326 327 if (variationIdInput && variationIdInput.value) { 328 productData.variation_id = variationIdInput.value; 329 } else if (variationSelect) { 330 // Prova a cercare la variazione selezionata dai dropdown 331 const attributeSelects = variationSelect.querySelectorAll('select[name^="attribute_"]'); 332 const selectedAttributes = {}; 333
334 attributeSelects.forEach(select => { 335 if (select.value) { 336 selectedAttributes[select.name] = select.value; 337 } 338 }); 339 } 340 341 // Cerca il nome del prodotto 342 const productTitle = document.querySelector('.product_title, .entry-title, h1.product-title, .product-name h1'); 343 if (productTitle) { 344 productData.product_name = productTitle.textContent.trim(); 345 } 346 347 // Cerca SKU 348 const skuElement = document.querySelector('.sku, .product_meta .sku_wrapper .sku'); 349 if (skuElement) { 350 productData.sku = skuElement.textContent.trim(); 351 } 352 353 // Cerca informazioni sulla variazione selezionata 354 const variationDescription = document.querySelector('.woocommerce-variation-description'); 355 const selectedVariationText = document.querySelector('.single_variation_wrap .single_variation'); 356 357 if (selectedVariationText && selectedVariationText.style.display !== 'none') { 358 const variationPrice = selectedVariationText.querySelector('.price'); 359 if (variationPrice) { 360 productData.variation_name = 'Variazione selezionata'; 361 } 362 } 363 364 // Costruisci il nome completo della variazione dalle selezioni 365 const attributeLabels = []; 366 document.querySelectorAll('.variations tr').forEach(row => { 367 const label = row.querySelector('label'); 368 const select = row.querySelector('select'); 369 370 if (label && select && select.value) { 371 const optionText = select.options[select.selectedIndex].text; 372 if (optionText && optionText !== 'Scegli un\'opzione') { 373 attributeLabels.push(`${label.textContent.replace(':', '').trim()}: ${optionText}`); 374 } 375 } 376 }); 377 378 if (attributeLabels.length > 0) { 379 productData.variation_name = attributeLabels.join(', '); 380 } 381 382 return productData; 383 } 384 385 /** 386 * Aggiorna il display delle informazioni prodotto nel popup 387 * @param {Object} productData - Dati del prodotto 388 */ 389 function updateProductDisplay(productData) { 390 const productInfoEl = document.querySelector(selectors.productInfo); 391 if (!productInfoEl) return; 392 393 const productNameEl = productInfoEl.querySelector('.jump-waiting-list__product-name'); 394 const variationEl = productInfoEl.querySelector('.jump-waiting-list__product-variation'); 395 396 if (productNameEl) { 397 productNameEl.textContent = productData.product_name || 'Prodotto selezionato'; 398 } 399 400 if (variationEl) { 401 if (productData.variation_name) { 402 variationEl.textContent = productData.variation_name; 403 variationEl.style.display = 'block'; 404 } else { 405 variationEl.style.display = 'none'; 406 } 407 } 408 409 // Aggiorna anche i campi hidden del form 410 updateFormHiddenFields(productData); 411 } 412 413 /** 414 * Aggiorna i campi hidden del form con i dati del prodotto 415 * @param {Object} productData - Dati del prodotto 416 */ 417 function updateFormHiddenFields(productData) { 418 const productIdField = document.querySelector('#jump-waiting-list-product-id'); 419 const variationIdField = document.querySelector('#jump-waiting-list-variation-id'); 420 421 if (productIdField) { 422 productIdField.value = productData.product_id || ''; 423 } 424 425 if (variationIdField) { 426 variationIdField.value = productData.variation_id || ''; 427 } 428 } 429 430 /** 431 * Apre il popup con i dati del prodotto 432 * @param {Object} productData - Dati del prodotto (opzionale) 433 * @param {Element} clickedElement - Elemento che ha scatenato l'evento (opzionale) 434 */ 435 function openPopup(productData = null, clickedElement = null) { 436 // Assicurati che il popup HTML esista 437 ensurePopupHTML(); 438 439 // Se il popup è già aperto, prima resetta i dati 440 if (popupState.isOpen) { 441 resetPopupForm(); 442 } 443 444 // Se non sono stati forniti dati del prodotto validi, prova a estrarli 445 if (!hasValidProductId(productData)) { 446 // 1) Tenta dagli attributi del pulsante cliccato 447 productData = extractProductFromElement(clickedElement); 448 } 449 450 if (!hasValidProductId(productData)) { 451 // 2) Tenta dal componente jump-card-ecommerce 452 productData = extractProductFromJumpCard(clickedElement); 453 } 454 455 // Verifica che abbiamo almeno un ID prodotto 456 if (!productData.product_id || productData.product_id === 0 || productData.product_id === '0') { 457 console.error('Unable to determine product ID'); 458 alert('Errore: impossibile determinare il prodotto. Ricarica la pagina e riprova.'); 459 return; 460 } 461
462 // Converti gli ID in numeri se sono stringhe 463 if (typeof productData.product_id === 'string') { 464 productData.product_id = parseInt(productData.product_id, 10); 465 } 466 if (productData.variation_id && typeof productData.variation_id === 'string') { 467 productData.variation_id = parseInt(productData.variation_id, 10); 468 } 469 470 popupState.currentProductData = productData; 471 472 // Aggiorna il display del prodotto e i campi hidden 473 updateProductDisplay(productData); 474 475 // Mostra il popup 476 const backdrop = document.querySelector(selectors.backdrop); 477 478 if (backdrop) { 479 backdrop.classList.add('jump-waiting-list__backdrop--visible'); 480 popupState.isOpen = true; 481 482 // Focus sull'input email 483 setTimeout(() => { 484 const emailInput = document.querySelector(selectors.emailInput); 485 if (emailInput) { 486 emailInput.focus(); 487 } 488 }, 300); 489 } else { 490 console.error('Backdrop element not found! Popup cannot be shown.'); 491 } 492 } 493 494 /** 495 * Chiude il popup 496 */ 497 function closePopup() { 498 const backdrop = document.querySelector(selectors.backdrop); 499 if (backdrop) { 500 backdrop.classList.remove('jump-waiting-list__backdrop--visible'); 501 popupState.isOpen = false; 502 popupState.currentProductData = null; 503 504 // Rimuovi l'overlay di successo se presente 505 const popup = document.querySelector(selectors.popup); 506 if (popup) { 507 const successOverlay = popup.querySelector('.jump-waiting-list__success-overlay'); 508 if (successOverlay) { 509 successOverlay.remove(); 510 } 511 } 512 513 // Reset completo del form e dei dati 514 resetPopupForm(); 515 } 516 } 517 518 /** 519 * Resetta completamente il form del popup 520 */ 521 function resetPopupForm() { 522 const form = document.querySelector(selectors.form); 523 if (form) { 524 form.reset(); 525 clearErrors(); 526 } 527 528 // Reset dei campi hidden 529 const productIdField = document.querySelector('#jump-waiting-list-product-id'); 530 const variationIdField = document.querySelector('#jump-waiting-list-variation-id'); 531 532 if (productIdField) { 533 productIdField.value = ''; 534 } 535 536 if (variationIdField) { 537 variationIdField.value = ''; 538 } 539 540 // Reset del display prodotto 541 const productInfoEl = document.querySelector(selectors.productInfo); 542 if (productInfoEl) { 543 const productNameEl = productInfoEl.querySelector('.jump-waiting-list__product-name'); 544 const variationEl = productInfoEl.querySelector('.jump-waiting-list__product-variation'); 545 546 if (productNameEl) { 547 productNameEl.textContent = 'Prodotto'; 548 } 549 550 if (variationEl) { 551 variationEl.textContent = ''; 552 variationEl.style.display = 'none'; 553 } 554 } 555 } 556 557 /** 558 * Pulisce tutti i messaggi di errore 559 */ 560 function clearErrors() { 561 document.querySelectorAll('.jump-waiting-list__error').forEach(error => { 562 error.remove(); 563 }); 564 565 document.querySelectorAll('.jump-waiting-list__input--error').forEach(input => { 566 input.classList.remove('jump-waiting-list__input--error'); 567 }); 568 } 569 570 /** 571 * Mostra un errore per un campo specifico 572 * @param {string} fieldSelector - Selettore del campo 573 * @param {string} message - Messaggio di errore 574 */ 575 function showFieldError(fieldSelector, message) { 576 const field = document.querySelector(fieldSelector); 577 if (!field) return; 578 579 // Rimuovi errori esistenti per questo campo 580 const existingError = field.parentNode.querySelector('.jump-waiting-list__error'); 581 if (existingError) { 582 existingError.remove(); 583 } 584 585 // Aggiungi classe di errore 586 field.classList.add('jump-waiting-list__input--error'); 587 588 // Crea e aggiungi il messaggio di errore 589 const errorEl = document.createElement('div'); 590 errorEl.className = 'jump-waiting-list__error'; 591 errorEl.textContent = message; 592 field.parentNode.appendChild(errorEl); 593 } 594 595 /** 596 * Valida il form 597 * @returns {boolean} True se il form è valido 598 */ 599 function validateForm() { 600 let isValid = true; 601 clearErrors(); 602 603 const emailInput = document.querySelector(selectors.emailInput); 604 const termsCheckbox = document.querySelector(selectors.termsCheckbox); 605 606 // Validazione email 607 if (!emailInput.value.trim()) { 608 showFieldError(selectors.emailInput, 'L\'email è obbligatoria'); 609 isValid = false;
610 } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailInput.value.trim())) { 611 showFieldError(selectors.emailInput, 'Inserisci un indirizzo email valido'); 612 isValid = false; 613 } 614 615 // Validazione privacy policy 616 if (!termsCheckbox.checked) { 617 showFieldError(selectors.termsCheckbox, 'Devi accettare la privacy policy'); 618 isValid = false; 619 } 620 621 return isValid; 622 } 623 624 /** 625 * Mostra il messaggio di successo 626 */ 627 function showSuccessMessage() { 628 const popup = document.querySelector(selectors.popup); 629 if (!popup) return; 630 631 // Invece di sostituire tutto il contenuto, mostra solo un messaggio temporaneo 632 const existingMessage = popup.querySelector('.jump-waiting-list__success-overlay'); 633 if (existingMessage) { 634 existingMessage.remove(); 635 } 636 637 // Crea un overlay di successo che non distrugge il form 638 const successOverlay = document.createElement('div'); 639 successOverlay.className = 'jump-waiting-list__success-overlay'; 640 successOverlay.style.cssText = ` 641 position: absolute; 642 top: 0; 643 left: 0; 644 right: 0; 645 bottom: 0; 646 background: rgba(255, 255, 255, 0.95); 647 display: flex; 648 align-items: center; 649 justify-content: center; 650 z-index: 1000; 651 border-radius: inherit; 652 `; 653 654 successOverlay.innerHTML = ` 655 <div class="jump-waiting-list__success" style="text-align: center; padding: 2rem;"> 656 <h3 class="jump-waiting-list__success-title">â Iscrizione completata!</h3> 657 <p class="jump-waiting-list__success-message"> 658 Ti invieremo una notifica quando il prodotto sarà nuovamente disponibile. 659 </p> 660 <p style="font-size: 0.875rem; color: #666; margin-top: 1rem;"> 661 Il popup si chiuderà automaticamente... 662 </p> 663 </div> 664 `; 665 666 popup.appendChild(successOverlay); 667 668 // Chiudi automaticamente dopo 3 secondi e resetta per permettere nuove iscrizioni 669 setTimeout(() => { 670 closePopup(); 671 // Il popup è ora pronto per essere utilizzato con un altro prodotto 672 }, 3000); 673 } 674 675 /** 676 * Gestisce l'invio del form 677 * @param {Event} e - Evento submit 678 */ 679 function handleFormSubmit(e) { 680 e.preventDefault(); 681 682 if (!validateForm()) { 683 return; 684 } 685 686 const submitBtn = document.querySelector(selectors.submitBtn); 687 const emailInput = document.querySelector(selectors.emailInput); 688 const termsCheckbox = document.querySelector(selectors.termsCheckbox); 689 690 // Stato di caricamento 691 submitBtn.disabled = true; 692 submitBtn.classList.add('jump-waiting-list__submit--loading'); 693 694 // Prepara i dati da inviare 695 const formData = new FormData(); 696 formData.append('action', 'jump_waiting_list_subscribe'); 697 formData.append('email', emailInput.value.trim()); 698 formData.append('product_id', popupState.currentProductData.product_id); 699 formData.append('variation_id', popupState.currentProductData.variation_id || ''); 700 formData.append('terms', termsCheckbox.checked ? '1' : '0'); 701 formData.append('nonce', jumpWaitingList.nonce); 702 703 // Invio AJAX 704 fetch(jumpWaitingList.ajaxUrl, { 705 method: 'POST', 706 body: formData 707 }) 708 .then(response => response.json()) 709 .then(data => { 710 if (data.success) { 711 showSuccessMessage(); 712 } else { 713 // Gestisci correttamente l'errore del server 714 const errorMessage = data.data && data.data.message ? data.data.message : 'Errore durante l\'iscrizione'; 715 alert('Errore: ' + errorMessage); 716 717 // Reset dei campi email per permettere una nuova iscrizione 718 // (manteniamo i dati del prodotto per permettere di riprovare) 719 const emailField = document.querySelector(selectors.emailInput); 720 if (emailField) { 721 emailField.value = ''; 722 } 723 } 724 }) 725 .catch(error => { 726 console.error('â Network/Parse error:', error); 727 alert('Errore di connessione: ' + error.message); 728 }) 729 .finally(() => { 730 // Ripristina il pulsante 731 submitBtn.disabled = false;
732 submitBtn.classList.remove('jump-waiting-list__submit--loading'); 733 }); 734 } 735 736 /** 737 * Inizializza gli event listener 738 */ 739 function initEventListeners() { 740 // Event listener per l'evento personalizzato 741 document.addEventListener('jump-add-to-waiting-list', function(e) { 742 // Passa sia i dati dell'evento che l'elemento target 743 openPopup(e.detail, e.target); 744 }); 745 746 // Event listener specifico per jump-button.Footer__AddToCart 747 document.addEventListener('click', function(e) { 748 // Gestione chiusura popup 749 if (e.target.matches(selectors.closeBtn) || e.target.closest(selectors.closeBtn)) { 750 closePopup(); 751 return; 752 } else if (e.target.matches(selectors.backdrop)) { 753 closePopup(); 754 return; 755 } 756 757 // Intercetta click su qualsiasi jump-button (non solo Footer__AddToCart) 758 const jumpButton = e.target.closest('jump-button'); 759 if (jumpButton) { 760 // Usa la funzione per verificare se è un pulsante waiting list 761 if (isWaitingListButton(jumpButton)) { 762 e.preventDefault(); 763 e.stopPropagation(); 764 765 // Estrai i dati dal jump-card-ecommerce genitore 766 openPopup(null, jumpButton); 767 return; 768 } 769 } 770 771 // Gestione click su altri pulsanti waiting list (fallback) 772 const waitingListBtn = e.target.closest('[data-waiting-list], .waiting-list-btn, .jump-waiting-list-trigger, .jump-waiting-list-btn'); 773 if (waitingListBtn && isWaitingListButton(waitingListBtn)) { 774 e.preventDefault(); 775 776 // Estrai i dati dal pulsante o dal suo jump-card genitore 777 openPopup(null, waitingListBtn); 778 } 779 }); 780 781 // Event listener per ESC 782 document.addEventListener('keydown', function(e) { 783 if (e.key === 'Escape' && popupState.isOpen) { 784 closePopup(); 785 } 786 }); 787 788 // Event listener per il form 789 document.addEventListener('submit', function(e) { 790 if (e.target.matches(selectors.form)) { 791 handleFormSubmit(e); 792 } 793 }); 794 795 // Event listener per rimuovere errori quando l'utente digita 796 document.addEventListener('input', function(e) { 797 if (e.target.matches(selectors.emailInput)) { 798 e.target.classList.remove('jump-waiting-list__input--error'); 799 const error = e.target.parentNode.querySelector('.jump-waiting-list__error'); 800 if (error) { 801 error.remove(); 802 } 803 } 804 }); 805 806 document.addEventListener('change', function(e) { 807 if (e.target.matches(selectors.termsCheckbox)) { 808 const error = e.target.parentNode.querySelector('.jump-waiting-list__error'); 809 if (error) { 810 error.remove(); 811 } 812 } 813 }); 814 } 815 816 /** 817 * Crea il markup HTML del popup se non esiste 818 */ 819 function ensurePopupHTML() { 820 if (document.querySelector(selectors.backdrop)) { 821 return; 822 } 823 824 const popupHTML = ` 825 <div class="jump-waiting-list__backdrop"> 826 <div class="jump-waiting-list__popup"> 827 <button type="button" class="jump-waiting-list__close" aria-label="Chiudi">×</button> 828 829 <div class="jump-waiting-list__header"> 830 <h2 class="jump-waiting-list__title">Avvisami quando disponibile</h2> 831 <p class="jump-waiting-list__subtitle">Ti invieremo una notifica quando il prodotto sarà nuovamente in stock</p> 832 </div> 833 834 <div class="jump-waiting-list__product-info"> 835 <div class="jump-waiting-list__product-name">Prodotto</div> 836 <div class="jump-waiting-list__product-variation" style="display: none;">Variazione</div> 837 </div> 838 839 <form class="jump-waiting-list__form"> 840 <div class="jump-waiting-list__field"> 841 <label for="jump-waiting-list-email" class="jump-waiting-list__label">Email *</label> 842 <input type="email" id="jump-waiting-list-email" class="jump-waiting-list__input" required> 843 </div> 844 845 <div class="jump-waiting-list__checkbox-field"> 846 <input type="checkbox" id="jump-waiting-list-terms" class="jump-waiting-list__checkbox" required> 847 <label for="jump-waiting-list-terms" class="jump-waiting-list__checkbox-label"> 848 Accetto la <a href="/privacy-policy" target="_blank">privacy policy</a> e acconsento al trattamento dei miei dati personali 849 </label> 850 </div> 851 852 <button type="submit" class="jump-waiting-list__submit">Iscrivimi alla waiting list</button> 853 </form> 854 </div> 855 </div> 856 `; 857 858 document.body.insertAdjacentHTML('beforeend', popupHTML); 859 } 860 861 /** 862 * Inizializzazione principale 863 */
864 function init() { 865 // Attendi che il DOM sia pronto 866 if (document.readyState === 'loading') { 867 document.addEventListener('DOMContentLoaded', function() { 868 ensurePopupHTML(); 869 initEventListeners(); 870 }); 871 } else { 872 ensurePopupHTML(); 873 initEventListeners(); 874 } 875 } 876 877 // Avvia l'inizializzazione 878 init(); 879 880})();
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.