WIP: Adding custom tempus event loader

This commit is contained in:
Ivymaster
2026-08-04 17:03:47 +02:00
parent 7759884d8d
commit 36a11ec2fd
3 changed files with 235 additions and 5 deletions
+1 -5
View File
@@ -1,6 +1,6 @@
import FhcCalendar from "./Base.js";
import { useEventLoader } from '../../composables/EventLoader.js';
import { useEventLoader } from '../../composables/Tempus/TempusEventLoader.js';
import ModeWeek from './Mode/Week.js';
import ModeMonth from './Mode/Month.js';
@@ -171,14 +171,10 @@ export default {
},
setup(props, context) {
const rangeInterval = Vue.ref(null);
const preserveRequestedRange = Vue.computed(() => {
return ['week', 'month'].includes(props.mode?.toLowerCase());
});
const { events, lv, reset } = useEventLoader(
rangeInterval,
props.getPromiseFunc,
preserveRequestedRange,
() => props.cacheMultiplier
);
+1
View File
@@ -1301,6 +1301,7 @@ export default {
:mode="currentMode"
:parkedEvents="parkedKeys"
:visible-lecturers="visibleLecturerUids"
:cacheMultiplier="currentMode === 'week' ? 0 : 0"
@drop="dropHandler"
@resize="resizeHandler"
@update:date="handleChangeDate"
@@ -0,0 +1,233 @@
export function useEventLoader(
rangeInterval,
getPromiseFunc,
cacheMultiplier = 1,
) {
let allEvents = Vue.ref([]);
const events = [];
const lv = Vue.ref(null);
let newlyLoadedEvents = [];
let cachedEventsStartTimestamp = null;
let cachedEventsEndTimestamp = null;
let allowedCacheStartTimestamp = null;
let allowedCacheEndTimestamp = null;
let currentlyDisplayedDateRange;
const reload = () => {
if (
currentlyDisplayedDateRange &&
currentlyDisplayedDateRange?.start?.ts ===
rangeInterval?.value?.start?.ts &&
currentlyDisplayedDateRange?.end?.ts === rangeInterval?.value?.end?.ts
) {
console.log(
"cached range is the same as requested range, skipping reload",
);
return;
}
currentlyDisplayedDateRange = Vue.toValue(rangeInterval);
if (
!currentlyDisplayedDateRange?.start ||
!currentlyDisplayedDateRange?.end
)
return;
if (!(currentlyDisplayedDateRange instanceof luxon.Interval)) return;
if (
cachedEventsStartTimestamp === currentlyDisplayedDateRange.start.ts &&
cachedEventsEndTimestamp === currentlyDisplayedDateRange.end.ts
) {
console.log(
"cached range is the same as requested range, skipping reload",
);
return;
}
const promises = requestEvents(
currentlyDisplayedDateRange.start.ts,
currentlyDisplayedDateRange.end.ts,
);
ensureCacheRangeIsAllowedRange(
allowedCacheStartTimestamp,
allowedCacheEndTimestamp,
);
if (promises.length === 0) {
allEvents.value = removeVisualForEventsLoading(
ensureEventsAreInValidCacheRange(allEvents.value),
);
return;
}
addVisualForEventsLoading();
Promise.allSettled(promises).then((results) => {
let newlyLoadedEvents = [];
results.forEach((res) => {
if (
!(res.status === "fulfilled" && res.value.meta.status === "success")
)
return;
if (res.value.meta.lv) lv.value = res.value.meta.lv;
newlyLoadedEvents = res.value.data;
});
let tempAllEvents = Array.from(
new Map(
[...allEvents.value, ...newlyLoadedEvents].map((event) => [
event.eindeutige_gruppen_id,
event,
]),
).values(),
);
allEvents.value = removeVisualForEventsLoading(
ensureEventsAreInValidCacheRange(tempAllEvents),
);
});
};
Vue.watchEffect(reload);
const reset = () => {
reload();
};
const requestEvents = (startTimestamp, endTimestamp) => {
let result = [];
if (!startTimestamp || !endTimestamp) return result;
if (startTimestamp >= endTimestamp) return result;
let modifiedRequestStartTimestamp = startTimestamp;
let modifiedRequestEndTimestamp = endTimestamp;
if (cachedEventsStartTimestamp && cachedEventsEndTimestamp) {
if (
startTimestamp < cachedEventsStartTimestamp &&
endTimestamp > cachedEventsEndTimestamp
) {
modifiedRequestStartTimestamp = startTimestamp;
modifiedRequestEndTimestamp = endTimestamp;
cachedEventsStartTimestamp = startTimestamp;
cachedEventsEndTimestamp = endTimestamp;
} else if (
startTimestamp < cachedEventsStartTimestamp &&
endTimestamp <= cachedEventsEndTimestamp
) {
modifiedRequestStartTimestamp = startTimestamp;
modifiedRequestEndTimestamp = cachedEventsStartTimestamp;
cachedEventsStartTimestamp = startTimestamp;
} else if (
startTimestamp >= cachedEventsStartTimestamp &&
endTimestamp > cachedEventsEndTimestamp
) {
modifiedRequestStartTimestamp = cachedEventsEndTimestamp;
modifiedRequestEndTimestamp = endTimestamp;
cachedEventsEndTimestamp = endTimestamp;
} else {
return result;
}
} else {
cachedEventsStartTimestamp = modifiedRequestStartTimestamp;
cachedEventsEndTimestamp = modifiedRequestEndTimestamp;
}
const cacheSize = Math.max(Vue.toValue(cacheMultiplier), 0);
const cachePadding = Math.round(
currentlyDisplayedDateRange.length() * cacheSize,
);
allowedCacheStartTimestamp = startTimestamp - cachePadding;
allowedCacheEndTimestamp = endTimestamp + cachePadding;
return mergePromiseElements(
getPromiseFunc(
getLuxonDateFromMillis(modifiedRequestStartTimestamp),
getLuxonDateFromMillis(modifiedRequestEndTimestamp),
),
result,
);
};
const addVisualForEventsLoading = (startTimestamp, endTimestamp) => {
allEvents.value.push({
loading_id: 1,
type: "loading",
isostart: getISODateFromTimestamp(currentlyDisplayedDateRange.start.ts),
isoend: getISODateFromTimestamp(currentlyDisplayedDateRange.end.ts),
});
};
const removeVisualForEventsLoading = (events) => {
return events.filter((event) => event.type !== "loading");
};
const ensureEventsAreInValidCacheRange = (events) => {
events = events.filter((event) => {
const start = getTimestampFromISODate(event.isostart);
const end = getTimestampFromISODate(event.isoend);
return (
allowedCacheStartTimestamp <= start && allowedCacheEndTimestamp >= end
);
});
return events;
};
const ensureCacheRangeIsAllowedRange = (
allowedCacheStartTimestamp,
allowedCacheEndTimestamp,
) => {
const cacheSize = Math.max(Vue.toValue(cacheMultiplier), 0);
const cachePadding = Math.round(
currentlyDisplayedDateRange.length() * cacheSize,
);
if (
cachedEventsStartTimestamp < allowedCacheEndTimestamp &&
cachedEventsEndTimestamp > allowedCacheStartTimestamp
) {
if (cachedEventsStartTimestamp < allowedCacheStartTimestamp) {
cachedEventsStartTimestamp = allowedCacheStartTimestamp;
}
if (cachedEventsEndTimestamp > allowedCacheEndTimestamp) {
cachedEventsEndTimestamp = allowedCacheEndTimestamp;
}
}
};
return { events: allEvents, lv, reset };
}
const mergePromiseElements = (n, o) => {
if (Array.isArray(n)) return o.concat(n);
return (o.push(n), o);
};
const getDateFromTimestamp = (timestamp) => {
return luxon.DateTime.fromMillis(timestamp).toFormat("yyyy-MM-dd");
};
const getISODateFromTimestamp = (timestamp) => {
return luxon.DateTime.fromMillis(timestamp).toISO();
};
const getTimestampFromISODate = (isoDate) => {
return luxon.DateTime.fromISO(isoDate).ts;
};
const getLuxonDateFromMillis = (millis) => {
return luxon.DateTime.fromMillis(millis);
};