/** * Homeschool Product Filter with Price Range and Sales Filter JavaScript */ jQuery(document).ready(function($) { const $filterForm = $('#homeschool-filter-form'); const $filterContainer = $('#homeschool-filter-container'); const $loadingIndicator = $('#filter-loading'); const $productContainer = $('.elementor-loop-container.elementor-grid').first(); const $paginationContainer = $('.elementor-pagination').first(); if ($productContainer.length === 0) { console.log('Product container not found'); return; } // Price slider variables let isDragging = false; let currentHandle = null; let sliderRect = null; let minPrice = 0; let maxPrice = 500; const SLIDER_MAX = 500; // Initialize price slider window.initializePriceSlider = function() { const $slider = $('#price-slider'); if ($slider.length === 0) return; updateSliderDisplay(); // Handle preset button clicks $('.price-preset-btn').on('click', function(e) { e.preventDefault(); const $btn = $(this); const min = parseInt($btn.data('min')); const max = parseInt($btn.data('max')); $('.price-preset-btn').removeClass('active'); $btn.addClass('active'); minPrice = min; maxPrice = max; updateSliderDisplay(); updatePriceInputs(); applyFilters(1); }); // Handle slider events $slider.on('mousedown touchstart', '.price-slider-handle', startDrag); $slider.on('mousedown touchstart', function(e) { if (!$(e.target).hasClass('price-slider-handle')) { const rect = this.getBoundingClientRect(); const clickPos = (e.originalEvent.clientX || e.originalEvent.touches[0].clientX) - rect.left; const percentage = Math.max(0, Math.min(100, (clickPos / rect.width) * 100)); const clickValue = Math.round((percentage / 100) * SLIDER_MAX); const minDiff = Math.abs(clickValue - minPrice); const maxDiff = Math.abs(clickValue - maxPrice); if (minDiff < maxDiff) { minPrice = clickValue; } else { maxPrice = clickValue; } if (minPrice > maxPrice) { [minPrice, maxPrice] = [maxPrice, minPrice]; } updateSliderDisplay(); updatePriceInputs(); clearPresetButtons(); applyFilters(1); } }); // Handle price input changes $('#min-price-input').on('change', function() { const value = Math.max(0, Math.min(SLIDER_MAX, parseInt($(this).val()) || 0)); minPrice = value; if (minPrice > maxPrice) maxPrice = minPrice; updateSliderDisplay(); updatePriceInputs(); clearPresetButtons(); applyFilters(1); }); $('#max-price-input').on('change', function() { const value = Math.max(0, Math.min(SLIDER_MAX, parseInt($(this).val()) || SLIDER_MAX)); maxPrice = value; if (maxPrice < minPrice) minPrice = maxPrice; updateSliderDisplay(); updatePriceInputs(); clearPresetButtons(); applyFilters(1); }); $(document).on('mousemove touchmove', handleDrag); $(document).on('mouseup touchend', stopDrag); }; function startDrag(e) { e.preventDefault(); isDragging = true; currentHandle = $(this).hasClass('min-handle') ? 'min' : 'max'; sliderRect = $('#price-slider')[0].getBoundingClientRect(); $('body').addClass('dragging-slider'); } function handleDrag(e) { if (!isDragging || !currentHandle) return; e.preventDefault(); const clientX = e.originalEvent.clientX || (e.originalEvent.touches && e.originalEvent.touches[0].clientX); if (!clientX || !sliderRect) return; const pos = clientX - sliderRect.left; const percentage = Math.max(0, Math.min(100, (pos / sliderRect.width) * 100)); const value = Math.round((percentage / 100) * SLIDER_MAX); if (currentHandle === 'min') { minPrice = Math.min(value, maxPrice); } else { maxPrice = Math.max(value, minPrice); } updateSliderDisplay(); updatePriceInputs(); clearPresetButtons(); } function stopDrag(e) { if (isDragging) { isDragging = false; currentHandle = null; sliderRect = null; $('body').removeClass('dragging-slider'); applyFilters(1); } } function updateSliderDisplay() { const minPercent = (minPrice / SLIDER_MAX) * 100; const maxPercent = (maxPrice / SLIDER_MAX) * 100; $('#min-handle').css('left', minPercent + '%'); $('#max-handle').css('left', maxPercent + '%'); $('#price-track').css({ 'left': minPercent + '%', 'width': (maxPercent - minPercent) + '%' }); $('#min-price-display').text(minPrice); $('#max-price-display').text(maxPrice >= SLIDER_MAX ? '500+' : maxPrice); $('#price-min').val(minPrice); $('#price-max').val(maxPrice); } function updatePriceInputs() { $('#min-price-input').val(minPrice); $('#max-price-input').val(maxPrice >= SLIDER_MAX ? '' : maxPrice); } function clearPresetButtons() { $('.price-preset-btn').removeClass('active'); } // Handle apply filters button $('#apply-filters').on('click', function(e) { e.preventDefault(); applyFilters(1); }); // Handle clear filters button $('#clear-filters').on('click', function(e) { e.preventDefault(); clearFilters(); }); // Auto-filter on checkbox change (including sales filter) $filterForm.on('change', 'input[type="checkbox"]', function() { applyFilters(1); }); // Auto-filter on search with delay let searchTimeout; $('#filter-search').on('input', function() { clearTimeout(searchTimeout); searchTimeout = setTimeout(function() { applyFilters(1); }, 500); }); // Handle pagination clicks $(document).on('click', '.filter-pagination .page-numbers', function(e) { e.preventDefault(); const page = $(this).data('page'); if (page) { applyFilters(page); } }); function applyFilters(page = 1) { const formData = new FormData(); const searchValue = $('#filter-search').val(); if (searchValue) { formData.append('search', searchValue); } const selectedCategories = []; $filterForm.find('input[name="categories[]"]:checked').each(function() { selectedCategories.push($(this).val()); }); selectedCategories.forEach(function(category) { formData.append('categories[]', category); }); // Add sales filter const salesOnly = $('#filter-sales').is(':checked'); if (salesOnly) { formData.append('sales_only', '1'); } formData.append('price_min', minPrice); formData.append('price_max', maxPrice); formData.append('page', page); formData.append('action', 'homeschool_filter_products'); formData.append('nonce', homeschool_filter_ajax.nonce); showLoading(); $.ajax({ url: homeschool_filter_ajax.ajax_url, type: 'POST', data: formData, processData: false, contentType: false, success: function(response) { if (response.success) { updateProductContainer(response.data.html); showResultsCount(response.data.found_posts, salesOnly); updateURL({ search: searchValue, categories: selectedCategories, sales_only: salesOnly, price_min: minPrice, price_max: maxPrice, page: page }); $('html, body').animate({ scrollTop: $productContainer.offset().top - 100 }, 300); } else { console.error('Filter error:', response.data); } }, error: function(xhr, status, error) { console.error('AJAX error:', error); }, complete: function() { hideLoading(); } }); } function clearFilters() { $filterForm[0].reset(); $('#filter-sales').prop('checked', false); minPrice = 0; maxPrice = SLIDER_MAX; updateSliderDisplay(); updatePriceInputs(); clearPresetButtons(); applyFilters(1); updateURL({}); } function updateProductContainer(html) { const $newContent = $(html); const $newProducts = $newContent.filter('.elementor-loop-container').add($newContent.find('.elementor-loop-container')); const $newPagination = $newContent.filter('.filter-pagination').add($newContent.find('.filter-pagination')); $productContainer.fadeOut(200, function() { if ($newProducts.length > 0) { $productContainer.html($newProducts.html()); } else { $productContainer.html(html); } $productContainer.fadeIn(200); }); if ($newPagination.length > 0) { if ($paginationContainer.length > 0) { $paginationContainer.replaceWith($newPagination); } else { $productContainer.after($newPagination); } } else { $('.filter-pagination').remove(); } } function showLoading() { $loadingIndicator.fadeIn(200); $productContainer.addClass('filtering-in-progress').css('opacity', '0.6'); $('#apply-filters').prop('disabled', true).text('Filtering...'); } function hideLoading() { $loadingIndicator.fadeOut(200); $productContainer.removeClass('filtering-in-progress').css('opacity', '1'); $('#apply-filters').prop('disabled', false).text('Apply Filters'); } function showResultsCount(count, salesOnly = false) { $('.filter-results-count').remove(); let countText = count === 1 ? '1 product found' : count + ' products found'; if (salesOnly) { countText += ' on sale'; } if (minPrice > 0 || maxPrice < SLIDER_MAX) { const priceText = minPrice === maxPrice ? ` at $${minPrice}` : ` between $${minPrice} - $${maxPrice >= SLIDER_MAX ? '500+' : maxPrice}`; countText += priceText; } const $count = $('