diff --git a/webui/backend/tests/golden/__pycache__/test_ui_smoke_golden.cpython-313.pyc b/webui/backend/tests/golden/__pycache__/test_ui_smoke_golden.cpython-313.pyc index 387bf88..d924355 100644 Binary files a/webui/backend/tests/golden/__pycache__/test_ui_smoke_golden.cpython-313.pyc and b/webui/backend/tests/golden/__pycache__/test_ui_smoke_golden.cpython-313.pyc differ diff --git a/webui/backend/tests/golden/test_ui_smoke_golden.py b/webui/backend/tests/golden/test_ui_smoke_golden.py index bd7f840..58fa5d5 100644 --- a/webui/backend/tests/golden/test_ui_smoke_golden.py +++ b/webui/backend/tests/golden/test_ui_smoke_golden.py @@ -200,7 +200,12 @@ class UiSmokeGoldenTest(unittest.TestCase): self.assertIn('function imageElements()', app_js) self.assertIn('function isImageSelection(item)', app_js) self.assertIn('async function openImageViewer()', app_js) + self.assertIn('if (isImageSelection(item)) {', app_js) + self.assertIn('openImageViewer();', app_js) self.assertIn('function isImageOpen()', app_js) + self.assertIn('requestAnimationFrame(() => {', app_js) + self.assertIn('if (!fitImageToViewport()) {', app_js) + self.assertIn('if (!viewport.clientWidth || !viewport.clientHeight) {', app_js) self.assertIn("`/api/files/image?", app_js) self.assertIn('if (isImageSelection(selected)) {', app_js) self.assertIn('document.getElementById("info-modal")', app_js) diff --git a/webui/html/app.js b/webui/html/app.js index 1fc8e6a..8e1ac4a 100644 --- a/webui/html/app.js +++ b/webui/html/app.js @@ -1009,7 +1009,16 @@ function renderPaneItems(pane) { } renderPaneItems(pane); }; - if (entry.kind === "file" && isVideoSelection({ path: entry.path, name: entry.name, kind: entry.kind })) { + if (entry.kind === "file" && isImageSelection({ path: entry.path, name: entry.name, kind: entry.kind })) { + row.ondblclick = (ev) => { + ev.stopPropagation(); + setActivePane(pane); + model.currentRowIndex = index; + setSingleSelectionAtIndex(pane, { path: entry.path, name: entry.name, kind: entry.kind }, index); + renderPaneItems(pane); + openImageViewer(); + }; + } else if (entry.kind === "file" && isVideoSelection({ path: entry.path, name: entry.name, kind: entry.kind })) { row.ondblclick = (ev) => { ev.stopPropagation(); setActivePane(pane); @@ -1827,13 +1836,21 @@ function fitImageToViewport() { const image = imageElements().image; const viewport = imageElements().viewport; if (!image.naturalWidth || !image.naturalHeight) { - return; + return false; + } + if (!viewport.clientWidth || !viewport.clientHeight) { + return false; } const widthScale = viewport.clientWidth / image.naturalWidth; const heightScale = viewport.clientHeight / image.naturalHeight; - imageViewerState.fitScale = Math.min(widthScale, heightScale, 1); + const fitScale = Math.min(widthScale, heightScale, 1); + if (!Number.isFinite(fitScale) || fitScale <= 0) { + return false; + } + imageViewerState.fitScale = fitScale; imageViewerState.scale = imageViewerState.fitScale; applyImageScale(); + return true; } function adjustImageZoom(multiplier) { @@ -2232,7 +2249,13 @@ async function openImageViewer() { image.error.textContent = ""; image.image.alt = selected.name; image.image.onload = () => { - fitImageToViewport(); + requestAnimationFrame(() => { + if (!fitImageToViewport()) { + requestAnimationFrame(() => { + fitImageToViewport(); + }); + } + }); image.image.onload = null; }; image.image.onerror = () => { @@ -2405,6 +2428,10 @@ function openCurrentDirectory() { navigateTo(pane, item.path); return; } + if (isImageSelection(item)) { + openImageViewer(); + return; + } if (isVideoSelection(item)) { openVideoViewer(); }