'use strict';
(function () {
const DATE_FORMAT_OPTIONS = JSON.parse(document.getElementById('bankimport-data').dataset.dateFormatOptions);
function badgeTextColor(hex) {
const r = parseInt(hex.slice(1,3),16);
const g = parseInt(hex.slice(3,5),16);
const b = parseInt(hex.slice(5,7),16);
return (0.299*r + 0.587*g + 0.114*b) > 128 ? '#1e293b' : '#ffffff';
}
function updatePreview(colorInput, hex) {
const preview = colorInput.closest('div')?.querySelector('.bi-kuerzel-preview');
if (!preview) return;
preview.style.background = hex;
preview.style.color = badgeTextColor(hex);
}
// ── Hilfsfunktionen ──────────────────────────────────────────────
function getFormatId(cell) {
return cell.closest('[data-format-id]')?.dataset.formatId;
}
function showError(cell, msg) {
cell.classList.add('bi-cell--error');
let err = cell.parentElement.querySelector('.bi-error-msg');
if (!err) { err = document.createElement('span'); err.className = 'bi-error-msg'; cell.after(err); }
err.textContent = msg;
setTimeout(() => { cell.classList.remove('bi-cell--error'); err.remove(); }, 3000);
}
async function saveField(formatId, field, value) {
const body = new URLSearchParams({ field, value: value ?? '' });
const res = await fetch(`/settings/bankimport/${formatId}/field`, {
method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' },
body: body.toString(),
});
return res.json();
}
function displayForCell(type, value, field) {
if (type === 'number' || type === 'nullint') {
if (value === '' || value === null || value === undefined) {
return '–';
}
return `${value}`;
}
if (type === 'char' || type === 'char0') {
if (value === '') return 'keines';
return `${value.replace(/&/g,'&').replace(//g,'>')}`;
}
if (type === 'dateformat') {
const example = DATE_FORMAT_OPTIONS[value] || '?';
return `${value}→ ${example}`;
}
if (type === 'template') {
if (!value) return 'nicht gesetzt';
const esc = value.replace(/&/g,'&').replace(//g,'>');
return `${esc}`;
}
if (type === 'text') {
return value.replace(/&/g,'&').replace(//g,'>');
}
return value;
}
// ── Klick-Handler für .bi-cell ───────────────────────────────────
document.addEventListener('click', (e) => {
const cell = e.target.closest('.bi-cell');
if (!cell || cell.querySelector('input,select')) return;
const field = cell.dataset.field;
const type = cell.dataset.type;
const rawValue = cell.dataset.value ?? '';
const formatId = getFormatId(cell);
if (!formatId) return;
const originalHTML = cell.innerHTML;
cell.innerHTML = '';
cell.classList.remove('bi-cell--error');
let el;
if (type === 'number' || type === 'nullint') {
el = document.createElement('input');
el.type = 'number';
el.min = cell.dataset.min ?? '0';
el.max = cell.dataset.max ?? '99';
el.value = rawValue;
} else if (type === 'char') {
el = document.createElement('input');
el.type = 'text';
el.maxLength = 1;
el.value = rawValue;
} else if (type === 'char0') {
el = document.createElement('input');
el.type = 'text';
el.maxLength = 1;
el.value = rawValue;
el.placeholder = '(leer)';
el.style.width = '70px';
} else if (type === 'dateformat') {
el = document.createElement('select');
for (const [fmt, example] of Object.entries(DATE_FORMAT_OPTIONS)) {
const opt = document.createElement('option');
opt.value = fmt;
opt.textContent = `${fmt} → ${example}`;
if (fmt === rawValue) opt.selected = true;
el.appendChild(opt);
}
} else if (type === 'template') {
el = document.createElement('input');
el.type = 'text';
el.value = rawValue;
el.style.width = '100%';
el.style.boxSizing = 'border-box';
} else {
el = document.createElement('input');
el.type = 'text';
el.value = rawValue;
el.style.width = '180px';
}
cell.appendChild(el);
el.focus();
if (el.tagName === 'INPUT' && el.type === 'text') el.select();
let done = false;
async function commit() {
if (done) return;
done = true;
const newVal = el.tagName === 'SELECT' ? el.value : el.value;
cell.classList.add('bi-cell--saving');
cell.innerHTML = '';
let json;
try {
json = await saveField(formatId, field, newVal);
} catch (_) {
json = { error: 'Verbindungsfehler.' };
}
cell.classList.remove('bi-cell--saving');
if (json.error) {
cell.innerHTML = originalHTML;
showError(cell, json.error);
return;
}
cell.dataset.value = newVal;
cell.innerHTML = displayForCell(type, newVal, field);
// Formatname im Card-Header synchronisieren
if (field === 'name') {
const title = cell.closest('.card')?.querySelector('.card-title');
if (title) title.dataset.value = newVal;
}
// Kürzel-Vorschau-Badge aktualisieren
if (field === 'kuerzel') {
const preview = cell.closest('div')?.querySelector('.bi-kuerzel-preview');
if (preview) preview.textContent = newVal;
}
}
function cancel() {
if (done) return;
done = true;
cell.innerHTML = originalHTML;
}
if (el.tagName === 'SELECT') {
el.addEventListener('change', commit);
el.addEventListener('keydown', (ev) => { if (ev.key === 'Escape') { ev.stopPropagation(); cancel(); } });
el.addEventListener('blur', () => { if (!done) commit(); });
} else {
el.addEventListener('blur', commit);
el.addEventListener('keydown', (ev) => {
if (ev.key === 'Enter') { ev.preventDefault(); el.blur(); }
if (ev.key === 'Escape') { ev.preventDefault(); cancel(); }
});
}
});
// ── Colorpicker für farbe ────────────────────────────────────────
document.addEventListener('input', (e) => {
const ci = e.target.closest('.bi-color');
if (ci) updatePreview(ci, ci.value);
});
document.addEventListener('change', async (e) => {
const ci = e.target.closest('.bi-color');
if (!ci) return;
const formatId = getFormatId(ci);
const field = ci.dataset.field;
const value = ci.value;
ci.disabled = true;
let json;
try { json = await saveField(formatId, field, value); }
catch (_) { json = { error: 'Verbindungsfehler.' }; }
ci.disabled = false;
if (json.error) {
showError(ci, json.error);
} else {
updatePreview(ci, value);
}
});
// ── Format löschen ──────────────────────────────────────────────
document.addEventListener('click', async (e) => {
const btn = e.target.closest('.bi-delete-format');
if (!btn) return;
const formatId = btn.dataset.formatId;
const formatName = btn.dataset.formatName;
if (!confirm(`Format „${formatName}" wirklich löschen?`)) return;
btn.disabled = true;
let json;
try {
const res = await fetch(`/settings/bankimport/${formatId}/delete`, { method: 'POST' });
json = await res.json();
} catch (_) {
json = { error: 'Verbindungsfehler.' };
}
if (json.error) {
alert(json.error);
btn.disabled = false;
return;
}
btn.closest('.card').remove();
});
// ── Vorschlags-Card verwerfen ────────────────────────────────────
const dismissBtn = document.getElementById('suggestion-dismiss');
if (dismissBtn) {
dismissBtn.addEventListener('click', async () => {
dismissBtn.disabled = true;
try {
await fetch('/settings/bankimport/dismiss-suggestion', { method: 'POST' });
} catch (_) {}
const card = document.getElementById('suggestion-card');
if (card) card.remove();
});
}
// ── Checkboxen für has_header_row ────────────────────────────────
document.addEventListener('change', async (e) => {
const cb = e.target.closest('.bi-checkbox');
if (!cb) return;
const label = cb.closest('.bi-checkbox-label');
const textSpan = label?.querySelector('.bi-checkbox-text');
const field = cb.dataset.field;
const formatId = getFormatId(cb);
if (!formatId) return;
const newVal = cb.checked ? '1' : '0';
cb.disabled = true;
let json;
try {
json = await saveField(formatId, field, newVal);
} catch (_) {
json = { error: 'Verbindungsfehler.' };
}
cb.disabled = false;
if (json.error) {
cb.checked = !cb.checked; // Revert
if (textSpan) textSpan.textContent = cb.checked ? 'Ja' : 'Nein';
alert(json.error);
return;
}
if (textSpan) textSpan.textContent = cb.checked ? 'Ja' : 'Nein';
});
})();