feat: Enhance case selection functionality with dedicated select button and improved event handling
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
{% load case_widgets %}
|
{% load case_widgets %}
|
||||||
|
|
||||||
{% partialdef case-series %}
|
{% partialdef case-series %}
|
||||||
@@ -475,6 +474,7 @@
|
|||||||
|
|
||||||
<details class="series-move-panel border rounded p-2">
|
<details class="series-move-panel border rounded p-2">
|
||||||
<summary class="small fw-semibold">Move selected series to another case</summary>
|
<summary class="small fw-semibold">Move selected series to another case</summary>
|
||||||
|
aaoecuthsaoehntu
|
||||||
{% if move_series_form %}
|
{% if move_series_form %}
|
||||||
<form id="move-selected-series-form" class="d-flex flex-column gap-2 mt-2">
|
<form id="move-selected-series-form" class="d-flex flex-column gap-2 mt-2">
|
||||||
{{ move_series_form.destination_case }}
|
{{ move_series_form.destination_case }}
|
||||||
@@ -498,6 +498,30 @@
|
|||||||
if (window.__moveSeriesCaseSelectionBound) return;
|
if (window.__moveSeriesCaseSelectionBound) return;
|
||||||
window.__moveSeriesCaseSelectionBound = true;
|
window.__moveSeriesCaseSelectionBound = true;
|
||||||
|
|
||||||
|
function applyMoveCaseSelection(casePk, caseTitle) {
|
||||||
|
if (!casePk) return;
|
||||||
|
|
||||||
|
const form = document.getElementById('move-selected-series-form');
|
||||||
|
const hiddenInput = form ? form.querySelector("[name='destination_case']") : null;
|
||||||
|
const label = document.getElementById('selected-move-case');
|
||||||
|
const results = document.getElementById('move-series-case-search-results');
|
||||||
|
if (!hiddenInput) return;
|
||||||
|
|
||||||
|
hiddenInput.value = casePk;
|
||||||
|
if (label) {
|
||||||
|
label.innerHTML = 'Selected destination: <strong>' + caseTitle + ' (' + casePk + ')</strong>';
|
||||||
|
label.classList.remove('text-muted');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results) {
|
||||||
|
results.querySelectorAll('.list-group-item[data-case-pk]').forEach(function (item) {
|
||||||
|
item.classList.toggle('active', String(item.getAttribute('data-case-pk')) === String(casePk));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
syncMoveSeriesSubmitState();
|
||||||
|
}
|
||||||
|
|
||||||
function syncMoveSeriesSubmitState() {
|
function syncMoveSeriesSubmitState() {
|
||||||
const form = document.getElementById('move-selected-series-form');
|
const form = document.getElementById('move-selected-series-form');
|
||||||
const hiddenInput = form ? form.querySelector("[name='destination_case']") : null;
|
const hiddenInput = form ? form.querySelector("[name='destination_case']") : null;
|
||||||
@@ -506,29 +530,44 @@
|
|||||||
submitBtn.disabled = !hiddenInput.value;
|
submitBtn.disabled = !hiddenInput.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.addEventListener('case:selected', async function (e) {
|
function selectFromRow(row) {
|
||||||
|
if (!row) return;
|
||||||
|
const casePk = row.getAttribute('data-case-pk');
|
||||||
|
const caseTitleEl = row.querySelector('h6');
|
||||||
|
const caseTitle = caseTitleEl ? caseTitleEl.textContent.trim() : ('Case #' + casePk);
|
||||||
|
applyMoveCaseSelection(casePk, caseTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hard fallback: capture-phase click listener scoped to this widget results.
|
||||||
|
document.addEventListener('click', function (e) {
|
||||||
|
try {
|
||||||
|
const row = e.target.closest('#move-series-case-search-results .list-group-item[data-case-pk]');
|
||||||
|
if (!row) return;
|
||||||
|
if (e.target.closest('a,button,form,input')) return;
|
||||||
|
selectFromRow(row);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Move series capture click handler error', err);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
// Mirror uploads-style delegated click handling directly on rows.
|
||||||
|
document.body.addEventListener('click', function (e) {
|
||||||
|
try {
|
||||||
|
const item = e.target.closest('#move-series-case-search-results .list-group-item[data-case-pk]');
|
||||||
|
if (!item) return;
|
||||||
|
if (e.target.closest('a,button,form,input')) return;
|
||||||
|
selectFromRow(item);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Move series row click handler error', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.addEventListener('case:selected', function (e) {
|
||||||
try {
|
try {
|
||||||
console.log('Received case:selected event', e);
|
|
||||||
const detail = e.detail || {};
|
const detail = e.detail || {};
|
||||||
const casePk = detail.casePk;
|
const casePk = detail.casePk;
|
||||||
const caseTitle = detail.caseTitle || ('Case #' + casePk);
|
const caseTitle = detail.caseTitle || ('Case #' + casePk);
|
||||||
if (!casePk) return;
|
applyMoveCaseSelection(casePk, caseTitle);
|
||||||
|
|
||||||
// Only react to selections from this move panel's widget.
|
|
||||||
if (!e.target || !e.target.closest('#move-selected-series-form')) return;
|
|
||||||
|
|
||||||
const form = document.getElementById('move-selected-series-form');
|
|
||||||
const hiddenInput = form ? form.querySelector("[name='destination_case']") : null;
|
|
||||||
const label = document.getElementById('selected-move-case');
|
|
||||||
if (!hiddenInput) return;
|
|
||||||
|
|
||||||
hiddenInput.value = casePk;
|
|
||||||
if (label) {
|
|
||||||
label.innerHTML = 'Selected destination: <strong>' + caseTitle + ' (' + casePk + ')</strong>';
|
|
||||||
label.classList.remove('text-muted');
|
|
||||||
}
|
|
||||||
|
|
||||||
syncMoveSeriesSubmitState();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Move series case:selected handler error', err);
|
console.error('Move series case:selected handler error', err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@
|
|||||||
</form>
|
</form>
|
||||||
<a class="btn btn-sm btn-outline-secondary ms-2" href="{% url 'atlas:case_detail' case.pk %}" target="_blank" rel="noopener">View</a>
|
<a class="btn btn-sm btn-outline-secondary ms-2" href="{% url 'atlas:case_detail' case.pk %}" target="_blank" rel="noopener">View</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:case_detail' case.pk %}">View</a>
|
<button type="button" class="btn btn-sm btn-outline-primary case-select-btn" data-case-select="{{ case.pk }}">Select</button>
|
||||||
|
<a class="btn btn-sm btn-outline-secondary ms-2" href="{% url 'atlas:case_detail' case.pk %}">View</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -60,8 +60,14 @@
|
|||||||
targetEl.addEventListener('click', function(e){
|
targetEl.addEventListener('click', function(e){
|
||||||
var item = e.target.closest('.list-group-item');
|
var item = e.target.closest('.list-group-item');
|
||||||
if (!item || !targetEl.contains(item)) return;
|
if (!item || !targetEl.contains(item)) return;
|
||||||
// Ignore clicks on interactive elements inside the item (links, buttons, forms, inputs)
|
|
||||||
if (e.target.closest('a,button,form,input')) return;
|
// Explicit select action button should always select the row.
|
||||||
|
if (e.target.closest('.case-select-btn')) {
|
||||||
|
e.preventDefault();
|
||||||
|
} else {
|
||||||
|
// Ignore other interactive elements inside the item (links, buttons, forms, inputs)
|
||||||
|
if (e.target.closest('a,button,form,input')) return;
|
||||||
|
}
|
||||||
|
|
||||||
var casePk = item.getAttribute('data-case-pk');
|
var casePk = item.getAttribute('data-case-pk');
|
||||||
if (!casePk) {
|
if (!casePk) {
|
||||||
|
|||||||
Reference in New Issue
Block a user