Hold'em: every seat on the ring is the same seat, and the ring is measured before it is believed #122
@@ -207,6 +207,43 @@ a {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
/* A field is as tall as it says it is.
|
||||
*
|
||||
* Form controls are content-box by default, and this stylesheet has been caught by that
|
||||
* twice already — the sidebar's panel headers and the rulings sheet's summaries both
|
||||
* carry a note about it. It was doing the same thing to the fields, and nobody had
|
||||
* measured them: the touch rule near the bottom of this file asks for `min-height: 44px`
|
||||
* on every input and select in a panel, 44 was being read as the *content* height, and
|
||||
* 8px of padding top and bottom plus a 1px border each side went on the outside of it.
|
||||
* Measured on an iPhone, all fifteen settings fields in the sidebar stood at 62px — 41%
|
||||
* over the number the rule that sizes them is written in terms of.
|
||||
*
|
||||
* Nothing looked wrong, which is why it lasted. 62px clears a 44px floor, so the sweep
|
||||
* had nothing to say, and one field is not obviously too tall. Fifteen of them are 180px
|
||||
* of scroll on a page whose whole argument is that a dealer is holding a phone in one
|
||||
* hand: Table Setup 941 to 869, the waiting list 212 to 194, and every panel in the
|
||||
* sidebar open 2,993 to 2,813.
|
||||
*
|
||||
* The raise pad's field is the one worth measuring rather than assuming, because it is
|
||||
* not only a field: its height is the action bar's height, the action bar's height is
|
||||
* published into --feltRoomPx, and the felt is laid out from what is left. Correcting it
|
||||
* takes 10px off the bar and hands them to the table. Measured on a Galaxy S8
|
||||
* twelve-handed at 20px text, which is where that matters most: the bar goes 248px to
|
||||
* 238, and seat 7's stack comes out from behind it — with the taller field the sweep
|
||||
* reported "$1,100 is 7/7 under div#actionBar", which is a figure a dealer cannot read
|
||||
* at all.
|
||||
*
|
||||
* Said about every field rather than about the surfaces they sit on, because a list of
|
||||
* surfaces is a list that goes stale. Written that way first, it already missed one: the
|
||||
* waiting list's name box asks for the same 44px two hundred lines from anything the
|
||||
* list named. The rule is identical either way and there is one fewer thing to keep up
|
||||
* to date. */
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* The grey rectangle goes from every control, fields included — a tapped input
|
||||
already shows a caret and a focus ring, which say the same thing more quietly. */
|
||||
.holdemBtn,
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// Forty-four pixels, meaning forty-four pixels.
|
||||
//
|
||||
// Every input and select a dealer touches has a rule asking for `min-height: 44px`, and
|
||||
// not one of them was 44px tall. Form controls are content-box by default, so 44 was
|
||||
// being read as the height of the text inside and 8px of padding top and bottom plus a
|
||||
// 1px border each side went on the outside of it. Measured on an iPhone: all fifteen
|
||||
// settings fields in the sidebar stood at 62px, and the raise pad's amount box at 66px
|
||||
// with the text turned up.
|
||||
//
|
||||
// Nothing looked wrong, which is why it lasted eleven rounds. 62px clears a 44px floor,
|
||||
// so the sweep — which asks whether a target is big enough, never whether it is the size
|
||||
// it was asked to be — had nothing to say about it. The cost is only visible in the
|
||||
// aggregate: fifteen fields at 18px over is 180px of sidebar, and the raise field's 10px
|
||||
// is 10px of felt, because the action bar's height is published into --feltRoomPx and
|
||||
// the table is laid out from what is left.
|
||||
//
|
||||
// This is the third time this stylesheet has been caught by content-box — the sidebar's
|
||||
// panel headers and the rulings sheet's summaries are the other two, and both carry a
|
||||
// note saying so. The note is in the stylesheet; the list of what it covers is here.
|
||||
const test = require("node:test");
|
||||
const { describe } = require("node:test");
|
||||
const assert = require("node:assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const CSS = fs.readFileSync(path.join(
|
||||
__dirname, "..", "..", "JoshHeaps.Net", "wwwroot", "css", "casino", "holdem.css"), "utf8");
|
||||
|
||||
// The rule, the selectors it is written against, and the note above it saying why.
|
||||
const boxSizing = () => {
|
||||
const note = CSS.indexOf("/* A field is as tall as it says it is.");
|
||||
assert.ok(note >= 0, "nothing in the stylesheet asks a field to be the height it states");
|
||||
const at = CSS.indexOf("box-sizing: border-box;", note);
|
||||
assert.ok(at >= 0);
|
||||
return CSS.slice(note, CSS.indexOf("}", at));
|
||||
};
|
||||
|
||||
// Every selector anywhere in the stylesheet that gives a typing field a 44px floor,
|
||||
// wherever the media query that holds it happens to live. Checkboxes and colour swatches
|
||||
// are left out: they are sized by an explicit width and height rather than by a floor
|
||||
// their padding can push past, which is the whole of the bug this guards.
|
||||
const touchSized = () => {
|
||||
const found = [];
|
||||
let from = 0;
|
||||
for (;;) {
|
||||
const hit = CSS.indexOf("min-height: 44px", from);
|
||||
if (hit === -1) break;
|
||||
from = hit + 1;
|
||||
const opens = CSS.lastIndexOf("{", hit);
|
||||
const prior = Math.max(CSS.lastIndexOf("}", opens), CSS.lastIndexOf("{", opens - 1),
|
||||
CSS.lastIndexOf("*/", opens));
|
||||
CSS.slice(prior + 1, opens).split(",")
|
||||
.map(line => line.trim())
|
||||
.filter(Boolean)
|
||||
.forEach(selector => found.push(selector));
|
||||
}
|
||||
return found.filter(selector =>
|
||||
/\b(input|select|textarea)\b|\.raiseInput/.test(selector) &&
|
||||
!/\[type="(checkbox|color)"\]/.test(selector));
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("a field is the height it says it is", () => {
|
||||
const rule = boxSizing();
|
||||
|
||||
// Every field, not a list of the surfaces fields sit on. The list version of this
|
||||
// rule was written first and had already missed one — see the note.
|
||||
test("said about the elements, so nothing can sit outside the list", () => {
|
||||
assert.match(rule, /(^|\n)input,\s*\n\s*select,\s*\n\s*textarea \{/);
|
||||
});
|
||||
|
||||
// The one field whose height is not only its own: it sets the action bar's height,
|
||||
// the bar's height is published into --feltRoomPx, and the felt is laid out from
|
||||
// what is left. Taking 10px off the bar gave them to the table.
|
||||
test("the felt's stake in it is written down", () => {
|
||||
assert.match(rule, /--feltRoomPx/);
|
||||
assert.match(rule, /248px to[\s*]*238/);
|
||||
});
|
||||
|
||||
test("and so is the measurement that found it", () => {
|
||||
assert.match(rule, /62px/);
|
||||
assert.match(rule, /fifteen settings fields/);
|
||||
});
|
||||
|
||||
// Two other rules in this file already carry a content-box note; this is the third
|
||||
// place it has bitten, and the note is what stops it being a fourth.
|
||||
test("and what it is about, so the next one is recognised", () => {
|
||||
assert.match(rule, /content-box/);
|
||||
assert.match(rule, /padding/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("nothing asks for a height it will not get", () => {
|
||||
// A durable guard rather than a snapshot. If a later round gives a field a 44px
|
||||
// floor, that floor is only the height the author meant while this rule reaches the
|
||||
// field — and nothing else in the suite would notice if it stopped.
|
||||
test("every field given a touch height is measured the way that height assumes", () => {
|
||||
const fields = touchSized();
|
||||
assert.ok(fields.length >= 4, `only ${fields.length} field rules found — the scrape has drifted`);
|
||||
// The rule names the element types themselves, so the only way a field escapes
|
||||
// is a later round narrowing it back to a list of places.
|
||||
const rule = boxSizing();
|
||||
fields.forEach(selector => {
|
||||
const kind = (selector.match(/\b(input|select|textarea)\b/) || [])[1]
|
||||
|| (/\.raiseInput/.test(selector) ? "input" : null);
|
||||
assert.ok(kind && new RegExp(`(^|\\n|,\\s*)${kind}\\b`).test(rule),
|
||||
`\`${selector}\` is given a touch height that box-sizing no longer reaches`);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user