From e1d62986c609ac9e73d914510a78f4a56d71a433 Mon Sep 17 00:00:00 2001 From: EthanThatOneKid <31261035+EthanThatOneKid@users.noreply.github.com> Date: Sun, 27 Feb 2022 13:36:55 -0800 Subject: [PATCH 01/11] set up logs to test new description parser --- src/lib/components/events/event-item.svelte | 4 ++- src/lib/ical/common.ts | 31 +++++++++++++-------- src/lib/ical/parse.ts | 3 ++ src/routes/events.json.ts | 6 ++-- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/lib/components/events/event-item.svelte b/src/lib/components/events/event-item.svelte index 4771985f6..2ed094901 100644 --- a/src/lib/components/events/event-item.svelte +++ b/src/lib/components/events/event-item.svelte @@ -53,7 +53,9 @@ rel="noopener noreferrer">Join
-

{info.description}

+

+ {@html info.description} +

diff --git a/src/lib/ical/common.ts b/src/lib/ical/common.ts index bb8252a54..b6b87f76c 100644 --- a/src/lib/ical/common.ts +++ b/src/lib/ical/common.ts @@ -145,21 +145,30 @@ export interface AcmEventDescription { variables: Map; } -export function parseDescription(content: string): AcmEventDescription { - const resultingLines = []; +export function parseDescription(content: string, prefix = 'ACM_'): AcmEventDescription { const variables = new Map(); - for (const line of content.split(/\\n/)) { - if (line.includes('=')) { - const [key, ...value] = line.split('='); - variables.set(key.trim(), value.join('=').trim()); - } else { - // Add line to unescaped description. - resultingLines.push(line.replace(/\\/g, '')); - } + let description = content.replace(/\\n/g, '
').replace(/\\/g, ''); + + console.log({ description }); + + // Extract variables from the description until there are no more. + while (description.includes(prefix)) { + const start = description.indexOf(prefix); + let end = description.indexOf('
', start); + if (end === -1) end = description.indexOf('\\n', start); + if (end === -1) end = description.length; + + const variable = description.substring(start, end); + + const splitAt = variable.indexOf('='); + const key = variable.substring(0, splitAt); + const value = variable.substring(splitAt + 1); + + variables.set(key, value); + description = description.substring(0, start) + description.substring(end); } - const description = resultingLines.join('\n'); return { description, variables }; } diff --git a/src/lib/ical/parse.ts b/src/lib/ical/parse.ts index b344443e1..24fc6b9d7 100644 --- a/src/lib/ical/parse.ts +++ b/src/lib/ical/parse.ts @@ -61,6 +61,9 @@ export function parse(icalData: string): AcmEvent[] { const recurring = checkForRecurrence(String(event['RRULE'])); const rawAcmPath = variables.get('ACM_PATH')?.toLowerCase(); + if (rawAcmPath !== undefined) { + console.log(`ACM_PATH variable found for ${summary}, using ${rawAcmPath}`); + } const acmPath = rawAcmPath === undefined ? acmGeneral diff --git a/src/routes/events.json.ts b/src/routes/events.json.ts index a2411e5b8..f04cb55ff 100644 --- a/src/routes/events.json.ts +++ b/src/routes/events.json.ts @@ -2,11 +2,13 @@ import { AcmEvent, parse } from '$lib/ical/parse'; import type { EndpointOutput } from '@sveltejs/kit'; import type { DefaultBody } from '@sveltejs/kit/types/endpoint'; +// Constants +const caching = false; // Make this false to disable server-side caching in development. +const expirationTimeout = 1e3 * 60 * 1; // Fetch updates every 1 minute. const ICAL_TARGET_URL = 'https://calendar.google.com/calendar/ical/738lnit63cr2lhp7jtduvj0c9g%40group.calendar.google.com/public/basic.ics'; -const caching = false; // Make this false to disable server-side caching in development. -const expirationTimeout = 1e3 * 60 * 3; // Fetch updates every 2 minutes. +// Globals let eventExpirationTimestamp = 0; let events: AcmEvent[] = []; From 931c040313fded89c203b0ca6215d56812570376 Mon Sep 17 00:00:00 2001 From: EthanThatOneKid <31261035+EthanThatOneKid@users.noreply.github.com> Date: Tue, 1 Mar 2022 20:33:24 -0800 Subject: [PATCH 02/11] Resolved bug in #309 --- src/lib/ical/common.ts | 18 +++++++++--------- src/lib/ical/parse.ts | 11 ++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/lib/ical/common.ts b/src/lib/ical/common.ts index b6b87f76c..61a6d025f 100644 --- a/src/lib/ical/common.ts +++ b/src/lib/ical/common.ts @@ -145,24 +145,24 @@ export interface AcmEventDescription { variables: Map; } -export function parseDescription(content: string, prefix = 'ACM_'): AcmEventDescription { +export function parseDescription(content: string, varPrefix = 'ACM_'): AcmEventDescription { const variables = new Map(); let description = content.replace(/\\n/g, '
').replace(/\\/g, ''); - console.log({ description }); - // Extract variables from the description until there are no more. - while (description.includes(prefix)) { - const start = description.indexOf(prefix); - let end = description.indexOf('
', start); - if (end === -1) end = description.indexOf('\\n', start); - if (end === -1) end = description.length; + while (description.includes(varPrefix)) { + const start = description.indexOf(varPrefix); + const nextTag = description.indexOf('<', start); + const end = + nextTag > -1 + ? nextTag // Stop at next HTML tag (e.g. '
') + : description.length; // Or stop at end of string const variable = description.substring(start, end); const splitAt = variable.indexOf('='); - const key = variable.substring(0, splitAt); + const key = variable.substring(0, splitAt).trim(); const value = variable.substring(splitAt + 1); variables.set(key, value); diff --git a/src/lib/ical/parse.ts b/src/lib/ical/parse.ts index 24fc6b9d7..7aba5694b 100644 --- a/src/lib/ical/parse.ts +++ b/src/lib/ical/parse.ts @@ -57,13 +57,8 @@ export function parse(icalData: string): AcmEvent[] { const time = date.toLocaleTimeString(ACM_LOCALE, { hour: 'numeric', minute: 'numeric' }); const slug = slugifyEvent(summary, month, day); - const recurring = checkForRecurrence(String(event['RRULE'])); - const rawAcmPath = variables.get('ACM_PATH')?.toLowerCase(); - if (rawAcmPath !== undefined) { - console.log(`ACM_PATH variable found for ${summary}, using ${rawAcmPath}`); - } const acmPath = rawAcmPath === undefined ? acmGeneral @@ -75,7 +70,7 @@ export function parse(icalData: string): AcmEvent[] { ? acmDev : acmGeneral; - collection.push({ + const item = { month, day, time, @@ -87,7 +82,9 @@ export function parse(icalData: string): AcmEvent[] { slug, recurring, acmPath, - }); + }; + + collection.push(item); return collection; }, []) From fea1a2cb5a196d06266177e9403dbb4170e9b3ab Mon Sep 17 00:00:00 2001 From: EthanThatOneKid <31261035+EthanThatOneKid@users.noreply.github.com> Date: Tue, 1 Mar 2022 22:03:43 -0800 Subject: [PATCH 03/11] Started making progress on fix/281 --- src/lib/components/events/event-item.svelte | 23 +++++++++ src/lib/components/utils/acm-toaster.svelte | 39 +++++++++++++++ src/lib/stores/toasts.ts | 55 +++++++++++++++++++++ src/routes/__layout.svelte | 2 + 4 files changed, 119 insertions(+) create mode 100644 src/lib/components/utils/acm-toaster.svelte create mode 100644 src/lib/stores/toasts.ts diff --git a/src/lib/components/events/event-item.svelte b/src/lib/components/events/event-item.svelte index 2ed094901..d24317d8c 100644 --- a/src/lib/components/events/event-item.svelte +++ b/src/lib/components/events/event-item.svelte @@ -1,6 +1,7 @@ + +
+ {#each $toasts as toastItem (toastItem.id)} +
+ {@html toastItem.content} + +
+ {/each} +
+ + diff --git a/src/lib/stores/toasts.ts b/src/lib/stores/toasts.ts new file mode 100644 index 000000000..b7ada38b1 --- /dev/null +++ b/src/lib/stores/toasts.ts @@ -0,0 +1,55 @@ +import { writable } from 'svelte/store'; + +const numToasts = writable(0); + +export enum ToastType { + Success = 'success', + Error = 'error', + Info = 'info', +} + +export interface Toast { + id: number; + content: string; + type?: ToastType; + dismissible?: boolean; + timeout?: number; +} + +export const toasts = writable([]); + +function makeToast( + id: number, + { content, type, dismissible, timeout }: Omit +): Required { + return { + id, + content: content, + type: type ?? ToastType.Info, + dismissible: dismissible ?? true, + timeout: timeout ?? 3e3, + }; +} + +export function toast(props: Omit) { + numToasts.update((value: number) => { + const nextToast = makeToast(value + 1, props); + + toasts.update((allToasts) => { + postponeDismissal(nextToast.id, nextToast.timeout); + allToasts = [...allToasts, nextToast]; + console.log({ allToasts }); + return allToasts; + }); + + return nextToast.id; + }); +} + +export function postponeDismissal(id: number, timeout: number) { + setTimeout(() => dismissToast(id), timeout); +} + +export function dismissToast(id: number) { + toasts.update((all) => all.filter((t) => t.id !== id)); +} diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte index bc7a87149..92c69d840 100644 --- a/src/routes/__layout.svelte +++ b/src/routes/__layout.svelte @@ -1,11 +1,13 @@