1class SnoreTestResultProduct { 2 constructor() { 3 this.instances = []; 4 document.querySelectorAll('.product').forEach((productEl, index) => { 5 const instance = index + 1; 6 const variationsJson = document.querySelector(`#variationsData${index > 0 ? '-' + instance : ''}`)?.innerHTML; 7 if (variationsJson) { 8 this.instances.push({ 9 element: productEl, 10 variations: JSON.parse(variationsJson), 11 instance: instance 12 }); 13 } 14 }); 15 this.init(); 16 } 17 18 init() { 19 document.querySelectorAll('.variation select').forEach(select => { 20 select.addEventListener('change', (e) => this.handleVariationChange(e)); 21 }); 22 } 23 24 handleVariationChange(event) { 25 const select = event.target; 26 const productEl = select.closest('.product'); 27 const instanceObj = this.instances.find(inst => inst.element === productEl); 28 if (!instanceObj) return; 29 30 const variations = instanceObj.variations; 31 let variationSlug = ''; 32 33 // Build slug from all selects in this product column 34 productEl.querySelectorAll('.variation select').forEach(sel => { 35 const selected = sel.options[sel.selectedIndex]; 36 variationSlug += selected.value; 37 }); 38 39 this.setVariation(variationSlug, instanceObj); 40 } 41 42 setVariation(variationSlug, instanceObj) { 43 const variation = instanceObj.variations[variationSlug]; 44 const productEl = instanceObj.element; 45 46 if (!variation || !variation.attributes) { 47 // disable add to cart, hide qty 48 productEl.querySelector('.snore-test-result-add-to-cart')?.setAttribute('disabled', ''); 49 productEl.querySelectorAll('.product-qty').forEach(qty => qty.classList.add('--hidden')); 50 return; 51 } 52 53 // Set hidden inputs (if any) 54 for (const [key, value] of Object.entries(variation.attributes)) { 55 productEl.querySelectorAll(`input[name="${key}"]`).forEach(input => input.value = value); 56 } 57 58 // Update add-to-cart link 59 const couponPart = productEl.querySelector('.snore-test-result-add-to-cart')?.getAttribute('href').split('&')[1] || ''; 60 productEl.querySelector('.snore-test-result-add-to-cart')?.setAttribute( 61 'href', 62 `/?add-to-cart=${variation.variation_id}&${couponPart}` 63 ); 64 65 // Update stock / qty label 66 productEl.querySelectorAll('.product-qty').forEach(qty => { 67 qty.classList.remove('--hidden', 'low-stock', 'no-stock', 'backorder'); 68 if (variation.max_qty >= 20) { 69 qty.classList.add('visually-hidden'); 70 qty.setAttribute('aria-hidden', 'true'); 71 } else if (variation.is_on_backorder) { 72 qty.classList.remove('visually-hidden'); 73 qty.classList.add('backorder'); 74 } else if (variation.max_qty > 0 && variation.max_qty <= 19) { 75 qty.classList.remove('visually-hidden'); 76 qty.classList.add('low-stock'); 77 } else { 78 qty.classList.remove('visually-hidden'); 79 qty.classList.add('no-stock'); 80 } 81 qty.innerHTML = variation.quantity_label; 82 qty.removeAttribute('aria-hidden'); 83 }); 84 85 // Enable/disable add-to-cart 86 const btn = productEl.querySelector('.snore-test-result-add-to-cart'); 87 if (variation.is_in_stock) { 88 btn?.removeAttribute('disabled'); 89 } else { 90 btn?.setAttribute('disabled', ''); 91 } 92 93 // Update price 94 const priceContainer = productEl.querySelector('.price.variation-price'); 95 const percentage = parseFloat(priceContainer?.dataset.percentage_discount) || 0; 96 const cleanPrice = parseFloat(variation.price_formatted.replace(/[^\d.,]/g, '').replace(',', '.')); 97 let finalPrice = cleanPrice; 98 if (percentage > 0) { 99 finalPrice = cleanPrice - (cleanPrice * percentage / 100); 100 } 101 102 // Update original & discount price
103 productEl.querySelectorAll(".variation-price .product-price-original .woocommerce-Price-amount").forEach(el => { 104 el.innerHTML = variation.price_formatted; 105 }); 106 productEl.querySelectorAll(".variation-price .discount-price .woocommerce-Price-amount").forEach(el => { 107 const symbol = variation.price_formatted.replace(/[0-9.,\s]/g, ''); 108 el.innerText = finalPrice.toFixed(2).replace('.', ',') + ' ' + symbol; 109 }); 110 } 111} 112 113document.addEventListener('DOMContentLoaded', () => { 114 window.snoreTestResultProduct = new SnoreTestResultProduct(); 115});
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.