diff --git a/frontend/css/app.css b/frontend/css/app.css
index c109e3e..39f383e 100644
--- a/frontend/css/app.css
+++ b/frontend/css/app.css
@@ -846,6 +846,15 @@ a { color: var(--primary); text-decoration: none; }
}
.popup-copy-item:hover { background: var(--bg-hover); }
.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 ──────────────────────────────────────── */
#modal-settings.modal-overlay {
diff --git a/frontend/js/calendar.js b/frontend/js/calendar.js
index 4f27111..a7faea5 100644
--- a/frontend/js/calendar.js
+++ b/frontend/js/calendar.js
@@ -1027,7 +1027,12 @@ function showEventPopup(ev, anchor) {
if (!menu.classList.contains('hidden')) { menu.classList.add('hidden'); return; }
const targets = buildWritableCalendars(ev);
if (!targets.length) { showToast('Keine Zielkalender verfügbar', true); return; }
- menu.innerHTML = `
` +
+ menu.innerHTML =
+ `` +
+ `` +
targets.map(c =>
``
).join('');
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 => {
el.addEventListener('click', async ev2 => {
ev2.stopPropagation();
+ const editFirst = document.getElementById('popup-copy-edit-cb').checked;
menu.classList.add('hidden');
popup.classList.add('hidden');
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');
}
+// 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) {
if (ev.source === 'ical') { showToast(t('event_readonly'), true); return; }
state.editingEvent = ev;
diff --git a/frontend/js/i18n.js b/frontend/js/i18n.js
index a9690ec..66a15f4 100644
--- a/frontend/js/i18n.js
+++ b/frontend/js/i18n.js
@@ -153,6 +153,7 @@ const translations = {
rec_ends: 'Endet', rec_never: 'Nie', rec_after_count: 'Nach Anzahl',
rec_on_date: 'Am Datum', rec_occurrences: 'Termine',
copy_to_calendar: 'Kopieren nach…', event_copied: 'Termin kopiert',
+ edit_before_copy: 'Vor dem Kopieren bearbeiten',
event_updated: 'Termin aktualisiert', event_created: 'Termin erstellt',
confirm_delete_event: '"{title}" wirklich 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_on_date: 'On date', rec_occurrences: 'occurrences',
copy_to_calendar: 'Copy to…', event_copied: 'Event copied',
+ edit_before_copy: 'Edit before copying',
event_updated: 'Event updated', event_created: 'Event created',
confirm_delete_event: 'Really delete "{title}"?',
confirm_delete_title: 'Delete event',