summaryrefslogtreecommitdiff
path: root/web/js/keyboard.js
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-03 19:17:04 +0300
committerPaul Buetow <paul@buetow.org>2026-05-03 19:17:04 +0300
commit30c2b0fe8232cc748ab2bded6ab4d76febe32425 (patch)
tree985578b326a1ff8fe7af395bf08471857376b8fc /web/js/keyboard.js
parent687b86cdeef2192272f0945ddd496322a9113f9e (diff)
fix(admin): fix rescan goroutine lifecycle and race on shared ScanProgress
- Protect adminService scan state (cancel func + progress pointer) with sync.Mutex. - Allocate fresh ScanProgress per trigger and pass it to the scanner, eliminating races on the previously shared progress struct. - Cancel previous scan context before starting a new one. - Add tests for cancellation, fresh progress per scan, concurrent triggers, and empty progress when never started. - Fix race-prone tests by polling Running==true before waiting for completion.
Diffstat (limited to 'web/js/keyboard.js')
-rw-r--r--web/js/keyboard.js50
1 files changed, 46 insertions, 4 deletions
diff --git a/web/js/keyboard.js b/web/js/keyboard.js
index 8623a10..951e573 100644
--- a/web/js/keyboard.js
+++ b/web/js/keyboard.js
@@ -3,6 +3,42 @@ export function initKeyboard(handlers) {
const tag = e.target.tagName;
const editing = tag === 'INPUT' || tag === 'TEXTAREA' || e.target.isContentEditable;
+ // Lightbox keyboard navigation (overrides global keys while open)
+ if (handlers.isLightboxOpen?.()) {
+ if (e.shiftKey && e.code === 'KeyS') {
+ e.preventDefault();
+ handlers.toggleSlideshow?.(e);
+ return;
+ }
+ switch (e.key) {
+ case 'ArrowLeft':
+ case 'h':
+ e.preventDefault();
+ handlers.lightboxPrev?.(e);
+ return;
+ case 'ArrowRight':
+ case 'l':
+ e.preventDefault();
+ handlers.lightboxNext?.(e);
+ return;
+ case 'Escape':
+ e.preventDefault();
+ handlers.closeLightbox?.(e);
+ return;
+ case '+':
+ case '=':
+ e.preventDefault();
+ handlers.zoomIn?.(e);
+ return;
+ case '-':
+ e.preventDefault();
+ handlers.zoomOut?.(e);
+ return;
+ }
+ // Allow only Escape/Arrows/h/l/+/−/Shift+S inside the lightbox; ignore everything else
+ return;
+ }
+
// Shares modal keyboard navigation (overrides global keys while open)
if (handlers.isSharesOpen?.()) {
switch (e.key) {
@@ -101,8 +137,15 @@ export function initKeyboard(handlers) {
}
if (e.code === 'KeyS') {
e.preventDefault();
- if (e.shiftKey) handlers.share?.(e);
- else handlers.sidebar?.(e);
+ if (e.shiftKey) {
+ if (handlers.isImageMode?.()) {
+ handlers.toggleSlideshow?.(e);
+ } else {
+ handlers.share?.(e);
+ }
+ } else {
+ handlers.sidebar?.(e);
+ }
return;
}
@@ -174,8 +217,7 @@ export function initKeyboard(handlers) {
case 'Escape': handlers.escape?.(e); break;
case 'Backspace': handlers.backspace?.(e); break;
case 'r': handlers.shuffle?.(e); break;
- case 's': handlers.sidebar?.(e); break;
- case 'S': handlers.share?.(e); break;
+ // Note: 's' / 'S' are handled above by the e.code === 'KeyS' block
case '/':
e.preventDefault();
handlers.search?.(e);