120 lines
4.5 KiB
JavaScript
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 sharedNormalize = window.AssetManagerNormalizeSearchText;
|
|
if (typeof sharedNormalize === 'function') {
|
|
return sharedNormalize(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);
|
|
})();
|