Skip to content

feat: normalize event text fields and show date range for multiday events#20

Merged
KristjanESPERANTO merged 3 commits intoMMRIZE:mainfrom
late4marshmellow:fix/normalize-event-text
Apr 6, 2026
Merged

feat: normalize event text fields and show date range for multiday events#20
KristjanESPERANTO merged 3 commits intoMMRIZE:mainfrom
late4marshmellow:fix/normalize-event-text

Conversation

@late4marshmellow
Copy link
Copy Markdown
Contributor

Summary

Replaces the shallow ensureString helper with a recursive normalizeEventText function that safely handles nested objects, arrays, and circular references — covering all event text fields including title, which was previously unguarded.

Also changes innerHTML assignments for description and location to textContent to prevent XSS from malformed calendar payloads.

Problem

Some calendar providers (e.g. certain Outlook/iCloud payloads) wrap event fields in nested objects, yielding [object Object] when stringified. The old ensureString only handled description and location, and was not recursive. Event title had no protection.

Changes

  • Replace ensureString with normalizeEventText(val, depth=0):
    • Handles null/undefined""
    • Handles arrays by joining non-empty normalized elements with ,
    • Tries a preferred key list (value, text, name, title) for plain objects before JSON.stringify fallback
    • Depth limit (10) guards against circular references
  • Apply normalizeEventText to title, description, and location in renderEvent, renderEventJournal, and renderEventAgenda
  • Apply to e.dataset.title
  • Change description and location render sites from innerHTML to textContent

…ayload handling

ensureString only handled shallow objects with known keys (val, value, text)
and fell back to String() which produced [object Object] for unknown shapes.

normalizeEventText handles:
- Nested objects recursively with a preferred-key priority list
- Arrays (joins with ', ')
- Circular reference detection via a seen-set
- All render sites: title (previously unguarded), description, location
- Uses textContent instead of innerHTML for safety
When showMultidayEventsOnce is true and event.isMultiday:
- Fullday multiday: show date range (e.g. 'Apr 3 - Apr 9') using
  multidayRangeLabelOptions format
- Timed multiday: show 'Apr 3 10:00 AM - Apr 9 2:00 PM' combining
  date and time for each endpoint

Uses existing startTime/endTime CSS classes so the module stylesheet
separator applies consistently. When showMultidayEventsOnce is false,
behaviour is unchanged.
@late4marshmellow
Copy link
Copy Markdown
Contributor Author

Backward compatibility note (re: renderEventAgenda changes)

The new showMultidayEventsOnce branch is fully backward compatible with MMM-CalendarExt3 users.

MMM-CalendarExt3 calls renderEventAgenda as:

const eDom = renderEventAgenda(event, options, moment)

Why this lives in CX3_Shared and not in MMM-CalendarExt3Agenda's own scripts:

The multiday time display is built entirely inside renderEventAgenda — it constructs and appends the DOM nodes for startTime/endTime. MMM-CalendarExt3Agenda only calls renderEventAgenda and receives a finished DOM element back. There is no hook to intercept or modify the time portion after the fact without patching into the returned DOM — which would be fragile. Placing the logic here, behind an explicit opt-in option, keeps it clean and self-contained.

The new behavior only activates when a consuming module explicitly passes showMultidayEventsOnce: true, as MMM-CalendarExt3Agenda does via PR MMRIZE/MMM-CalendarExt3Agenda#87.

Remove 'description', 'location', and 'html' from the preferred key
list, and add the missing 'title'.

'description' and 'location' are event-level fields, not generic
text-container properties. Including them as preferred keys means any
object that happens to have a 'description' key would have its
description extracted instead of its actual text value — wrong
semantics.

'html' would pass raw markup through to textContent, rendering tag
literals visibly in the UI.

'title' was the obvious gap: a common iCal object shape is
{title: "…"} which previously fell through to the flattening
fallback instead of being extracted directly.
@KristjanESPERANTO KristjanESPERANTO changed the base branch from main to develop April 6, 2026 12:03
@KristjanESPERANTO KristjanESPERANTO changed the base branch from develop to main April 6, 2026 12:03
@KristjanESPERANTO KristjanESPERANTO merged commit cfebb64 into MMRIZE:main Apr 6, 2026
@KristjanESPERANTO KristjanESPERANTO changed the title fix: replace ensureString with recursive normalizeEventText feat: normalize event text fields and show date range for multiday events Apr 6, 2026
@KristjanESPERANTO
Copy link
Copy Markdown
Member

Thanks! I'm building a new release :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants