Files
JoshHeaps.Net/tests/holdem/selectsOnFocus.test.js
jheapsandClaude Opus 5 f199148046 A pre-filled amount is a suggestion, so reaching for the box replaces it
Every amount box in this tool opens pre-filled: the raise pad offers the minimum, Add
chips offers a buy-in, the seat editor offers the stack a player already has. A dealer
taps one because they want a different number -- and a tap puts the caret after the
suggestion rather than over it.

Driven on an emulated phone:

  raise pad shows 4      tap, type "60"    -> 460
  add chips shows 200    tap, type "50"    -> 20050
  seat stack shows 200   tap, type "175"   -> 200175

The raise pad is the most time-critical control in the tool, and 460 is a number the
dealer never said. The all-in warning happens to catch that one against a $200 stack;
against a deeper stack it is simply accepted, and the pot is wrong from then on.

Number boxes now select what is in them when they take focus, so the first digit
typed replaces the suggestion.

  raise pad     4 -> "60"
  add chips   200 -> "50"
  seat stack  200 -> "175"
  a name      Cal -> "CalX"

That last line is the point of the rule. Only number boxes: type=number, or the
type=text/inputmode=decimal pair the raise pad uses to get a keypad without spinner
arrows. A name or a note is a thing you edit, and selecting all of it on focus would
be the same mistake pointing the other way.

Delegated from the document rather than wired per field. The raise pad, the add-chips
sheet and the seat editor all rebuild their inputs on every render, and a box added
later should not have to remember to ask for this.

The select is deferred a tick. Doing it inside the focus handler loses the race with
the browser placing its own caret, and the selection collapses again the moment the
tap completes.

10 tests (224 total) on the predicate, including the ones that must stay false --
name, note, colour swatch, checkbox, select, and an input with no type stated.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
2026-09-01 14:40:04 -06:00

54 lines
2.0 KiB
JavaScript

// Which fields replace their contents when a dealer reaches for them.
const test = require("node:test");
const assert = require("node:assert");
const { Money } = require("./load");
// Enough of an input to answer the question, without a DOM.
const field = (props = {}) => ({ tagName: "INPUT", type: "text", inputMode: "", ...props });
test("a number box selects", () => {
assert.equal(Money.selectsOnFocus(field({ type: "number" })), true);
});
test("a decimal keypad box selects", () => {
// The raise pad's amount is type=text with inputmode=decimal, so the phone shows
// a number pad without the browser's spinner arrows.
assert.equal(Money.selectsOnFocus(field({ type: "text", inputMode: "decimal" })), true);
});
test("a name does not", () => {
// Selecting all of a name on focus is the same mistake pointing the other way:
// a name is a thing you edit, not a suggestion you replace.
assert.equal(Money.selectsOnFocus(field({ type: "text" })), false);
});
test("a colour swatch does not", () => {
assert.equal(Money.selectsOnFocus(field({ type: "color" })), false);
});
test("a checkbox does not", () => {
assert.equal(Money.selectsOnFocus(field({ type: "checkbox" })), false);
});
test("a textarea does not, whatever it is asked", () => {
assert.equal(Money.selectsOnFocus({ tagName: "TEXTAREA", type: "text", inputMode: "decimal" }), false);
});
test("a select does not", () => {
assert.equal(Money.selectsOnFocus({ tagName: "SELECT", type: "select-one" }), false);
});
test("case doesn't matter", () => {
assert.equal(Money.selectsOnFocus(field({ type: "NUMBER" })), true);
assert.equal(Money.selectsOnFocus(field({ type: "TEXT", inputMode: "DECIMAL" })), true);
});
test("nothing at all is not a field", () => {
assert.equal(Money.selectsOnFocus(null), false);
assert.equal(Money.selectsOnFocus(undefined), false);
});
test("a field with no type stated is a text box, so it does not", () => {
assert.equal(Money.selectsOnFocus({ tagName: "INPUT" }), false);
});