From 58fd1612a1d917d4d48df0a33a011b415876c638 Mon Sep 17 00:00:00 2001 From: John Thomson Date: Thu, 9 Jul 2026 10:52:45 -0500 Subject: [PATCH 1/3] Add plan document for converting Talking Book tool to React A design/hand-off document (Steps 0-5) describing how to convert the last non-React toolbox tool to React: move the AudioRecording engine to the page iframe, turn the button-state machine and controls into a React component in the toolbox, and stop audioRecording.ts from being duplicated into the page bundle. Step 6 (retiring the legacy non-React toolbox framework) is documented as a deferred follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../TalkingBook-React-Conversion-Plan.md | 327 ++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 src/BloomBrowserUI/bookEdit/toolbox/talkingBook/TalkingBook-React-Conversion-Plan.md diff --git a/src/BloomBrowserUI/bookEdit/toolbox/talkingBook/TalkingBook-React-Conversion-Plan.md b/src/BloomBrowserUI/bookEdit/toolbox/talkingBook/TalkingBook-React-Conversion-Plan.md new file mode 100644 index 000000000000..478afac598f7 --- /dev/null +++ b/src/BloomBrowserUI/bookEdit/toolbox/talkingBook/TalkingBook-React-Conversion-Plan.md @@ -0,0 +1,327 @@ +# Plan: Convert the Talking Book tool to React + +**Status:** proposed / not yet started. +**Scope of this document:** Steps 0–5 (the conversion). Step 6 (retiring the old +non-React toolbox framework) is deferred to a separate follow-up PR and is described +briefly at the end so it isn't lost. + +Talking Book is the **last** non-React toolbox tool. Converting it lets us later delete +the entire legacy non-React tool framework (Step 6). + +--- + +## 1. Current architecture (as of this writing) + +### 1.1 `talkingBook.ts` +`TalkingBookTool implements ITool` directly (not via `ToolboxToolReactAdaptor`). Its +`makeRootElement()` **throws** — the tool's UI is the pug file +`talkingBookToolboxTool.pug`, routed in through two legacy hard-coded maps: + +- `subpath` in `toolbox.ts` (~line 1273): `talkingBookTool: "talkingBook/talkingBookToolboxTool.html"` +- `legacyToolSubPathByToolId` in `ToolboxRoot.tsx` (~line 71): `talkingBook: "talkingBook/talkingBookToolboxTool.html"` + +`talkingBook.ts` is a thin lifecycle shim that forwards to the `AudioRecording` +singleton: `showTool` (async: `initializeTalkingBookToolAsync` + `setupForRecordingAsync`), +`newPageReady` (async), `hideTool`, `detachFromPage`, and async markup +(`isUpdateMarkupAsync() === true`; `updateMarkupAsync()` returns +`getAudioRecorder().getUpdateMarkupAction()`). + +### 1.2 `audioRecording.ts` (~4,900 lines) — engine **and** tool UI, running in the toolbox iframe +This is the important, counter-intuitive fact: **the `AudioRecording` object currently +runs in the _toolbox_ iframe, not the page iframe.** Evidence: + +- The constructor reads toolbox controls via its own `document`: + `document.getElementById("audio-split")`, `#audio-meter`, `#player`. +- `initializeTalkingBookToolAsync` wires jQuery handlers to the toolbox buttons + (`$("#audio-record").mousedown(...).mouseup(...)`, `$("#audio-next").click(...)`, etc.). +- It reaches _into_ the page iframe for content via + `getPageFrame()` → `parent.window.document.getElementById("page")` and `getPageDocBody()`. + +So the object owns two very different kinds of responsibility: + +1. **Tool UI** (toolbox side): the 7 main buttons, their counters, the level meter, + device selection, the `