feat: 'Vor dem Kopieren bearbeiten' Checkbox im Kopieren-Popup

Über der Kalenderliste im Kopieren-Menü gibt es jetzt eine Checkbox
'Vor dem Kopieren bearbeiten'. Wenn aktiviert und ein Ziel-Kalender
geklickt wird, öffnet sich der Termin-erstellen-Dialog mit allen
Daten des Quell-Termins vorausgefüllt (Titel, Datum, Ort, Beschreibung,
Farbe, Wiederholung) und dem Ziel-Kalender vorausgewählt.
This commit is contained in:
Scarriffle
2026-05-05 18:11:33 +02:00
parent 4aaf6672f7
commit dd18a0b594
3 changed files with 64 additions and 2 deletions

View File

@@ -846,6 +846,15 @@ a { color: var(--primary); text-decoration: none; }
} }
.popup-copy-item:hover { background: var(--bg-hover); } .popup-copy-item:hover { background: var(--bg-hover); }
.popup-copy-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; } .popup-copy-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.popup-copy-edit-toggle {
display: flex; align-items: center; gap: 8px;
padding: 6px 14px 8px;
font-size: 12px; color: var(--text-2);
cursor: pointer;
border-bottom: 1px solid var(--border);
margin-bottom: 4px;
}
.popup-copy-edit-toggle input[type="checkbox"] { margin: 0; cursor: pointer; }
/* ── Settings Page ──────────────────────────────────────── */ /* ── Settings Page ──────────────────────────────────────── */
#modal-settings.modal-overlay { #modal-settings.modal-overlay {

View File

@@ -1027,7 +1027,12 @@ function showEventPopup(ev, anchor) {
if (!menu.classList.contains('hidden')) { menu.classList.add('hidden'); return; } if (!menu.classList.contains('hidden')) { menu.classList.add('hidden'); return; }
const targets = buildWritableCalendars(ev); const targets = buildWritableCalendars(ev);
if (!targets.length) { showToast('Keine Zielkalender verfügbar', true); return; } if (!targets.length) { showToast('Keine Zielkalender verfügbar', true); return; }
menu.innerHTML = `<div class="popup-copy-label">${t('copy_to_calendar')}</div>` + menu.innerHTML =
`<div class="popup-copy-label">${t('copy_to_calendar')}</div>` +
`<label class="popup-copy-edit-toggle">
<input type="checkbox" id="popup-copy-edit-cb" />
<span>${t('edit_before_copy')}</span>
</label>` +
targets.map(c => targets.map(c =>
`<div class="popup-copy-item" data-cal-idx="${c._idx}"> `<div class="popup-copy-item" data-cal-idx="${c._idx}">
<span class="popup-copy-dot" style="background:${c.color}"></span> <span class="popup-copy-dot" style="background:${c.color}"></span>
@@ -1035,13 +1040,22 @@ function showEventPopup(ev, anchor) {
</div>` </div>`
).join(''); ).join('');
menu.classList.remove('hidden'); menu.classList.remove('hidden');
// Stop clicks on the checkbox label from closing the menu
menu.querySelector('.popup-copy-edit-toggle').addEventListener('click', e2 => e2.stopPropagation());
menu.querySelectorAll('.popup-copy-item').forEach(el => { menu.querySelectorAll('.popup-copy-item').forEach(el => {
el.addEventListener('click', async ev2 => { el.addEventListener('click', async ev2 => {
ev2.stopPropagation(); ev2.stopPropagation();
const editFirst = document.getElementById('popup-copy-edit-cb').checked;
menu.classList.add('hidden'); menu.classList.add('hidden');
popup.classList.add('hidden'); popup.classList.add('hidden');
const cal = targets[parseInt(el.dataset.calIdx)]; const cal = targets[parseInt(el.dataset.calIdx)];
await copyEventToCalendar(ev, cal); if (editFirst) {
openCopyEditModal(ev, cal);
} else {
await copyEventToCalendar(ev, cal);
}
}); });
}); });
}; };
@@ -1149,6 +1163,43 @@ function openNewEventModal(date) {
openModal('modal-event'); openModal('modal-event');
} }
// Open the create-event modal pre-filled with an existing event's data, so
// the user can edit before copying it into the target calendar.
function openCopyEditModal(ev, targetCal) {
state.editingEvent = null;
state.selectedEventColor = ev.color || '';
document.getElementById('modal-event-title-label').textContent = 'Termin erstellen';
document.getElementById('ev-title').value = ev.title || '';
document.getElementById('ev-location').value = ev.location || '';
document.getElementById('ev-description').value = ev.description || '';
document.getElementById('ev-allday').checked = !!ev.allDay;
if (ev.allDay) {
setDtValue('ev-start-date', (ev.start || '').slice(0, 10), 'date');
setDtValue('ev-end-date', (ev.end || '').slice(0, 10), 'date');
} else {
const s = new Date(ev.start);
const e = new Date(ev.end);
setDtValue('ev-start', toLocalDatetimeInput(s), 'datetime');
setDtValue('ev-end', toLocalDatetimeInput(e), 'datetime');
}
toggleAlldayFields(!!ev.allDay);
// Map target calendar to the dropdown's option value
let selectedId;
if (targetCal.type === 'caldav') selectedId = targetCal.id;
else selectedId = `${targetCal.type}-${targetCal.id}`;
populateCalendarSelect(selectedId);
resetColorPicker(ev.color || '');
resetRecurrenceUI();
if (ev.rrule) parseRruleIntoUI(ev.rrule);
document.getElementById('ev-delete').classList.add('hidden');
openModal('modal-event');
}
function openEditEventModal(ev) { function openEditEventModal(ev) {
if (ev.source === 'ical') { showToast(t('event_readonly'), true); return; } if (ev.source === 'ical') { showToast(t('event_readonly'), true); return; }
state.editingEvent = ev; state.editingEvent = ev;

View File

@@ -153,6 +153,7 @@ const translations = {
rec_ends: 'Endet', rec_never: 'Nie', rec_after_count: 'Nach Anzahl', rec_ends: 'Endet', rec_never: 'Nie', rec_after_count: 'Nach Anzahl',
rec_on_date: 'Am Datum', rec_occurrences: 'Termine', rec_on_date: 'Am Datum', rec_occurrences: 'Termine',
copy_to_calendar: 'Kopieren nach…', event_copied: 'Termin kopiert', copy_to_calendar: 'Kopieren nach…', event_copied: 'Termin kopiert',
edit_before_copy: 'Vor dem Kopieren bearbeiten',
event_updated: 'Termin aktualisiert', event_created: 'Termin erstellt', event_updated: 'Termin aktualisiert', event_created: 'Termin erstellt',
confirm_delete_event: '"{title}" wirklich löschen?', confirm_delete_event: '"{title}" wirklich löschen?',
confirm_delete_title: 'Termin löschen', confirm_delete_title: 'Termin löschen',
@@ -361,6 +362,7 @@ const translations = {
rec_ends: 'Ends', rec_never: 'Never', rec_after_count: 'After count', rec_ends: 'Ends', rec_never: 'Never', rec_after_count: 'After count',
rec_on_date: 'On date', rec_occurrences: 'occurrences', rec_on_date: 'On date', rec_occurrences: 'occurrences',
copy_to_calendar: 'Copy to…', event_copied: 'Event copied', copy_to_calendar: 'Copy to…', event_copied: 'Event copied',
edit_before_copy: 'Edit before copying',
event_updated: 'Event updated', event_created: 'Event created', event_updated: 'Event updated', event_created: 'Event created',
confirm_delete_event: 'Really delete "{title}"?', confirm_delete_event: 'Really delete "{title}"?',
confirm_delete_title: 'Delete event', confirm_delete_title: 'Delete event',