/** * Sort Manager - handles sorting of plot items by name and creation time */ export class SortManager { constructor() { this.currentSort = 'name'; this.currentOrder = 'asc'; this.init(); } /** * Initialize sort controls */ init() { // Use setTimeout to ensure DOM is ready setTimeout(() => { this.setupSortButtons(); this.loadSavedSort(); }, 100); } /** * Setup sort button event listeners */ setupSortButtons() { const sortButtons = document.querySelectorAll('.sort-btn'); const orderButton = document.querySelector('.sort-order-btn'); if (sortButtons.length === 0) { setTimeout(() => this.setupSortButtons(), 500); return; } sortButtons.forEach((button) => { const sortType = button.getAttribute('data-sort'); button.addEventListener('click', (e) => { e.preventDefault(); this.setSortType(sortType); }); }); if (orderButton) { orderButton.addEventListener('click', (e) => { e.preventDefault(); this.toggleSortOrder(); }); } // Initialize button states this.updateSortButtons(); this.updateOrderButton(); } /** * Set the sort type (name or time) */ setSortType(sortType) { if (sortType === this.currentSort) return; this.currentSort = sortType; this.updateSortButtons(); this.sortPlots(); this.saveSortPreference(); } /** * Toggle sort order between ascending and descending */ toggleSortOrder() { this.currentOrder = this.currentOrder === 'asc' ? 'desc' : 'asc'; this.updateOrderButton(); this.sortPlots(); this.saveSortPreference(); } /** * Update visual state of sort buttons */ updateSortButtons() { const sortButtons = document.querySelectorAll('.sort-btn'); sortButtons.forEach(btn => { if (btn.getAttribute('data-sort') === this.currentSort) { btn.classList.add('active'); } else { btn.classList.remove('active'); } }); } /** * Update visual state of order button */ updateOrderButton() { const orderButton = document.querySelector('.sort-order-btn'); if (orderButton) { orderButton.textContent = this.currentOrder === 'asc' ? '↑' : '↓'; orderButton.setAttribute('data-order', this.currentOrder); orderButton.title = `Sort Order: ${this.currentOrder === 'asc' ? 'Ascending' : 'Descending'}`; } } /** * Sort the plot items */ sortPlots() { const plotContainer = document.getElementById('plotContainer'); if (!plotContainer) return; const plotItems = Array.from(plotContainer.children); plotItems.sort((a, b) => { let valueA, valueB; if (this.currentSort === 'name') { valueA = a.getAttribute('data-name') || ''; valueB = b.getAttribute('data-name') || ''; // Natural sort for better number handling const result = valueA.localeCompare(valueB, undefined, { numeric: true, sensitivity: 'base' }); return this.currentOrder === 'asc' ? result : -result; } else if (this.currentSort === 'time') { valueA = parseInt(a.getAttribute('data-time') || '0'); valueB = parseInt(b.getAttribute('data-time') || '0'); const result = valueA - valueB; return this.currentOrder === 'asc' ? result : -result; } return 0; }); // Re-append sorted items plotItems.forEach(item => { plotContainer.appendChild(item); }); } /** * Save sort preferences to localStorage */ saveSortPreference() { try { localStorage.setItem('gallery-sort-type', this.currentSort); localStorage.setItem('gallery-sort-order', this.currentOrder); } catch (e) { // Ignore localStorage errors } } /** * Load saved sort preferences */ loadSavedSort() { try { const savedSort = localStorage.getItem('gallery-sort-type'); const savedOrder = localStorage.getItem('gallery-sort-order'); if (savedSort && ['name', 'time'].includes(savedSort)) { this.currentSort = savedSort; } if (savedOrder && ['asc', 'desc'].includes(savedOrder)) { this.currentOrder = savedOrder; } this.updateSortButtons(); this.updateOrderButton(); // Sort immediately if there are plots setTimeout(() => this.sortPlots(), 100); } catch (e) { // Ignore localStorage errors, use defaults } } /** * Get current sort settings */ getCurrentSort() { return { type: this.currentSort, order: this.currentOrder }; } /** * Refresh sorting (call this when plot content changes) */ refresh() { this.sortPlots(); } }