class PopupManager { constructor() { this.currentTab = null; this.currentDomain = null; this.currentConfig = null; this.init(); } async init() { await this.loadCurrentTab(); await this.loadConfig(); await this.loadProfiles(); this.setupUI(); this.setupEventListeners(); } async loadCurrentTab() { try { const tabs = await browser.tabs.query({ active: true, currentWindow: true }); this.currentTab = tabs[0]; if (this.currentTab.url) { this.currentDomain = this.extractDomain(this.currentTab.url); document.getElementById('current-domain').textContent = this.currentDomain; } } catch (error) { console.error('Failed to load current tab:', error); document.getElementById('current-domain').textContent = 'Unknown domain'; } } extractDomain(url) { try { const urlObj = new URL(url); return urlObj.hostname.replace(/^www\./, ''); } catch (e) { return null; } } async loadConfig() { try { const response = await browser.runtime.sendMessage({ action: 'getConfig' }); const config = response.config || { domains: {} }; this.applyTheme(config.settings && config.settings.theme); this.currentConfig = this.currentDomain && config.domains ? config.domains[this.currentDomain] || null : null; } catch (error) { console.error('Failed to load config:', error); this.currentConfig = null; } } applyTheme(theme) { document.documentElement.dataset.theme = ['light', 'dark', 'system'].includes(theme) ? theme : 'system'; } async loadProfiles() { try { const response = await browser.runtime.sendMessage({ action: 'getProfiles' }); const profiles = response.profiles || {}; this.updateProfileSelect(profiles); } catch (error) { console.error('Failed to load profiles:', error); } } updateProfileSelect(profiles) { const select = document.getElementById('popup-profile-select'); // Clear select, keeping only default option select.innerHTML = ''; // Add profiles Object.keys(profiles).sort().forEach(profileName => { const option = document.createElement('option'); option.value = profileName; option.textContent = profileName; select.appendChild(option); }); } // Fill form with profile data fillFormFromProfile(profileName) { if (!profileName) { // If empty profile selected, do nothing return; } // Get profile data browser.runtime.sendMessage({ action: 'getProfile', profileName }) .then(response => { const profile = response.profile; if (profile) { // Fill form fields document.getElementById('popup-proxy-type').value = profile.type || 'http'; document.getElementById('popup-proxy-host').value = profile.host || ''; document.getElementById('popup-proxy-port').value = profile.port || ''; document.getElementById('popup-proxy-username').value = profile.username || ''; document.getElementById('popup-proxy-password').value = profile.password || ''; } }) .catch(error => { console.error('Failed to load profile for form:', error); }); } setupUI() { const enableCheckbox = document.getElementById('enable-proxy'); const proxyForm = document.getElementById('proxy-form'); const noProxyInfo = document.getElementById('no-proxy-info'); if (this.currentConfig) { // Proxy configured for this domain enableCheckbox.checked = Boolean(this.currentConfig.enabled); enableCheckbox.disabled = false; // Show/hide form based on checkbox state this.updateFormVisibility(enableCheckbox.checked); noProxyInfo.classList.add('hidden'); // Populate form this.populateForm(); } else { // Proxy not configured enableCheckbox.checked = false; enableCheckbox.disabled = !this.currentDomain; proxyForm.classList.add('hidden'); noProxyInfo.classList.remove('hidden'); } } updateFormVisibility(showForm) { const proxyForm = document.getElementById('proxy-form'); proxyForm.classList.toggle('hidden', !showForm); } populateForm() { if (!this.currentConfig) return; document.getElementById('popup-proxy-type').value = this.currentConfig.type || 'http'; document.getElementById('popup-proxy-host').value = this.currentConfig.host || ''; document.getElementById('popup-proxy-port').value = this.currentConfig.port || ''; document.getElementById('popup-proxy-username').value = this.currentConfig.username || ''; document.getElementById('popup-proxy-password').value = this.currentConfig.password || ''; } async saveConfig() { if (!this.currentDomain) return; // Collect form data const domainConfig = { type: document.getElementById('popup-proxy-type').value, host: document.getElementById('popup-proxy-host').value.trim(), port: parseInt(document.getElementById('popup-proxy-port').value, 10), username: document.getElementById('popup-proxy-username').value.trim() || null, password: document.getElementById('popup-proxy-password').value || null, enabled: document.getElementById('enable-proxy').checked }; // Validation if (!domainConfig.host || !domainConfig.port) { this.showError('Host and port are required'); return false; } if (domainConfig.port < 1 || domainConfig.port > 65535) { this.showError('Port must be between 1 and 65535'); return false; } try { // Use centralized API for domain update const response = await browser.runtime.sendMessage({ action: 'updateDomain', domain: this.currentDomain, domainConfig: domainConfig }); return response.success; } catch (error) { console.error('Failed to save config:', error); this.showError('Failed to save configuration'); return false; } } async removeDomainConfig() { try { // Use centralized API for domain removal const response = await browser.runtime.sendMessage({ action: 'removeDomain', domain: this.currentDomain }); return response.success; } catch (error) { console.error('Failed to remove config:', error); return false; } } async toggleProxy(enabled) { if (!this.currentDomain) return; try { const response = await browser.runtime.sendMessage({ action: 'toggleProxy', domain: this.currentDomain, enabled: enabled }); if (!response.success) { // If domain not configured, show message this.showError('Domain not configured. Use "Apply & Reload" to configure proxy first.'); // Return checkbox to previous state document.getElementById('enable-proxy').checked = !enabled; } } catch (error) { console.error('Failed to toggle proxy:', error); this.showError('Failed to toggle proxy'); // Return checkbox to previous state document.getElementById('enable-proxy').checked = !enabled; } } async applyAndReload() { const success = await this.saveConfig(); if (success && this.currentTab) { // Reload tab await browser.tabs.reload(this.currentTab.id); // Close popup window.close(); } } showError(message) { // Simple error display implementation const errorDiv = document.createElement('div'); errorDiv.className = 'error-message'; errorDiv.textContent = message; errorDiv.style.cssText = ` background-color: #f8d7da; color: #721c24; padding: 10px; margin: 10px 0; border-radius: 4px; border: 1px solid #f5c6cb; `; const main = document.querySelector('.popup-main'); main.insertBefore(errorDiv, main.firstChild); setTimeout(() => errorDiv.remove(), 3000); } setupEventListeners() { // Proxy toggle (quick enable/disable) document.getElementById('enable-proxy').addEventListener('change', async (e) => { const enabled = e.target.checked; this.updateFormVisibility(enabled); // Show/hide form // A new domain has no stored configuration yet; Apply & Reload saves it. if (this.currentConfig) { await this.toggleProxy(enabled); } }); // Apply settings document.getElementById('apply-proxy').addEventListener('click', () => { this.applyAndReload(); }); // Open settings document.getElementById('open-options').addEventListener('click', () => { browser.runtime.openOptionsPage(); window.close(); }); // Show/hide password document.querySelector('.toggle-password').addEventListener('click', (e) => { const input = document.getElementById('popup-proxy-password'); const type = input.type === 'password' ? 'text' : 'password'; input.type = type; e.target.textContent = type === 'password' ? '👁' : '👁️‍🗨️'; }); // Handle Enter in form document.querySelectorAll('input').forEach(input => { input.addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.applyAndReload(); } }); }); // Fill form from profile document.getElementById('popup-profile-select').addEventListener('change', (e) => { this.fillFormFromProfile(e.target.value); }); } } // Initialization document.addEventListener('DOMContentLoaded', () => { new PopupManager(); });