// Tab management class TabManager { constructor() { this.tabs = []; this.activeTabId = null; this.tabCounter = 0; this.init(); } init() { this.tabBar = document.getElementById('tab-bar'); this.browserContainer = document.getElementById('browser-container'); this.newTabBtn = document.getElementById('new-tab-btn'); this.newTabBtn.addEventListener('click', () => this.addTab()); // Add initial tab this.addTab(); } addTab(url = '') { const tabId = ++this.tabCounter; const tab = { id: tabId, url: url || '', title: 'New Tab', favicon: '', iframe: document.createElement('iframe') }; tab.iframe.className = 'w-full h-full rounded-lg hidden'; tab.iframe.sandbox = 'allow-same-origin allow-scripts allow-popups allow-forms'; this.browserContainer.appendChild(tab.iframe); const tabElement = document.createElement('button'); tabElement.className = 'px-4 py-1 rounded-t-lg tab-inactive flex items-center space-x-2 smooth-transition'; tabElement.dataset.tabId = tabId; const favicon = document.createElement('img'); favicon.className = 'w-4 h-4'; favicon.src = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEyIDJDNi40ODcgMiAyIDYuNDg3IDIgMTJzNC40ODcgMTAgMTAgMTAgMTAtNC40ODcgMTAtMTBTMTcuNTEzIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6IiBmaWxsPSJ3aGl0ZSIvPjwvc3ZnPg=='; favicon.alt = ''; const title = document.createElement('span'); title.className = 'truncate max-w-xs'; title.textContent = 'New Tab'; const closeBtn = document.createElement('button'); closeBtn.className = 'ml-2 hover:text-red-400'; closeBtn.innerHTML = ''; closeBtn.addEventListener('click', (e) => { e.stopPropagation(); this.closeTab(tabId); }); tabElement.appendChild(favicon); tabElement.appendChild(title); tabElement.appendChild(closeBtn); tabElement.addEventListener('click', () => this.switchTab(tabId)); this.tabBar.insertBefore(tabElement, this.newTabBtn); this.tabs.push({ ...tab, element: tabElement, faviconElement: favicon, titleElement: title }); this.switchTab(tabId); feather.replace(); } switchTab(tabId) { this.tabs.forEach(tab => { const isActive = tab.id === tabId; tab.element.classList.toggle('tab-active', isActive); tab.element.classList.toggle('tab-inactive', !isActive); tab.iframe.classList.toggle('hidden', !isActive); }); this.activeTabId = tabId; const activeTab = this.getActiveTab(); // Focus the iframe if (activeTab.iframe.contentWindow) { activeTab.iframe.contentWindow.focus(); } } closeTab(tabId) { if (this.tabs.length <= 1) { return; // Don't close the last tab } const tabIndex = this.tabs.findIndex(tab => tab.id === tabId); if (tabIndex === -1) return; const tab = this.tabs[tabIndex]; this.browserContainer.removeChild(tab.iframe); this.tabBar.removeChild(tab.element); this.tabs.splice(tabIndex, 1); if (this.activeTabId === tabId) { this.switchTab(this.tabs[Math.max(0, tabIndex - 1)].id); } } getActiveTab() { return this.tabs.find(tab => tab.id === this.activeTabId); } navigateActiveTab(url) { const tab = this.getActiveTab(); if (!tab) return; try { // Simple proxy handling - in a real proxy, you'd need server-side handling tab.iframe.src = url; tab.url = url; tab.titleElement.textContent = 'Loading...'; } catch (error) { console.error('Navigation error:', error); } } } // Initialize the proxy when DOM is loaded document.addEventListener('DOMContentLoaded', () => { const tabManager = new TabManager(); window.tabManager = tabManager; // Make it accessible for debugging // Example of how you might handle URL navigation // In a real implementation, you'd have a proper proxy backend document.getElementById('navigate-btn')?.addEventListener('click', () => { const urlInput = document.getElementById('url-input'); if (urlInput && urlInput.value) { tabManager.navigateActiveTab(urlInput.value); } }); });