some ICS fixes, handle empty calendar list
This commit is contained in:
parent
d7d86601f0
commit
6bf9758605
@ -89,7 +89,7 @@ function display_event_date(item) {
|
|||||||
return m("span.timerange", display_date_utc(start, utc_start_date), " - ", display_date_utc(end_day, utc_end_day_date));
|
return m("span.timerange", display_date_utc(start, utc_start_date), " - ", display_date_utc(end_day, utc_end_day_date));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start_date === end_date) {
|
if (start_date === end_date) {
|
||||||
return m("span.timerange", display_datetime(start, `${start_date}, ${start_time}`), " - ", display_datetime(end, end_time));
|
return m("span.timerange", display_datetime(start, `${start_date}, ${start_time}`), " - ", display_datetime(end, end_time));
|
||||||
} else {
|
} else {
|
||||||
@ -102,31 +102,43 @@ function display_event_date(item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeICSField(text) {
|
function format_ICS_text(text) {
|
||||||
return text.replace(/\\/g, "\\\\")
|
return text.replace(/[\\,;]/g, "\\$&") // escape backslash and separators
|
||||||
.replace(/[,;]/g, "\\$&")
|
.replace(/\n/g, "\\n") // escape newline
|
||||||
.replace(/\n/g, "\\n");
|
.replace(/[\x00-\x1f]+/g, " ") // replace control characters with whitespace
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_ICS_date(date) {
|
||||||
|
if (date) {
|
||||||
|
date = new Date(date);
|
||||||
|
} else {
|
||||||
|
date = new Date(); // default to "now"
|
||||||
|
}
|
||||||
|
// remove "-" and ":" separators (but keep "T"), and drop microseconds
|
||||||
|
return date.toISOString().replace(/-|:|\.\d+/g, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function createICSLink(item, settings) {
|
function createICSLink(item, settings) {
|
||||||
const start = new Date(item.calculated.startDate).toISOString().replace(/-|:|\.\d+/g, '');
|
const start = format_ICS_date(item.calculated.startDate);
|
||||||
const end = new Date(item.calculated.endDate).toISOString().replace(/-|:|\.\d+/g, '');
|
const end = format_ICS_date(item.calculated.endDate);
|
||||||
|
|
||||||
const summary = item.base.caption;
|
const summary = item.base.caption;
|
||||||
const description = item.base.information || "";
|
const description = item.base.information || "";
|
||||||
const location = item.base.address?.meetingAt || "";
|
const location = item.base.address?.meetingAt || "";
|
||||||
|
|
||||||
// Escape special characters for ICS fields
|
// Escape special characters for ICS fields
|
||||||
const escapedSummary = escapeICSField(summary /* .replace(/['"]/g, "") */);
|
const escapedSummary = format_ICS_text(summary /* .replace(/['"]/g, "") */);
|
||||||
const escapedDescription = escapeICSField(description /* .replace(/['"]/g, "") */);
|
const escapedDescription = format_ICS_text(description /* .replace(/['"]/g, "") */);
|
||||||
const escapedLocation = escapeICSField(location);
|
const escapedLocation = format_ICS_text(location);
|
||||||
|
|
||||||
const icsContent = `BEGIN:VCALENDAR
|
const icsContent = `BEGIN:VCALENDAR
|
||||||
VERSION:2.0
|
VERSION:2.0
|
||||||
PRODID:-//Evang Kirchengemeinde Malmsheim//Gottesdienste//EN
|
PRODID:-//churchtools-next-events//EN
|
||||||
BEGIN:VEVENT
|
BEGIN:VEVENT
|
||||||
UID:${crypto.randomUUID()}@malmsheim-evangelisch.de
|
UID:appointment-${item.base.id}@${window.location.hostname}
|
||||||
DTSTAMP:${new Date().toISOString().replace(/-|:|\.\d+/g, '')}
|
CREATED:${format_ICS_date(item.base.meta?.createdDate)}
|
||||||
|
LAST-MODIFIED:${format_ICS_date(item.base.meta?.modifiedDate)}
|
||||||
DTSTART:${start}
|
DTSTART:${start}
|
||||||
DTEND:${end}
|
DTEND:${end}
|
||||||
SUMMARY:${escapedSummary}
|
SUMMARY:${escapedSummary}
|
||||||
@ -273,7 +285,7 @@ var AppointmentLocation = {
|
|||||||
if (!location) {
|
if (!location) {
|
||||||
return m("[");
|
return m("[");
|
||||||
}
|
}
|
||||||
|
|
||||||
return m("p", [
|
return m("p", [
|
||||||
fa_solid_icon(settings, "location-dot"),
|
fa_solid_icon(settings, "location-dot"),
|
||||||
" ",
|
" ",
|
||||||
@ -293,7 +305,7 @@ var AppointmentLink = {
|
|||||||
if (!url.startsWith("http")) {
|
if (!url.startsWith("http")) {
|
||||||
url = "https://" + url;
|
url = "https://" + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m("p", [
|
return m("p", [
|
||||||
fa_solid_icon(settings, "link"),
|
fa_solid_icon(settings, "link"),
|
||||||
" ",
|
" ",
|
||||||
@ -389,24 +401,30 @@ async function load_events(dom_node, defaults) {
|
|||||||
credentials: "omit",
|
credentials: "omit",
|
||||||
mode: "cors",
|
mode: "cors",
|
||||||
}
|
}
|
||||||
|
|
||||||
const r_cal_regex = new RegExp(settings.calendar_regex, "i");
|
const r_cal_regex = new RegExp(settings.calendar_regex, "i");
|
||||||
const r_event_regex = new RegExp(settings.event_regex, "i");
|
const r_event_regex = new RegExp(settings.event_regex, "i");
|
||||||
const all_calendars = (await (await fetch(settings.instance + "/api/calendars", req_config)).json()).data;
|
const all_calendars = (await (await fetch(settings.instance + "/api/calendars", req_config)).json()).data;
|
||||||
const calendars = all_calendars.filter((calendar) => r_cal_regex.exec(calendar.name));
|
const calendars = all_calendars.filter((calendar) => r_cal_regex.exec(calendar.name));
|
||||||
const calendar_ids = calendars.map((calendar) => calendar.id);
|
const calendar_ids = calendars.map((calendar) => calendar.id);
|
||||||
|
|
||||||
const filters = calendar_ids.map((cal_id) => `calendar_ids[]=${cal_id}`);
|
let appointments;
|
||||||
const from = new Date();
|
|
||||||
filters.push(`from=${format_date(from)}`);
|
if (calendar_ids.length) {
|
||||||
const to = new Date(from.valueOf() + settings.days * 86400 * 1000);
|
const filters = calendar_ids.map((cal_id) => `calendar_ids[]=${cal_id}`);
|
||||||
filters.push(`to=${format_date(to)}`);
|
const from = new Date();
|
||||||
const query = filters.join("&");
|
filters.push(`from=${format_date(from)}`);
|
||||||
const all_appointments = (await (await fetch(settings.instance + `/api/calendars/appointments?${query}`, req_config)).json()).data;
|
const to = new Date(from.valueOf() + settings.days * 86400 * 1000);
|
||||||
const appointments = all_appointments.filter((appointment) => r_event_regex.exec(appointment.base.title));
|
filters.push(`to=${format_date(to)}`);
|
||||||
|
const query = filters.join("&");
|
||||||
if (appointments.length > settings.limit) {
|
const all_appointments = (await (await fetch(settings.instance + `/api/calendars/appointments?${query}`, req_config)).json()).data;
|
||||||
appointments.length = settings.limit;
|
appointments = all_appointments.filter((appointment) => r_event_regex.exec(appointment.base.title));
|
||||||
|
|
||||||
|
if (appointments.length > settings.limit) {
|
||||||
|
appointments.length = settings.limit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
appointments = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Appointments = {
|
const Appointments = {
|
||||||
|
Loading…
Reference in New Issue
Block a user