Spaces:
Running
Running
| // 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 = '<i data-feather="x" class="w-3 h-3"></i>'; | |
| 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); | |
| } | |
| }); | |
| }); |