Files
Assetmanager/app/static/js/asset-duplicates.js
T
2026-08-03 21:51:54 +00:00

120 lines
4.5 KiB
JavaScript

(() => {
function initialize() {
const table = document.getElementById('asset-table');
const openButton = document.getElementById('duplicate-search-button');
const dialog = document.getElementById('duplicate-search-dialog');
const select = document.getElementById('duplicate-field-select');
const applyButton = document.getElementById('duplicate-apply-button');
const clearButton = document.getElementById('duplicate-clear-button');
const ignoreEmpty = document.getElementById('duplicate-ignore-empty');
const caseInsensitive = document.getElementById('duplicate-case-insensitive');
const summary = document.getElementById('duplicate-search-summary');
if (!table || !openButton || !dialog || table.dataset.duplicateSearchReady === '1') return;
table.dataset.duplicateSearchReady = '1';
const dataRows = () => [...table.tBodies[0].rows].filter(row => !row.querySelector('.empty-state'));
const normallyVisible = row => {
if (row.classList.contains('duplicate-hidden')) return false;
if (row.hidden || row.classList.contains('hidden')) return false;
const style = getComputedStyle(row);
return style.display !== 'none' && style.visibility !== 'hidden';
};
const availableFields = () => [...table.querySelectorAll('thead tr:first-child th[data-field]')]
.filter(th => th.style.display !== 'none')
.map(th => ({
field: th.dataset.field,
label: th.dataset.label || th.textContent.trim()
}));
function fillSelect() {
const previous = select.value;
select.innerHTML = '';
availableFields().forEach(item => {
const option = document.createElement('option');
option.value = item.field;
option.textContent = item.label;
select.appendChild(option);
});
if ([...select.options].some(option => option.value === previous)) {
select.value = previous;
}
}
function clearDuplicateFilter() {
dataRows().forEach(row => row.classList.remove('duplicate-hidden', 'duplicate-match'));
summary.hidden = true;
window.dispatchEvent(new Event('asset-table-filter-changed'));
}
function normalize(value) {
const sharedKey = window.AssetManagerGermanSearchKey;
if (typeof sharedKey === 'function') {
return sharedKey(value, {
caseSensitive: !caseInsensitive.checked,
collapseWhitespace: true
});
}
let result = String(value || '').trim().replace(/\s+/g, ' ');
if (caseInsensitive.checked) result = result.toLocaleLowerCase();
return result;
}
function applyDuplicateFilter() {
// Remove only our previous result first. Normal column filters stay intact.
dataRows().forEach(row => row.classList.remove('duplicate-hidden', 'duplicate-match'));
const field = select.value;
if (!field) return;
const candidates = dataRows().filter(normallyVisible);
const groups = new Map();
candidates.forEach(row => {
const cell = row.querySelector(`td[data-field="${CSS.escape(field)}"]`);
const value = normalize(cell?.textContent || '');
if (ignoreEmpty.checked && !value) return;
const rows = groups.get(value) || [];
rows.push(row);
groups.set(value, rows);
});
const duplicateRows = new Set();
let duplicateGroups = 0;
groups.forEach(rows => {
if (rows.length > 1) {
duplicateGroups += 1;
rows.forEach(row => duplicateRows.add(row));
}
});
candidates.forEach(row => {
if (duplicateRows.has(row)) {
row.classList.add('duplicate-match');
} else {
row.classList.add('duplicate-hidden');
}
});
summary.textContent = `${duplicateRows.size} Datensätze in ${duplicateGroups} Dublettengruppen gefunden.`;
summary.hidden = false;
window.dispatchEvent(new Event('asset-table-filter-changed'));
dialog.close();
}
openButton.addEventListener('click', () => {
// Search always starts from the current normal filter result, not from
// a previous duplicate result.
clearDuplicateFilter();
fillSelect();
dialog.showModal();
});
applyButton.addEventListener('click', applyDuplicateFilter);
clearButton.addEventListener('click', clearDuplicateFilter);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialize);
} else {
initialize();
}
window.addEventListener('asset-table-content-reloaded', initialize);
})();