// Global variables let albumsData = []; let filteredData = []; let currentPage = 1; const itemsPerPage = 50; let isReversed = false; // DOM elements const albumsGrid = document.getElementById('albumsGrid'); const searchInput = document.getElementById('searchInput'); const statusFilter = document.getElementById('statusFilter'); const sortBy = document.getElementById('sortBy'); const reverseButton = document.getElementById('reverseButton'); const jumpToRank = document.getElementById('jumpToRank'); const jumpButton = document.getElementById('jumpButton'); const loading = document.getElementById('loading'); const error = document.getElementById('error'); const stats = document.getElementById('stats'); // Initialize the application document.addEventListener('DOMContentLoaded', function() { loadAlbumsData(); setupEventListeners(); handleUrlParams(); }); // Setup event listeners function setupEventListeners() { searchInput.addEventListener('input', debounce(handleSearch, 300)); statusFilter.addEventListener('change', handleFilter); sortBy.addEventListener('change', handleSort); reverseButton.addEventListener('click', handleReverse); jumpButton.addEventListener('click', handleJumpToRank); jumpToRank.addEventListener('keypress', handleRankKeypress); // Add scroll listener for infinite scroll window.addEventListener('scroll', handleScroll); } // Load albums data from CSV async function loadAlbumsData() { try { const response = await fetch('top_500_albums_2023.csv'); if (!response.ok) { throw new Error('Failed to load data'); } const csvText = await response.text(); albumsData = parseCSV(csvText); filteredData = [...albumsData]; hideLoading(); renderAlbums(); updateStats(); } catch (err) { console.error('Error loading data:', err); showError(); } } // Parse CSV data function parseCSV(csvText) { const lines = csvText.split('\n'); const headers = lines[0].split(',').map(h => h.trim().replace(/"/g, '')); const albums = []; for (let i = 1; i < lines.length; i++) { const line = lines[i].trim(); if (!line) continue; // Handle CSV parsing with proper quote handling const values = parseCSVLine(line); if (values.length < headers.length) continue; const album = {}; headers.forEach((header, index) => { album[header] = values[index] ? values[index].replace(/"/g, '').trim() : ''; }); // Convert rank to number album.Rank = parseInt(album.Rank) || 0; // Extract year from Info field const yearMatch = album.Info ? album.Info.match(/\b(19|20)\d{2}\b/) : null; album.Year = yearMatch ? parseInt(yearMatch[0]) : null; albums.push(album); } return albums; } // Parse a single CSV line handling quotes and commas function parseCSVLine(line) { const values = []; let current = ''; let inQuotes = false; for (let i = 0; i < line.length; i++) { const char = line[i]; if (char === '"') { inQuotes = !inQuotes; } else if (char === ',' && !inQuotes) { values.push(current); current = ''; } else { current += char; } } values.push(current); return values; } // Render albums function renderAlbums() { const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const albumsToShow = filteredData.slice(0, endIndex); if (currentPage === 1) { albumsGrid.innerHTML = ''; } albumsToShow.slice(startIndex).forEach(album => { const albumCard = createAlbumCard(album); albumsGrid.appendChild(albumCard); }); } // Create album card element function createAlbumCard(album) { const card = document.createElement('div'); card.className = 'album-card'; card.setAttribute('data-rank', album.Rank); const statusClass = getStatusClass(album.Status); const statusText = formatStatus(album.Status); card.innerHTML = `