// Sets page functionality // Check if we're in pagination mode (server-side) or original mode (client-side) function isPaginationMode() { const gridElement = document.querySelector('#grid'); return gridElement && gridElement.getAttribute('data-grid') === 'false'; } // Initialize filter and sort states for sets page function initializeCollapsibleStates() { initializePageCollapsibleStates('sets', 'grid-filter', 'grid-sort'); } // Setup page functionality document.addEventListener("DOMContentLoaded", () => { // Initialize collapsible states (filter and sort) initializeCollapsibleStates(); const searchInput = document.getElementById('grid-search'); const searchClear = document.getElementById('grid-search-clear'); // Initialize duplicate filter functionality initializeDuplicateFilter(); // Initialize clear filters button initializeClearFiltersButton(); if (searchInput && searchClear) { if (isPaginationMode()) { // PAGINATION MODE - Server-side search const searchForm = document.createElement('form'); searchForm.style.display = 'none'; searchInput.parentNode.appendChild(searchForm); searchForm.appendChild(searchInput.cloneNode(true)); // Handle Enter key for search searchInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); performServerSearch(); } }); // Handle search button click (if exists) const searchButton = document.querySelector('[data-search-trigger]'); if (searchButton) { searchButton.addEventListener('click', performServerSearch); } // Clear search searchClear.addEventListener('click', () => { searchInput.value = ''; performServerSearch(); }); function performServerSearch() { const currentUrl = new URL(window.location); const searchQuery = searchInput.value.trim(); if (searchQuery) { currentUrl.searchParams.set('search', searchQuery); } else { currentUrl.searchParams.delete('search'); } // Reset to page 1 when searching currentUrl.searchParams.set('page', '1'); window.location.href = currentUrl.toString(); } // Setup sort buttons for pagination mode setupPaginationSortButtons(); // Setup filter dropdowns for pagination mode setupPaginationFilterDropdowns(); // Initialize filter dropdowns from URL parameters initializeFilterDropdowns(); // Initialize sort button states and icons for pagination mode const urlParams = new URLSearchParams(window.location.search); const currentSort = urlParams.get('sort'); const currentOrder = urlParams.get('order'); window.initializeSortButtonStates(currentSort, currentOrder); } else { // ORIGINAL MODE - Client-side filtering with grid scripts // Initialize filter dropdowns from URL parameters for client-side mode too initializeClientSideFilterDropdowns(); } } }); function setupPaginationSortButtons() { // Sort button functionality for pagination mode const sortButtons = document.querySelectorAll('[data-sort-attribute]'); const clearButton = document.querySelector('[data-sort-clear]'); sortButtons.forEach(button => { button.addEventListener('click', () => { const attribute = button.dataset.sortAttribute; const isDesc = button.dataset.sortDesc === 'true'; // PAGINATION MODE - Server-side sorting const currentUrl = new URL(window.location); const currentSort = currentUrl.searchParams.get('sort'); const currentOrder = currentUrl.searchParams.get('order'); // Determine new sort direction let newOrder = isDesc ? 'desc' : 'asc'; if (currentSort === attribute) { // Toggle direction if clicking the same column newOrder = currentOrder === 'asc' ? 'desc' : 'asc'; } currentUrl.searchParams.set('sort', attribute); currentUrl.searchParams.set('order', newOrder); // Update sort icon immediately before navigation updateSortIcon(newOrder); // Reset to page 1 when sorting currentUrl.searchParams.set('page', '1'); window.location.href = currentUrl.toString(); }); }); if (clearButton) { clearButton.addEventListener('click', () => { // PAGINATION MODE - Clear server-side sorting const currentUrl = new URL(window.location); currentUrl.searchParams.delete('sort'); currentUrl.searchParams.delete('order'); // Reset sort icon to default ascending updateSortIcon('asc'); currentUrl.searchParams.set('page', '1'); window.location.href = currentUrl.toString(); }); } } function initializeFilterDropdowns() { // Set filter dropdown values from URL parameters const urlParams = new URLSearchParams(window.location.search); // Set each filter dropdown value if the parameter exists const yearParam = urlParams.get('year'); if (yearParam) { const yearDropdown = document.getElementById('grid-year'); if (yearDropdown) { yearDropdown.value = yearParam; } } const themeParam = urlParams.get('theme'); if (themeParam) { const themeDropdown = document.getElementById('grid-theme'); if (themeDropdown) { // Try to set the theme value directly first (for theme names) themeDropdown.value = themeParam; // If that didn't work and the param is numeric (theme ID), // try to find the corresponding theme name by looking at cards if (themeDropdown.value !== themeParam && /^\d+$/.test(themeParam)) { // Look for a card with this theme ID and get its theme name const cardWithTheme = document.querySelector(`[data-theme-id="${themeParam}"]`); if (cardWithTheme) { const themeName = cardWithTheme.getAttribute('data-theme'); if (themeName) { themeDropdown.value = themeName; } } } } } const statusParam = urlParams.get('status'); if (statusParam) { const statusDropdown = document.getElementById('grid-status'); if (statusDropdown) { statusDropdown.value = statusParam; } } const ownerParam = urlParams.get('owner'); if (ownerParam) { const ownerDropdown = document.getElementById('grid-owner'); if (ownerDropdown) { ownerDropdown.value = ownerParam; } } const purchaseLocationParam = urlParams.get('purchase_location'); if (purchaseLocationParam) { const purchaseLocationDropdown = document.getElementById('grid-purchase-location'); if (purchaseLocationDropdown) { purchaseLocationDropdown.value = purchaseLocationParam; } } const storageParam = urlParams.get('storage'); if (storageParam) { const storageDropdown = document.getElementById('grid-storage'); if (storageDropdown) { storageDropdown.value = storageParam; } } const tagParam = urlParams.get('tag'); if (tagParam) { const tagDropdown = document.getElementById('grid-tag'); if (tagDropdown) { tagDropdown.value = tagParam; } } } function initializeClientSideFilterDropdowns() { // Set filter dropdown values from URL parameters and trigger filtering for client-side mode const urlParams = new URLSearchParams(window.location.search); let needsFiltering = false; // Check if we have any filter parameters to avoid flash of all content const hasFilterParams = urlParams.has('year') || urlParams.has('theme') || urlParams.has('storage') || urlParams.has('purchase_location'); // If we have filter parameters, temporarily hide the grid to prevent flash if (hasFilterParams) { const gridElement = document.querySelector('#grid'); if (gridElement && gridElement.getAttribute('data-grid') === 'true') { gridElement.style.opacity = '0'; } } // Set year filter if parameter exists const yearParam = urlParams.get('year'); if (yearParam) { const yearDropdown = document.getElementById('grid-year'); if (yearDropdown) { yearDropdown.value = yearParam; needsFiltering = true; } } // Set theme filter - handle both theme names and theme IDs const themeParam = urlParams.get('theme'); if (themeParam) { const themeDropdown = document.getElementById('grid-theme'); if (themeDropdown) { if (/^\d+$/.test(themeParam)) { // Theme parameter is an ID, need to convert to theme name by looking at cards const themeNameFromId = findThemeNameById(themeParam); if (themeNameFromId) { themeDropdown.value = themeNameFromId; needsFiltering = true; } } else { // Theme parameter is already a name themeDropdown.value = themeParam.toLowerCase(); needsFiltering = true; } } } // Set storage filter if parameter exists const storageParam = urlParams.get('storage'); if (storageParam) { const storageDropdown = document.getElementById('grid-storage'); if (storageDropdown) { storageDropdown.value = storageParam; needsFiltering = true; } } // Set purchase location filter if parameter exists const purchaseLocationParam = urlParams.get('purchase_location'); if (purchaseLocationParam) { const purchaseLocationDropdown = document.getElementById('grid-purchase-location'); if (purchaseLocationDropdown) { purchaseLocationDropdown.value = purchaseLocationParam; needsFiltering = true; } } // Trigger filtering if any parameters were set if (needsFiltering) { // Try to trigger filtering immediately const tryToFilter = () => { const gridElement = document.querySelector('#grid'); if (gridElement && gridElement.getAttribute('data-grid') === 'true' && window.gridInstances) { const gridInstance = window.gridInstances[gridElement.id]; if (gridInstance && gridInstance.filter) { // This is client-side mode, trigger the filter directly gridInstance.filter.filter(); // Show the grid again after filtering if (hasFilterParams) { gridElement.style.opacity = '1'; gridElement.style.transition = 'opacity 0.2s ease-in-out'; } return true; } } return false; }; // Try filtering immediately if (!tryToFilter()) { // If not ready, try again with a shorter delay setTimeout(() => { if (!tryToFilter()) { // Final attempt with longer delay setTimeout(tryToFilter, 100); } }, 50); } } } function findThemeNameById(themeId) { // Look through all cards to find the theme name for this theme ID const cards = document.querySelectorAll('.card[data-theme-id]'); for (const card of cards) { if (card.getAttribute('data-theme-id') === themeId) { return card.getAttribute('data-theme'); } } return null; } function setupPaginationFilterDropdowns() { // Filter dropdown functionality for pagination mode const filterDropdowns = document.querySelectorAll('#grid-filter select'); filterDropdowns.forEach(dropdown => { dropdown.addEventListener('change', () => { performServerFilter(); }); }); function performServerFilter() { const currentUrl = new URL(window.location); // Get all filter values const statusFilter = document.getElementById('grid-status')?.value || ''; const themeFilter = document.getElementById('grid-theme')?.value || ''; const yearFilter = document.getElementById('grid-year')?.value || ''; const ownerFilter = document.getElementById('grid-owner')?.value || ''; const purchaseLocationFilter = document.getElementById('grid-purchase-location')?.value || ''; const storageFilter = document.getElementById('grid-storage')?.value || ''; const tagFilter = document.getElementById('grid-tag')?.value || ''; // Update URL parameters if (statusFilter) { currentUrl.searchParams.set('status', statusFilter); } else { currentUrl.searchParams.delete('status'); } if (themeFilter) { currentUrl.searchParams.set('theme', themeFilter); } else { currentUrl.searchParams.delete('theme'); } if (yearFilter) { currentUrl.searchParams.set('year', yearFilter); } else { currentUrl.searchParams.delete('year'); } if (ownerFilter) { currentUrl.searchParams.set('owner', ownerFilter); } else { currentUrl.searchParams.delete('owner'); } if (purchaseLocationFilter) { currentUrl.searchParams.set('purchase_location', purchaseLocationFilter); } else { currentUrl.searchParams.delete('purchase_location'); } if (storageFilter) { currentUrl.searchParams.set('storage', storageFilter); } else { currentUrl.searchParams.delete('storage'); } if (tagFilter) { currentUrl.searchParams.set('tag', tagFilter); } else { currentUrl.searchParams.delete('tag'); } // Reset to page 1 when filtering currentUrl.searchParams.set('page', '1'); window.location.href = currentUrl.toString(); } } // Set grouping functionality function initializeSetGrouping() { const groupToggle = document.getElementById('group-identical-sets'); if (!groupToggle) return; // Load saved state from localStorage const savedState = localStorage.getItem('groupIdenticalSets') === 'true'; groupToggle.checked = savedState; // Apply grouping on page load if enabled if (savedState) { applySetGrouping(); } // Listen for toggle changes groupToggle.addEventListener('change', function() { // Save state to localStorage localStorage.setItem('groupIdenticalSets', this.checked); if (this.checked) { applySetGrouping(); } else { removeSetGrouping(); } }); } function applySetGrouping() { const grid = document.getElementById('grid'); if (!grid) return; const setCards = Array.from(grid.children); const groupedSets = {}; // Group sets by rebrickable_set_id setCards.forEach(cardCol => { const setCard = cardCol.querySelector('.card[data-set-id]'); if (!setCard) return; const setId = setCard.getAttribute('data-set-id'); const rebrickableId = setCard.getAttribute('data-rebrickable-id'); if (!rebrickableId) return; if (!groupedSets[rebrickableId]) { groupedSets[rebrickableId] = []; } groupedSets[rebrickableId].push({ cardCol: cardCol, setId: setId, rebrickableId: rebrickableId }); }); // Process each group Object.keys(groupedSets).forEach(rebrickableId => { const group = groupedSets[rebrickableId]; if (group.length > 1) { createGroupedSetDisplay(group); } }); } function createGroupedSetDisplay(setGroup) { const firstSet = setGroup[0]; const firstCard = firstSet.cardCol.querySelector('.card'); if (!firstCard) return; // Calculate aggregate stats let totalMissing = 0; let totalDamaged = 0; let allSetIds = []; setGroup.forEach(set => { const card = set.cardCol.querySelector('.card'); // Get missing and damaged counts from existing data attributes const missingCount = parseInt(card.getAttribute('data-missing') || '0'); const damagedCount = parseInt(card.getAttribute('data-damaged') || '0'); totalMissing += missingCount; totalDamaged += damagedCount; allSetIds.push(set.setId); }); // Create grouped card container const groupContainer = document.createElement('div'); groupContainer.className = firstSet.cardCol.className + ' set-group-container'; groupContainer.innerHTML = `