diff --git a/static/app.js b/static/app.js index 2cbecba..bda30e3 100644 --- a/static/app.js +++ b/static/app.js @@ -127,35 +127,18 @@ import { toggleSectionPracticePopover, } from './js/section-practice.js'; import { configureHost } from './js/host.js'; +// The playback transport. These used to BE app.js — they are imported back now, and the +// four modules that reached for them through the host seam import them directly instead. +import { + setPlayButtonState, jucePlayer, _audioTime, _audioDuration, _songEventPayload, + _markPlaybackPaused, _markPlaybackResumed, _emitPlaybackStopped, _emitSongPositionChanged, + _waitForSongReady, _resetAudioSeekState, _audioSeek, togglePlay, seekBy, audioSeekGen, +} from './js/transport.js'; // Demo analytics — real impl set by demo.js; no-op in normal builds window.feedBackDemoTrack = window.feedBackDemoTrack ?? null; -// Sync the play/pause button's icon and accessible state in one place so -// screen readers, tooltips, and aria-pressed stay aligned with playback. -// Updates the existing child's src in place rather than rewriting -// innerHTML, so any future children (fallback label, loading spinner, …) -// survive state changes. -function setPlayButtonState(isPlaying) { - const btn = document.getElementById('btn-play'); - if (!btn) return; - const label = isPlaying ? 'Pause' : 'Play'; - const icon = isPlaying ? 'pause' : 'play'; - let img = btn.querySelector('img.button-icon-svg'); - if (!img) { - img = document.createElement('img'); - img.className = 'button-icon-svg'; - img.alt = ''; - img.setAttribute('aria-hidden', 'true'); - btn.appendChild(img); - } - img.src = `/static/svg/${icon}.svg`; - btn.setAttribute('aria-label', label); - btn.setAttribute('aria-pressed', isPlaying ? 'true' : 'false'); - btn.title = label; -} - // ── Global keyboard shortcuts ───────────────────────────────────────────── // // `/` focuses the active screen's search input (Library / Favorites); @@ -3502,20 +3485,6 @@ function retuneSong(filename, title, tuning, target) { }; } -// ── Player ─────────────────────────────────────────────────────────────── -// `audio` now lives in ./js/audio-el.js so carved-out modules can reach the -// player without importing app.js back (which would close a cycle). Same -// element, same handle, same lookup — just imported instead of declared here. -let _lastSongPositionEventAt = 0; - -function _emitSongPositionChanged(time, duration) { - const now = Date.now(); - if (now - _lastSongPositionEventAt < 250) return; - _lastSongPositionEventAt = now; - const payload = (typeof _songEventPayload === 'function') ? _songEventPayload() : { time }; - window.feedBack.emit('song:position-changed', Object.assign(payload, { duration })); -} - function _applyPreservePitch(el) { if (!el) return; if ('preservesPitch' in el) el.preservesPitch = true; @@ -3529,94 +3498,6 @@ _applyPreservePitch(audio); // through the JUCE backing track player instead of the HTML5