Enhance finding and display set widgets with explicit case filtering and badge indicators
This commit is contained in:
@@ -13,6 +13,13 @@
|
||||
hx-trigger="keyup changed delay:400ms"
|
||||
autocomplete="off">
|
||||
|
||||
<div class="mt-1">
|
||||
<span id="{{ input_id }}-case-badge" class="badge bg-secondary" style="display: {% if case %}inline-block{% else %}none{% endif %};">
|
||||
{% if case %}Filtering: {{ case.title|escape }}{% endif %}
|
||||
</span>
|
||||
<button type="button" id="{{ input_id }}-clear-case" class="btn btn-sm btn-outline-secondary ms-2" style="display: {% if case %}inline-block{% else %}none{% endif %};">✕</button>
|
||||
</div>
|
||||
|
||||
<div id="{{ target_id }}" class="mt-2">
|
||||
{% include 'atlas/partials/_displayset_search_results.html' with displaysets=displaysets case=case %}
|
||||
</div>
|
||||
@@ -46,3 +53,62 @@
|
||||
} catch(e) { console.error('displayset search widget init error', e); }
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
try{
|
||||
var input = document.getElementById('{{ input_id|default:"displayset-search-input" }}');
|
||||
if(!input) return;
|
||||
|
||||
// Ensure a current-case-meta element exists
|
||||
var meta = document.getElementById('current-case-meta');
|
||||
if(!meta){
|
||||
meta = document.createElement('div');
|
||||
meta.id = 'current-case-meta';
|
||||
meta.style.display = 'none';
|
||||
var container = document.currentScript && document.currentScript.parentNode ? document.currentScript.parentNode : document.body;
|
||||
container.insertBefore(meta, container.firstChild);
|
||||
}
|
||||
|
||||
// Populate meta from server-rendered attributes if present (existing behavior)
|
||||
// If not present, do not attempt further heuristics here; widget owns filter logic.
|
||||
|
||||
// If meta has case info, push it into the input dataset and to a nearby textarea so the inserter can read it
|
||||
var casePk = meta.getAttribute('data-current-case');
|
||||
var caseTitle = meta.getAttribute('data-current-case-title') || '';
|
||||
var badge = document.getElementById('{{ input_id }}-case-badge');
|
||||
var clearBtn = document.getElementById('{{ input_id }}-clear-case');
|
||||
|
||||
function applyCaseToInputs(pk, title){
|
||||
if(pk){
|
||||
input.dataset.currentCase = pk;
|
||||
if(title) input.dataset.currentCaseTitle = title;
|
||||
// find a nearby textarea (same form or container)
|
||||
var container = input.closest('form,div') || document.body;
|
||||
var ta = container.querySelector('textarea');
|
||||
if(ta){ ta.dataset.currentCase = pk; if(title) ta.dataset.currentCaseTitle = title; }
|
||||
if(badge){ badge.style.display = 'inline-block'; badge.textContent = 'Filtering: ' + (title || ('#' + pk)); }
|
||||
if(clearBtn) clearBtn.style.display = 'inline-block';
|
||||
} else {
|
||||
delete input.dataset.currentCase; delete input.dataset.currentCaseTitle;
|
||||
var container = input.closest('form,div') || document.body;
|
||||
var ta = container.querySelector('textarea');
|
||||
if(ta){ delete ta.dataset.currentCase; delete ta.dataset.currentCaseTitle; }
|
||||
if(badge) badge.style.display = 'none';
|
||||
if(clearBtn) clearBtn.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
if(casePk){ applyCaseToInputs(casePk, caseTitle); }
|
||||
|
||||
if(clearBtn){ clearBtn.addEventListener('click', function(){
|
||||
// clear widget-level filter state and refresh results without case
|
||||
applyCaseToInputs(null, null);
|
||||
// remove any hx-vals forcing a case param
|
||||
try{ input.removeAttribute('hx-vals'); }catch(e){}
|
||||
input.dispatchEvent(new Event('input'));
|
||||
}); }
|
||||
|
||||
}catch(e){ console.error('displayset widget meta init error', e); }
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
hx-trigger="keyup changed delay:400ms"
|
||||
autocomplete="off">
|
||||
|
||||
<div class="mt-1">
|
||||
<span id="{{ input_id }}-case-badge" class="badge bg-secondary" style="display: {% if case %}inline-block{% else %}none{% endif %};">
|
||||
{% if case %}Filtering: {{ case.title|escape }}{% endif %}
|
||||
</span>
|
||||
<button type="button" id="{{ input_id }}-clear-case" class="btn btn-sm btn-outline-secondary ms-2" style="display: {% if case %}inline-block{% else %}none{% endif %};">✕</button>
|
||||
</div>
|
||||
|
||||
<div id="{{ target_id }}" class="mt-2">
|
||||
{% include 'atlas/partials/_finding_search_results.html' with findings=findings case=case %}
|
||||
</div>
|
||||
@@ -22,12 +29,45 @@
|
||||
var input = document.getElementById('{{ input_id|default:"finding-search-input" }}');
|
||||
if (!input) return;
|
||||
var timer = null;
|
||||
|
||||
// If server provided a case via inclusion, ensure widget sets dataset and nearby textarea dataset
|
||||
var meta = document.getElementById('current-case-meta');
|
||||
var casePk = meta ? meta.getAttribute('data-current-case') : null;
|
||||
var caseTitle = meta ? meta.getAttribute('data-current-case-title') : '';
|
||||
var badge = document.getElementById('{{ input_id }}-case-badge');
|
||||
var clearBtn = document.getElementById('{{ input_id }}-clear-case');
|
||||
|
||||
function applyCaseToInputs(pk, title){
|
||||
if(pk){
|
||||
input.dataset.currentCase = pk;
|
||||
if(title) input.dataset.currentCaseTitle = title;
|
||||
var container = input.closest('form,div') || document.body;
|
||||
var ta = container.querySelector('textarea');
|
||||
if(ta){ ta.dataset.currentCase = pk; if(title) ta.dataset.currentCaseTitle = title; }
|
||||
if(badge){ badge.style.display = 'inline-block'; badge.textContent = 'Filtering: ' + (title || ('#' + pk)); }
|
||||
if(clearBtn) clearBtn.style.display = 'inline-block';
|
||||
} else {
|
||||
delete input.dataset.currentCase; delete input.dataset.currentCaseTitle;
|
||||
var container = input.closest('form,div') || document.body;
|
||||
var ta = container.querySelector('textarea');
|
||||
if(ta){ delete ta.dataset.currentCase; delete ta.dataset.currentCaseTitle; }
|
||||
if(badge) badge.style.display = 'none';
|
||||
if(clearBtn) clearBtn.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
if(casePk){ applyCaseToInputs(casePk, caseTitle); }
|
||||
|
||||
if(clearBtn){ clearBtn.addEventListener('click', function(){ applyCaseToInputs(null, null); try{ input.removeAttribute('hx-vals'); }catch(e){}; input.dispatchEvent(new Event('input')); }); }
|
||||
|
||||
input.addEventListener('input', function(){
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = setTimeout(function(){
|
||||
try {
|
||||
var q = encodeURIComponent(input.value || '');
|
||||
var url = "{% url 'atlas:finding_search' %}?q=" + q + ({% if case %} "&case={{ case.pk }}" {% else %} '' {% endif %});
|
||||
// Respect dataset-based case filter if present
|
||||
var caseParam = input.dataset.currentCase ? '&case=' + encodeURIComponent(input.dataset.currentCase) : '';
|
||||
var url = "{% url 'atlas:finding_search' %}?q=" + q + caseParam;
|
||||
var target = '#{{ target_id|default:"finding-search-results" }}';
|
||||
if (window.htmx && typeof window.htmx.ajax === 'function') {
|
||||
window.htmx.ajax('GET', url, { target: target, swap: 'innerHTML' });
|
||||
|
||||
Reference in New Issue
Block a user