commit 52750646db8dab46ac911582ba1df13f78b64beb
parent 1b85c81805e570141caffebc5f34258cbb932ea5
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Thu, 1 Oct 2026 21:16:12 -0400
report-to-video: the popup page's clamp writes \\s in its template, so the composed page trims trailing whitespace with /\s+$/ instead of stripping trailing letters s off a clamped quoted paragraph; a test reads the regex off a composed page; the quirk says both pages write \\s (the popup's page hash changes, so cached popup windows re-render once)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/umtool/docs/quirks.md b/umtool/docs/quirks.md
@@ -247,10 +247,12 @@ frame sees the built timeline.
**A backslash in a page's script is a template literal's first.** The page
modules write their runtime script inside a JS template literal, where `\s`
is not an escape and becomes a plain `s`: the popup's `replace(/\s+$/, "")`
-reaches the page as `replace(/s+$/, "")` (it strips trailing letters s, not
-spaces, in the one case it runs: a clamped card whose paragraphs were dropped
-after one that fit exactly). The feed's page writes `\\s`. Read in the
-module the regex looks right; only the composed page shows the wrong one.
+reached the page as `replace(/s+$/, "")` and stripped trailing letters s, not
+spaces, in the one case it runs (a clamped card whose paragraphs were dropped
+after one that fit exactly), so a quoted word lost its last letter. Both the
+popup's and the feed's pages write `\\s` in the module; read in the module a
+single backslash looks right, and only the composed page shows the wrong one,
+which is why `chrome-posts.test.mjs` reads the regex off a composed page.
**Switching the posts layout moves the footage, so it is a rebuild, not a
re-render.** The feed frames every footage segment into its own box when the
diff --git a/umtool/report-to-video/chrome-posts.mjs b/umtool/report-to-video/chrome-posts.mjs
@@ -381,7 +381,7 @@ export function postsHtml(schedule, render, window, opts = {}) {
if (cut && shown && !(shown.p.scrollHeight > shown.p.clientHeight + 1)) {
// Dropped paragraphs after one that fit exactly: say so on it. The
// clamp it already has turns an overflowing "…" into the ellipsis.
- shown.p.textContent = shown.p.textContent.replace(/\s+$/, "") + " …";
+ shown.p.textContent = shown.p.textContent.replace(/\\s+$/, "") + " …";
shown.p.style.webkitLineClamp = String(shown.lines);
}
}
diff --git a/umtool/report-to-video/chrome-posts.test.mjs b/umtool/report-to-video/chrome-posts.test.mjs
@@ -132,6 +132,18 @@ test("nothing on the page leaves the machine; the post's own link is only in its
}
});
+test("the page's clamp trims trailing whitespace only: a word ending in s keeps its s", () => {
+ const { html } = c2Page();
+ // The template literal must emit the regex's backslash: written as /\s+$/
+ // in the template, the page received /s+$/ and cut a quoted word's last s.
+ const m = /shown\.p\.textContent\.replace\((\/.*?\/), ""\)/.exec(html);
+ assert.ok(m, "the clamp's ellipsis line is on the page");
+ assert.equal(m[1], "/\\s+$/");
+ const re = new Function(`return ${m[1]};`)();
+ assert.equal("three Rescues".replace(re, ""), "three Rescues");
+ assert.equal("three Rescues \n ".replace(re, ""), "three Rescues");
+});
+
test("the page's times are postSchedule's: data, enter and leave cues", () => {
const { sched, html, win } = c2Page();
const d = dataOf(html);