1(function ($) { 2 "use strict"; 3 4 const initTbiSlider = () => { 5 try { 6 const slider = document.getElementById('tbiProductSlider'); 7 const wrapper = document.getElementById('tbiSliderWrapper'); 8 9 if (!slider || !wrapper) return false; 10 if (slider.classList.contains('tbi-initialized')) return true; 11 slider.classList.add('tbi-initialized'); 12 13 let isDragging = false; 14 let startPos = 0; 15 let currentTranslate = 0; 16 let prevTranslate = 0; 17 let animationID; 18 19 const getMaxScroll = () => -(slider.scrollWidth - wrapper.offsetWidth); 20 slider.style.transform = `translateX(0px)`; 21 22 // --- Drag/Touch Events --- 23 const dragStart = (e) => { 24 isDragging = true; 25 startPos = e.type.includes('mouse') ? e.pageX : e.touches[0].clientX; 26 slider.classList.add('dragging'); 27 animationID = requestAnimationFrame(animation); 28 }; 29 30 const dragAction = (e) => { 31 if (!isDragging) return; 32 const currentPosition = e.type.includes('mouse') ? e.pageX : e.touches[0].clientX; 33 currentTranslate = prevTranslate + (currentPosition - startPos); 34 }; 35 36 const dragEnd = () => { 37 if (!isDragging) return; 38 isDragging = false; 39 cancelAnimationFrame(animationID); 40 slider.classList.remove('dragging'); 41 42 const max = getMaxScroll(); 43 if (currentTranslate > 0) currentTranslate = 0; 44 if (currentTranslate < max) currentTranslate = max; 45 46 prevTranslate = currentTranslate; 47 slider.style.transform = `translateX(${currentTranslate}px)`; 48 }; 49 50 const animation = () => { 51 slider.style.transform = `translateX(${currentTranslate}px)`; 52 if (isDragging) requestAnimationFrame(animation); 53 }; 54 55 slider.onmousedown = dragStart; 56 slider.ontouchstart = dragStart; 57 window.onmousemove = dragAction; 58 window.ontouchmove = dragAction; 59 window.onmouseup = dragEnd; 60 window.ontouchend = dragEnd; 61 62 // --- Click Guard (Blocks title link if dragging) --- 63 slider.addEventListener('click', (e) => { 64 const moveDistance = Math.abs(currentTranslate - prevTranslate); 65 // If we are clicking the Add to Cart button, don't block it 66 if (e.target.closest('.tbi-add-cart-btn')) return; 67 68 if (moveDistance > 10) { 69 e.preventDefault(); 70 e.stopPropagation(); 71 } 72 }, true); 73 74 // --- Navigation Buttons --- 75 const nextBtn = wrapper.querySelector('.next'); 76 const prevBtn = wrapper.querySelector('.prev'); 77 if (nextBtn) nextBtn.onclick = () => { 78 currentTranslate = Math.max(currentTranslate - 280, getMaxScroll()); 79 prevTranslate = currentTranslate; 80 slider.style.transform = `translateX(${currentTranslate}px)`; 81 }; 82 if (prevBtn) prevBtn.onclick = () => { 83 currentTranslate = Math.min(currentTranslate + 280, 0); 84 prevTranslate = currentTranslate; 85 slider.style.transform = `translateX(${currentTranslate}px)`; 86 }; 87 88 return true; 89 } catch (e) { 90 return false; 91 } 92 }; 93 94 // --- AJAX Add to Cart (Delegated) --- 95 $(document).on('click', '.tbi-add-cart-btn', function (e) { 96 e.preventDefault(); 97 e.stopPropagation(); 98 99 const $button = $(this); 100 const productId = $button.data('product-id'); 101 102 if ($button.hasClass('adding') || $button.hasClass('added')) return; 103 104 $button.addClass('adding').html('<i class="fas fa-spinner fa-spin"></i>'); 105 106 $.ajax({ 107 url: tbi_ajax.ajax_url, 108 type: 'POST', 109 data: { 110 action: 'tbi_add_to_cart', 111 product_id: productId, 112 quantity: 1, 113 nonce: tbi_ajax.nonce 114 }, 115 success: function (response) { 116 if (response.success) { 117 $button.removeClass('adding').addClass('added').html('<i class="fas fa-check"></i>'); 118 119 // Trigger Woodmart/WC fragments update 120 $(document.body).trigger('added_to_cart', [response.data.fragments, response.data.cart_hash]); 121 122 setTimeout(() => { 123 $button.removeClass('added').html('<i class="fas fa-shopping-bag"></i>'); 124 }, 2000); 125 } 126 } 127 }); 128 }); 129 130 // Init slider once if present â no polling loop on every page. 131 onReady(function () { 132 initTbiSlider(); 133 }); 134 135 function onReady(fn) { 136 if (document.readyState === 'loading') { 137 document.addEventListener('DOMContentLoaded', fn); 138 } else { 139 fn(); 140 } 141 } 142 143 $(document.body).on('updated_wc_div added_to_cart removed_from_cart', function () { 144 setTimeout(initTbiSlider, 500); 145 }); 146 147 148 149 150 151})(jQuery); 152 153(function($) { 154 'use strict'; 155 156 var updateTimeout = null; 157 var isProcessing = false;
158 159 $(document).on('change', '.shipping_method', function() { 160 // Clear any pending timeout 161 clearTimeout(updateTimeout); 162 163 // Debounce to prevent multiple rapid clicks 164 updateTimeout = setTimeout(function() { 165 // Prevent double processing 166 if (isProcessing) { 167 return; 168 } 169 170 isProcessing = true; 171 172 var $cartContent = $('.widget_shopping_cart_content'); 173 var shippingMethods = {}; 174 175 // Collect all checked shipping methods 176 $('.shipping_method:checked').each(function() { 177 var index = $(this).data('index') || 0; 178 var value = $(this).val(); 179 180 if (value) { 181 shippingMethods[index] = value; 182 } 183 }); 184 185 // Show loading indicator 186 if ($cartContent.length) { 187 $cartContent.addClass('wd-loading-dimmed'); 188 } 189 190 // Send AJAX request 191 $.ajax({ 192 type: 'POST', 193 url: woodmart_settings.ajaxurl, 194 data: { 195 action: 'woodmart_update_mini_cart_shipping', 196 shipping_method: shippingMethods, 197 security: '<?php echo wp_create_nonce("woodmart-shipping-nonce"); ?>' 198 }, 199 success: function(response) { 200 if (response.success) { 201 // **THE KEY LINE**: Trigger WooCommerce fragment refresh 202 // This will make WooCommerce recalculate and update everything 203 $(document.body).trigger('wc_fragment_refresh'); 204 205 // Also trigger WoodMart specific events 206 $(document.body).trigger('woodmart_update_cart_totals'); 207 } 208 }, 209 error: function(xhr, status, error) { 210 console.error('Shipping update failed:', error); 211 212 // Show error message briefly 213 if ($cartContent.length) { 214 $cartContent.prepend( 215 '<div class="wd-shipping-error woocommerce-error">' + 216 'Versandaktualisierung fehlgeschlagen. Bitte Seite neu laden.' + 217 '</div>' 218 ); 219 220 setTimeout(function() { 221 $cartContent.find('.wd-shipping-error').fadeOut(300, function() { 222 $(this).remove(); 223 }); 224 }, 3000); 225 } 226 }, 227 complete: function() { 228 // Hide loading indicator 229 if ($cartContent.length) { 230 setTimeout(function() { 231 $cartContent.removeClass('wd-loading-dimmed'); 232 }, 300); 233 } 234 235 // Reset processing flag 236 isProcessing = false; 237 } 238 }); 239 240 }, 300); // 300ms debounce delay 241 }); 242 243 // Handle page load - ensure shipping methods are properly initialized 244 $(window).on('load', function() { 245 setTimeout(function() { 246 // Trigger initial fragment refresh to ensure sync 247 $(document.body).trigger('wc_fragment_refresh'); 248 }, 500); 249 }); 250 251})(jQuery);
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.