Major new version #2

Merged
LeoVasanko merged 86 commits from vol002 into main 2025-08-26 05:58:24 +01:00
4 changed files with 63 additions and 57 deletions
Showing only changes of commit cd4ce6f69e - Show all commits

View File

@ -244,10 +244,16 @@ function openCreateDialog(selectionData = null) {
recurrenceWeekdays.value[startingDay] = true
initialWeekday.value = startingDay
let days = 1
if (start && end && start <= end) {
const s = fromLocalString(start, DEFAULT_TZ)
const e = fromLocalString(end, DEFAULT_TZ)
days = Math.max(1, (e - s) / 86400000 + 1)
}
editingEventId.value = calendarStore.createEvent({
title: '',
startDate: start,
endDate: end,
days,
colorId: colorId.value,
recur:
recurrenceEnabled.value && repeat.value !== 'none'
@ -306,7 +312,8 @@ function openEditDialog(payload) {
if (event.recur.freq === 'weeks' && occurrenceIndex >= 0) {
const pattern = event.recur.weekdays || []
const baseStart = fromLocalString(event.startDate, DEFAULT_TZ)
const baseEnd = fromLocalString(event.endDate, DEFAULT_TZ)
const baseEnd = new Date(fromLocalString(event.startDate, DEFAULT_TZ))
baseEnd.setDate(baseEnd.getDate() + (event.days || 1) - 1)
if (occurrenceIndex === 0) {
occurrenceDate = baseStart
weekday = baseStart.getDay()

View File

@ -1,5 +1,5 @@
import { ref } from 'vue'
import { addDays, differenceInWeeks, differenceInCalendarDays } from 'date-fns'
import { addDays, differenceInWeeks } from 'date-fns'
import {
toLocalString,
fromLocalString,
@ -72,19 +72,27 @@ export function createVirtualWeekManager({
const collectEventsForDate = (dateStr, curDateObj) => {
const storedEvents = []
for (const ev of calendarStore.events.values()) {
if (!ev.recur && dateStr >= ev.startDate && dateStr <= ev.endDate) {
storedEvents.push(ev)
if (!ev.recur) {
const evEnd = toLocalString(
addDays(fromLocalString(ev.startDate, DEFAULT_TZ), (ev.days || 1) - 1),
DEFAULT_TZ,
)
if (dateStr >= ev.startDate && dateStr <= evEnd) {
storedEvents.push({ ...ev, endDate: evEnd })
}
}
}
const dayEvents = [...storedEvents]
for (const base of repeatingBases) {
if (dateStr >= base.startDate && dateStr <= base.endDate) {
dayEvents.push({ ...base, _recurrenceIndex: 0, _baseId: base.id })
const baseEnd = toLocalString(
addDays(fromLocalString(base.startDate, DEFAULT_TZ), (base.days || 1) - 1),
DEFAULT_TZ,
)
if (dateStr >= base.startDate && dateStr <= baseEnd) {
dayEvents.push({ ...base, endDate: baseEnd, _recurrenceIndex: 0, _baseId: base.id })
continue
}
const baseStart = fromLocalString(base.startDate, DEFAULT_TZ)
const baseEnd = fromLocalString(base.endDate, DEFAULT_TZ)
const spanDays = Math.max(0, differenceInCalendarDays(baseEnd, baseStart))
const spanDays = (base.days || 1) - 1
const currentDate = curDateObj
let occurrenceFound = false
for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) {
@ -303,19 +311,27 @@ export function createVirtualWeekManager({
// Rebuild events list for this day
const storedEvents = []
for (const ev of calendarStore.events.values()) {
if (!ev.recur && dateStr >= ev.startDate && dateStr <= ev.endDate) {
storedEvents.push(ev)
if (!ev.recur) {
const evEnd = toLocalString(
addDays(fromLocalString(ev.startDate, DEFAULT_TZ), (ev.days || 1) - 1),
DEFAULT_TZ,
)
if (dateStr >= ev.startDate && dateStr <= evEnd) {
storedEvents.push({ ...ev, endDate: evEnd })
}
}
}
const dayEvents = [...storedEvents]
for (const base of repeatingBases) {
if (dateStr >= base.startDate && dateStr <= base.endDate) {
dayEvents.push({ ...base, _recurrenceIndex: 0, _baseId: base.id })
const baseEndStr = toLocalString(
addDays(fromLocalString(base.startDate, DEFAULT_TZ), (base.days || 1) - 1),
DEFAULT_TZ,
)
if (dateStr >= base.startDate && dateStr <= baseEndStr) {
dayEvents.push({ ...base, endDate: baseEndStr, _recurrenceIndex: 0, _baseId: base.id })
continue
}
const baseStart = fromLocalString(base.startDate, DEFAULT_TZ)
const baseEnd = fromLocalString(base.endDate, DEFAULT_TZ)
const spanDays = Math.max(0, differenceInCalendarDays(baseEnd, baseStart))
const spanDays = (base.days || 1) - 1
const currentDate = fromLocalString(dateStr, DEFAULT_TZ)
let occurrenceFound = false
for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) {

View File

@ -127,14 +127,18 @@ export const useCalendarStore = defineStore('calendar', {
},
createEvent(eventData) {
const singleDay = eventData.startDate === eventData.endDate
let days = 1
if (typeof eventData.days === 'number') {
days = Math.max(1, Math.floor(eventData.days))
}
const singleDay = days === 1
const event = {
id: this.generateId(),
title: eventData.title,
startDate: eventData.startDate,
endDate: eventData.endDate,
days,
colorId:
eventData.colorId ?? this.selectEventColorId(eventData.startDate, eventData.endDate),
eventData.colorId ?? this.selectEventColorId(eventData.startDate, eventData.startDate),
startTime: singleDay ? eventData.startTime || '09:00' : null,
durationMinutes: singleDay ? eventData.durationMinutes || 60 : null,
recur:
@ -149,7 +153,7 @@ export const useCalendarStore = defineStore('calendar', {
}
: null,
}
this.events.set(event.id, { ...event, isSpanning: event.startDate < event.endDate })
this.events.set(event.id, { ...event, isSpanning: event.days > 1 })
this.notifyEventsChanged()
return event.id
},
@ -164,7 +168,7 @@ export const useCalendarStore = defineStore('calendar', {
const endDate = fromLocalString(endDateStr, DEFAULT_TZ)
for (const ev of this.events.values()) {
const evStart = fromLocalString(ev.startDate)
const evEnd = fromLocalString(ev.endDate)
const evEnd = addDays(evStart, (ev.days || 1) - 1)
if (evEnd < startDate || evStart > endDate) continue
if (ev.colorId >= 0 && ev.colorId < 8) colorCounts[ev.colorId]++
}
@ -202,17 +206,10 @@ export const useCalendarStore = defineStore('calendar', {
this.deleteEvent(baseId)
return
}
const oldStart = fromLocalString(base.startDate, DEFAULT_TZ)
const oldEnd = fromLocalString(base.endDate, DEFAULT_TZ)
const durationDays = Math.max(0, differenceInCalendarDays(oldEnd, oldStart))
const newEndStr = toLocalString(
addDays(fromLocalString(nextStartStr, DEFAULT_TZ), durationDays),
DEFAULT_TZ,
)
base.startDate = nextStartStr
base.endDate = newEndStr
// keep same days length
if (numericCount !== Infinity) base.recur.count = String(Math.max(1, numericCount - 1))
this.events.set(baseId, { ...base, isSpanning: base.startDate < base.endDate })
this.events.set(baseId, { ...base, isSpanning: base.days > 1 })
this.notifyEventsChanged()
},
@ -234,14 +231,6 @@ export const useCalendarStore = defineStore('calendar', {
base.recur.count = occurrenceIndex
const nextStartStr = getOccurrenceDate(snapshot, occurrenceIndex + 1, DEFAULT_TZ)
if (!nextStartStr) return
const durationDays = Math.max(
0,
differenceInCalendarDays(
fromLocalString(snapshot.endDate),
fromLocalString(snapshot.startDate),
),
)
const newEndStr = toLocalString(addDays(fromLocalString(nextStartStr), durationDays))
const originalNumeric =
snapshot.recur.count === 'unlimited' ? Infinity : parseInt(snapshot.recur.count, 10)
let remainingCount = 'unlimited'
@ -253,7 +242,7 @@ export const useCalendarStore = defineStore('calendar', {
this.createEvent({
title: snapshot.title,
startDate: nextStartStr,
endDate: newEndStr,
days: snapshot.days,
colorId: snapshot.colorId,
recur: snapshot.recur
? {
@ -283,8 +272,7 @@ export const useCalendarStore = defineStore('calendar', {
const snapshot = this.events.get(eventId)
if (!snapshot) return
const prevStart = fromLocalString(snapshot.startDate, DEFAULT_TZ)
const prevEnd = fromLocalString(snapshot.endDate, DEFAULT_TZ)
const prevDurationDays = Math.max(0, differenceInCalendarDays(prevEnd, prevStart))
const prevDurationDays = (snapshot.days || 1) - 1
const newStart = fromLocalString(newStartStr, DEFAULT_TZ)
const newEnd = fromLocalString(newEndStr, DEFAULT_TZ)
const proposedDurationDays = Math.max(0, differenceInCalendarDays(newEnd, newStart))
@ -292,10 +280,7 @@ export const useCalendarStore = defineStore('calendar', {
if (mode === 'resize-left' || mode === 'resize-right')
finalDurationDays = proposedDurationDays
snapshot.startDate = newStartStr
snapshot.endDate = toLocalString(
addDays(fromLocalString(newStartStr, DEFAULT_TZ), finalDurationDays),
DEFAULT_TZ,
)
snapshot.days = finalDurationDays + 1
if (
rotatePattern &&
(mode === 'move' || mode === 'resize-left') &&
@ -310,7 +295,7 @@ export const useCalendarStore = defineStore('calendar', {
snapshot.recur.weekdays = this._rotateWeekdayPattern(snapshot.recur.weekdays, shift)
}
}
this.events.set(eventId, { ...snapshot, isSpanning: snapshot.startDate < snapshot.endDate })
this.events.set(eventId, { ...snapshot, isSpanning: snapshot.days > 1 })
this.notifyEventsChanged()
},
@ -398,7 +383,7 @@ export const useCalendarStore = defineStore('calendar', {
const newId = this.createEvent({
title: base.title,
startDate: newStartStr,
endDate: newEndStr,
days: base.days,
colorId: base.colorId,
recur: {
freq: base.recur.freq,
@ -430,7 +415,7 @@ export const useCalendarStore = defineStore('calendar', {
return newId
},
splitRepeatSeries(baseId, occurrenceIndex, newStartStr, newEndStr) {
splitRepeatSeries(baseId, occurrenceIndex, newStartStr, _newEndStr) {
const base = this.events.get(baseId)
if (!base || !base.recur) return null
const originalCountRaw = base.recur.count
@ -446,7 +431,7 @@ export const useCalendarStore = defineStore('calendar', {
return this.createEvent({
title: base.title,
startDate: newStartStr,
endDate: newEndStr,
days: base.days,
colorId: base.colorId,
recur: base.recur
? {
@ -484,11 +469,12 @@ export const useCalendarStore = defineStore('calendar', {
})
},
deserialize(value) {
return JSON.parse(value, (_k, v) => {
const revived = JSON.parse(value, (_k, v) => {
if (v && v.__map) return new Map(v.data)
if (v && v.__set) return new Set(v.data)
return v
})
return revived
},
},
},

View File

@ -23,9 +23,8 @@ const monthAbbr = [
'nov',
'dec',
]
// Calendar year bounds (used instead of config.min_year / config.max_year)
const MIN_YEAR = 1901
const MAX_YEAR = 2100
const MIN_YEAR = 100 // less than 100 is interpreted as 19xx
const MAX_YEAR = 9999
// Core helpers ------------------------------------------------------------
/**
@ -230,9 +229,7 @@ function getOccurrenceDate(event, occurrenceIndex, timeZone = DEFAULT_TZ) {
}
function getVirtualOccurrenceEndDate(event, occurrenceStartDate, timeZone = DEFAULT_TZ) {
const baseStart = fromLocalString(event.startDate, timeZone)
const baseEnd = fromLocalString(event.endDate, timeZone)
const spanDays = Math.max(0, dateFns.differenceInCalendarDays(baseEnd, baseStart))
const spanDays = Math.max(0, (event.days || 1) - 1)
const occurrenceStart = fromLocalString(occurrenceStartDate, timeZone)
return toLocalString(dateFns.addDays(occurrenceStart, spanDays), timeZone)
}