summaryrefslogtreecommitdiff
path: root/web/js/keyboard.js
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-17 15:25:52 +0300
committerPaul Buetow <paul@buetow.org>2026-05-17 15:25:52 +0300
commit914bd7cd6aa14e839332a98d91c30b19865b0cf2 (patch)
tree02b11537237a204048589e14ed24938b805e42f7 /web/js/keyboard.js
parent3b24f0e1be832584d6550e8cc3e5d24329f66f90 (diff)
Restructure repo: move Go server into player-server/
Diffstat (limited to 'web/js/keyboard.js')
-rw-r--r--web/js/keyboard.js308
1 files changed, 0 insertions, 308 deletions
diff --git a/web/js/keyboard.js b/web/js/keyboard.js
deleted file mode 100644
index 1636754..0000000
--- a/web/js/keyboard.js
+++ /dev/null
@@ -1,308 +0,0 @@
-export function initKeyboard(handlers) {
- document.addEventListener('keydown', (e) => {
- const tag = e.target.tagName;
- const nativeControl = tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' ||
- tag === 'BUTTON' || tag === 'A' || 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) {
- case 'ArrowUp':
- case 'k':
- e.preventDefault();
- handlers.sharesNavUp?.(e);
- return;
- case 'ArrowDown':
- case 'j':
- e.preventDefault();
- handlers.sharesNavDown?.(e);
- return;
- case 'Enter':
- e.preventDefault();
- handlers.sharesCopy?.(e);
- return;
- case 'Delete':
- e.preventDefault();
- handlers.sharesDelete?.(e);
- return;
- case 'Escape':
- e.preventDefault();
- handlers.sharesToggle?.(e);
- return;
- }
- // Allow only Escape/Enter/Arrows/k/j/d inside the shares modal; ignore everything else
- return;
- }
-
- // Media info modal keyboard scrolling.
- if (handlers.isMediaInfoOpen?.()) {
- switch (e.key) {
- case 'ArrowUp':
- case 'k':
- e.preventDefault();
- handlers.mediaInfoScroll?.(-1, e);
- return;
- case 'ArrowDown':
- case 'j':
- e.preventDefault();
- handlers.mediaInfoScroll?.(1, e);
- return;
- case 'Escape':
- e.preventDefault();
- handlers.closeMediaInfo?.(e);
- return;
- }
- return;
- }
-
- if (nativeControl) {
- if (e.key === 'Escape') {
- e.target.blur();
- handlers.escape?.(e);
- }
- return;
- }
-
- // Tab / Shift+Tab set navigation when sidebar is open
- if (e.key === 'Tab') {
- if (handlers.isSidebarOpen?.()) {
- e.preventDefault();
- if (e.shiftKey) {
- handlers.prevSet?.(e);
- } else {
- handlers.nextSet?.(e);
- }
- }
- return;
- }
-
- // Space toggles focused set selection when sidebar is focused/open
- if (e.key === ' ') {
- if (handlers.isSidebarFocused?.()) {
- e.preventDefault();
- handlers.toggleSetSelect?.(e);
- return;
- }
- e.preventDefault();
- handlers.playPause?.(e);
- return;
- }
-
- if (e.ctrlKey || e.metaKey || e.altKey) return; // don't intercept browser shortcuts
-
- const imageDelta = fullscreenImageDelta(e);
- if (imageDelta && handlers.imageFullscreenNavigate?.(imageDelta)) {
- e.preventDefault();
- return;
- }
-
- if (/^[1-9]$/.test(e.key) && handlers.selectSetByHotkey?.(e.key)) {
- e.preventDefault();
- return;
- }
-
- if (e.shiftKey) {
- switch (e.key) {
- case 'ArrowUp':
- case 'ArrowDown':
- case 'ArrowLeft':
- case 'ArrowRight': {
- const dx = e.key === 'ArrowLeft' ? -10 : e.key === 'ArrowRight' ? 10 : 0;
- const dy = e.key === 'ArrowUp' ? -10 : e.key === 'ArrowDown' ? 10 : 0;
- const acted = handlers.shiftCropPosition?.(dx, dy);
- if (acted) {
- e.preventDefault();
- return;
- }
- break;
- }
- }
- }
-
- if (e.shiftKey && e.code === 'KeyN') {
- e.preventDefault();
- handlers.nextTrack?.(e);
- return;
- }
- if (e.shiftKey && e.code === 'KeyP') {
- e.preventDefault();
- handlers.prevTrack?.(e);
- return;
- }
- if (e.code === 'KeyS') {
- e.preventDefault();
- handlers.share?.(e);
- return;
- }
-
- switch (e.key) {
- // Navigation
- case 'ArrowUp':
- e.preventDefault();
- handlers.navUp?.(e);
- break;
- case 'ArrowDown':
- e.preventDefault();
- handlers.navDown?.(e);
- break;
- case 'ArrowLeft':
- if (handlers.seekBackward?.(e)) {
- e.preventDefault();
- break;
- }
- handlers.navLeft?.(e);
- break;
- case 'ArrowRight':
- if (handlers.seekForward?.(e)) {
- e.preventDefault();
- break;
- }
- handlers.navRight?.(e);
- break;
- // Vim-style navigation
- case 'k':
- e.preventDefault();
- handlers.navUp?.(e);
- break;
- case 'j':
- e.preventDefault();
- handlers.navDown?.(e);
- break;
- case 'h':
- if (handlers.seekBackward?.(e)) {
- e.preventDefault();
- break;
- }
- handlers.navLeft?.(e);
- break;
- case 'l':
- if (handlers.seekForward?.(e)) {
- e.preventDefault();
- break;
- }
- handlers.navRight?.(e);
- break;
- case 'PageUp':
- if (handlers.seekPercent?.(e, -0.10)) {
- e.preventDefault();
- }
- break;
- case 'PageDown':
- if (handlers.seekPercent?.(e, 0.10)) {
- e.preventDefault();
- }
- break;
- case 'Enter':
- e.preventDefault();
- handlers.enter?.(e);
- break;
- case 'n':
- handlers.notes?.(e);
- break;
- case 'p':
- e.preventDefault();
- handlers.playPause?.(e);
- break;
- case 'N':
- e.preventDefault();
- handlers.nextTrack?.(e);
- break;
- case 'P':
- e.preventDefault();
- handlers.prevTrack?.(e);
- break;
- case 'C': handlers.toggleMinimize?.(e); break;
- case 'f': handlers.fullscreen?.(e); break;
- case 'c': handlers.toggleCrop?.(e); break;
- case 'x':
- e.preventDefault();
- handlers.cycleCropPosition?.(e);
- break;
- case 'Escape': handlers.escape?.(e); break;
- case 'Backspace': handlers.backspace?.(e); break;
- case 'r': handlers.shuffle?.(e); break;
- case 'R':
- e.preventDefault();
- handlers.playRandom?.(e);
- break;
- case 'M':
- e.preventDefault();
- handlers.rescanMedia?.(e);
- break;
- // Note: 's' / 'S' are handled above by the e.code === 'KeyS' block
- case '/':
- e.preventDefault();
- handlers.search?.(e);
- break;
- case 'i': handlers.mediaInfo?.(e); break;
- case 'd': handlers.toggleDetach?.(e); break;
- case 'D': handlers.download?.(e); break;
- case 'u': handlers.upload?.(e); break;
- case 'L': handlers.sharesToggle?.(e); break;
- case 'T': handlers.regenThumbnail?.(e); break;
- case 'q':
- e.preventDefault();
- handlers.stopAndClose?.(e);
- break;
- case '?':
- e.preventDefault();
- handlers.help?.(e);
- break;
- }
- });
-}
-
-function fullscreenImageDelta(e) {
- switch (e.key) {
- case 'ArrowLeft':
- case 'ArrowUp':
- case 'h':
- case 'k':
- case 'PageUp':
- return e.key === 'PageUp' ? -10 : -1;
- case 'ArrowRight':
- case 'ArrowDown':
- case 'j':
- case 'l':
- case 'PageDown':
- return e.key === 'PageDown' ? 10 : 1;
- default:
- return 0;
- }
-}