1jQuery(document).ready(function ($) { 2 const variationCache = new Map(); 3 4 $(document).on('change', '.amq-variation-select', function () { 5 const productContainer = $(this).closest('.xoo-wsc-sp-product'); 6 const selected_variations = getSelectionsAndUpdateLinks(productContainer); 7 8 if (isProductVariationFullySelected(productContainer, selected_variations)) { 9 getProductFromSelection(productContainer, selected_variations); 10 } else { 11 resetToBasePrice(productContainer); 12 } 13 }); 14 15 function resetToBasePrice(productContainer) { 16 var base_price = productContainer.find('.xoo-wsc-sp-title').data('base_price'); 17 18 // Disable Add to Cart button if not all variations are selected 19 productContainer.find('.xoo-wsc-sp-price > ins .amount bdi').html(formatPrice(base_price)); 20 productContainer.find('.add_to_cart_button').removeClass('amq_cross_sell_add_to_cart'); 21 productContainer.find('.starts_at').show(); 22 } 23 24 function isProductVariationFullySelected(productContainer, selected_variations) { 25 return productContainer.find('.amq-variation-select').length === Object.keys(selected_variations).length; 26 } 27 28 function formatPrice(price) { 29 const num = Number(price); 30 31 if (!Number.isFinite(num)) { 32 console.warn('Ungültiger Preiswert empfangen:', price); 33 return ''; 34 } 35 36 return new Intl.NumberFormat('de-DE', { 37 style: 'currency', 38 currency: 'EUR' 39 }).format(num); 40 } 41 42 function getProductFromSelection(productContainer, selected_variations) { 43 const product_id = productContainer.find('.xoo-wsc-sp-title').data('product_id'); 44 const cacheKey = generateCacheKey(product_id, selected_variations); 45 46 // Prüfen ob bereits im Cache vorhanden 47 if (variationCache.has(cacheKey)) { 48 const cachedResponse = variationCache.get(cacheKey); 49 updateProductDisplay(productContainer, cachedResponse); 50 return; 51 } 52 53 // Prüfen ob bereits ein Request für diese Variation läuft 54 if (productContainer.data('loading-variation-key') === cacheKey) { 55 return; 56 } 57 58 productContainer.find('.loading-overlay').css("display", "flex").hide().fadeIn(); 59 productContainer.data('loading-variation-key', cacheKey); 60 61 const requestData = { ...selected_variations }; 62 requestData['product_id'] = product_id; 63 64 $.ajax({ 65 url: '/?wc-ajax=get_variation', 66 type: 'POST', 67 data: requestData, 68 success: function (response) { 69 if (response && response.variation_id) { 70 // Response im Cache speichern 71 variationCache.set(cacheKey, response); 72 updateProductDisplay(productContainer, response); 73 } 74 }, 75 error: function (data) { 76 console.log("not found"); 77 }, 78 complete: function () { 79 productContainer.find('.loading-overlay').fadeOut(); 80 productContainer.removeData('loading-variation-key'); 81 } 82 83 }); 84 } 85 86 function generateCacheKey(product_id, selected_variations) { 87 const sortedKeys = Object.keys(selected_variations).sort(); 88 const variationString = sortedKeys.map(key => `${key}:${selected_variations[key]}`).join('|'); 89 return `${product_id}_${variationString}`; 90 } 91 92 function updateProductDisplay(productContainer, response) { 93 const regularPrice = formatPrice(response.display_price); 94 const addToCartButton = productContainer.find('.add_to_cart_button'); 95 96 const vid = Number(response.variation_id); 97 if (Number.isInteger(vid)) { 98 addToCartButton 99 .attr('href', '?add-to-cart=' + vid) 100 .attr('data-variation_id', vid) 101 .addClass('amq_cross_sell_add_to_cart'); 102 } 103 104 productContainer.find('img').attr({ 105 src: response.image.full_src, 106 srcset: response.image.srcset 107 });
108 productContainer.find('.starts_at').hide(); 109 110 if (response.amq_cross_selling_price) { 111 const salePrice = formatPrice(response.amq_cross_selling_price); 112 const rabattAmount = formatPrice(response.display_price - response.amq_cross_selling_price); 113 114 productContainer.find('.xoo-wsc-sp-price > ins .amount bdi').html(salePrice); 115 productContainer.find('.xoo-wsc-sp-price > del .amount bdi').html(regularPrice); 116 productContainer.find('.xoo-wsc-sp-price > .amq-discount-message .amount bdi').html(rabattAmount); 117 } else { 118 productContainer.find('.xoo-wsc-sp-price > ins .amount bdi').html(regularPrice); 119 } 120 } 121 122 function getSelectionsAndUpdateLinks(productContainer) { 123 const selectedVariations = {}; 124 125 productContainer.find('.amq-variation-select').each(function () { 126 const attributeName = this.name; 127 const attributeValue = this.value; 128 if (attributeValue) { 129 selectedVariations[attributeName] = attributeValue; 130 } 131 toggleAmqFloatingLabel(this); 132 }); 133 134 const queryString = $.param({ ...selectedVariations, source: 'side_cart-product_page' }); 135 const productLink = productContainer.find('.xoo-wsc-sp-title').data('product_link').split('?')[0] + '?' + queryString; 136 137 productContainer.find('.xoo-wsc-sp-left-col a, .xoo-wsc-sp-title a').attr('href', productLink); 138 return selectedVariations; 139 } 140 141 function toggleAmqFloatingLabel(select) { 142 const container = $(select).closest('.amq-floating-label'); 143 container.toggleClass('amq-active', !!$(select).val()); 144 } 145 146 (function addSourceParamToProduct() { 147 const searchParams = new URLSearchParams(window.location.search); 148 149 if (searchParams.has('source')) { 150 const source = searchParams.get('source'); // No need for escape, URLSearchParams handles decoding 151 const hiddenInputSelector = '#cross_selling_source'; 152 153 if (!document.querySelector(hiddenInputSelector)) { 154 const input = document.createElement('input'); 155 input.type = 'hidden'; 156 input.id = 'cross_selling_source'; 157 input.name = 'cross_selling_source'; 158 input.value = source; 159 160 document.querySelector('form.variations_form')?.appendChild(input); 161 } 162 } 163 })(); 164 165 $('.amq-floating-label select').each(function () { 166 toggleAmqFloatingLabel(this); 167 }); 168 169 $(document).on('change focus blur', '.amq-floating-label select', function (event) { 170 if (event.type === 'change' || (event.type === 'focus' && !$(this).val()) || (event.type === 'blur' && $(this).val())) { 171 toggleAmqFloatingLabel(this); 172 } 173 }); 174 175 $(document.body).on('xoo_wsc_cart_toggled wc_fragments_refreshed xoo_wsc_cart_updated', function () { 176 $('.xoo-wsc-sp-product').each(function () { 177 const productContainer = $(this); 178 const selectedVariations = getSelectionsAndUpdateLinks(productContainer); 179 180 if (isProductVariationFullySelected(productContainer, selectedVariations)) { 181 getProductFromSelection(productContainer, selectedVariations); 182 } 183 }); 184 }); 185 186 $(document).on('click', '.amq-collapsible-button', function () { 187 $(this).toggleClass('active') 188 .closest('.amq-collapsible-container') 189 .find('.amq-collapsible-content, .amq-variation-container') 190 .slideToggle(() => $('ul.xoo-wsc-sp-slider').trigger('resize')); 191 }); 192 193 $(document).on('click', '.amq_cross_sell_add_to_cart', function (e) { 194 e.preventDefault(); 195 196 var $button = $(this); 197 var product_id = $button.data('product_id'); 198 var variation_id = $button.data('variation_id'); 199 var parent_product_id = $button.data('parent_product_id'); 200 201 $button.addClass('loading xoo-wsc-loading'); 202 203 $(document.body).trigger('adding_to_cart', [$button, []]); 204 205 $.ajax({ 206 url: '/?wc-ajax=add_cross_sell_to_cart', // WooCommerce AJAX endpoint 207 type: 'POST', 208 data: { 209 product_id: product_id, 210 variation_id: variation_id, 211 parent_product_id: parent_product_id, 212 }, 213 success: function (response) { 214 if (response.fragments) { 215 // Trigger event so themes can refresh other areas. 216 $(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $button]); 217 } else if (response.error) { 218 console.error(response.error); 219 } 220 else { 221 window.location.reload(); 222 } 223 }, 224 error: function () { 225 console.error('An error occurred while adding the product to the cart.'); 226 }, 227 complete: function () { 228 $button 229 .removeClass('loading xoo-wsc-loading') 230 .addClass('added'); 231 } 232 }); 233 }); 234 235});
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.