From 074e3b7becbbff246bbcd8429021f6bbf092fedd Mon Sep 17 00:00:00 2001 From: Guangda Zhang Date: Mon, 8 Jun 2026 21:52:28 -0700 Subject: [PATCH] fix: use cmd/ctrl+enter to open search result in a new tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shift+Enter (shipped in the previous change) opened a new *window* rather than a new tab: window.open() reads the live keyboard modifiers, and a held Shift is the OS "new window" convention. Bind the new-tab action to Cmd/Ctrl+Enter instead, mirroring the Cmd/Ctrl+Click affordance on result rows — Cmd/Ctrl maps to "new tab", so window.open() does the right thing with no workaround. Shift+Enter is no longer bound. The modal stays open after opening a tab so you can fan out to several files. Hint updated to a platform-aware "⌘↵ / Ctrl+↵ new tab". Co-Authored-By: Claude Opus 4.8 (1M context) --- e2e/tests/file-search.spec.ts | 6 ++---- src/assets/static/js/file-search.js | 25 +++++++++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/e2e/tests/file-search.spec.ts b/e2e/tests/file-search.spec.ts index 64306c7..d14c91e 100644 --- a/e2e/tests/file-search.spec.ts +++ b/e2e/tests/file-search.spec.ts @@ -69,7 +69,7 @@ test.describe("file search", () => { await expect(page).toHaveURL(/\/README\.md$/); }); - test("Shift+Enter opens the selected file in a new tab, leaving the modal open", async ({ + test("Cmd+Enter opens the selected file in a new tab, leaving the modal open", async ({ page, }) => { await page.goto("/README.md"); @@ -79,13 +79,11 @@ test.describe("file search", () => { const dialog = page.locator("dialog.mdbrowse-search"); const [popup] = await Promise.all([ page.context().waitForEvent("page"), - page.keyboard.press("Shift+Enter"), + page.keyboard.press("Meta+Enter"), ]); await popup.waitForLoadState(); await expect(popup).toHaveURL(/\/runbooks\/deploy\.md$/); - - // Original tab stayed put and the modal is still open for the next pick. await expect(page).toHaveURL(/\/README\.md$/); await expect(dialog).toBeVisible(); }); diff --git a/src/assets/static/js/file-search.js b/src/assets/static/js/file-search.js index 95b5b3d..84640cd 100644 --- a/src/assets/static/js/file-search.js +++ b/src/assets/static/js/file-search.js @@ -64,9 +64,11 @@ moveSelection(-1); } else if (e.key === "Enter") { e.preventDefault(); - // Shift+Enter opens the result in a new tab and leaves the modal open, - // so you can fan out to several files in one pass. - navigateToSelected(e.shiftKey); + // Cmd/Ctrl+Enter opens the result in a new tab and leaves the modal open, + // so you can fan out to several files in one pass. Mirrors the + // Cmd/Ctrl+Click affordance on result rows (and the new-tab=Cmd/Ctrl + // convention, vs Shift which the browser reads as "new window"). + navigateToSelected(e.metaKey || e.ctrlKey); } // Escape is handled natively by . }); @@ -152,8 +154,11 @@ // Navigate to `path`. When `newTab` is truthy, open it in a new tab and keep // the current page (and the search modal) intact; otherwise replace the - // current page. window.open() here runs synchronously inside a keydown/click - // handler, so it counts as a user gesture and won't trip popup blockers. + // current page. window.open(url, "_blank") opens a tab by default — the only + // modifier that the browser reinterprets as "new window" is Shift, which we + // intentionally don't bind (new-tab is Cmd/Ctrl, matching Cmd/Ctrl+Click). + // Runs synchronously inside the keydown/click handler, so it's a user gesture + // and won't trip popup blockers. function open(path, newTab) { if (newTab) window.open(path, "_blank"); else location.assign(path); @@ -211,13 +216,21 @@ // Expose for tests. window.__mdbrowseSearch = { filter: filter, score: score }; + // Used only to pick the modifier glyph in the hint (⌘ vs Ctrl). + function isMacLike() { + var p = (navigator.platform || navigator.userAgent || "").toLowerCase(); + return p.indexOf("mac") !== -1 || p.indexOf("iphone") !== -1 || p.indexOf("ipad") !== -1; + } + function buildDialog() { var d = document.createElement("dialog"); d.className = "mdbrowse-search"; d.innerHTML = '
' + '' + - '⇧↵ new tab · Esc close' + + '' + + (isMacLike() ? "⌘↵" : "Ctrl+↵") + + " new tab · Esc close" + "
" + '
    ' + '';