fix: open desktop browser popups in place

Loads target=_blank links inside the context panel browser
Handles webview popup navigation from Electron
This commit is contained in:
Bohdan Triapitsyn
2026-05-30 02:04:32 +03:00
parent f9e9f30873
commit 2b4b963f24
2 changed files with 67 additions and 0 deletions
+23
View File
@@ -3062,6 +3062,29 @@ contextMenu({
showCopyLink: true,
});
const loadUrlInsideWebContents = (contents, rawUrl) => {
try {
const url = new URL(rawUrl);
if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;
if (contents.isDestroyed()) return false;
void contents.loadURL(url.toString()).catch((error) => {
log.warn('[webview] failed to load popup URL in place:', error);
});
return true;
} catch {
return false;
}
};
app.on('web-contents-created', (_event, contents) => {
if (contents.getType() !== 'webview') return;
contents.setWindowOpenHandler(({ url }) => {
loadUrlInsideWebContents(contents, url);
return { action: 'deny' };
});
});
// All desktop_* IPC and dialog:open run with full Electron main privileges
// (fs access, shell.openPath, spawn, app.relaunch, …). The preload shim is
// injected into every webContents in the window, including remote hosts the
@@ -452,6 +452,40 @@ const DESKTOP_BROWSER_CANCEL_INSPECT_SCRIPT = `(() => {
if (overlay) overlay.remove();
})()`;
const DESKTOP_BROWSER_SAME_WEBVIEW_NAVIGATION_SCRIPT = `(() => {
if (window.__openchamberSameWebviewNavigationInstalled) return;
window.__openchamberSameWebviewNavigationInstalled = true;
const navigate = (rawUrl) => {
if (typeof rawUrl !== 'string' || rawUrl.length === 0) return false;
try {
const url = new URL(rawUrl, window.location.href);
if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;
window.location.assign(url.href);
return true;
} catch (_error) {
return false;
}
};
const originalOpen = window.open.bind(window);
window.open = (url, target, features) => {
if (navigate(url)) return null;
return originalOpen(url, target, features);
};
document.addEventListener('click', (event) => {
if (event.defaultPrevented) return;
const target = event.target;
if (!(target instanceof Element)) return;
const anchor = target.closest('a[target="_blank"][href]');
if (!(anchor instanceof HTMLAnchorElement)) return;
if (!navigate(anchor.href)) return;
event.preventDefault();
event.stopPropagation();
}, true);
})()`;
const normalizeBrowserUrl = (value: string): string => {
const trimmed = value.trim();
if (!trimmed) return 'about:blank';
@@ -1377,11 +1411,18 @@ const DesktopBrowserPane: React.FC<DesktopBrowserPaneProps> = ({ initialUrl, dir
}
};
const installSameWebviewNavigation = () => {
try {
webview.executeJavaScript?.(DESKTOP_BROWSER_SAME_WEBVIEW_NAVIGATION_SCRIPT, true).catch(() => {});
} catch { /* webview not ready */ }
};
webview.addEventListener('did-navigate', onNavigate);
webview.addEventListener('did-navigate-in-page', onNavigate);
webview.addEventListener('did-start-loading', onStartLoading);
webview.addEventListener('did-stop-loading', onStopLoading);
webview.addEventListener('new-window', onNewWindow);
webview.addEventListener('dom-ready', installSameWebviewNavigation);
// Check current loading state imperatively — we may have missed the event
try {
@@ -1390,6 +1431,7 @@ const DesktopBrowserPane: React.FC<DesktopBrowserPaneProps> = ({ initialUrl, dir
syncUrl();
}
} catch { /* webview not ready */ }
installSameWebviewNavigation();
return () => {
if (loadingTimerRef.current) clearTimeout(loadingTimerRef.current);
@@ -1398,6 +1440,7 @@ const DesktopBrowserPane: React.FC<DesktopBrowserPaneProps> = ({ initialUrl, dir
webview.removeEventListener('did-start-loading', onStartLoading);
webview.removeEventListener('did-stop-loading', onStopLoading);
webview.removeEventListener('new-window', onNewWindow);
webview.removeEventListener('dom-ready', installSameWebviewNavigation);
};
}, [persistUrl]);
@@ -1547,6 +1590,7 @@ const DesktopBrowserPane: React.FC<DesktopBrowserPaneProps> = ({ initialUrl, dir
ref={webviewRef}
src={normalizeBrowserUrl(initialUrl)}
partition="persist:openchamber-browser"
allowpopups
style={{ width: '100%', height: '100%', border: 'none' }}
/>
{(!currentUrl || currentUrl === 'about:blank') && !isLoading ? (