From e8dc253f03fdea001c3a07b6234162760e7c320b Mon Sep 17 00:00:00 2001 From: Andrew Zambazos Date: Thu, 31 Jul 2025 22:40:37 +1200 Subject: [PATCH] Improve theme and navigation IPC between pages Enhanced inter-process communication for theme updates and navigation between home, settings, and main browser pages. Theme changes in settings now propagate to home via Electron IPC and postMessage fallback. Navigation requests from home and other webviews are handled more robustly, supporting both Electron IPC and postMessage. Also refactored tab creation and improved event handling for better reliability. --- renderer/customization.js | 9 +++-- renderer/home.html | 43 ++++++++++++------------ renderer/home.js | 18 ++++++++-- renderer/script.js | 69 ++++++++++++++++++++++++++++----------- renderer/settings.js | 12 +++++-- site-history.json | 5 +++ 6 files changed, 109 insertions(+), 47 deletions(-) diff --git a/renderer/customization.js b/renderer/customization.js index eaf1c9d..5af1b36 100644 --- a/renderer/customization.js +++ b/renderer/customization.js @@ -478,10 +478,13 @@ class BrowserCustomizer { applyThemeToPages() { // This will be called to apply theme to home.html and other pages - // We'll store the theme and let other pages load it this.saveTheme(); - - // If we have access to other windows/frames, apply there too + + // Send theme update to host (for settings webview) + if (window.electronAPI && typeof window.electronAPI.sendToHost === 'function') { + window.electronAPI.sendToHost('theme-update', this.currentTheme); + } + // Fallback: send via postMessage (for iframe embedding) try { if (window.parent && window.parent !== window) { window.parent.postMessage({ diff --git a/renderer/home.html b/renderer/home.html index 35e505d..b7c6125 100644 --- a/renderer/home.html +++ b/renderer/home.html @@ -76,36 +76,39 @@ diff --git a/renderer/home.js b/renderer/home.js index 9e64858..ef5c738 100644 --- a/renderer/home.js +++ b/renderer/home.js @@ -87,11 +87,16 @@ function renderBookmarks() { // Navigate via IPC to host page box.onclick = () => { + const url = b.url; if (window.electronAPI && typeof window.electronAPI.sendToHost === 'function') { - window.electronAPI.sendToHost('navigate', b.url); + window.electronAPI.sendToHost('navigate', url); } else { console.error('Unable to send navigation IPC to host'); } + // Fallback: post message to embedding page + if (window.parent && typeof window.parent.postMessage === 'function') { + window.parent.postMessage({ type: 'navigate', url }, '*'); + } }; box.appendChild(label); @@ -205,7 +210,16 @@ searchBtn.addEventListener('click', () => { const searchEngineUrl = searchEngines[selectedSearchEngine]; target = `${searchEngineUrl}${encodeURIComponent(input)}`; } - window.location.href = target; + // Always send navigation request to host + if (window.electronAPI && typeof window.electronAPI.sendToHost === 'function') { + window.electronAPI.sendToHost('navigate', target); + return; + } + // Fallback: post message to embedding page + if (window.parent && typeof window.parent.postMessage === 'function') { + window.parent.postMessage({ type: 'navigate', url: target }, '*'); + return; + } }); searchInput.addEventListener('keydown', e => { diff --git a/renderer/script.js b/renderer/script.js index f1f326b..076b352 100644 --- a/renderer/script.js +++ b/renderer/script.js @@ -75,7 +75,7 @@ async function saveBookmarks(newBookmarks) { // Load bookmarks when the script starts loadBookmarks(); -// Home tab will be created on DOMContentLoaded event +// Initial home tab will be created on DOMContentLoaded // Remove iframe-based navigation listener (using webview IPC now) @@ -108,6 +108,8 @@ function createTab(inputUrl) { }; tabs.push(tab); setActiveTab(id); + // Render the tab bar so the new home tab appears + renderTabs(); return id; } @@ -116,16 +118,6 @@ function createTab(inputUrl) { console.log('[DEBUG] createTab() resolvedUrl =', resolvedUrl); const webview = document.createElement('webview'); - - webview.id = `tab-${id}`; - webview.src = resolvedUrl; - webview.setAttribute('allowpopups', ''); - webview.setAttribute('partition', 'persist:default'); - webview.setAttribute('preload', '../preload.js'); - webview.classList.add('active'); - - webview.addEventListener('did-fail-load', handleLoadFail(id)); - webview.addEventListener('page-title-updated', e => updateTabMetadata(id, 'title', e.title)); webview.addEventListener('page-favicon-updated', e => { if (e.favicons.length > 0) updateTabMetadata(id, 'favicon', e.favicons[0]); }); @@ -186,6 +178,14 @@ function createTab(inputUrl) { createTab(e.url); }); + // After creating dynamic webview: + webview.addEventListener('ipc-message', e => { + if (e.channel === 'theme-update') { + const home = document.getElementById('home-webview'); + if (home) home.send('theme-update', ...e.args); + } + }); + webviewsEl.appendChild(webview); tabs.push({ @@ -324,6 +324,14 @@ function convertHomeTabToWebview(tabId, inputUrl, resolvedUrl) { createTab(e.url); }); + // After creating dynamic webview: + webview.addEventListener('ipc-message', e => { + if (e.channel === 'theme-update') { + const home = document.getElementById('home-webview'); + if (home) home.send('theme-update', ...e.args); + } + }); + // Add webview to DOM webviewsEl.appendChild(webview); @@ -486,7 +494,9 @@ function renderTabs() { }); // add the “+” at the end const plus = document.createElement('div'); - plus.className = 'tab'; plus.textContent = '+'; plus.onclick = () => createTab(); + plus.className = 'tab'; + plus.textContent = '+'; + plus.onclick = () => createTab(); frag.appendChild(plus); tabBarEl.innerHTML = ''; // clear once @@ -533,10 +543,9 @@ function reload() { } } - +// Function to open the Settings page function openSettings() { - urlBox.value = 'browser://settings'; - navigate(); + createTab('browser://settings'); } // Toggle menu dropdown @@ -562,16 +571,38 @@ window.addEventListener('DOMContentLoaded', () => { } createTab(); - // Listen for navigation IPC messages from home webview - const homeWebview = document.getElementById('home-webview'); - if (homeWebview) { - homeWebview.addEventListener('ipc-message', e => { + // Handle IPC messages from the static home webview (bookmarks navigation) + const staticHome = document.getElementById('home-webview'); + if (staticHome) { + staticHome.addEventListener('ipc-message', (e) => { if (e.channel === 'navigate' && e.args[0]) { urlBox.value = e.args[0]; navigate(); } }); } + // Listen for IPC messages from other webviews (e.g., settings) + webviewsEl.addEventListener('ipc-message', (e) => { + // Navigation messages from home or other pages + if (e.channel === 'navigate' && e.args[0]) { + urlBox.value = e.args[0]; + navigate(); + } + // Theme update from settings webview + if (e.channel === 'theme-update' && e.args[0]) { + const homeWebview = document.getElementById('home-webview'); + if (homeWebview) { + homeWebview.send('theme-update', e.args[0]); + } + } + }); + // Fallback: listen for postMessage navigations from home webview + window.addEventListener('message', (event) => { + if (event.data && event.data.type === 'navigate' && event.data.url) { + urlBox.value = event.data.url; + navigate(); + } + }); // only now bind the reload button (guaranteed to exist) const reloadBtn = document.getElementById('reload-btn'); reloadBtn.addEventListener('click', reload); diff --git a/renderer/settings.js b/renderer/settings.js index 5b4b870..31c7d43 100644 --- a/renderer/settings.js +++ b/renderer/settings.js @@ -1,4 +1,5 @@ // Use require('electron') since webviews have nodeIntegrationInSubFrames: true +// In settings webview we use the same preload API as main windows const { ipcRenderer } = require('electron'); const clearBtn = document.getElementById('clear-data-btn'); @@ -14,11 +15,10 @@ function showStatus(message) { } clearBtn.onclick = async () => { - statusDiv.classList.remove('hidden'); // Show spinner immediately - statusText.textContent = 'Clearing all browser data...'; // Update text while clearing + statusDiv.classList.remove('hidden'); + statusText.textContent = 'Clearing all browser data...'; try { - // Invoke the main process to clear cookies, local storage, and cache const ok = await ipcRenderer.invoke('clear-browser-data'); showStatus(ok ? 'All browser data and bookmarks cleared!' @@ -26,5 +26,11 @@ clearBtn.onclick = async () => { } catch (error) { console.error('Error clearing browser data:', error); showStatus('An error occurred while clearing data.'); + } finally { + // Send theme update to host after clearing + const currentTheme = window.browserCustomizer ? window.browserCustomizer.currentTheme : null; + if (currentTheme && window.electronAPI && typeof window.electronAPI.sendToHost === 'function') { + window.electronAPI.sendToHost('theme-update', currentTheme); + } } }; diff --git a/site-history.json b/site-history.json index 7223fd2..53389b7 100644 --- a/site-history.json +++ b/site-history.json @@ -2,6 +2,11 @@ "https://www.youtube.com/", "https://github.com/", "file:///X:/Projects/Code/NebulaBrowser/renderer/index.html", + "https://youtube.com/", + "file:///X:/Projects/Code/NebulaBrowser/renderer/index.html", + "https://youtube.com/", + "file:///X:/Projects/Code/NebulaBrowser/renderer/index.html", + "file:///X:/Projects/Code/NebulaBrowser/renderer/index.html", "file:///X:/Projects/Code/NebulaBrowser/renderer/index.html", "file:///X:/Projects/Code/NebulaBrowser/renderer/index.html", "file:///X:/Projects/Code/NebulaBrowser/renderer/index.html",