/** * @fileoverview Main application file for Debrid Services Comparison * Handles data fetching, table generation, search functionality, and comparison features */ // Class to handle table-related operations class TableManager { /** * @param {string} containerId - ID of the table container element * @param {string} searchInputId - ID of the search input element * @param {string} clearIconId - ID of the clear search icon element */ constructor(containerId, searchInputId, clearIconId) { this.container = document.getElementById(containerId); this.searchInput = document.getElementById(searchInputId); this.clearIcon = document.getElementById(clearIconId); this.setupSearchFunctionality(); } /** * Generates a table from provided data * @param {Object} data - Table data object * @returns {void} */ generateTable(data) { if (!data || Object.keys(data).length === 0) { this.container.innerHTML = '

No data available.

'; return; } const providers = Object.keys(data[Object.keys(data)[0]]); const tableHTML = ` ${providers.map(provider => ``).join('')} ${Object.entries(data).map(([host, providerData]) => ` ${providers.map(provider => ` `).join('')} `).join('')}
Service Name${provider}
${host} ${providerData[provider] === 'yes' ? '✅' : '❌'}
`; this.container.innerHTML = tableHTML; } /** * Sets up search functionality for the table * @private */ setupSearchFunctionality() { this.searchInput?.addEventListener('input', () => { const searchTerm = this.searchInput.value.toLowerCase(); const rows = this.container.querySelectorAll('table tbody tr'); this.clearIcon.style.display = searchTerm ? 'block' : 'none'; rows.forEach(row => { const serviceName = row.querySelector('td:first-child')?.textContent.toLowerCase(); row.style.display = serviceName?.includes(searchTerm) ? '' : 'none'; }); }); this.clearIcon?.addEventListener('click', () => { this.searchInput.value = ''; this.clearIcon.style.display = 'none'; this.searchInput.dispatchEvent(new Event('input')); }); } } // Class to handle comparison functionality class ComparisonManager { /** * @param {string} containerId - ID of the comparison container * @param {string} select1Id - ID of the first provider select element * @param {string} select2Id - ID of the second provider select element * @param {Object} data - Comparison data object */ constructor(containerId, select1Id, select2Id, data) { this.container = document.getElementById(containerId); this.select1 = document.getElementById(select1Id); this.select2 = document.getElementById(select2Id); this.data = data; this.setupEventListeners(); this.populateDropdowns(); } /** * Populates provider dropdowns with available options * @private */ populateDropdowns() { const providers = Object.keys(this.data[Object.keys(this.data)[0]]); [this.select1, this.select2].forEach(select => { providers.forEach(provider => { const option = document.createElement('option'); option.value = provider; option.textContent = provider; select.appendChild(option); }); }); } /** * Generates comparison table for selected providers * @private */ generateCompareTable() { const provider1 = this.select1.value; const provider2 = this.select2.value; if (!provider1 || !provider2) return; const tableHTML = ` ${Object.entries(this.data).map(([host, providerData]) => ` `).join('')}
Service Name ${provider1} ${provider2}
${host} ${providerData[provider1] === 'yes' ? '✅' : '❌'} ${providerData[provider2] === 'yes' ? '✅' : '❌'}
`; this.container.innerHTML = tableHTML; this.container.style.display = 'block'; this.setupCloseButton(); } /** * Sets up event listeners for comparison functionality * @private */ setupEventListeners() { [this.select1, this.select2].forEach(select => { select?.addEventListener('change', () => this.generateCompareTable()); }); } /** * Sets up close button functionality * @private */ setupCloseButton() { document.getElementById('close-compare')?.addEventListener('click', () => { this.container.style.display = 'none'; }); } } // Class to handle pricing table generation class PricingManager { /** * @param {string} containerId - ID of the pricing section container */ constructor(containerId) { this.container = document.getElementById(containerId); } /** * Generates pricing table from provided data * @param {Object} data - Pricing data object */ generatePricingTable(data) { if (!data?.plans?.length) { this.container.innerHTML = '

Error: Invalid pricing data structure.

'; return; } const services = Object.keys(data.plans[0]).filter(key => key !== 'name'); const tableHTML = ` ${services.map(service => ``).join('')} ${data.plans.map(plan => ` ${services.map(service => ``).join('')} `).join('')}
Plans${service}
${plan.name}${plan[service]}
`; this.container.innerHTML = tableHTML; } } // Main application initialization document.addEventListener('DOMContentLoaded', async () => { // Initialize table managers const fileHostsTable = new TableManager( 'file-hosts-table-container', 'host-search-input', 'clear-host-search' ); const adultHostsTable = new TableManager( 'adult-hosts-table-container', 'adult-host-search-input', 'clear-adult-host-search' ); const pricingManager = new PricingManager('pricing'); try { // Fetch all required data concurrently const [fileHostsData, adultHostsData, pricingData] = await Promise.all([ fetch('./json/file-hosts.json').then(res => res.json()), fetch('./json/adult-hosts.json').then(res => res.json()), fetch('./json/pricing.json').then(res => res.json()) ]); // Generate tables and initialize comparison fileHostsTable.generateTable(fileHostsData); adultHostsTable.generateTable(adultHostsData); pricingManager.generatePricingTable(pricingData); // Initialize comparison manager new ComparisonManager( 'compare-table-container', 'provider1', 'provider2', fileHostsData ); } catch (error) { console.error('Error initializing application:', error); const errorMessage = '

Error loading data. Please try again later.

'; fileHostsTable.container.innerHTML = errorMessage; adultHostsTable.container.innerHTML = errorMessage; pricingManager.container.innerHTML = errorMessage; } });