Major new version #2
@ -244,10 +244,16 @@ function openCreateDialog(selectionData = null) {
|
|||||||
recurrenceWeekdays.value[startingDay] = true
|
recurrenceWeekdays.value[startingDay] = true
|
||||||
initialWeekday.value = startingDay
|
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({
|
editingEventId.value = calendarStore.createEvent({
|
||||||
title: '',
|
title: '',
|
||||||
startDate: start,
|
startDate: start,
|
||||||
endDate: end,
|
days,
|
||||||
colorId: colorId.value,
|
colorId: colorId.value,
|
||||||
recur:
|
recur:
|
||||||
recurrenceEnabled.value && repeat.value !== 'none'
|
recurrenceEnabled.value && repeat.value !== 'none'
|
||||||
@ -306,7 +312,8 @@ function openEditDialog(payload) {
|
|||||||
if (event.recur.freq === 'weeks' && occurrenceIndex >= 0) {
|
if (event.recur.freq === 'weeks' && occurrenceIndex >= 0) {
|
||||||
const pattern = event.recur.weekdays || []
|
const pattern = event.recur.weekdays || []
|
||||||
const baseStart = fromLocalString(event.startDate, DEFAULT_TZ)
|
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) {
|
if (occurrenceIndex === 0) {
|
||||||
occurrenceDate = baseStart
|
occurrenceDate = baseStart
|
||||||
weekday = baseStart.getDay()
|
weekday = baseStart.getDay()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { addDays, differenceInWeeks, differenceInCalendarDays } from 'date-fns'
|
import { addDays, differenceInWeeks } from 'date-fns'
|
||||||
import {
|
import {
|
||||||
toLocalString,
|
toLocalString,
|
||||||
fromLocalString,
|
fromLocalString,
|
||||||
@ -72,19 +72,27 @@ export function createVirtualWeekManager({
|
|||||||
const collectEventsForDate = (dateStr, curDateObj) => {
|
const collectEventsForDate = (dateStr, curDateObj) => {
|
||||||
const storedEvents = []
|
const storedEvents = []
|
||||||
for (const ev of calendarStore.events.values()) {
|
for (const ev of calendarStore.events.values()) {
|
||||||
if (!ev.recur && dateStr >= ev.startDate && dateStr <= ev.endDate) {
|
if (!ev.recur) {
|
||||||
storedEvents.push(ev)
|
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]
|
const dayEvents = [...storedEvents]
|
||||||
for (const base of repeatingBases) {
|
for (const base of repeatingBases) {
|
||||||
if (dateStr >= base.startDate && dateStr <= base.endDate) {
|
const baseEnd = toLocalString(
|
||||||
dayEvents.push({ ...base, _recurrenceIndex: 0, _baseId: base.id })
|
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
|
continue
|
||||||
}
|
}
|
||||||
const baseStart = fromLocalString(base.startDate, DEFAULT_TZ)
|
const spanDays = (base.days || 1) - 1
|
||||||
const baseEnd = fromLocalString(base.endDate, DEFAULT_TZ)
|
|
||||||
const spanDays = Math.max(0, differenceInCalendarDays(baseEnd, baseStart))
|
|
||||||
const currentDate = curDateObj
|
const currentDate = curDateObj
|
||||||
let occurrenceFound = false
|
let occurrenceFound = false
|
||||||
for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) {
|
for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) {
|
||||||
@ -303,19 +311,27 @@ export function createVirtualWeekManager({
|
|||||||
// Rebuild events list for this day
|
// Rebuild events list for this day
|
||||||
const storedEvents = []
|
const storedEvents = []
|
||||||
for (const ev of calendarStore.events.values()) {
|
for (const ev of calendarStore.events.values()) {
|
||||||
if (!ev.recur && dateStr >= ev.startDate && dateStr <= ev.endDate) {
|
if (!ev.recur) {
|
||||||
storedEvents.push(ev)
|
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]
|
const dayEvents = [...storedEvents]
|
||||||
for (const base of repeatingBases) {
|
for (const base of repeatingBases) {
|
||||||
if (dateStr >= base.startDate && dateStr <= base.endDate) {
|
const baseEndStr = toLocalString(
|
||||||
dayEvents.push({ ...base, _recurrenceIndex: 0, _baseId: base.id })
|
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
|
continue
|
||||||
}
|
}
|
||||||
const baseStart = fromLocalString(base.startDate, DEFAULT_TZ)
|
const spanDays = (base.days || 1) - 1
|
||||||
const baseEnd = fromLocalString(base.endDate, DEFAULT_TZ)
|
|
||||||
const spanDays = Math.max(0, differenceInCalendarDays(baseEnd, baseStart))
|
|
||||||
const currentDate = fromLocalString(dateStr, DEFAULT_TZ)
|
const currentDate = fromLocalString(dateStr, DEFAULT_TZ)
|
||||||
let occurrenceFound = false
|
let occurrenceFound = false
|
||||||
for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) {
|
for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) {
|
||||||
|
@ -127,14 +127,18 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
createEvent(eventData) {
|
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 = {
|
const event = {
|
||||||
id: this.generateId(),
|
id: this.generateId(),
|
||||||
title: eventData.title,
|
title: eventData.title,
|
||||||
startDate: eventData.startDate,
|
startDate: eventData.startDate,
|
||||||
endDate: eventData.endDate,
|
days,
|
||||||
colorId:
|
colorId:
|
||||||
eventData.colorId ?? this.selectEventColorId(eventData.startDate, eventData.endDate),
|
eventData.colorId ?? this.selectEventColorId(eventData.startDate, eventData.startDate),
|
||||||
startTime: singleDay ? eventData.startTime || '09:00' : null,
|
startTime: singleDay ? eventData.startTime || '09:00' : null,
|
||||||
durationMinutes: singleDay ? eventData.durationMinutes || 60 : null,
|
durationMinutes: singleDay ? eventData.durationMinutes || 60 : null,
|
||||||
recur:
|
recur:
|
||||||
@ -149,7 +153,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
}
|
}
|
||||||
this.events.set(event.id, { ...event, isSpanning: event.startDate < event.endDate })
|
this.events.set(event.id, { ...event, isSpanning: event.days > 1 })
|
||||||
this.notifyEventsChanged()
|
this.notifyEventsChanged()
|
||||||
return event.id
|
return event.id
|
||||||
},
|
},
|
||||||
@ -164,7 +168,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
const endDate = fromLocalString(endDateStr, DEFAULT_TZ)
|
const endDate = fromLocalString(endDateStr, DEFAULT_TZ)
|
||||||
for (const ev of this.events.values()) {
|
for (const ev of this.events.values()) {
|
||||||
const evStart = fromLocalString(ev.startDate)
|
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 (evEnd < startDate || evStart > endDate) continue
|
||||||
if (ev.colorId >= 0 && ev.colorId < 8) colorCounts[ev.colorId]++
|
if (ev.colorId >= 0 && ev.colorId < 8) colorCounts[ev.colorId]++
|
||||||
}
|
}
|
||||||
@ -202,17 +206,10 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
this.deleteEvent(baseId)
|
this.deleteEvent(baseId)
|
||||||
return
|
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.startDate = nextStartStr
|
||||||
base.endDate = newEndStr
|
// keep same days length
|
||||||
if (numericCount !== Infinity) base.recur.count = String(Math.max(1, numericCount - 1))
|
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()
|
this.notifyEventsChanged()
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -234,14 +231,6 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
base.recur.count = occurrenceIndex
|
base.recur.count = occurrenceIndex
|
||||||
const nextStartStr = getOccurrenceDate(snapshot, occurrenceIndex + 1, DEFAULT_TZ)
|
const nextStartStr = getOccurrenceDate(snapshot, occurrenceIndex + 1, DEFAULT_TZ)
|
||||||
if (!nextStartStr) return
|
if (!nextStartStr) return
|
||||||
const durationDays = Math.max(
|
|
||||||
0,
|
|
||||||
differenceInCalendarDays(
|
|
||||||
fromLocalString(snapshot.endDate),
|
|
||||||
fromLocalString(snapshot.startDate),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
const newEndStr = toLocalString(addDays(fromLocalString(nextStartStr), durationDays))
|
|
||||||
const originalNumeric =
|
const originalNumeric =
|
||||||
snapshot.recur.count === 'unlimited' ? Infinity : parseInt(snapshot.recur.count, 10)
|
snapshot.recur.count === 'unlimited' ? Infinity : parseInt(snapshot.recur.count, 10)
|
||||||
let remainingCount = 'unlimited'
|
let remainingCount = 'unlimited'
|
||||||
@ -253,7 +242,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
this.createEvent({
|
this.createEvent({
|
||||||
title: snapshot.title,
|
title: snapshot.title,
|
||||||
startDate: nextStartStr,
|
startDate: nextStartStr,
|
||||||
endDate: newEndStr,
|
days: snapshot.days,
|
||||||
colorId: snapshot.colorId,
|
colorId: snapshot.colorId,
|
||||||
recur: snapshot.recur
|
recur: snapshot.recur
|
||||||
? {
|
? {
|
||||||
@ -283,8 +272,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
const snapshot = this.events.get(eventId)
|
const snapshot = this.events.get(eventId)
|
||||||
if (!snapshot) return
|
if (!snapshot) return
|
||||||
const prevStart = fromLocalString(snapshot.startDate, DEFAULT_TZ)
|
const prevStart = fromLocalString(snapshot.startDate, DEFAULT_TZ)
|
||||||
const prevEnd = fromLocalString(snapshot.endDate, DEFAULT_TZ)
|
const prevDurationDays = (snapshot.days || 1) - 1
|
||||||
const prevDurationDays = Math.max(0, differenceInCalendarDays(prevEnd, prevStart))
|
|
||||||
const newStart = fromLocalString(newStartStr, DEFAULT_TZ)
|
const newStart = fromLocalString(newStartStr, DEFAULT_TZ)
|
||||||
const newEnd = fromLocalString(newEndStr, DEFAULT_TZ)
|
const newEnd = fromLocalString(newEndStr, DEFAULT_TZ)
|
||||||
const proposedDurationDays = Math.max(0, differenceInCalendarDays(newEnd, newStart))
|
const proposedDurationDays = Math.max(0, differenceInCalendarDays(newEnd, newStart))
|
||||||
@ -292,10 +280,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
if (mode === 'resize-left' || mode === 'resize-right')
|
if (mode === 'resize-left' || mode === 'resize-right')
|
||||||
finalDurationDays = proposedDurationDays
|
finalDurationDays = proposedDurationDays
|
||||||
snapshot.startDate = newStartStr
|
snapshot.startDate = newStartStr
|
||||||
snapshot.endDate = toLocalString(
|
snapshot.days = finalDurationDays + 1
|
||||||
addDays(fromLocalString(newStartStr, DEFAULT_TZ), finalDurationDays),
|
|
||||||
DEFAULT_TZ,
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
rotatePattern &&
|
rotatePattern &&
|
||||||
(mode === 'move' || mode === 'resize-left') &&
|
(mode === 'move' || mode === 'resize-left') &&
|
||||||
@ -310,7 +295,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
snapshot.recur.weekdays = this._rotateWeekdayPattern(snapshot.recur.weekdays, shift)
|
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()
|
this.notifyEventsChanged()
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -398,7 +383,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
const newId = this.createEvent({
|
const newId = this.createEvent({
|
||||||
title: base.title,
|
title: base.title,
|
||||||
startDate: newStartStr,
|
startDate: newStartStr,
|
||||||
endDate: newEndStr,
|
days: base.days,
|
||||||
colorId: base.colorId,
|
colorId: base.colorId,
|
||||||
recur: {
|
recur: {
|
||||||
freq: base.recur.freq,
|
freq: base.recur.freq,
|
||||||
@ -430,7 +415,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
return newId
|
return newId
|
||||||
},
|
},
|
||||||
|
|
||||||
splitRepeatSeries(baseId, occurrenceIndex, newStartStr, newEndStr) {
|
splitRepeatSeries(baseId, occurrenceIndex, newStartStr, _newEndStr) {
|
||||||
const base = this.events.get(baseId)
|
const base = this.events.get(baseId)
|
||||||
if (!base || !base.recur) return null
|
if (!base || !base.recur) return null
|
||||||
const originalCountRaw = base.recur.count
|
const originalCountRaw = base.recur.count
|
||||||
@ -446,7 +431,7 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
return this.createEvent({
|
return this.createEvent({
|
||||||
title: base.title,
|
title: base.title,
|
||||||
startDate: newStartStr,
|
startDate: newStartStr,
|
||||||
endDate: newEndStr,
|
days: base.days,
|
||||||
colorId: base.colorId,
|
colorId: base.colorId,
|
||||||
recur: base.recur
|
recur: base.recur
|
||||||
? {
|
? {
|
||||||
@ -484,11 +469,12 @@ export const useCalendarStore = defineStore('calendar', {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
deserialize(value) {
|
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.__map) return new Map(v.data)
|
||||||
if (v && v.__set) return new Set(v.data)
|
if (v && v.__set) return new Set(v.data)
|
||||||
return v
|
return v
|
||||||
})
|
})
|
||||||
|
return revived
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -23,9 +23,8 @@ const monthAbbr = [
|
|||||||
'nov',
|
'nov',
|
||||||
'dec',
|
'dec',
|
||||||
]
|
]
|
||||||
// Calendar year bounds (used instead of config.min_year / config.max_year)
|
const MIN_YEAR = 100 // less than 100 is interpreted as 19xx
|
||||||
const MIN_YEAR = 1901
|
const MAX_YEAR = 9999
|
||||||
const MAX_YEAR = 2100
|
|
||||||
|
|
||||||
// Core helpers ------------------------------------------------------------
|
// Core helpers ------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
@ -230,9 +229,7 @@ function getOccurrenceDate(event, occurrenceIndex, timeZone = DEFAULT_TZ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getVirtualOccurrenceEndDate(event, occurrenceStartDate, timeZone = DEFAULT_TZ) {
|
function getVirtualOccurrenceEndDate(event, occurrenceStartDate, timeZone = DEFAULT_TZ) {
|
||||||
const baseStart = fromLocalString(event.startDate, timeZone)
|
const spanDays = Math.max(0, (event.days || 1) - 1)
|
||||||
const baseEnd = fromLocalString(event.endDate, timeZone)
|
|
||||||
const spanDays = Math.max(0, dateFns.differenceInCalendarDays(baseEnd, baseStart))
|
|
||||||
const occurrenceStart = fromLocalString(occurrenceStartDate, timeZone)
|
const occurrenceStart = fromLocalString(occurrenceStartDate, timeZone)
|
||||||
return toLocalString(dateFns.addDays(occurrenceStart, spanDays), timeZone)
|
return toLocalString(dateFns.addDays(occurrenceStart, spanDays), timeZone)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user