mirror of
https://github.com/zadam/trilium.git
synced 2025-11-10 15:25:51 +01:00
chore(react/collections/calendar): render calendar events
This commit is contained in:
@@ -47,27 +47,6 @@ function parseDate(str: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source: https://stackoverflow.com/a/30465299/4898894
|
|
||||||
function getMonthsInDateRange(startDate: string, endDate: string) {
|
|
||||||
const start = startDate.split("-");
|
|
||||||
const end = endDate.split("-");
|
|
||||||
const startYear = parseInt(start[0]);
|
|
||||||
const endYear = parseInt(end[0]);
|
|
||||||
const dates: string[] = [];
|
|
||||||
|
|
||||||
for (let i = startYear; i <= endYear; i++) {
|
|
||||||
const endMonth = i != endYear ? 11 : parseInt(end[1]) - 1;
|
|
||||||
const startMon = i === startYear ? parseInt(start[1]) - 1 : 0;
|
|
||||||
|
|
||||||
for (let j = startMon; j <= endMonth; j = j > 12 ? j % 12 || 11 : j + 1) {
|
|
||||||
const month = j + 1;
|
|
||||||
const displayMonth = month < 10 ? "0" + month : month;
|
|
||||||
dates.push([i, displayMonth].join("-"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dates;
|
|
||||||
}
|
|
||||||
|
|
||||||
function padNum(num: number) {
|
function padNum(num: number) {
|
||||||
return `${num <= 9 ? "0" : ""}${num}`;
|
return `${num <= 9 ? "0" : ""}${num}`;
|
||||||
}
|
}
|
||||||
@@ -835,7 +814,6 @@ export default {
|
|||||||
restartDesktopApp,
|
restartDesktopApp,
|
||||||
reloadTray,
|
reloadTray,
|
||||||
parseDate,
|
parseDate,
|
||||||
getMonthsInDateRange,
|
|
||||||
formatDateISO,
|
formatDateISO,
|
||||||
formatDateTime,
|
formatDateTime,
|
||||||
formatTimeInterval,
|
formatTimeInterval,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { EventInput, EventSourceInput } from "@fullcalendar/core/index.js";
|
import { EventInput, EventSourceFuncArg, EventSourceInput } from "@fullcalendar/core/index.js";
|
||||||
import froca from "../../../services/froca";
|
import froca from "../../../services/froca";
|
||||||
import { formatDateToLocalISO, getCustomisableLabel, offsetDate } from "./utils";
|
import { formatDateToLocalISO, getCustomisableLabel, getMonthsInDateRange, offsetDate } from "./utils";
|
||||||
import FNote from "../../../entities/fnote";
|
import FNote from "../../../entities/fnote";
|
||||||
|
import server from "../../../services/server";
|
||||||
|
|
||||||
interface Event {
|
interface Event {
|
||||||
startDate: string,
|
startDate: string,
|
||||||
@@ -30,6 +31,50 @@ export async function buildEvents(noteIds: string[]) {
|
|||||||
return events.flat();
|
return events.flat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function buildEventsForCalendar(note: FNote, e: EventSourceFuncArg) {
|
||||||
|
const events: EventInput[] = [];
|
||||||
|
|
||||||
|
// Gather all the required date note IDs.
|
||||||
|
const dateRange = getMonthsInDateRange(e.startStr, e.endStr);
|
||||||
|
let allDateNoteIds: string[] = [];
|
||||||
|
for (const month of dateRange) {
|
||||||
|
// TODO: Deduplicate get type.
|
||||||
|
const dateNotesForMonth = await server.get<Record<string, string>>(`special-notes/notes-for-month/${month}?calendarRoot=${note.noteId}`);
|
||||||
|
const dateNoteIds = Object.values(dateNotesForMonth);
|
||||||
|
allDateNoteIds = [...allDateNoteIds, ...dateNoteIds];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request all the date notes.
|
||||||
|
const dateNotes = await froca.getNotes(allDateNoteIds);
|
||||||
|
const childNoteToDateMapping: Record<string, string> = {};
|
||||||
|
for (const dateNote of dateNotes) {
|
||||||
|
const startDate = dateNote.getLabelValue("dateNote");
|
||||||
|
if (!startDate) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.push(await buildEvent(dateNote, { startDate }));
|
||||||
|
|
||||||
|
if (dateNote.hasChildren()) {
|
||||||
|
const childNoteIds = await dateNote.getSubtreeNoteIds();
|
||||||
|
for (const childNoteId of childNoteIds) {
|
||||||
|
childNoteToDateMapping[childNoteId] = startDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request all child notes of date notes in a single run.
|
||||||
|
const childNoteIds = Object.keys(childNoteToDateMapping);
|
||||||
|
const childNotes = await froca.getNotes(childNoteIds);
|
||||||
|
for (const childNote of childNotes) {
|
||||||
|
const startDate = childNoteToDateMapping[childNote.noteId];
|
||||||
|
const event = await buildEvent(childNote, { startDate });
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return events.flat();
|
||||||
|
}
|
||||||
|
|
||||||
async function buildEvent(note: FNote, { startDate, endDate, startTime, endTime }: Event) {
|
async function buildEvent(note: FNote, { startDate, endDate, startTime, endTime }: Event) {
|
||||||
const customTitleAttributeName = note.getLabelValue("calendar:title");
|
const customTitleAttributeName = note.getLabelValue("calendar:title");
|
||||||
const titles = await parseCustomTitle(customTitleAttributeName, note);
|
const titles = await parseCustomTitle(customTitleAttributeName, note);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DateSelectArg, LocaleInput, PluginDef } from "@fullcalendar/core/index.js";
|
import { DateSelectArg, EventSourceFuncArg, LocaleInput, PluginDef } from "@fullcalendar/core/index.js";
|
||||||
import { ViewModeProps } from "../interface";
|
import { ViewModeProps } from "../interface";
|
||||||
import Calendar from "./calendar";
|
import Calendar from "./calendar";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||||
@@ -12,7 +12,7 @@ import server from "../../../services/server";
|
|||||||
import { parseStartEndDateFromEvent, parseStartEndTimeFromEvent } from "./utils";
|
import { parseStartEndDateFromEvent, parseStartEndTimeFromEvent } from "./utils";
|
||||||
import dialog from "../../../services/dialog";
|
import dialog from "../../../services/dialog";
|
||||||
import { t } from "../../../services/i18n";
|
import { t } from "../../../services/i18n";
|
||||||
import { buildEvents } from "./event_builder";
|
import { buildEvents, buildEventsForCalendar } from "./event_builder";
|
||||||
|
|
||||||
interface CalendarViewData {
|
interface CalendarViewData {
|
||||||
|
|
||||||
@@ -58,6 +58,8 @@ export default function CalendarView({ note, noteIds }: ViewModeProps<CalendarVi
|
|||||||
const eventBuilder = useMemo(() => {
|
const eventBuilder = useMemo(() => {
|
||||||
if (!isCalendarRoot) {
|
if (!isCalendarRoot) {
|
||||||
return async () => await buildEvents(noteIds);
|
return async () => await buildEvents(noteIds);
|
||||||
|
} else {
|
||||||
|
return async (e: EventSourceFuncArg) => await buildEventsForCalendar(note, e);
|
||||||
}
|
}
|
||||||
}, [isCalendarRoot, noteIds]);
|
}, [isCalendarRoot, noteIds]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { DateSelectArg } from "@fullcalendar/core/index.js";
|
import { DateSelectArg } from "@fullcalendar/core/index.js";
|
||||||
import { EventImpl } from "@fullcalendar/core/internal";
|
import { EventImpl } from "@fullcalendar/core/internal";
|
||||||
|
import FNote from "../../../entities/fnote";
|
||||||
|
|
||||||
export function parseStartEndDateFromEvent(e: DateSelectArg | EventImpl) {
|
export function parseStartEndDateFromEvent(e: DateSelectArg | EventImpl) {
|
||||||
const startDate = formatDateToLocalISO(e.start);
|
const startDate = formatDateToLocalISO(e.start);
|
||||||
@@ -79,3 +80,24 @@ export function getCustomisableLabel(note: FNote, defaultLabelName: string, cust
|
|||||||
|
|
||||||
return note.getLabelValue(defaultLabelName);
|
return note.getLabelValue(defaultLabelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Source: https://stackoverflow.com/a/30465299/4898894
|
||||||
|
export function getMonthsInDateRange(startDate: string, endDate: string) {
|
||||||
|
const start = startDate.split("-");
|
||||||
|
const end = endDate.split("-");
|
||||||
|
const startYear = parseInt(start[0]);
|
||||||
|
const endYear = parseInt(end[0]);
|
||||||
|
const dates: string[] = [];
|
||||||
|
|
||||||
|
for (let i = startYear; i <= endYear; i++) {
|
||||||
|
const endMonth = i != endYear ? 11 : parseInt(end[1]) - 1;
|
||||||
|
const startMon = i === startYear ? parseInt(start[1]) - 1 : 0;
|
||||||
|
|
||||||
|
for (let j = startMon; j <= endMonth; j = j > 12 ? j % 12 || 11 : j + 1) {
|
||||||
|
const month = j + 1;
|
||||||
|
const displayMonth = month < 10 ? "0" + month : month;
|
||||||
|
dates.push([i, displayMonth].join("-"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dates;
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,22 +30,11 @@ export default class CalendarView extends ViewMode<{}> {
|
|||||||
|
|
||||||
this.$root = $(TPL);
|
this.$root = $(TPL);
|
||||||
this.$calendarContainer = this.$root.find(".calendar-container");
|
this.$calendarContainer = this.$root.find(".calendar-container");
|
||||||
this.isCalendarRoot = false;
|
|
||||||
args.$parent.append(this.$root);
|
args.$parent.append(this.$root);
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderList(): Promise<JQuery<HTMLElement> | undefined> {
|
async renderList(): Promise<JQuery<HTMLElement> | undefined> {
|
||||||
const { Calendar } = await import("@fullcalendar/core");
|
|
||||||
|
|
||||||
let eventBuilder: EventSourceFunc;
|
|
||||||
if (!this.isCalendarRoot) {
|
|
||||||
eventBuilder =
|
|
||||||
} else {
|
|
||||||
eventBuilder = async (e: EventSourceFuncArg) => await this.#buildEventsForCalendar(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
const calendar = new Calendar(this.$calendarContainer[0], {
|
const calendar = new Calendar(this.$calendarContainer[0], {
|
||||||
events: eventBuilder,
|
|
||||||
select: (e) => this.#onCalendarSelection(e),
|
select: (e) => this.#onCalendarSelection(e),
|
||||||
eventChange: (e) => this.#onEventMoved(e),
|
eventChange: (e) => this.#onEventMoved(e),
|
||||||
height: "100%",
|
height: "100%",
|
||||||
@@ -183,50 +172,6 @@ export default class CalendarView extends ViewMode<{}> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async #buildEventsForCalendar(e: EventSourceFuncArg) {
|
|
||||||
const events: EventInput[] = [];
|
|
||||||
|
|
||||||
// Gather all the required date note IDs.
|
|
||||||
const dateRange = utils.getMonthsInDateRange(e.startStr, e.endStr);
|
|
||||||
let allDateNoteIds: string[] = [];
|
|
||||||
for (const month of dateRange) {
|
|
||||||
// TODO: Deduplicate get type.
|
|
||||||
const dateNotesForMonth = await server.get<Record<string, string>>(`special-notes/notes-for-month/${month}?calendarRoot=${this.parentNote.noteId}`);
|
|
||||||
const dateNoteIds = Object.values(dateNotesForMonth);
|
|
||||||
allDateNoteIds = [...allDateNoteIds, ...dateNoteIds];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request all the date notes.
|
|
||||||
const dateNotes = await froca.getNotes(allDateNoteIds);
|
|
||||||
const childNoteToDateMapping: Record<string, string> = {};
|
|
||||||
for (const dateNote of dateNotes) {
|
|
||||||
const startDate = dateNote.getLabelValue("dateNote");
|
|
||||||
if (!startDate) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
events.push(await CalendarView.buildEvent(dateNote, { startDate }));
|
|
||||||
|
|
||||||
if (dateNote.hasChildren()) {
|
|
||||||
const childNoteIds = await dateNote.getSubtreeNoteIds();
|
|
||||||
for (const childNoteId of childNoteIds) {
|
|
||||||
childNoteToDateMapping[childNoteId] = startDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request all child notes of date notes in a single run.
|
|
||||||
const childNoteIds = Object.keys(childNoteToDateMapping);
|
|
||||||
const childNotes = await froca.getNotes(childNoteIds);
|
|
||||||
for (const childNote of childNotes) {
|
|
||||||
const startDate = childNoteToDateMapping[childNote.noteId];
|
|
||||||
const event = await CalendarView.buildEvent(childNote, { startDate });
|
|
||||||
events.push(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return events.flat();
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) {
|
buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) {
|
||||||
if (!this.calendar) {
|
if (!this.calendar) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user