diff --git a/chrome.html b/chrome.html index dc16609..d477449 100644 --- a/chrome.html +++ b/chrome.html @@ -267,7 +267,9 @@ $("search").addEventListener("keydown", (e) => { if (e.key === "Enter") { const q = $("search").value.trim(); if (q) T.search(q); } }); $("back").onclick = () => T.back(); $("fwd").onclick = () => T.forward(); - $("reload").onclick = () => T.reload(); + // Shift-click on the reload button = hard reload (bypass cache), same + // convention as Chrome/Firefox. Keyboard alternative: Ctrl+Shift+R. + $("reload").onclick = (e) => T.reload(e.shiftKey); $("home").onclick = () => T.goHome(); $("logo").onclick = () => T.openSettings(); $("secbadge").onclick = () => { const r = $("secbadge").getBoundingClientRect(); T.toggleSiteInfo({ x: Math.round(r.left), y: Math.round(r.bottom + 4) }); }; @@ -511,7 +513,7 @@ $("loadbar").classList.toggle("on", !!d.loading); const rb = $("reload"); if (d.loading) { rb.innerHTML = STOP_SVG; rb.title = "Stop"; rb.onclick = () => T.stop(); } - else { rb.innerHTML = RELOAD_SVG; rb.title = "Reload"; rb.onclick = () => T.reload(); } + else { rb.innerHTML = RELOAD_SVG; rb.title = "Reload (Shift-click: hard reload)"; rb.onclick = (ev) => T.reload(ev.shiftKey); } if (document.activeElement !== $("url")) $("url").value = d.url || ""; current.url = d.url || ""; const active = d.tabs.find((t) => t.active); diff --git a/main.js b/main.js index 15b2781..c8d459d 100644 --- a/main.js +++ b/main.js @@ -1761,7 +1761,11 @@ ipcMain.handle("home-cards-set", (e, cards) => { if (!isHomePageSender(e.sende ipcMain.handle("home-cards-reset", (e) => { if (!isHomePageSender(e.sender)) return false; try { fs.unlinkSync(homeCardsFile()); } catch {} return true; }); ipcMain.handle("go-back", () => { const wc = activeTab()?.view.webContents; if (wc?.navigationHistory.canGoBack()) wc.navigationHistory.goBack(); }); ipcMain.handle("go-forward", () => { const wc = activeTab()?.view.webContents; if (wc?.navigationHistory.canGoForward()) wc.navigationHistory.goForward(); }); -ipcMain.handle("reload", () => activeTab()?.view.webContents.reload()); +ipcMain.handle("reload", (_e, hard) => { + const wc = activeTab()?.view.webContents; + if (!wc) return; + try { hard ? wc.reloadIgnoringCache() : wc.reload(); } catch {} +}); ipcMain.handle("stop", () => { const t = activeTab(); try { t?.view.webContents.stop(); } catch {} setLoading(t, false); }); ipcMain.handle("toggle-tor", () => { torState === "off" ? startTor() : stopTor(); }); ipcMain.handle("open-settings", () => { const ex = tabs.find((t) => t.settings); if (ex) return setActive(ex.id); createTab(null, { settings: true }); }); @@ -2543,15 +2547,35 @@ ipcMain.handle("bcnr:getRecordVersion", async (_e, name) => { } catch { return null; } }); -// Ctrl+Shift+M anywhere in Theseus opens (or focuses) the Messages panel. -// One app-level hook: no per-window wiring, no per-tab plumbing, matches -// however many WebContents Theseus ends up owning. +// App-level keyboard shortcuts. One `web-contents-created` hook covers +// every WebContents (chrome, tab views, overlays) without per-view wiring. +// Reload/hard-reload always target the active tab, regardless of which +// view received the key (URL bar focused, overlay focused, etc.), so the +// user's mental model matches every browser they've ever used. app.on("web-contents-created", (_event, wc) => { wc.on("before-input-event", (e, input) => { if (input.type !== "keyDown") return; + // Ctrl+Shift+M -> Messages panel if (input.control && input.shift && (input.key === "M" || input.key === "m")) { openHermesWindow(); - e.preventDefault(); + return e.preventDefault(); + } + // Reload: F5 or Ctrl+R soft; Ctrl+F5 or Ctrl+Shift+R hard (bypass cache). + // Chromium's built-in accelerators are unreliable once the app menu is + // null (Menu.setApplicationMenu(null) above), and none of them cover + // the hard variants anyway — so we wire all four explicitly. + const isR = input.key === "R" || input.key === "r"; + const isF5 = input.key === "F5"; + if (isF5 || (input.control && isR)) { + const t = activeTab(); + if (t && !t.settings) { + const hard = (input.control && input.shift && isR) || (input.control && isF5); + try { + if (hard) t.view.webContents.reloadIgnoringCache(); + else t.view.webContents.reload(); + } catch {} + } + return e.preventDefault(); } }); }); diff --git a/preload.js b/preload.js index e3dc7ea..f024d3d 100644 --- a/preload.js +++ b/preload.js @@ -20,7 +20,7 @@ contextBridge.exposeInMainWorld("theseus", { goHome: () => ipcRenderer.invoke("go-home"), back: () => ipcRenderer.invoke("go-back"), forward: () => ipcRenderer.invoke("go-forward"), - reload: () => ipcRenderer.invoke("reload"), + reload: (hard) => ipcRenderer.invoke("reload", !!hard), stop: () => ipcRenderer.invoke("stop"), toggleTor: () => ipcRenderer.invoke("toggle-tor"), openSettings: () => ipcRenderer.invoke("open-settings"),