From 574c0ed59ae4bfd0109fe91c3fedd0d9c6bab9ae Mon Sep 17 00:00:00 2001 From: Local Dev Date: Sat, 29 Aug 2026 22:22:47 +0200 Subject: [PATCH] Theseus: preserve query on link-navigation intercept + immediate address-bar reflect Two related navigation bugs, both surfacing when a page inside a tab tries to submit a search: 1. will-navigate rewriter dropped the query string and fragment. Every dotted host went through navigateTab(id, parsed.hostname + parsed.pathname) which stripped ?q=... The classic-form-GET search engines (Google, Brave, Bing, Startpage, Yandex, Ecosia, Mojeek, ...) all silently landed on their /search endpoint with no query, so no results ever showed. DuckDuckGo only appeared to work because its in-page search uses history.pushState + XHR and never triggered will-navigate to begin with. Fix: pass the whole URL (minus scheme) so query + fragment survive. 2. Address bar showed the previous page's URL until the new page's did-navigate fired. navigateTab called setLoading() -> emitTabs() BEFORE assigning t.url, so the chrome renderer received the stale URL and painted it (goURL() blurs the input on Enter, so the "don't clobber typed text" guard didn't skip the write). Fix: assign t.url from host+rest immediately, before setLoading. --- main.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/main.js b/main.js index 5e15af1..4b4658b 100644 --- a/main.js +++ b/main.js @@ -1255,7 +1255,14 @@ function createTab(initial, opts = {}) { return navigateTab(id, target + rest); } if (parsed.protocol === "bns:") return; - if (isBnsHost(parsed.hostname)) { e.preventDefault(); navigateTab(id, parsed.hostname + parsed.pathname); } + if (isBnsHost(parsed.hostname)) { + // Preserve query + fragment. Dropping them broke every search engine + // that submits via a classic form GET (Google's /search?q=foo lost + // the ?q=, so the results page opened blank). DuckDuckGo only + // appeared to work because its search is a client-side pushState. + e.preventDefault(); + navigateTab(id, u.replace(/^[a-z]+:\/\//i, "")); + } } catch {} }); // "You have unsaved changes" confirmation: fires when the page's beforeunload @@ -1381,13 +1388,18 @@ async function navigateTab(id, input) { const t = tabById(id); if (!t) return; let q = String(input).trim(); if (!q) return; - setLoading(t, true); // show the loading indicator immediately (covers BNS resolution) // Address bar doubles as a search box: anything that isn't a URL/hostname // (a bare word, or a phrase with spaces) becomes a web search. if (!looksLikeUrl(q)) q = SEARCH(q); const raw = q.replace(/^[a-z]+:\/\//i, ""); const host = raw.split("/")[0].toLowerCase(); const rest = raw.slice(host.length) || "/"; + // Reflect the target URL immediately so the address bar doesn't keep + // showing the previous page's URL for the whole load duration. Without + // this, emitTabs below (triggered by setLoading) carries the old t.url + // and the chrome renderer paints it, since we blurred the input on Enter. + t.url = "https://" + host + (rest === "/" ? "" : rest); + setLoading(t, true); // show the loading indicator immediately (covers BNS resolution) t.nav = (t.nav || 0) + 1; // Legacy "also on BCNR" chip state — kept clean; the passive switch is gone