mirror of
https://gitea.baerentsen.space/FrederikBaerentsen/BrickTracker.git
synced 2026-01-01 06:11:36 -06:00
771 lines
25 KiB
JavaScript
771 lines
25 KiB
JavaScript
// 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 = `
|
|
<div class="card set-group-card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
<button class="btn btn-sm btn-outline-primary me-2 group-toggle-btn"
|
|
type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#group-${setGroup[0].rebrickableId}"
|
|
aria-expanded="false">
|
|
<i class="ri-arrow-right-line"></i>
|
|
</button>
|
|
<span class="fw-bold">${firstCard.querySelector('.card-title')?.textContent || 'Set'}</span>
|
|
<span class="badge bg-secondary ms-2">${setGroup.length} sets</span>
|
|
</div>
|
|
<div class="d-flex gap-1">
|
|
${totalMissing > 0 ? `<span class="badge bg-warning text-dark">${totalMissing} missing</span>` : ''}
|
|
${totalDamaged > 0 ? `<span class="badge bg-danger">${totalDamaged} damaged</span>` : ''}
|
|
</div>
|
|
</div>
|
|
<div class="collapse" id="group-${setGroup[0].rebrickableId}">
|
|
<div class="card-body">
|
|
<div class="row set-group-items"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// Add individual set cards to the group
|
|
const groupItems = groupContainer.querySelector('.set-group-items');
|
|
setGroup.forEach(set => {
|
|
const itemContainer = document.createElement('div');
|
|
itemContainer.className = 'col-12 mb-2';
|
|
|
|
// Clone the original card but make it smaller
|
|
const clonedCard = set.cardCol.querySelector('.card').cloneNode(true);
|
|
clonedCard.classList.add('set-group-item');
|
|
|
|
itemContainer.appendChild(clonedCard);
|
|
groupItems.appendChild(itemContainer);
|
|
|
|
// Hide the original card
|
|
set.cardCol.style.display = 'none';
|
|
set.cardCol.classList.add('grouped-set-hidden');
|
|
});
|
|
|
|
// Insert the grouped container before the first hidden set
|
|
firstSet.cardCol.parentNode.insertBefore(groupContainer, firstSet.cardCol);
|
|
|
|
// Add event listener to toggle arrow icon
|
|
const toggleBtn = groupContainer.querySelector('.group-toggle-btn');
|
|
const collapseElement = groupContainer.querySelector('.collapse');
|
|
|
|
collapseElement.addEventListener('shown.bs.collapse', () => {
|
|
toggleBtn.querySelector('i').className = 'ri-arrow-down-line';
|
|
});
|
|
|
|
collapseElement.addEventListener('hidden.bs.collapse', () => {
|
|
toggleBtn.querySelector('i').className = 'ri-arrow-right-line';
|
|
});
|
|
}
|
|
|
|
function removeSetGrouping() {
|
|
// Show all hidden sets
|
|
const hiddenSets = document.querySelectorAll('.grouped-set-hidden');
|
|
hiddenSets.forEach(setCol => {
|
|
setCol.style.display = '';
|
|
setCol.classList.remove('grouped-set-hidden');
|
|
});
|
|
|
|
// Remove all group containers
|
|
const groupContainers = document.querySelectorAll('.set-group-container');
|
|
groupContainers.forEach(container => {
|
|
container.remove();
|
|
});
|
|
}
|
|
|
|
// Initialize duplicate/consolidated filter functionality
|
|
function initializeDuplicateFilter() {
|
|
const duplicateFilterButton = document.getElementById('duplicate-filter-toggle');
|
|
if (!duplicateFilterButton) return;
|
|
|
|
// Check if the filter should be active from URL parameters
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const isDuplicateFilterActive = urlParams.get('duplicate') === 'true';
|
|
|
|
// Set initial button state
|
|
if (isDuplicateFilterActive) {
|
|
duplicateFilterButton.classList.remove('btn-outline-secondary');
|
|
duplicateFilterButton.classList.add('btn-secondary');
|
|
}
|
|
|
|
duplicateFilterButton.addEventListener('click', () => {
|
|
const isCurrentlyActive = duplicateFilterButton.classList.contains('btn-secondary');
|
|
const newState = !isCurrentlyActive;
|
|
|
|
// Update button appearance
|
|
if (newState) {
|
|
duplicateFilterButton.classList.remove('btn-outline-secondary');
|
|
duplicateFilterButton.classList.add('btn-secondary');
|
|
} else {
|
|
duplicateFilterButton.classList.remove('btn-secondary');
|
|
duplicateFilterButton.classList.add('btn-outline-secondary');
|
|
}
|
|
|
|
if (isPaginationMode()) {
|
|
// SERVER-SIDE MODE - Update URL parameter
|
|
performDuplicateFilterServer(newState);
|
|
} else {
|
|
// CLIENT-SIDE MODE - Apply filtering directly
|
|
applyDuplicateFilter(newState);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Server-side duplicate filter
|
|
function performDuplicateFilterServer(showOnlyDuplicates) {
|
|
const currentUrl = new URL(window.location);
|
|
|
|
if (showOnlyDuplicates) {
|
|
currentUrl.searchParams.set('duplicate', 'true');
|
|
} else {
|
|
currentUrl.searchParams.delete('duplicate');
|
|
}
|
|
|
|
// Reset to page 1 when filtering
|
|
currentUrl.searchParams.set('page', '1');
|
|
window.location.href = currentUrl.toString();
|
|
}
|
|
|
|
// Apply duplicate/consolidated filter
|
|
function applyDuplicateFilter(showOnlyDuplicates) {
|
|
// Get the grid container and all column containers (not just the cards)
|
|
const gridContainer = document.getElementById('grid');
|
|
if (!gridContainer) {
|
|
console.warn('Grid container not found');
|
|
return;
|
|
}
|
|
|
|
// Try multiple selectors to find column containers
|
|
let columnContainers = gridContainer.querySelectorAll('.col-md-6');
|
|
if (columnContainers.length === 0) {
|
|
columnContainers = gridContainer.querySelectorAll('[class*="col-"]');
|
|
}
|
|
|
|
if (!showOnlyDuplicates) {
|
|
// Show all column containers by removing the duplicate-filter-hidden class
|
|
columnContainers.forEach(col => {
|
|
col.classList.remove('duplicate-filter-hidden');
|
|
});
|
|
// Trigger the existing grid filter to refresh
|
|
triggerGridRefresh();
|
|
return;
|
|
}
|
|
|
|
// Check if we're in consolidated mode by looking for data-instance-count
|
|
const consolidatedMode = document.querySelector('[data-instance-count]') !== null;
|
|
|
|
if (consolidatedMode) {
|
|
// CONSOLIDATED MODE: Show only sets with instance count > 1
|
|
columnContainers.forEach(col => {
|
|
const card = col.querySelector('[data-set-id]');
|
|
if (card) {
|
|
const instanceCount = parseInt(card.dataset.instanceCount || '1');
|
|
if (instanceCount > 1) {
|
|
col.classList.remove('duplicate-filter-hidden');
|
|
} else {
|
|
col.classList.add('duplicate-filter-hidden');
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
// NON-CONSOLIDATED MODE: Show only sets that appear multiple times
|
|
const setByCounts = {};
|
|
|
|
// Count occurrences of each set
|
|
columnContainers.forEach(col => {
|
|
const card = col.querySelector('[data-set-id]');
|
|
if (card) {
|
|
const rebrickableId = card.dataset.rebrickableId;
|
|
if (rebrickableId) {
|
|
setByCounts[rebrickableId] = (setByCounts[rebrickableId] || 0) + 1;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Show/hide based on count
|
|
columnContainers.forEach(col => {
|
|
const card = col.querySelector('[data-set-id]');
|
|
if (card) {
|
|
const rebrickableId = card.dataset.rebrickableId;
|
|
if (rebrickableId && setByCounts[rebrickableId] > 1) {
|
|
col.classList.remove('duplicate-filter-hidden');
|
|
} else {
|
|
col.classList.add('duplicate-filter-hidden');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Trigger the existing grid filter to refresh and respect our duplicate filter
|
|
triggerGridRefresh();
|
|
}
|
|
|
|
// Helper function to trigger grid filter refresh
|
|
function triggerGridRefresh() {
|
|
// Check if we have a grid instance with filter capability
|
|
if (window.gridInstances) {
|
|
const gridElement = document.getElementById('grid');
|
|
if (gridElement && window.gridInstances[gridElement.id]) {
|
|
const gridInstance = window.gridInstances[gridElement.id];
|
|
if (gridInstance.filter) {
|
|
// Trigger the existing filter to refresh
|
|
gridInstance.filter.filter();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize clear filters button functionality
|
|
function initializeClearFiltersButton() {
|
|
const clearFiltersButton = document.getElementById('grid-filter-clear');
|
|
if (!clearFiltersButton) return;
|
|
|
|
clearFiltersButton.addEventListener('click', () => {
|
|
if (isPaginationMode()) {
|
|
// SERVER-SIDE PAGINATION MODE: Remove all filter parameters and redirect to base URL
|
|
const currentUrl = new URL(window.location);
|
|
|
|
// Remove all filter parameters
|
|
const filterParams = ['status', 'theme', 'year', 'owner', 'purchase_location', 'storage', 'tag', 'duplicate'];
|
|
filterParams.forEach(param => {
|
|
currentUrl.searchParams.delete(param);
|
|
});
|
|
|
|
// Also remove page parameter to go back to clean base URL
|
|
currentUrl.searchParams.delete('page');
|
|
|
|
// Navigate to cleaned URL (will be just /sets if no other params)
|
|
window.location.href = currentUrl.toString();
|
|
} else {
|
|
// CLIENT-SIDE MODE: Reset all filter dropdowns to empty string
|
|
const filterDropdowns = [
|
|
'grid-status',
|
|
'grid-theme',
|
|
'grid-year',
|
|
'grid-owner',
|
|
'grid-purchase-location',
|
|
'grid-storage',
|
|
'grid-tag'
|
|
];
|
|
|
|
filterDropdowns.forEach(dropdownId => {
|
|
const dropdown = document.getElementById(dropdownId);
|
|
if (dropdown) {
|
|
dropdown.value = '';
|
|
}
|
|
});
|
|
|
|
// Clear duplicate filter if active
|
|
const duplicateButton = document.getElementById('duplicate-filter-toggle');
|
|
if (duplicateButton && duplicateButton.classList.contains('btn-secondary')) {
|
|
duplicateButton.classList.remove('btn-secondary');
|
|
duplicateButton.classList.add('btn-outline-secondary');
|
|
applyDuplicateFilter(false);
|
|
}
|
|
|
|
// Remove page parameter from URL if present (without reloading)
|
|
const currentUrl = new URL(window.location);
|
|
if (currentUrl.searchParams.has('page')) {
|
|
currentUrl.searchParams.delete('page');
|
|
window.history.replaceState({}, '', currentUrl.toString());
|
|
}
|
|
|
|
// Trigger filtering if grid instance exists
|
|
triggerGridRefresh();
|
|
}
|
|
});
|
|
} |