diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts
index 1a861d9b5..e2987728b 100644
--- a/src/public/app/widgets/view_widgets/calendar_view.ts
+++ b/src/public/app/widgets/view_widgets/calendar_view.ts
@@ -48,6 +48,11 @@ const TPL = `
.calendar-container .fc-button {
padding: 0.2em 0.5em;
}
+
+ .calendar-container .promoted-attribute {
+ font-size: 0.85em;
+ opacity: 0.85;
+ }
@@ -119,13 +124,24 @@ export default class CalendarView extends ViewMode {
height: "100%",
eventContent: (e => {
let html = "";
+ const { iconClass, promotedAttributes } = e.event.extendedProps;
- const iconClass = e.event.extendedProps.iconClass;
+ // Title and icon
if (iconClass) {
html += `
`;
}
-
html += utils.escapeHtml(e.event.title);
+
+ // Promoted attributes
+ if (promotedAttributes) {
+ for (const [ name, value ] of Object.entries(promotedAttributes)) {
+ html += `\
+
+ ${name}: ${value}
+
`;
+ }
+ }
+
return { html };
}),
dateClick: async (e) => {
@@ -279,7 +295,7 @@ export default class CalendarView extends ViewMode {
const events: EventSourceInput = [];
for (const note of notes) {
- let startDate = note.getLabelValue("startDate");
+ const startDate = note.getLabelValue("startDate");
if (note.hasChildren()) {
const childrenEventData = await this.#buildEvents(note.getChildNoteIds());
@@ -304,6 +320,13 @@ export default class CalendarView extends ViewMode {
const titles = await CalendarView.#parseCustomTitle(customTitle, note);
const color = note.getLabelValue("calendar:color") ?? note.getLabelValue("color");
const events: EventInput[] = [];
+
+ const calendarPromotedAttributes = note.getLabelValue("calendar:promotedAttributes");
+ let promotedAttributesData = null;
+ if (calendarPromotedAttributes) {
+ promotedAttributesData = await this.#buildPromotedAttributes(note, calendarPromotedAttributes);
+ }
+
for (const title of titles) {
const eventData: EventInput = {
title: title,
@@ -311,7 +334,8 @@ export default class CalendarView extends ViewMode {
url: `#${note.noteId}`,
noteId: note.noteId,
color: color ?? undefined,
- iconClass: note.getLabelValue("iconClass")
+ iconClass: note.getLabelValue("iconClass"),
+ promotedAttributes: promotedAttributesData
};
const endDateOffset = CalendarView.#offsetDate(endDate ?? startDate, 1);
@@ -323,6 +347,35 @@ export default class CalendarView extends ViewMode {
return events;
}
+ static async #buildPromotedAttributes(note: FNote, calendarPromotedAttributes: string) {
+ const promotedAttributeNames = calendarPromotedAttributes.split(",");
+ const filteredPromotedAttributes = note.getPromotedDefinitionAttributes().filter((attr) => promotedAttributeNames.includes(attr.name));
+ const result: Record
= {};
+
+ for (const promotedAttribute of filteredPromotedAttributes) {
+ const [ type, name ] = promotedAttribute.name.split(":", 2);
+ const definition = promotedAttribute.getDefinition();
+
+ if (definition.multiplicity !== "single") {
+ // TODO: Add support for multiple definitions.
+ continue;
+ }
+
+ // TODO: Add support for relations
+ if (type !== "label" || !note.hasLabel(name)) {
+ continue;
+ }
+
+ const value = note.getLabelValue(name);
+ const friendlyName = definition.promotedAlias ?? name;
+ if (friendlyName && value) {
+ result[friendlyName] = value;
+ }
+ }
+
+ return result;
+ }
+
static async #parseCustomTitle(customTitleValue: string | null, note: FNote, allowRelations = true): Promise {
if (customTitleValue) {
const attributeName = customTitleValue.substring(1);