Consolidated parts.js, problems.js and minifigures.js

This commit is contained in:
2025-09-24 20:18:30 +02:00
parent cce96af09b
commit fc405e0832
4 changed files with 273 additions and 430 deletions

View File

@@ -37,6 +37,14 @@ function initializeCollapsibleState(elementId, storageKey) {
function initializePageCollapsibleStates(pagePrefix, filterElementId = 'table-filter', sortElementId = 'table-sort') {
initializeCollapsibleState(filterElementId, `${pagePrefix}-filter-state`);
initializeCollapsibleState(sortElementId, `${pagePrefix}-sort-state`);
// Initialize sort icons based on current URL parameters (for all pages)
const urlParams = new URLSearchParams(window.location.search);
const currentSort = urlParams.get('sort');
const currentOrder = urlParams.get('order');
if (currentSort || currentOrder) {
updateSortIcon(currentOrder);
}
}
// Shared function to preserve filter state during filter changes
@@ -76,6 +84,48 @@ function isPaginationModeForTable(tableId) {
return tableElement && tableElement.getAttribute('data-table') === 'false';
}
// Update sort icon based on current sort direction
function updateSortIcon(sortDirection = null) {
// Find the main sort icon (could be in grid-sort or table-sort)
const sortIcon = document.querySelector('#grid-sort .ri-sort-asc, #grid-sort .ri-sort-desc, #table-sort .ri-sort-asc, #table-sort .ri-sort-desc');
if (!sortIcon) return;
// Remove existing sort classes
sortIcon.classList.remove('ri-sort-asc', 'ri-sort-desc');
// Add appropriate class based on sort direction
if (sortDirection === 'desc') {
sortIcon.classList.add('ri-sort-desc');
} else {
sortIcon.classList.add('ri-sort-asc');
}
}
// Initialize sort button states and icons for pagination mode
window.initializeSortButtonStates = function(currentSort, currentOrder) {
const sortButtons = document.querySelectorAll('[data-sort-attribute]');
// Update main sort icon
updateSortIcon(currentOrder);
if (currentSort) {
sortButtons.forEach(btn => {
// Clear all buttons first
btn.classList.remove('btn-primary');
btn.classList.add('btn-outline-primary');
btn.removeAttribute('data-current-direction');
// Set active state for current sort
if (btn.dataset.sortAttribute === currentSort) {
btn.classList.remove('btn-outline-primary');
btn.classList.add('btn-primary');
btn.dataset.currentDirection = currentOrder || 'asc';
}
});
}
};
// Shared sort button setup function
window.setupSharedSortButtons = function(tableId, tableInstanceGlobal, columnMap) {
const sortButtons = document.querySelectorAll('[data-sort-attribute]');
@@ -138,6 +188,9 @@ window.setupSharedSortButtons = function(tableId, tableInstanceGlobal, columnMap
// Apply sort using Simple DataTables API
tableInstance.table.columns.sort(columnIndex, newDirection);
// Update sort icon to reflect new direction
updateSortIcon(newDirection);
}
}
});
@@ -162,6 +215,9 @@ window.setupSharedSortButtons = function(tableId, tableInstanceGlobal, columnMap
btn.removeAttribute('data-current-direction');
});
// Reset sort icon to default ascending
updateSortIcon('asc');
// Reset table sort - remove all sorting
const tableInstance = window[tableInstanceGlobal];
if (tableInstance) {
@@ -181,4 +237,163 @@ window.setupSharedSortButtons = function(tableId, tableInstanceGlobal, columnMap
}
});
}
};
// =================================================================
// SHARED FUNCTIONS FOR PAGE-SPECIFIC OPERATIONS
// =================================================================
// Shared pagination mode detection (works for any table/grid ID)
window.isPaginationModeForPage = function(elementId, attributeName = 'data-table') {
const element = document.querySelector(`#${elementId}`);
return element && element.getAttribute(attributeName) === 'false';
};
// Shared URL parameter update helper
window.updateUrlParams = function(params, resetPage = true) {
const currentUrl = new URL(window.location);
// Apply parameter updates
Object.entries(params).forEach(([key, value]) => {
if (value === null || value === undefined || value === '' || value === 'all') {
currentUrl.searchParams.delete(key);
} else {
currentUrl.searchParams.set(key, value);
}
});
// Reset to page 1 if requested
if (resetPage) {
currentUrl.searchParams.set('page', '1');
}
// Navigate to updated URL
window.location.href = currentUrl.toString();
};
// Shared filter application (supports owner and color filters)
window.applyPageFilters = function(tableId) {
const ownerSelect = document.getElementById('filter-owner');
const colorSelect = document.getElementById('filter-color');
const params = {};
// Handle owner filter
if (ownerSelect) {
params.owner = ownerSelect.value;
}
// Handle color filter
if (colorSelect) {
params.color = colorSelect.value;
}
// Update URL with new parameters
window.updateUrlParams(params, true);
};
// Shared search setup for both pagination and client-side modes
window.setupPageSearch = function(tableId, searchInputId, clearButtonId, tableInstanceGlobal) {
const searchInput = document.getElementById(searchInputId);
const searchClear = document.getElementById(clearButtonId);
if (!searchInput || !searchClear) return;
const isPaginationMode = window.isPaginationModeForPage(tableId);
if (isPaginationMode) {
// PAGINATION MODE - Server-side search with Enter key
searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
const searchValue = e.target.value.trim();
window.updateUrlParams({ search: searchValue }, true);
}
});
// Clear search
searchClear.addEventListener('click', () => {
searchInput.value = '';
window.updateUrlParams({ search: null }, true);
});
} else {
// ORIGINAL MODE - Client-side instant search via Simple DataTables
const setupClientSearch = () => {
const tableElement = document.querySelector(`table[data-table="true"]#${tableId}`);
const tableInstance = window[tableInstanceGlobal];
if (tableElement && tableInstance) {
// Enable search functionality
tableInstance.table.searchable = true;
// Instant search as user types
searchInput.addEventListener('input', (e) => {
const searchValue = e.target.value.trim();
tableInstance.table.search(searchValue);
});
// Clear search
searchClear.addEventListener('click', () => {
searchInput.value = '';
tableInstance.table.search('');
});
} else {
// If table instance not ready, try again
setTimeout(setupClientSearch, 100);
}
};
setTimeout(setupClientSearch, 100);
}
};
// Shared function to preserve filter state and apply filters
window.applyFiltersAndKeepState = function(tableId, storageKey) {
const filterElement = document.getElementById('table-filter');
const wasOpen = filterElement && filterElement.classList.contains('show');
// Apply the filters
window.applyPageFilters(tableId);
// Store the state to restore after page reload
if (wasOpen) {
sessionStorage.setItem(storageKey, 'open');
}
};
// Shared initialization for table pages (parts, problems, minifigures)
window.initializeTablePage = function(config) {
const {
pagePrefix, // e.g., 'parts', 'problems', 'minifigures'
tableId, // e.g., 'parts', 'problems', 'minifigures'
searchInputId = 'table-search',
clearButtonId = 'table-search-clear',
tableInstanceGlobal, // e.g., 'partsTableInstance', 'problemsTableInstance'
sortColumnMap, // Column mapping for sort buttons
hasColorDropdown = true
} = config;
// Initialize collapsible states (filter and sort)
initializePageCollapsibleStates(pagePrefix);
// Setup search functionality
window.setupPageSearch(tableId, searchInputId, clearButtonId, tableInstanceGlobal);
// Setup color dropdown if needed
if (hasColorDropdown) {
setupColorDropdown();
}
// Setup sort buttons with shared functionality
if (sortColumnMap) {
window.setupSharedSortButtons(tableId, tableInstanceGlobal, sortColumnMap);
}
// Initialize sort button states and icons for pagination mode
if (window.isPaginationModeForPage(tableId)) {
const urlParams = new URLSearchParams(window.location.search);
const currentSort = urlParams.get('sort');
const currentOrder = urlParams.get('order');
window.initializeSortButtonStates(currentSort, currentOrder);
}
};

View File

@@ -112,113 +112,25 @@ document.addEventListener("DOMContentLoaded", () => {
// Setup sort buttons for both modes
setupSortButtons();
// Initialize sort button states and icons for pagination mode
if (isPaginationMode()) {
const urlParams = new URLSearchParams(window.location.search);
const currentSort = urlParams.get('sort');
const currentOrder = urlParams.get('order');
window.initializeSortButtonStates(currentSort, currentOrder);
}
});
function setupSortButtons() {
// Sort button functionality
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';
if (isPaginationMode()) {
// 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);
// Reset to page 1 when sorting
currentUrl.searchParams.set('page', '1');
window.location.href = currentUrl.toString();
} else {
// ORIGINAL MODE - Client-side sorting with Simple DataTables
const columnMap = {
'name': 1,
'parts': 2,
'quantity': 3,
'missing': 4, // Only if visible
'damaged': 5, // Only if visible, adjust based on missing column
'sets': 6 // Adjust based on visible columns
};
const columnIndex = columnMap[attribute];
if (columnIndex !== undefined && window.brickTableInstance) {
// Determine sort direction
const isCurrentlyActive = button.classList.contains('btn-primary');
const currentDirection = button.dataset.currentDirection || (isDesc ? 'desc' : 'asc');
const newDirection = isCurrentlyActive ?
(currentDirection === 'asc' ? 'desc' : 'asc') :
(isDesc ? 'desc' : 'asc');
// Clear other active buttons
sortButtons.forEach(btn => {
btn.classList.remove('btn-primary');
btn.classList.add('btn-outline-primary');
btn.removeAttribute('data-current-direction');
});
// Mark this button as active
button.classList.remove('btn-outline-primary');
button.classList.add('btn-primary');
button.dataset.currentDirection = newDirection;
// Apply sort using Simple DataTables API
window.brickTableInstance.table.columns.sort(columnIndex, newDirection);
}
}
});
});
if (clearButton) {
clearButton.addEventListener('click', () => {
if (isPaginationMode()) {
// PAGINATION MODE - Clear server-side sorting
const currentUrl = new URL(window.location);
currentUrl.searchParams.delete('sort');
currentUrl.searchParams.delete('order');
currentUrl.searchParams.set('page', '1');
window.location.href = currentUrl.toString();
} else {
// ORIGINAL MODE - Clear client-side sorting
// Clear all sort buttons
sortButtons.forEach(btn => {
btn.classList.remove('btn-primary');
btn.classList.add('btn-outline-primary');
btn.removeAttribute('data-current-direction');
});
// Reset table sort - remove all sorting
if (window.brickTableInstance) {
// Destroy and recreate to clear sorting
const tableElement = document.querySelector('#minifigures');
const currentPerPage = window.brickTableInstance.table.options.perPage;
window.brickTableInstance.table.destroy();
setTimeout(() => {
// Create new instance using the globally available BrickTable class
const newInstance = new window.BrickTable(tableElement, currentPerPage);
window.brickTableInstance = newInstance;
// Re-enable search functionality
newInstance.table.searchable = true;
}, 50);
}
}
});
}
const columnMap = {
'name': 1,
'parts': 2,
'quantity': 3,
'missing': 4,
'damaged': 5,
'sets': 6
};
// Use shared sort buttons setup from collapsible-state.js
window.setupSharedSortButtons('minifigures', 'brickTableInstance', columnMap);
}

View File

@@ -1,174 +1,27 @@
// Parts page functionality
function applyFilters() {
const ownerSelect = document.getElementById('filter-owner');
const colorSelect = document.getElementById('filter-color');
const currentUrl = new URL(window.location);
// Reset to first page when filters change (only for pagination mode)
const tableElement = document.querySelector('#parts');
if (tableElement && tableElement.getAttribute('data-table') === 'false') {
currentUrl.searchParams.set('page', '1');
}
// Handle owner filter
if (ownerSelect) {
const selectedOwner = ownerSelect.value;
if (selectedOwner === 'all') {
currentUrl.searchParams.delete('owner');
} else {
currentUrl.searchParams.set('owner', selectedOwner);
}
}
// Handle color filter
if (colorSelect) {
const selectedColor = colorSelect.value;
if (selectedColor === 'all') {
currentUrl.searchParams.delete('color');
} else {
currentUrl.searchParams.set('color', selectedColor);
}
}
window.location.href = currentUrl.toString();
}
// setupColorDropdown is now in shared collapsible-state.js
// Initialize filter and sort states for parts page
function initializeCollapsibleStates() {
initializePageCollapsibleStates('parts');
}
// Parts page functionality - now uses shared functions
// Keep filters expanded after selection
function applyFiltersAndKeepOpen() {
preserveCollapsibleStateOnChange('table-filter', 'parts-filter-state');
applyFilters();
window.applyFiltersAndKeepState('parts', 'parts-filter-state');
}
function setupSortButtons() {
const columnMap = {
'name': 1,
'color': 2,
'quantity': 3,
'missing': 4,
'damaged': 5,
'sets': 6,
'minifigures': 7
};
// Use shared sort buttons setup from collapsible-state.js
window.setupSharedSortButtons('parts', 'partsTableInstance', columnMap);
}
// Check if pagination mode is enabled
function isPaginationMode() {
const tableElement = document.querySelector('#parts');
// In pagination mode, table has data-table="false"
// In original mode, table has data-table="true"
return tableElement && tableElement.getAttribute('data-table') === 'false';
}
// Initialize sort button states for pagination mode
function initializeSortButtonStates() {
const currentUrl = new URL(window.location);
const currentSort = currentUrl.searchParams.get('sort');
const currentOrder = currentUrl.searchParams.get('order');
if (currentSort) {
const sortButtons = document.querySelectorAll('[data-sort-attribute]');
sortButtons.forEach(btn => {
// Clear all buttons first
btn.classList.remove('btn-primary');
btn.classList.add('btn-outline-primary');
btn.removeAttribute('data-current-direction');
// Set active state for current sort
if (btn.dataset.sortAttribute === currentSort) {
btn.classList.remove('btn-outline-primary');
btn.classList.add('btn-primary');
btn.dataset.currentDirection = currentOrder || 'asc';
}
});
}
}
// Setup table search and sort functionality
// Initialize parts page
document.addEventListener("DOMContentLoaded", () => {
const searchInput = document.getElementById('table-search');
const searchClear = document.getElementById('table-search-clear');
// Initialize collapsible states (filter and sort)
initializeCollapsibleStates();
// Setup color dropdown with color squares
setupColorDropdown();
if (searchInput && searchClear) {
if (isPaginationMode()) {
// PAGINATION MODE - Server-side search with Enter key
// Search on Enter key press
searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
const currentUrl = new URL(window.location);
const searchValue = e.target.value.trim();
// Reset to first page when searching
currentUrl.searchParams.set('page', '1');
if (searchValue) {
currentUrl.searchParams.set('search', searchValue);
} else {
currentUrl.searchParams.delete('search');
}
window.location.href = currentUrl.toString();
}
});
// Clear search
searchClear.addEventListener('click', () => {
const currentUrl = new URL(window.location);
currentUrl.searchParams.delete('search');
currentUrl.searchParams.set('page', '1');
window.location.href = currentUrl.toString();
});
} else {
// ORIGINAL MODE - Client-side instant search via Simple DataTables
// Wait for table to be initialized
const setupClientSearch = () => {
const tableElement = document.querySelector('table[data-table="true"]');
if (tableElement && window.partsTableInstance) {
// Enable search functionality
window.partsTableInstance.table.searchable = true;
// Instant search as user types
searchInput.addEventListener('input', (e) => {
const searchValue = e.target.value.trim();
window.partsTableInstance.table.search(searchValue);
});
// Clear search
searchClear.addEventListener('click', () => {
searchInput.value = '';
window.partsTableInstance.table.search('');
});
} else {
// If table instance not ready, try again
setTimeout(setupClientSearch, 100);
}
};
setTimeout(setupClientSearch, 100);
}
}
// Setup sort buttons
setupSortButtons();
// Initialize sort button states for pagination mode
if (isPaginationMode()) {
initializeSortButtonStates();
}
// Use shared table page initialization
window.initializeTablePage({
pagePrefix: 'parts',
tableId: 'parts',
tableInstanceGlobal: 'partsTableInstance',
sortColumnMap: {
'name': 1,
'color': 2,
'quantity': 3,
'missing': 4,
'damaged': 5,
'sets': 6,
'minifigures': 7
},
hasColorDropdown: true
});
});

View File

@@ -1,163 +1,26 @@
// Check if we're in pagination mode (server-side) or original mode (client-side)
function isPaginationMode() {
const tableElement = document.querySelector('#problems');
return tableElement && tableElement.getAttribute('data-table') === 'false';
}
// Initialize filter and sort states for problems page
function initializeCollapsibleStates() {
initializePageCollapsibleStates('problems');
}
// Apply filters with current state
function applyFilters() {
const ownerSelect = document.getElementById('filter-owner');
const colorSelect = document.getElementById('filter-color');
const currentUrl = new URL(window.location);
// Reset to first page when filters change (only for pagination mode)
if (isPaginationMode()) {
currentUrl.searchParams.set('page', '1');
}
// Handle owner filter
if (ownerSelect) {
const selectedOwner = ownerSelect.value;
if (selectedOwner === 'all') {
currentUrl.searchParams.delete('owner');
} else {
currentUrl.searchParams.set('owner', selectedOwner);
}
}
// Handle color filter
if (colorSelect) {
const selectedColor = colorSelect.value;
if (selectedColor === 'all') {
currentUrl.searchParams.delete('color');
} else {
currentUrl.searchParams.set('color', selectedColor);
}
}
window.location.href = currentUrl.toString();
}
// Problems page functionality - now uses shared functions
// Keep filters expanded after selection
function applyFiltersAndKeepOpen() {
preserveCollapsibleStateOnChange('table-filter', 'problems-filter-state');
applyFilters();
window.applyFiltersAndKeepState('problems', 'problems-filter-state');
}
// setupColorDropdown is now in shared collapsible-state.js
// Setup sort button functionality
function setupSortButtons() {
const columnMap = {
'name': 1,
'color': 2,
'quantity': 3,
'missing': 4,
'damaged': 5,
'sets': 6,
'minifigures': 7
};
// Use shared sort buttons setup from collapsible-state.js
window.setupSharedSortButtons('problems', 'problemsTableInstance', columnMap);
}
// Problems page functionality
function setupProblemsPage() {
// Handle search input
const searchInput = document.getElementById('table-search');
const clearButton = document.getElementById('table-search-clear');
if (searchInput && clearButton) {
let searchTimeout;
// Search on input
searchInput.addEventListener('input', function() {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
if (isPaginationMode()) {
// PAGINATION MODE - Server-side search via URL parameters
const url = new URL(window.location);
if (this.value.trim()) {
url.searchParams.set('search', this.value.trim());
} else {
url.searchParams.delete('search');
}
url.searchParams.delete('page'); // Reset to first page
window.location.href = url.toString();
} else {
// ORIGINAL MODE - Client-side instant search via Simple DataTables
const searchValue = this.value.trim();
const tableElement = document.querySelector('table[data-table="true"]');
if (tableElement && window.problemsTableInstance) {
// Enable searchable functionality
window.problemsTableInstance.table.searchable = true;
// Perform the search
if (searchValue) {
window.problemsTableInstance.table.search(searchValue);
} else {
// Clear search
window.problemsTableInstance.table.search('');
}
}
}
}, 500);
});
// Clear search
clearButton.addEventListener('click', function() {
if (isPaginationMode()) {
// PAGINATION MODE - Clear via URL parameters
searchInput.value = '';
const url = new URL(window.location);
url.searchParams.delete('search');
url.searchParams.delete('page');
window.location.href = url.toString();
} else {
// ORIGINAL MODE - Clear via DataTables API
searchInput.value = '';
if (window.problemsTableInstance) {
window.problemsTableInstance.table.search('');
}
}
});
}
// Initialize collapsible states (filter and sort)
initializeCollapsibleStates();
// Setup sort and filter functionality (from parts.js)
setupSortButtons();
setupColorDropdown();
// Update active sort button based on current URL parameters
const urlParams = new URLSearchParams(window.location.search);
const currentSort = urlParams.get('sort');
const currentOrder = urlParams.get('order');
if (currentSort) {
const activeButton = document.querySelector(`[data-sort-attribute="${currentSort}"]`);
if (activeButton) {
activeButton.classList.add('active');
// Add direction indicator
if (currentOrder === 'desc') {
activeButton.classList.add('btn-primary');
activeButton.classList.remove('btn-outline-primary');
}
}
}
}
// Helper function to check if we're in pagination mode
function isPaginationMode() {
const tableElement = document.querySelector('#problems');
return tableElement && tableElement.getAttribute('data-table') === 'false';
}
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', setupProblemsPage);
// Initialize problems page
document.addEventListener("DOMContentLoaded", () => {
// Use shared table page initialization
window.initializeTablePage({
pagePrefix: 'problems',
tableId: 'problems',
tableInstanceGlobal: 'problemsTableInstance',
sortColumnMap: {
'name': 1,
'color': 2,
'quantity': 3,
'missing': 4,
'damaged': 5,
'sets': 6,
'minifigures': 7
},
hasColorDropdown: true
});
});