From c947cba5a7c9d7946ed2cb5b7b03ff172f3bcc20 Mon Sep 17 00:00:00 2001 From: Ross Date: Fri, 15 May 2026 20:11:31 +0100 Subject: [PATCH] feat(viewer): Enhance viewer functionality with sidebar and popout support --- .../atlas/collection_case_view_take.html | 385 ++++++++++++++++-- atlas/templates/atlas/viewer_local.html | 104 +++-- 2 files changed, 435 insertions(+), 54 deletions(-) diff --git a/atlas/templates/atlas/collection_case_view_take.html b/atlas/templates/atlas/collection_case_view_take.html index 5df440b6..f91462d5 100644 --- a/atlas/templates/atlas/collection_case_view_take.html +++ b/atlas/templates/atlas/collection_case_view_take.html @@ -101,39 +101,59 @@ {% endif %} - {% if collection.show_ohif_viewer %} -
- - {% if question_completed %} - - {% else %} - - {% endif %} - + {% if collection.show_ohif_viewer or collection.show_ohif_viewer_link or collection.show_built_in_viewer %} +
+ {% if collection.show_built_in_viewer %} +
+ Viewer + +
+
+
+
+
+ Series +
+
+
+
+
+
+
+
+ {% endif %} + + {% if collection.show_ohif_viewer %} + + {% if question_completed %} + + {% else %} + + {% endif %} +
+ {% endif %} + + {% if collection.show_ohif_viewer_link %} +
+ {% if question_completed %} + + {% else %} + + {% endif %} +
+ {% endif %} +
{% endif %} - {% if collection.show_ohif_viewer_link %} -
- {% if question_completed %} - - {% else %} - - {% endif %} -
- {% endif %} - - {% if collection.show_built_in_viewer %} - -
- Viewer -
-
- {% comment %}
@@ -165,8 +185,6 @@
{% endcomment %} - {% else %} - {% endif %} {% if show_discussion and case.discussion %}
@@ -335,6 +353,14 @@ + + {% endblock %} @@ -823,4 +959,191 @@ + + {% endblock js %} diff --git a/atlas/templates/atlas/viewer_local.html b/atlas/templates/atlas/viewer_local.html index bc46503e..e1fe6df6 100644 --- a/atlas/templates/atlas/viewer_local.html +++ b/atlas/templates/atlas/viewer_local.html @@ -86,6 +86,7 @@ document.title = "Case: {{current_case.title}}"; console.log('ready'); const bc = new BroadcastChannel("viva_load"); + const POPOUT_STATE_KEY = 'rad_local_viewer_popout_state'; // Centralized hide helper and delegated close handling for local viewer function hideResourceLocal(){ const disp=document.getElementById('resourceDisplay'); const inner=document.getElementById('resourceInner'); if(disp) disp.style.display='none'; if(inner) inner.innerHTML=''; } @@ -114,6 +115,83 @@ } catch (err) { console.warn('Viewer initialization deferred/fallback:', err); } } + function applyViewerPayload(payload) { + if (!payload || payload.type !== 'open') { + return; + } + + var root = document.getElementById('root'); + var awaiting = document.getElementById('awaiting-modal'); + if (!root) { + return; + } + + if (awaiting) { + awaiting.style.display = 'none'; + } + + if (payload.namedStacks) { + root.dataset.namedStacks = payload.namedStacks; + } else { + delete root.dataset.namedStacks; + } + + if (payload.images) { + root.dataset.images = payload.images; + } else { + delete root.dataset.images; + } + + if (payload.viewerstate && Object.keys(payload.viewerstate).length > 0) { + root.dataset.viewerstate = payload.viewerstate; + } else { + delete root.dataset.viewerstate; + } + + if (payload.annotations && Object.keys(payload.annotations).length > 0) { + root.dataset.annotationjson = payload.annotations; + } else { + delete root.dataset.annotationjson; + } + + mountDicomViewersSafely(); + } + + function persistViewerPayload(payload) { + try { + localStorage.setItem(POPOUT_STATE_KEY, JSON.stringify(payload)); + } catch (e) { + console.warn('Could not persist viewer payload', e); + } + } + + function readPersistedViewerPayload() { + try { + var saved = localStorage.getItem(POPOUT_STATE_KEY); + return saved ? JSON.parse(saved) : null; + } catch (e) { + console.warn('Could not read persisted viewer payload', e); + return null; + } + } + + var savedPayload = readPersistedViewerPayload(); + if (savedPayload) { + applyViewerPayload(savedPayload); + } + + window.addEventListener('storage', function (event) { + if (event.key !== POPOUT_STATE_KEY || !event.newValue) { + return; + } + + try { + applyViewerPayload(JSON.parse(event.newValue)); + } catch (e) { + console.warn('Could not parse updated viewer payload', e); + } + }); + bc.onmessage = (event) => { // Ensure any existing overlay is closed on new load try { hideResourceLocal(); } catch(_) {} @@ -179,33 +257,13 @@ if (event.data.url && isMediaUrl(event.data.url)) { // show resource overlay and do not attempt to mount DICOM viewer if (showResource(event.data.url)) { + persistViewerPayload(event.data); bc.postMessage({"type": "open-complete-local"}); return; } } - // Hide modal when data is loaded - document.getElementById("awaiting-modal").style.display = "none"; - document.getElementById("root").dataset.images = event.data.images; - - if ( - event.data.viewerstate && - Object.keys(event.data.viewerstate).length > 0 - ) { - document.getElementById("root").dataset.viewerstate = event.data.viewerstate; - } else { - delete document.getElementById("root").dataset.viewerstate; - } - console.log("Annotations:", event.data.annotations); - if ( - event.data.annotations && - Object.keys(event.data.annotations).length > 0 - ) { - document.getElementById("root").dataset.annotationjson = event.data.annotations; - } else { - delete document.getElementById("root").dataset.annotationjson; - } - - mountDicomViewersSafely(); + persistViewerPayload(event.data); + applyViewerPayload(event.data); bc.postMessage({"type": "open-complete-local"}); } };