diff --git a/docs/app.js b/docs/app.js index 47e3282..c93efcd 100644 --- a/docs/app.js +++ b/docs/app.js @@ -1,173 +1,263 @@ -document.addEventListener('DOMContentLoaded', async () => { - const fileHostsTableContainer = document.getElementById('file-hosts-table-container'); - const hostSearchInput = document.getElementById('host-search-input'); - const clearHostSearchIcon = document.getElementById('clear-host-search'); - const provider1Select = document.getElementById('provider1'); - const provider2Select = document.getElementById('provider2'); - const compareTableContainer = document.getElementById('compare-table-container'); - const closeCompareButton = document.getElementById('close-compare'); +/** + * @fileoverview Main application file for Debrid Services Comparison + * Handles data fetching, table generation, search functionality, and comparison features + */ - const adultHostsTableContainer = document.getElementById('adult-hosts-table-container'); - const adultHostSearchInput = document.getElementById('adult-host-search-input'); - const clearAdultHostSearchIcon = document.getElementById('clear-adult-host-search'); - - const pricingSection = document.getElementById('pricing'); // Targeting the 'Pricing' section - - // Initially hide the comparison table container - compareTableContainer.style.display = 'none'; - - try { - const [fileHostsResponse, adultHostsResponse, pricingResponse] = await Promise.all([ - fetch('./json/file-hosts.json'), - fetch('./json/adult-hosts.json'), - fetch('./json/pricing.json') // Fetching the pricing data - ]); - const fileHostsData = await fileHostsResponse.json(); - const adultHostsData = await adultHostsResponse.json(); - const pricingData = await pricingResponse.json(); // Parsed pricing data - - // Function to generate a table - const generateTable = (data, tableId) => { - const container = document.getElementById(tableId); - let tableHTML = ``; - const providers = Object.keys(data[Object.keys(data)[0]]); - providers.forEach(provider => { - tableHTML += ``; - }); - tableHTML += ''; - - for (const host in data) { - tableHTML += ``; - providers.forEach(provider => { - const status = data[host][provider]; - const icon = status === 'yes' ? '✅' : '❌'; - tableHTML += ``; - }); - tableHTML += ''; - } - tableHTML += '
Service Name${provider}
${host}${icon}
'; - container.innerHTML = tableHTML; - }; - - // Function to generate the pricing table - const generatePricingTable = (pricingData) => { - let tableHTML = ''; - // Extract service names from the first plan object - if (pricingData.plans && pricingData.plans.length > 0) { - const services = Object.keys(pricingData.plans[0]).filter(key => key !== 'name'); - services.forEach(service => { - tableHTML += ``; - }); - tableHTML += ''; - - pricingData.plans.forEach(plan => { - tableHTML += ''; - tableHTML += ``; - services.forEach(service => { - tableHTML += ``; - }); - tableHTML += ''; - }); - - tableHTML += '
Plans${service}
${plan.name}${plan[service]}
'; - pricingSection.innerHTML = tableHTML; - } else { - pricingSection.innerHTML = '

Error: Pricing data structure is incorrect.

'; - } - }; - - // Function to populate provider dropdowns - const populateProviderDropdowns = (data) => { - const providers = Object.keys(data[Object.keys(data)[0]]); - providers.forEach(provider => { - const option1 = document.createElement('option'); - option1.value = provider; - option1.textContent = provider; - provider1Select.appendChild(option1); - - const option2 = document.createElement('option'); - option2.value = provider; - option2.textContent = provider; - provider2Select.appendChild(option2); - }); - }; - - // Function to generate the comparison table - const generateCompareTable = (data, provider1, provider2) => { - let tableHTML = ''; - - for (const host in data) { - const status1 = data[host][provider1]; - const status2 = data[host][provider2]; - const icon1 = status1 === 'yes' ? '✅' : '❌'; - const icon2 = status2 === 'yes' ? '✅' : '❌'; - tableHTML += ``; - } - - tableHTML += '
Service Name' + provider1 + '' + provider2 + '
${host}${icon1}${icon2}
'; - compareTableContainer.innerHTML = `` + tableHTML; - // Re-add the event listener for the close button after it's generated - document.getElementById('close-compare').addEventListener('click', () => { - compareTableContainer.style.display = 'none'; - }); - compareTableContainer.style.display = 'block'; - }; - - // Function for search functionality with clear icon visibility - const setupSearch = (searchInput, clearIcon, tableContainerId) => { - searchInput.addEventListener('input', () => { - const searchTerm = searchInput.value.toLowerCase(); - const rows = document.querySelectorAll(`#${tableContainerId} table tbody tr`); - if (!rows) return; - - // Show/hide clear icon based on input - 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'; - }); - }); - - clearIcon.addEventListener('click', () => { - searchInput.value = ''; - clearIcon.style.display = 'none'; - // Trigger the input event to refresh the table - searchInput.dispatchEvent(new Event('input')); - }); - }; - - // Initial table generation and dropdown population - generateTable(fileHostsData, 'file-hosts-table-container'); - generateTable(adultHostsData, 'adult-hosts-table-container'); - populateProviderDropdowns(fileHostsData); - generatePricingTable(pricingData); // Generate pricing table - - // Setup search for both tables - setupSearch(hostSearchInput, clearHostSearchIcon, 'file-hosts-table-container'); - setupSearch(adultHostSearchInput, clearAdultHostSearchIcon, 'adult-hosts-table-container'); - - // Comparison functionality - const handleCompare = () => { - const provider1 = provider1Select.value; - const provider2 = provider2Select.value; - if (provider1 && provider2) { - generateCompareTable(fileHostsData, provider1, provider2); - } - }; - - provider1Select.addEventListener('change', handleCompare); - provider2Select.addEventListener('change', handleCompare); - - // Close comparison functionality - closeCompareButton.addEventListener('click', () => { - compareTableContainer.style.display = 'none'; - }); - - } catch (error) { - console.error('Error fetching or parsing JSON:', error); - fileHostsTableContainer.innerHTML = '

Error loading file hosts data.

'; - adultHostsTableContainer.innerHTML = '

Error loading adult hosts data.

'; - pricingSection.innerHTML = '

Error loading pricing data.

'; +// 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(); } -}); \ No newline at end of file + + /** + * 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; + } + }); \ No newline at end of file