Much simpler undo/redo handling, bugs fixed and less code.
This commit is contained in:
		| @@ -22,10 +22,18 @@ import { shallowRef } from 'vue' | ||||
| const eventDialogRef = shallowRef(null) | ||||
| function openCreateEventDialog(eventData) { | ||||
|   if (!eventDialogRef.value) return | ||||
|   // Capture baseline before dialog opens (new event creation flow) | ||||
|   try { | ||||
|     calendarStore.$history?._baselineIfNeeded?.(true) | ||||
|   } catch {} | ||||
|   const selectionData = { startDate: eventData.startDate, dayCount: eventData.dayCount } | ||||
|   setTimeout(() => eventDialogRef.value?.openCreateDialog(selectionData), 30) | ||||
| } | ||||
| function openEditEventDialog(eventClickPayload) { | ||||
|   // Capture baseline before editing existing event | ||||
|   try { | ||||
|     calendarStore.$history?._baselineIfNeeded?.(true) | ||||
|   } catch {} | ||||
|   eventDialogRef.value?.openEditDialog(eventClickPayload) | ||||
| } | ||||
| const viewport = ref(null) | ||||
|   | ||||
| @@ -22,6 +22,8 @@ const props = defineProps({ | ||||
| const emit = defineEmits(['clear-selection']) | ||||
|  | ||||
| const calendarStore = useCalendarStore() | ||||
| // Track baseline signature when dialog opens to decide if we need an undo snapshot on close | ||||
| let dialogBaselineSig = null | ||||
|  | ||||
| const showDialog = ref(false) | ||||
| // Anchoring: element of the DayCell representing the event's start date. | ||||
| @@ -208,7 +210,8 @@ function resolveAnchorFromDate(dateStr) { | ||||
| } | ||||
|  | ||||
| function openCreateDialog(selectionData = null) { | ||||
|   calendarStore.$history?.beginCompound() | ||||
|   // Pre-change snapshot (before creating stub event) | ||||
|   calendarStore.$history?.push?.() | ||||
|   if (unsavedCreateId.value && !eventSaved.value) { | ||||
|     if (calendarStore.events?.has(unsavedCreateId.value)) { | ||||
|       calendarStore.deleteEvent(unsavedCreateId.value) | ||||
| @@ -272,6 +275,7 @@ function openCreateDialog(selectionData = null) { | ||||
|   // anchor to the starting day cell | ||||
|   anchorElement.value = resolveAnchorFromDate(start) | ||||
|   showDialog.value = true | ||||
|   // (Pre snapshot already taken before stub creation) | ||||
|  | ||||
|   nextTick(() => { | ||||
|     if (titleInput.value) { | ||||
| @@ -284,7 +288,6 @@ function openCreateDialog(selectionData = null) { | ||||
| } | ||||
|  | ||||
| function openEditDialog(payload) { | ||||
|   calendarStore.$history?.beginCompound() | ||||
|   if ( | ||||
|     dialogMode.value === 'create' && | ||||
|     unsavedCreateId.value && | ||||
| @@ -348,6 +351,8 @@ function openEditDialog(payload) { | ||||
|   // anchor to base event start date | ||||
|   anchorElement.value = resolveAnchorFromDate(event.startDate) | ||||
|   showDialog.value = true | ||||
|   // Pre-change snapshot (only once when dialog opens) | ||||
|   calendarStore.$history?.push?.() | ||||
|  | ||||
|   nextTick(() => { | ||||
|     if (titleInput.value) { | ||||
| @@ -360,7 +365,6 @@ function openEditDialog(payload) { | ||||
| } | ||||
|  | ||||
| function closeDialog() { | ||||
|   calendarStore.$history?.endCompound() | ||||
|   showDialog.value = false | ||||
| } | ||||
|  | ||||
| @@ -392,13 +396,11 @@ function saveEvent() { | ||||
|     unsavedCreateId.value = null | ||||
|   } | ||||
|   if (dialogMode.value === 'create') emit('clear-selection') | ||||
|   calendarStore.$history?.endCompound() | ||||
|   closeDialog() | ||||
| } | ||||
|  | ||||
| function deleteEventAll() { | ||||
|   if (editingEventId.value) calendarStore.deleteEvent(editingEventId.value) | ||||
|   calendarStore.$history?.endCompound() | ||||
|   closeDialog() | ||||
| } | ||||
|  | ||||
| @@ -408,14 +410,12 @@ function deleteEventOne() { | ||||
|   } else if (isRepeatingBaseEdit.value && editingEventId.value) { | ||||
|     calendarStore.deleteFirstOccurrence(editingEventId.value) | ||||
|   } | ||||
|   calendarStore.$history?.endCompound() | ||||
|   closeDialog() | ||||
| } | ||||
|  | ||||
| function deleteEventFrom() { | ||||
|   if (!occurrenceContext.value) return | ||||
|   calendarStore.deleteFromOccurrence(occurrenceContext.value) | ||||
|   calendarStore.$history?.endCompound() | ||||
|   closeDialog() | ||||
| } | ||||
|  | ||||
| @@ -431,8 +431,6 @@ watch([recurrenceEnabled, recurrenceInterval, recurrenceFrequency], () => { | ||||
| }) | ||||
| watch(showDialog, (val, oldVal) => { | ||||
|   if (oldVal && !val) { | ||||
|     // Closed (cancel, escape, outside click) -> end compound session | ||||
|     calendarStore.$history?.endCompound() | ||||
|     if (dialogMode.value === 'create' && unsavedCreateId.value && !eventSaved.value) { | ||||
|       if (calendarStore.events?.has(unsavedCreateId.value)) { | ||||
|         calendarStore.deleteEvent(unsavedCreateId.value) | ||||
|   | ||||
| @@ -314,7 +314,46 @@ function startLocalDrag(init, evt) { | ||||
|     realizedId: null, | ||||
|   } | ||||
|  | ||||
|   store.$history?.beginCompound() | ||||
|   // If history is empty (no baseline), create a baseline snapshot BEFORE any movement mutations | ||||
|   try { | ||||
|     const isResize = init.mode === 'resize-left' || init.mode === 'resize-right' | ||||
|     // Move: only baseline if history empty. Resize: force baseline (so undo returns to pre-resize) but only once. | ||||
|     store.$history?._baselineIfNeeded?.(isResize) | ||||
|     const evs = [] | ||||
|     if (store.events instanceof Map) { | ||||
|       for (const [id, ev] of store.events) { | ||||
|         evs.push({ | ||||
|           id, | ||||
|           start: ev.startDate, | ||||
|           days: ev.days, | ||||
|           title: ev.title, | ||||
|           color: ev.colorId, | ||||
|           recur: ev.recur | ||||
|             ? { | ||||
|                 f: ev.recur.freq, | ||||
|                 i: ev.recur.interval, | ||||
|                 c: ev.recur.count, | ||||
|                 w: Array.isArray(ev.recur.weekdays) ? ev.recur.weekdays.join('') : null, | ||||
|               } | ||||
|             : null, | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|     console.debug( | ||||
|       isResize ? '[history] pre-resize baseline snapshot' : '[history] pre-drag baseline snapshot', | ||||
|       { | ||||
|         mode: init.mode, | ||||
|         events: evs, | ||||
|         weekend: store.weekend, | ||||
|         firstDay: store.config?.first_day, | ||||
|       }, | ||||
|     ) | ||||
|   } catch {} | ||||
|  | ||||
|   // Enter drag suppression (prevent intermediate pushes) | ||||
|   try { | ||||
|     store.$history?._beginDrag?.() | ||||
|   } catch {} | ||||
|  | ||||
|   if (evt.currentTarget && evt.pointerId !== undefined) { | ||||
|     try { | ||||
| @@ -453,7 +492,10 @@ function onDragPointerUp(e) { | ||||
|       justDragged.value = false | ||||
|     }, 120) | ||||
|   } | ||||
|   store.$history?.endCompound() | ||||
|   // End drag suppression regardless; no post snapshot (pre-only model) | ||||
|   try { | ||||
|     store.$history?._endDrag?.() | ||||
|   } catch {} | ||||
| } | ||||
|  | ||||
| const min = (a, b) => (a < b ? a : b) | ||||
|   | ||||
| @@ -95,6 +95,10 @@ function toggleVisibility() { | ||||
| // Settings dialog integration | ||||
| const settingsDialog = ref(null) | ||||
| function openSettings() { | ||||
|   // Capture baseline before opening settings | ||||
|   try { | ||||
|     calendarStore.$history?._baselineIfNeeded?.(true) | ||||
|   } catch {} | ||||
|   settingsDialog.value?.open() | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Leo Vasanko
					Leo Vasanko