fix(theseus): prompts taller than the toolbar were cut off

The chrome view is exactly as tall as its rows, and a fixed-position
prompt mask adds nothing to the height it reports, so any prompt taller
than the toolbar — the new two-field favorites form lost its title and
buttons — was clipped at the view's edge. The view now grows to fit the
open prompt and shrinks back when it closes.
This commit is contained in:
Local Dev 2026-09-25 08:30:19 +02:00
parent df6eb5d35b
commit 5edf8dc306

View file

@ -1106,16 +1106,28 @@
} }
// In-page prompt modal — window.prompt is disabled in Electron BrowserViews. // In-page prompt modal — window.prompt is disabled in Electron BrowserViews.
// Resolves to the trimmed string on OK, or null on Cancel / Escape / mask click. // Resolves to the trimmed string on OK, or null on Cancel / Escape / mask click.
// The chrome view is only as tall as its rows, and a fixed-position mask
// adds nothing to body.scrollHeight — so a prompt taller than the rows was
// cut off at the view's edge (the two-field favorites form lost its title
// and buttons). Grow the view to fit the box while a prompt is open;
// done() calls syncHeight() to shrink it back.
function growForPrompt(mask) {
try {
const box = mask.querySelector(".promptbox");
const need = box ? Math.ceil(box.getBoundingClientRect().height) + 56 : 0;
T.setChromeHeight(Math.max(document.body.scrollHeight, need));
} catch {}
}
function inPrompt(label, initial) { function inPrompt(label, initial) {
return new Promise((resolve) => { return new Promise((resolve) => {
const mask = document.createElement("div"); mask.className = "promptmask"; const mask = document.createElement("div"); mask.className = "promptmask";
mask.innerHTML = `<div class="promptbox"><div class="plbl">${label.replace(/</g,"&lt;")}</div>` mask.innerHTML = `<div class="promptbox"><div class="plbl">${label.replace(/</g,"&lt;")}</div>`
+ `<input type="text" spellcheck="false">` + `<input type="text" spellcheck="false">`
+ `<div class="pact"><button class="pbtn pcancel" type="button">Cancel</button><button class="pbtn primary pok" type="button">OK</button></div></div>`; + `<div class="pact"><button class="pbtn pcancel" type="button">Cancel</button><button class="pbtn primary pok" type="button">OK</button></div></div>`;
document.body.appendChild(mask); document.body.appendChild(mask); growForPrompt(mask);
const input = mask.querySelector("input"); const input = mask.querySelector("input");
input.value = String(initial ?? ""); input.value = String(initial ?? "");
const done = (val) => { try { mask.remove(); } catch {} document.removeEventListener("keydown", key); resolve(val); }; const done = (val) => { try { mask.remove(); } catch {} document.removeEventListener("keydown", key); syncHeight(); resolve(val); };
const key = (e) => { if (e.key === "Escape") done(null); else if (e.key === "Enter") done(input.value.trim() || null); }; const key = (e) => { if (e.key === "Escape") done(null); else if (e.key === "Enter") done(input.value.trim() || null); };
document.addEventListener("keydown", key); document.addEventListener("keydown", key);
mask.addEventListener("mousedown", (e) => { if (e.target === mask) done(null); }); mask.addEventListener("mousedown", (e) => { if (e.target === mask) done(null); });
@ -1148,7 +1160,7 @@
+ `<div class="pfield"><label>Title</label><input type="text" class="ptitle" spellcheck="false" placeholder="Filled in from the address — edit as you like"></div>` + `<div class="pfield"><label>Title</label><input type="text" class="ptitle" spellcheck="false" placeholder="Filled in from the address — edit as you like"></div>`
+ `<div class="perr" hidden></div>` + `<div class="perr" hidden></div>`
+ `<div class="pact"><button class="pbtn pcancel" type="button">Cancel</button><button class="pbtn primary pok" type="button">Save</button></div></div>`; + `<div class="pact"><button class="pbtn pcancel" type="button">Cancel</button><button class="pbtn primary pok" type="button">Save</button></div></div>`;
document.body.appendChild(mask); document.body.appendChild(mask); growForPrompt(mask);
const url = mask.querySelector(".purl"), title = mask.querySelector(".ptitle"), err = mask.querySelector(".perr"); const url = mask.querySelector(".purl"), title = mask.querySelector(".ptitle"), err = mask.querySelector(".perr");
url.value = String(initial.url ?? ""); title.value = String(initial.title ?? ""); url.value = String(initial.url ?? ""); title.value = String(initial.title ?? "");
let titleTouched = !!title.value; let titleTouched = !!title.value;
@ -1160,7 +1172,7 @@
}; };
url.addEventListener("input", autoTitle); url.addEventListener("input", autoTitle);
title.addEventListener("input", () => { titleTouched = title.value.trim().length > 0; if (!titleTouched) autoTitle(); }); title.addEventListener("input", () => { titleTouched = title.value.trim().length > 0; if (!titleTouched) autoTitle(); });
const done = (val) => { try { mask.remove(); } catch {} document.removeEventListener("keydown", key); resolve(val); }; const done = (val) => { try { mask.remove(); } catch {} document.removeEventListener("keydown", key); syncHeight(); resolve(val); };
const submit = () => { const submit = () => {
const norm = normalizeBookmarkUrl(url.value); const norm = normalizeBookmarkUrl(url.value);
if (!norm) { err.textContent = "That doesn't look like a web address."; err.hidden = false; url.focus(); return; } if (!norm) { err.textContent = "That doesn't look like a web address."; err.hidden = false; url.focus(); return; }