Add the Browser tab: a live web page with no browser chrome

A new tab (globe, after Maps) shows one web page full-bleed in the content area —
no address bar, bookmarks or scrollbars — built for It Is Written but usable with
any page. It loads at startup and keeps running in the background.

Stage (browser-tab.js, browser-guest-preload.cjs):
- An Electron <webview> per Browser tab, in its own sandboxed process and persistent
  session. The pages live in one persistent layer inside .tab-content: every tab
  switch rebuilds .tab-content and moving a webview reloads it, so app.js now clears
  around that layer (clearTabContentKeepingBrowser).
- Tapping a text field brings up the Prayer tab's keyboard (createPrayerKeyboard with
  a sink) and types into the page with trusted input; Enter submits; the keyboard puts
  itself away when the page moves focus on (e.g. after a search). The OS touch
  keyboard is suppressed with inputmode="none" while a field is focused.
- Tapping a scripture reference opens it in a new Bible tab, in the translation
  printed beside it when that one is switched on. References are found with the app's
  own scanner: scripture-scan.js gains scanAll() (every match with its offsets),
  translationAfter() and isTranslation(); scanText/parseSlide are unchanged.
- Input inside a webview never reaches the app, so the page reports activity (idle
  splash) and five-finger touches (blank the screen) itself.
- main.cjs: webviewTag on; every webview is forced sandboxed, context-isolated, no Node,
  http(s) only, with the guest preload. No new windows (opened in place), no permission
  prompts, no downloads, no pinch-zoom, no alert/confirm/prompt boxes, and "Leave
  site?" can never block Reload or Start page. The session reports plain Chrome.
- server.js CSP: frame-src allows http(s) (a webview is a frame to CSP); style-src and
  font-src allow https (the follower's srcdoc copy inherits this policy).

Everywhere a tab kind is listed:
- app.js: create at startup and on Reset, icon, visibility defaults, + menu, fixed
  mode, no ink layer, tool handling, OSC kind + information line (the page's search
  term), phone remote scroll / tap / page buttons, OSC show / reload / home actions,
  live setting changes, translation for tapped references.
- quick-dock, tool-wheel, presentation-tools: no drawing tools on the tab.
- Phone remote: tab label, one finger scrolls the page (taps still tap), hint text;
  mirror-stream.js reports the page's scroll for the phone's local preview.
- Follower screen: the stage publishes a script-free copy of the page's DOM (only while
  a follower is linked), its scroll and form fields; the follower shows it in
  sandboxed, double-buffered frames; the relay keeps the page for late joiners.
- OSC: /bibleapp/browser, /bibleapp/browser/reload, /bibleapp/browser/home;
  tab_kind/browser feedback. Admin and phone allow-lists updated.
- Settings: Tab Visibility, a Browser Tab section (start page, page size, scripture
  taps, return to start page), Service Profiles carry its settings, OSC references.
- Admin console: show the tab, reload / start page, start page and page size.
- BROWSER_TAB.md documents it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:25:15 -04:00
co-authored by Claude Opus 5.5
parent a0c3921edd
commit e7e527197f
20 changed files with 1780 additions and 60 deletions
+79
View File
@@ -0,0 +1,79 @@
# Browser tab
One web page, full screen in the tab: no address bar, bookmarks or scrollbars — just the page, in the
same area the Graphics tab uses. It loads when the app starts and keeps running while other tabs are
showing, so it is ready the moment it is opened. Built for It Is Written
(`https://it-is-written-waters-church.vercel.app/`), but any web page works.
## On the stage
| Do this | What happens |
|---|---|
| Drag a finger | The page scrolls. |
| Tap a text box on the page | The app's own keyboard (the Prayer tab's) comes up and types into it. Enter submits; the keyboard puts itself away when the page moves on (e.g. after a search). × closes it; tap the box again to bring it back. |
| Tap a scripture reference (e.g. "Isaiah 41:10") | It opens in a new Bible tab, at that verse, in the translation printed beside it (NIV, ESV…) when that translation is switched on. |
| Tap anything else | Works on the page as normal. |
| Leave the tab and come back | The page is exactly as it was: same search, same place, same typing. |
Pen, highlighter, laser and spotlight are off on this tab (the page takes every touch — that is how it
scrolls and is typed into), as on Graphics and Maps. Touches on the page keep the idle splash away, and
five fingers still blank the screen.
**If the page gets stuck or a tap wanders off the site:** the ⟳ refresh button puts it back on its start
page (along with the rest of the app), or use Companion / the admin console below.
## Settings › Browser Tab
- **Start page** — the page the tab opens. Blank = It Is Written. Changing it takes the tab there.
- **Page size** — Auto lays the page out like a tablet and scales it to fill the width (about 200% on the
portrait TV). Pick a percentage if a site looks too small or too big.
- **Tap a scripture reference…** — on by default.
- **Return to the start page** — the tab remembers where it was while the app runs (so a trip to Settings
does not lose a search); this clears that.
All three settings travel with **Service Profiles**, so each service type can have its own start page.
The tab can be hidden in **Tab Visibility** like any other, and more can be opened from the **+** menu.
## From Companion, the phone and the admin console
| | |
|---|---|
| OSC `/bibleapp/browser` | Show the Browser tab |
| OSC `/bibleapp/browser/reload` | Reload the page |
| OSC `/bibleapp/browser/home` | Back to the start page |
| Feedback `/bibleapp/feedback/state/tab_kind/browser` | `1` while it is showing |
| Information line | `4/10 Browser \| hope \| LIVE` — the page's search term (or title) |
The **phone remote** shows the page in its TV view: tap to press things on it, drag (one finger or two)
to scroll, and the page buttons move it a screen at a time. The **admin console** can show the tab,
reload it, send it home, and change the start page and page size.
The **follower screen** shows the same page, clean, and follows its scroll, typing and anything opened on
it. It is fed the stage's copy of the page rather than loading the site itself — loading it would re-run
the search and could put different results on the program feed.
## How it works
- **Stage:** each Browser tab is an Electron `<webview>` — Chrome's engine in its own sandboxed process
and its own session (`persist:browser-tab`, so a site's settings and sign-ins survive restarts).
`main.cjs` forces its settings: no Node, sandboxed, only http(s), no new windows (links that would open
one open in place), no permission prompts, no downloads, no pinch-zoom, no dialog boxes, and "Leave
site?" can never block Reload or Start page.
- **The pages live in their own layer** (`#browserTabHost`) inside `.tab-content`. Every tab switch
rebuilds `.tab-content`, and moving or recreating a webview reloads its page, so app.js clears around
that layer (`clearTabContentKeepingBrowser`) and switching tabs only shows or hides it.
- **`browser-guest-preload.cjs`** runs inside the page (invisible to the site) and reports what the app
cannot see from outside: a tapped text field, a tapped reference (found with the app's own
`scripture-scan.js` — the same rules ProPresenter Sync uses), scroll, activity, five fingers, and — only
while a follower is linked — a script-free copy of the page's DOM.
- **`browser-tab.js`** owns the tab: the pages, the keyboard (via `createPrayerKeyboard` with a "sink"),
scripture taps, scrolling for the phone / OSC / admin, and the follower's copy. On the follower it
shows that copy in sandboxed frames (no scripts); in a plain browser (admin offstage copy, `npm start`)
it shows the live page in an iframe — keyboard and scripture taps need the stage.
## Limits worth knowing
- The follower's copy is the page's DOM, not video: anything drawn by script into a `<canvas>`, and
script-driven animation, will not move there. Whatever computer shows the follower screen needs to reach the site's fonts
and images over the internet, as the stage does.
- In a plain browser (admin offstage copy) some sites refuse to be shown inside another page.