Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -2,13 +2,15 @@
|
||||
|
||||
{% partialdef case-series %}
|
||||
{% for series in ordered_series %}
|
||||
<article class="series-block series-block-interactive"
|
||||
<article class="series-block series-block-interactive series-block-draggable"
|
||||
id="series-block-{{ series.pk }}"
|
||||
data-series-id="{{series.pk}}"
|
||||
data-series-label="Series {{ forloop.counter }}"
|
||||
data-series-name="{{ series|escape }}"
|
||||
data-image-ids='{{ series.get_image_url_array_and_count.0 }}'
|
||||
data-series-detail-url="{% url 'atlas:series_detail' pk=series.pk %}"
|
||||
data-series-popup-url="/atlas/series/{{series.pk}}">
|
||||
data-series-popup-url="/atlas/series/{{series.pk}}"
|
||||
draggable="true">
|
||||
<input type="checkbox" class="hide" name="series-ids" value="{{series.pk}}">
|
||||
<div class="series-card-shell">
|
||||
<button type="button"
|
||||
@@ -216,6 +218,29 @@
|
||||
border-color: rgba(13, 110, 253, 0.3);
|
||||
}
|
||||
|
||||
/* Draggable series block */
|
||||
.series-block-draggable {
|
||||
cursor: grab;
|
||||
position: relative;
|
||||
}
|
||||
.series-block-draggable:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
.series-block-draggable::after {
|
||||
content: '\2807';
|
||||
position: absolute;
|
||||
top: 0.35rem;
|
||||
right: 0.35rem;
|
||||
font-size: 0.85rem;
|
||||
color: rgba(120, 150, 200, 0.45);
|
||||
pointer-events: none;
|
||||
line-height: 1;
|
||||
}
|
||||
.series-block-draggable.dragging {
|
||||
opacity: 0.55;
|
||||
box-shadow: 0 4px 16px rgba(25, 118, 210, 0.35);
|
||||
}
|
||||
|
||||
.series-block-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -1836,6 +1861,106 @@
|
||||
});
|
||||
})();
|
||||
|
||||
// ── Series-block drag-and-drop to viewer viewports ──────────────────
|
||||
(function initSeriesBlockDrag() {
|
||||
if (window.__seriesBlockDragBound) return;
|
||||
window.__seriesBlockDragBound = true;
|
||||
|
||||
function getApiKey(viewerEl) {
|
||||
if (!viewerEl) return null;
|
||||
return viewerEl.id ? viewerEl.id.replace(/[^a-zA-Z0-9_]/g, '_') : null;
|
||||
}
|
||||
|
||||
function getMainViewer() {
|
||||
return document.getElementById('main_viewer') || document.querySelector('.dicom-viewer-root');
|
||||
}
|
||||
|
||||
document.querySelectorAll('.series-block-draggable[data-image-ids]').forEach(function (block) {
|
||||
block.addEventListener('dragstart', function (e) {
|
||||
const rawIds = block.getAttribute('data-image-ids') || '[]';
|
||||
const name = block.getAttribute('data-series-name') || block.getAttribute('data-series-label') || 'Series';
|
||||
try {
|
||||
// Validate it parses
|
||||
JSON.parse(rawIds);
|
||||
} catch (_) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
e.dataTransfer.setData('text/dv3d-imageids', rawIds);
|
||||
e.dataTransfer.setData('text/dv3d-stack-name', name);
|
||||
e.dataTransfer.effectAllowed = 'copy';
|
||||
block.classList.add('dragging');
|
||||
|
||||
// Ensure viewer is open so viewports can receive the drop.
|
||||
const viewerDetails = document.getElementById('dicom-viewer-details');
|
||||
if (viewerDetails && !viewerDetails.hasAttribute('open')) {
|
||||
viewerDetails.setAttribute('open', 'open');
|
||||
viewerDetails.dispatchEvent(new Event('toggle', { bubbles: true }));
|
||||
}
|
||||
});
|
||||
block.addEventListener('dragend', function () {
|
||||
block.classList.remove('dragging');
|
||||
});
|
||||
});
|
||||
|
||||
// Update View / View-in-new-pane buttons to use the direct external
|
||||
// stack API when image IDs are embedded on the series block, falling
|
||||
// back to the legacy state-import path when they are not.
|
||||
document.querySelectorAll('.series-open-primary-btn').forEach(function (btn) {
|
||||
btn._origClick = btn.onclick;
|
||||
btn.addEventListener('click', async function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
const seriesId = btn.getAttribute('data-series-id');
|
||||
const block = document.querySelector(`.series-block-draggable[data-series-id='${seriesId}']`);
|
||||
const rawIds = block ? block.getAttribute('data-image-ids') : null;
|
||||
if (!rawIds) return; // fall through to legacy handler
|
||||
let imageIds;
|
||||
try { imageIds = JSON.parse(rawIds); } catch (_) { return; }
|
||||
if (!Array.isArray(imageIds) || imageIds.length === 0) return;
|
||||
e.preventDefault();
|
||||
const viewerEl = getMainViewer();
|
||||
const apiKey = getApiKey(viewerEl);
|
||||
const loadFn = apiKey ? window[`loadExternalStack_${apiKey}`] : null;
|
||||
if (loadFn) {
|
||||
const name = btn.getAttribute('data-series-name') || 'Series';
|
||||
// Ensure viewer is visible first
|
||||
const viewerDetails = document.getElementById('dicom-viewer-details');
|
||||
if (viewerDetails && !viewerDetails.hasAttribute('open')) {
|
||||
viewerDetails.setAttribute('open', 'open');
|
||||
viewerDetails.dispatchEvent(new Event('toggle', { bubbles: true }));
|
||||
}
|
||||
try { await loadFn(imageIds, name); } catch (err) { console.error('loadExternalStack failed', err); }
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
|
||||
document.querySelectorAll('.series-open-new-viewport-btn').forEach(function (btn) {
|
||||
btn.addEventListener('click', async function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
const seriesId = btn.getAttribute('data-series-id');
|
||||
const block = document.querySelector(`.series-block-draggable[data-series-id='${seriesId}']`);
|
||||
const rawIds = block ? block.getAttribute('data-image-ids') : null;
|
||||
if (!rawIds) return;
|
||||
let imageIds;
|
||||
try { imageIds = JSON.parse(rawIds); } catch (_) { return; }
|
||||
if (!Array.isArray(imageIds) || imageIds.length === 0) return;
|
||||
e.preventDefault();
|
||||
const viewerEl = getMainViewer();
|
||||
const apiKey = getApiKey(viewerEl);
|
||||
const loadFn = apiKey ? window[`loadExternalStackNewViewport_${apiKey}`] : null;
|
||||
if (loadFn) {
|
||||
const name = btn.getAttribute('data-series-name') || 'Series';
|
||||
const viewerDetails = document.getElementById('dicom-viewer-details');
|
||||
if (viewerDetails && !viewerDetails.hasAttribute('open')) {
|
||||
viewerDetails.setAttribute('open', 'open');
|
||||
viewerDetails.dispatchEvent(new Event('toggle', { bubbles: true }));
|
||||
}
|
||||
try { await loadFn(imageIds, name); } catch (err) { console.error('loadExternalStackNewViewport failed', err); }
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
})();
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
+175
-175
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user