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:
+31
-1
@@ -55,7 +55,8 @@
|
||||
lastScroll: null,
|
||||
lastKey: null, // the passage whose stroke list was last sent (see buildSnapshot)
|
||||
liveActive: false,
|
||||
rafId: null, lastPumpAt: 0, lastZoom: ''
|
||||
rafId: null, lastPumpAt: 0, lastZoom: '',
|
||||
browserVer: 0, lastBrowserY: null, lastBrowserInputs: '' // the Browser tab's page (see buildSnapshot)
|
||||
};
|
||||
|
||||
function app() { return window.bibleApp || null; }
|
||||
@@ -208,6 +209,22 @@
|
||||
if (html != null) snap.prayer = html;
|
||||
} else if (t.mode === 'ask') {
|
||||
snap.ask = b ? b.askMessages(t.id) : [];
|
||||
} else if (t.mode === 'browser' && window.__browserTab) {
|
||||
/*
|
||||
* The Browser tab's page, as DOM with its scripts stripped (browser-tab.js) — the booth shows THIS
|
||||
* page rather than loading the site itself, which would re-run the search and could put different
|
||||
* results on the program feed. The HTML is tens of KB, so like the stroke list it rides along only
|
||||
* when the page changed, the tab changed, or on a forced full republish; the relay completes its
|
||||
* retained copy for screens that join later (follower-link.js). Scroll and form fields are small.
|
||||
*/
|
||||
var bs = window.__browserTab.stageState(t.id);
|
||||
if (bs) {
|
||||
snap.browser = bs;
|
||||
if (bs.domVer && (bs.domVer !== S.browserVer || S.lastSnapshot === '')) {
|
||||
var bh = window.__browserTab.stageHtml(t.id);
|
||||
if (bh && bh.ver === bs.domVer) { snap.browser.html = bh.html; S.browserVer = bs.domVer; }
|
||||
}
|
||||
}
|
||||
}
|
||||
// The notes tab tracks which point it is on; harmless elsewhere.
|
||||
if (typeof t.notesCurrentIndex === 'number') snap.notesIndex = t.notesCurrentIndex;
|
||||
@@ -241,6 +258,17 @@
|
||||
if (top !== S.lastScroll) { S.lastScroll = top; send({ type: 'scroll', tabId: t.id, scrollTop: top }); }
|
||||
}
|
||||
|
||||
// The Browser tab's page: its scroll per frame (coarse scroll makes text lurch, as above), and its form
|
||||
// fields as they are typed into — a few bytes a keystroke, never the whole page again.
|
||||
if (t.mode === 'browser' && window.__browserTab) {
|
||||
var bst = window.__browserTab.stageState(t.id);
|
||||
if (bst) {
|
||||
if (bst.scrollY !== S.lastBrowserY) { S.lastBrowserY = bst.scrollY; send({ type: 'browserScroll', tabId: t.id, y: bst.scrollY }); }
|
||||
var iv = bst.inputs ? JSON.stringify(bst.inputs) : '';
|
||||
if (iv !== S.lastBrowserInputs) { S.lastBrowserInputs = iv; if (bst.inputs) send({ type: 'browserInputs', tabId: t.id, values: bst.inputs }); }
|
||||
}
|
||||
}
|
||||
|
||||
// Maps pinch-zoom / pan, per frame while it changes (a pinch is as continuous as a stroke).
|
||||
var car = b.carousel(t.id);
|
||||
if (car && car.zoom) {
|
||||
@@ -292,6 +320,8 @@
|
||||
* Defined on every copy of the app; both are no-ops while this copy is not publishing.
|
||||
*/
|
||||
window.__followerPublish = {
|
||||
// browser-tab.js asks this to decide whether the page should bother publishing its DOM at all.
|
||||
isOpen: function () { return !!S.open; },
|
||||
invalidate: function () { S.strokeFingerprint = ''; S.lastKey = null; S.lastSnapshot = ''; if (S.open) { try { tick(); } catch (_) {} } },
|
||||
clearAll: function () { if (S.open) send({ type: 'clearAll', ts: Date.now() }); this.invalidate(); }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user