mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 21:11:30 +08:00 
			
		
		
		
	fix(view/calendar): add basic support for promoted attributes
This commit is contained in:
		
							parent
							
								
									249c42e781
								
							
						
					
					
						commit
						07147bf857
					
				| @ -48,6 +48,11 @@ const TPL = ` | |||||||
|     .calendar-container .fc-button { |     .calendar-container .fc-button { | ||||||
|         padding: 0.2em 0.5em; |         padding: 0.2em 0.5em; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     .calendar-container .promoted-attribute { | ||||||
|  |         font-size: 0.85em; | ||||||
|  |         opacity: 0.85; | ||||||
|  |     } | ||||||
|     </style> |     </style> | ||||||
| 
 | 
 | ||||||
|     <div class="calendar-container"> |     <div class="calendar-container"> | ||||||
| @ -119,13 +124,24 @@ export default class CalendarView extends ViewMode { | |||||||
|             height: "100%", |             height: "100%", | ||||||
|             eventContent: (e => { |             eventContent: (e => { | ||||||
|                 let html = ""; |                 let html = ""; | ||||||
|  |                 const { iconClass, promotedAttributes } = e.event.extendedProps; | ||||||
| 
 | 
 | ||||||
|                 const iconClass = e.event.extendedProps.iconClass; |                 // Title and icon
 | ||||||
|                 if (iconClass) { |                 if (iconClass) { | ||||||
|                     html += `<span class="${iconClass}"></span> `; |                     html += `<span class="${iconClass}"></span> `; | ||||||
|                 } |                 } | ||||||
| 
 |  | ||||||
|                 html += utils.escapeHtml(e.event.title); |                 html += utils.escapeHtml(e.event.title); | ||||||
|  | 
 | ||||||
|  |                 // Promoted attributes
 | ||||||
|  |                 if (promotedAttributes) { | ||||||
|  |                     for (const [ name, value ] of Object.entries(promotedAttributes)) { | ||||||
|  |                         html += `\ | ||||||
|  |                         <div class="promoted-attribute"> | ||||||
|  |                             <span class="promoted-attribute-name">${name}</span>: <span class="promoted-attribute-value">${value}</span> | ||||||
|  |                         </div>`;
 | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 return { html }; |                 return { html }; | ||||||
|             }), |             }), | ||||||
|             dateClick: async (e) => { |             dateClick: async (e) => { | ||||||
| @ -306,27 +322,22 @@ export default class CalendarView extends ViewMode { | |||||||
|         const events: EventInput[] = []; |         const events: EventInput[] = []; | ||||||
|         // the user can specify one or multiple attributes to be promoted onto the calendar view by setting `#calendar:promotedAttributes` at the note level
 |         // the user can specify one or multiple attributes to be promoted onto the calendar view by setting `#calendar:promotedAttributes` at the note level
 | ||||||
|         // their values will then be rentered into the event title and appear as "[eventIcon] $eventTitle [#promotedAttributeX=valueX] [#promotedAttributeY=valueY]"
 |         // their values will then be rentered into the event title and appear as "[eventIcon] $eventTitle [#promotedAttributeX=valueX] [#promotedAttributeY=valueY]"
 | ||||||
|         const promotedAttrs = note | 
 | ||||||
|             .getAttributes() |         const calendarPromotedAttributes = note.getLabelValue("calendar:promotedAttributes"); | ||||||
|             .filter((attr) => attr.type == "label" && attr.name == "calendar:promotedAttribute") |         let promotedAttributesData = null; | ||||||
|             .map((attr) => attr.value.substring(1)); |         if (calendarPromotedAttributes) { | ||||||
|         let titleExtended = ""; |             promotedAttributesData = await this.#buildPromotedAttributes(note, calendarPromotedAttributes); | ||||||
|         if (promotedAttrs && promotedAttrs.length) { |  | ||||||
|             const promotedValues = note |  | ||||||
|                 .getAttributes() |  | ||||||
|                 .filter((attr) => promotedAttrs.includes(attr.name)) |  | ||||||
|                 .map((attr) => [attr.name, attr.value]); |  | ||||||
|             for (const defined of promotedValues) titleExtended = titleExtended + ` [#${defined[0]}="${defined[1]}"]`; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for (const title of titles) { |         for (const title of titles) { | ||||||
|             const eventData: EventInput = { |             const eventData: EventInput = { | ||||||
|                 title: title + titleExtended, |                 title: title, | ||||||
|                 start: startDate, |                 start: startDate, | ||||||
|                 url: `#${note.noteId}`, |                 url: `#${note.noteId}`, | ||||||
|                 noteId: note.noteId, |                 noteId: note.noteId, | ||||||
|                 color: color ?? undefined, |                 color: color ?? undefined, | ||||||
|                 iconClass: note.getLabelValue("iconClass") |                 iconClass: note.getLabelValue("iconClass"), | ||||||
|  |                 promotedAttributes: promotedAttributesData | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             const endDateOffset = CalendarView.#offsetDate(endDate ?? startDate, 1); |             const endDateOffset = CalendarView.#offsetDate(endDate ?? startDate, 1); | ||||||
| @ -338,6 +349,35 @@ export default class CalendarView extends ViewMode { | |||||||
|         return events; |         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<string, string> = {}; | ||||||
|  | 
 | ||||||
|  |         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<string[]> { |     static async #parseCustomTitle(customTitleValue: string | null, note: FNote, allowRelations = true): Promise<string[]> { | ||||||
|         if (customTitleValue) { |         if (customTitleValue) { | ||||||
|             const attributeName = customTitleValue.substring(1); |             const attributeName = customTitleValue.substring(1); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran