feat: O key opens the current clip in the full file

Extracts the "Open in file" button handler into openClipInFile() and
binds O in the shared keydown listener as a keyboard alternative, so
clip review never needs the mouse: J/K/U/I to step, O to drop into the
full recording for context.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 16:24:30 +02:00
parent 13419244e8
commit 9f1a6ff711
3 changed files with 12 additions and 7 deletions
+10 -5
View File
@@ -185,7 +185,7 @@ body.clip-open{padding-bottom:70px}
<label id="clip-auto-label"><input type="checkbox" id="clip-auto" checked> Auto-advance</label>
<label id="clip-hl-label" title="J/K, Prev/Next and auto-advance skip everything outside the top sections"><input type="checkbox" id="clip-hl-only"> Highlights only</label>
<label id="clip-top-label" title="How many top-scored sections count as highlights">Top <input type="number" id="clip-top" min="1" step="1" value="50" aria-label="Number of top-scored sections treated as highlights"></label>
<button id="clip-context" title="Open the full recording at this position">Open in file</button>
<button id="clip-context" title="Open the full recording at this position (O)" aria-label="Open in file (O)">Open in file</button>
<button id="clip-close" aria-label="Close clip player">&times;</button>
</div>
<script>
@@ -425,7 +425,9 @@ document.getElementById('clip-audio').addEventListener('ended', () => {
if (document.getElementById('clip-auto').checked)
stepClip(1, highlightsOnly());
});
document.getElementById('clip-context').addEventListener('click', () => {
// "Open in file": switch from the current clip to the full recording at the
// same position. Bound to the clip-bar button and the O key.
function openClipInFile() {
const c = clipQueue[clipCursor];
if (!c) return;
document.getElementById('clip-audio').pause();
@@ -437,7 +439,8 @@ document.getElementById('clip-context').addEventListener('click', () => {
row.scrollIntoView({block: 'center'});
}
seekToSection(c.fileIdx, c.filename, c.start, c.end, null);
});
}
document.getElementById('clip-context').addEventListener('click', openClipInFile);
// filename|margin|gap|minDur -> analysis result, so re-renders (filtering,
// refresh) never refetch what this session already has
@@ -516,15 +519,17 @@ async function analyse(idx, filename, cell, btn, force = false) {
}
}
// J/K = previous/next section, U/I = previous/next highlight (top-N by score).
// J/K = previous/next section, U/I = previous/next highlight (top-N by score),
// O = open the current clip in the full file.
// With "Highlights only" checked, J/K behave like U/I.
// Only when focus is not in an input.
document.addEventListener('keydown', e => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
if (e.ctrlKey || e.metaKey || e.altKey) return;
const key = e.key.toLowerCase();
if (key !== 'j' && key !== 'k' && key !== 'u' && key !== 'i') return;
if (key !== 'j' && key !== 'k' && key !== 'u' && key !== 'i' && key !== 'o') return;
e.preventDefault();
if (key === 'o') { openClipInFile(); return; }
const dir = (key === 'j' || key === 'u') ? -1 : 1;
const hlOnly = key === 'u' || key === 'i' || highlightsOnly();