From ef167b834a9b9304130798e2647197eecb7d9607 Mon Sep 17 00:00:00 2001 From: martin-forge <228563004+martin-forge@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:53:40 +0100 Subject: [PATCH] read Google Calendar descriptions as plain text The Google Calendar API documents the event description field as one that can contain HTML, and Calendar's own editor stores markup there. TaskNotes consumes that string as plain text everywhere: event tooltips, the ICS event info modal, copy as markdown, the {{icsEventDescription}} template variable, generated note bodies, and folder templates. Several of those write the value into the vault, so raw markup was persisted into notes and folder names. Normalize the description once at the Google provider boundary, preserving paragraph breaks, list structure, and link targets. Plain text is returned unchanged, so angle-bracketed addresses and placeholders are untouched. Descriptions sent back to Google are always rebuilt from the task, so this does not round-trip flattened text into Calendar. --- docs/releases/unreleased.md | 4 + src/services/GoogleCalendarService.ts | 3 +- src/utils/calendarDescription.ts | 259 +++++++++++++++++++ tests/__mocks__/obsidian.ts | 8 + tests/services/GoogleCalendarService.test.ts | 40 ++- tests/unit/utils/calendarDescription.test.ts | 125 +++++++++ 6 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 src/utils/calendarDescription.ts create mode 100644 tests/unit/utils/calendarDescription.test.ts diff --git a/docs/releases/unreleased.md b/docs/releases/unreleased.md index cc1bd1185..0631421d4 100644 --- a/docs/releases/unreleased.md +++ b/docs/releases/unreleased.md @@ -35,3 +35,7 @@ When a change has user-facing documentation, include a canonical tasknotes.dev l ## Fixed - Fixed `PUT /api/tasks/:id` ignoring empty arrays for `contexts` and `blockedBy`: sending `{"contexts": []}` or `{"blockedBy": []}` now clears the corresponding frontmatter field instead of silently leaving the previous value in place. The deletion pass previously fired only on a literal `undefined`, which JSON cannot express, so HTTP clients had no way to clear these fields. Thanks to @tgrosinger for the contribution. +- (#2193) Google Calendar event descriptions written with formatting now read as + plain text in event details, copied text, and generated notes, instead of + showing raw HTML tags. Paragraph breaks, list structure, and link addresses are + kept. Thanks to @martin-forge for the contribution. diff --git a/src/services/GoogleCalendarService.ts b/src/services/GoogleCalendarService.ts index 68ab065a5..c8566f6fa 100644 --- a/src/services/GoogleCalendarService.ts +++ b/src/services/GoogleCalendarService.ts @@ -16,6 +16,7 @@ import { validateCalendarId, validateEventId, validateRequired } from "./validat import { CalendarProvider, ProviderCalendar } from "./CalendarProvider"; import { createTaskNotesLogger } from "../utils/tasknotesLogger"; import { publishUserNotice } from "../core/userNotices"; +import { normalizeCalendarDescription } from "../utils/calendarDescription"; const tasknotesLogger = createTaskNotesLogger({ tag: "Services/GoogleCalendarService" }); @@ -499,7 +500,7 @@ export class GoogleCalendarService extends CalendarProvider { id: `google-${calendarId}-${googleEvent.id}`, subscriptionId: `google-${calendarId}`, title: googleEvent.summary || "Untitled Event", - description: googleEvent.description, + description: normalizeCalendarDescription(googleEvent.description), start: start, end: end, allDay: allDay, diff --git a/src/utils/calendarDescription.ts b/src/utils/calendarDescription.ts new file mode 100644 index 000000000..7fc07320e --- /dev/null +++ b/src/utils/calendarDescription.ts @@ -0,0 +1,259 @@ +import { sanitizeHTMLToDom } from "obsidian"; + +/** + * Plain-text normalization for calendar event descriptions. + * + * The Google Calendar API documents the event `description` field as one that + * "can contain HTML". Google Calendar and third-party integrations therefore + * store markup such as `

`, `
`, `