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