Fix: server URL and password fields ignored typing
The Enter-key handlers were expression-bodied arrows assigned to DOM on…
properties: `(e) => e.key === "Enter" && submit()` returns false for every
other key, and an on… handler returning false cancels the event, so the
server URL ("Use my phone") and both master-password fields accepted no input.
Use block bodies, and add scripts/check-handlers.mjs (run by npm run build)
to fail the build on handlers that can return false.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc --noEmit && vite build",
|
"build": "node scripts/check-handlers.mjs && tsc --noEmit && vite build",
|
||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Fails the build if a DOM `on…` handler property is assigned an expression-bodied arrow function, e.g.
|
||||||
|
// input.onkeydown = (e) => e.key === "Enter" && submit();
|
||||||
|
// Such a handler returns `false` for every other key, and a DOM `on…` handler that returns `false` cancels the
|
||||||
|
// event, so the field silently stops accepting typing. Use a block body: `(e) => { if (…) submit(); }`.
|
||||||
|
import { readFileSync, readdirSync, statSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
|
||||||
|
// An `on…` handler property assigned an arrow with an expression body (not `{`) that can evaluate to false.
|
||||||
|
const handler = /\.on[a-z]+\s*=\s*(?:async\s*)?\([^)]*\)\s*=>(?!\s*\{)(.*)$/;
|
||||||
|
const canBeFalse = /&&|\|\||[=!]==?|[<>]=?/;
|
||||||
|
const files = [];
|
||||||
|
(function walk(dir) {
|
||||||
|
for (const name of readdirSync(dir)) {
|
||||||
|
const p = join(dir, name);
|
||||||
|
if (statSync(p).isDirectory()) walk(p);
|
||||||
|
else if (p.endsWith(".ts")) files.push(p);
|
||||||
|
}
|
||||||
|
})("src");
|
||||||
|
|
||||||
|
let failed = false;
|
||||||
|
for (const file of files) {
|
||||||
|
readFileSync(file, "utf8")
|
||||||
|
.split("\n")
|
||||||
|
.forEach((line, i) => {
|
||||||
|
const m = handler.exec(line);
|
||||||
|
if (m && canBeFalse.test(m[1])) {
|
||||||
|
console.error(`${file}:${i + 1}: on… handler needs a block body (a returned false cancels the event)\n ${line.trim()}`);
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (failed) process.exit(1);
|
||||||
+10
-3
@@ -122,7 +122,10 @@ function phonePanel(body: HTMLElement, status: SyncStatus) {
|
|||||||
start.disabled = false;
|
start.disabled = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
url.onkeydown = (e) => e.key === "Enter" && start.click();
|
// Block body on purpose: a DOM `on…` handler that returns `false` cancels the event, which would block typing.
|
||||||
|
url.onkeydown = (e) => {
|
||||||
|
if (e.key === "Enter") start.click();
|
||||||
|
};
|
||||||
if (!url.value) url.focus();
|
if (!url.value) url.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +258,9 @@ function finishSetup(body: HTMLElement, view: SetupView) {
|
|||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
};
|
};
|
||||||
btn.onclick = submit;
|
btn.onclick = submit;
|
||||||
pw.onkeydown = (e) => e.key === "Enter" && void submit();
|
pw.onkeydown = (e) => {
|
||||||
|
if (e.key === "Enter") void submit();
|
||||||
|
};
|
||||||
body.replaceChildren(
|
body.replaceChildren(
|
||||||
el("p", {}, "Signing in to ", el("strong", { textContent: view.server_host }), "."),
|
el("p", {}, "Signing in to ", el("strong", { textContent: view.server_host }), "."),
|
||||||
el("p", { className: "muted", textContent: view.preapproved ? "This computer is pre-approved." : "Another device will need to approve this computer." }),
|
el("p", { className: "muted", textContent: view.preapproved ? "This computer is pre-approved." : "Another device will need to approve this computer." }),
|
||||||
@@ -339,7 +344,9 @@ function renderUnlock(state: AppState) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
btn.onclick = submit;
|
btn.onclick = submit;
|
||||||
pw.onkeydown = (e) => e.key === "Enter" && void submit();
|
pw.onkeydown = (e) => {
|
||||||
|
if (e.key === "Enter") void submit();
|
||||||
|
};
|
||||||
const card = el("div", { className: "card" }, el("h2", { textContent: "Kestrove is locked" }), pw);
|
const card = el("div", { className: "card" }, el("h2", { textContent: "Kestrove is locked" }), pw);
|
||||||
if (!state.remembers_secret_key) card.append(sk);
|
if (!state.remembers_secret_key) card.append(sk);
|
||||||
card.append(btn, err);
|
card.append(btn, err);
|
||||||
|
|||||||
Reference in New Issue
Block a user