Keep the audiobooks frame alive when switching tabs
build-container / build (push) Successful in 2m12s

The frame was rebuilt with the page content on every route change, which
stopped playback. It now lives outside the view and is only shown or hidden.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-20 14:33:09 -04:00
1 parent cff7e9e59c
commit b5fb8b9c03
3 files changed
+20 -5

No files matched your search

+12 -4
View File
@@ -128,7 +128,8 @@ function route() {
try { editor?.destroyEditor(); } catch {}
editor = null;
document.body.classList.toggle('editing', name === 'edit');
document.body.classList.remove('inedit');
document.body.classList.remove('inedit', 'onaudio');
const aw = $('#audiowrap'); if (aw) aw.className = 'off'; // hide (not destroy) the audiobooks frame
renderNav(name === 'edit' ? 'files' : name);
routes[name](rest.map(decodeURIComponent));
$('#view').scrollTop = 0;
@@ -465,11 +466,18 @@ function viewAudio() {
const url = cfg.audiobooks, c = abCreds();
$('#view').innerHTML = `<div class="wrap"><h1>Audio</h1>
<p class="sub">${esc(new URL(url).host)}</p>
<div class="bar"><a class="btn" href="${esc(url)}" target="_blank" rel="noopener">Open in new tab</a>
<div class="bar" style="margin-bottom:0"><a class="btn" href="${esc(url)}" target="_blank" rel="noopener">Open in new tab</a>
${c.u ? `<button class="btn ghost" id="cu">${icon('copy')}Username</button>` : ''}
${c.p ? `<button class="btn ghost" id="cp">${icon('copy')}Password</button>` : ''}
${c.u || c.p ? '' : '<a class="btn ghost" href="#/settings">Save sign-in</a>'}</div>
<iframe class="frame" src="${esc(url)}" title="Audiobooks" allow="autoplay; fullscreen; picture-in-picture; clipboard-write"></iframe></div>`;
${c.u || c.p ? '' : '<a class="btn ghost" href="#/settings">Save sign-in</a>'}</div></div>`;
// Create the frame once and keep it: it is only shown/hidden, never rebuilt, so playback carries on across tabs.
const wrap = $('#audiowrap');
if (!wrap.firstChild) {
const f = document.createElement('iframe');
f.src = url; f.title = 'Audiobooks'; f.allow = 'autoplay; fullscreen; picture-in-picture; clipboard-write';
wrap.appendChild(f);
}
wrap.className = 'on'; document.body.classList.add('onaudio');
const copy = async (v, what) => { try { await navigator.clipboard.writeText(v); toast(what + ' copied. Paste it into the sign-in box.'); } catch { toast('Could not copy'); } };
const cu = $('#cu'), cp = $('#cp');
if (cu) cu.onclick = () => copy(c.u, 'Username');
+1 -1
View File
@@ -17,7 +17,7 @@
<body>
<div id="shell">
<nav id="nav" aria-label="Main"></nav>
<div id="main"><main id="view"></main><div id="player" hidden></div></div>
<div id="main"><main id="view"></main><div id="audiowrap" class="off"></div><div id="player" hidden></div></div>
</div>
<div id="toast" role="status"></div>
<script src="/webauthn.js"></script>
+7
View File
@@ -194,3 +194,10 @@ input[type=search] { width: 100%; min-height: 44px; padding: 0 14px; border-radi
/* Editor inside the Office tab: keep the nav, drop the page padding so the editor fills the space */
body.inedit #view { padding: 0; display: flex; flex-direction: column; }
/* Audiobooks frame lives outside #view so it keeps playing when you change tabs */
#audiowrap.off { position: fixed; left: -9999px; top: 0; width: 360px; height: 480px; overflow: hidden; }
#audiowrap.on { flex: 1; min-height: 0; padding: 0 calc(var(--sar) + 16px) 16px calc(var(--sal) + 16px); }
#audiowrap iframe { width: 100%; height: 100%; border: 1px solid var(--line); border-radius: 16px; background: var(--panel); }
body.onaudio #view { flex: none; overflow: visible; padding-bottom: 8px; }
@media (min-width: 768px) { #audiowrap.on { padding-right: 32px; padding-left: 32px; padding-bottom: 24px; } }