diff options
author | bobzel <zzzman@gmail.com> | 2024-09-04 22:58:40 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-09-04 22:58:40 -0400 |
commit | 9014cc474a039f0daef6cc0ee2011329da7703ac (patch) | |
tree | 12f45bb9b20d8ee435ad8d7dc9d1b505a493b03a /src | |
parent | df5217eea01b6ee3ce03ceede030306d05f19c58 (diff) |
more fixes for calendarBox to preserve selection when view changes.
Diffstat (limited to 'src')
-rw-r--r-- | src/ClientUtils.ts | 22 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCalendarView.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/calendarBox/CalendarBox.scss | 1 | ||||
-rw-r--r-- | src/client/views/nodes/calendarBox/CalendarBox.tsx | 56 |
4 files changed, 50 insertions, 33 deletions
diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index d149c2eae..01eda7e98 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -648,24 +648,14 @@ export function DivWidth(ele: HTMLElement | null): number { } export function dateRangeStrToDates(dateStr: string) { + const toDate = (str: string) => { + return !str.includes('T') && str.includes('-') ? new Date(Number(str.split('-')[0]), Number(str.split('-')[1]) - 1, Number(str.split('-')[2])) : new Date(str); + }; // dateStr in yyyy-mm-dd format const dateRangeParts = dateStr.split('|'); // splits into from and to date - if (dateRangeParts.length < 2) return { startDate: new Date(), endDate: new Date() }; - return { startDate: new Date(dateRangeParts[0]), endDate: new Date(dateRangeParts[1]) }; - const fromParts = dateRangeParts[0].split('-'); - const toParts = dateRangeParts[1].split('-'); - - const fromYear = parseInt(fromParts[0]); - const fromMonth = parseInt(fromParts[1]) - 1; - const fromDay = parseInt(fromParts[2]?.split('T')[0]); - const fromHour = parseInt(fromParts[2]?.split('T')[1]?.split(':')[0] || '12'); - - const toYear = parseInt(toParts[0]); - const toMonth = parseInt(toParts[1]) - 1; - const toDay = parseInt(toParts[2]?.split('T')[0]); - const toHour = parseInt(fromParts[2]?.split('T')[1]?.split(':')[0] || '12'); - - return { startDate: new Date(fromYear, fromMonth, fromDay, fromHour), endDate: new Date(toYear, toMonth, toDay, toHour) }; + if (dateRangeParts.length < 2 && !dateRangeParts[0]) return { start: new Date(), end: new Date() }; + if (dateRangeParts.length < 2) return { start: toDate(dateRangeParts[0]), end: toDate(dateRangeParts[0]) }; + return { start: new Date(dateRangeParts[0]), end: new Date(dateRangeParts[1]) }; } function replaceCanvases(oldDiv: HTMLElement, newDiv: HTMLElement) { diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx index c1f0b314b..30fd9fc2b 100644 --- a/src/client/views/collections/CollectionCalendarView.tsx +++ b/src/client/views/collections/CollectionCalendarView.tsx @@ -38,8 +38,8 @@ export class CollectionCalendarView extends CollectionSubView() { const aDateRangeStr = StrCast(DocListCast(calendarA.data).lastElement()?.date_range); const bDateRangeStr = StrCast(DocListCast(calendarB.data).lastElement()?.date_range); - const { startDate: aFromDate, endDate: aToDate } = dateRangeStrToDates(aDateRangeStr); - const { startDate: bFromDate, endDate: bToDate } = dateRangeStrToDates(bDateRangeStr); + const { start: aFromDate, end: aToDate } = dateRangeStrToDates(aDateRangeStr); + const { start: bFromDate, end: bToDate } = dateRangeStrToDates(bDateRangeStr); if (aFromDate > bFromDate) { return -1; // a comes first diff --git a/src/client/views/nodes/calendarBox/CalendarBox.scss b/src/client/views/nodes/calendarBox/CalendarBox.scss index df6ce3e64..f8ac4b2d1 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.scss +++ b/src/client/views/nodes/calendarBox/CalendarBox.scss @@ -2,6 +2,7 @@ display: flex; width: 100%; height: 100%; + transform-origin: top left; .calendarBox-wrapper { width: 100%; height: 100%; diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx index 9452cc10a..678b7dd0b 100644 --- a/src/client/views/nodes/calendarBox/CalendarBox.tsx +++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx @@ -1,7 +1,8 @@ -import { Calendar, EventClickArg, EventSourceInput } from '@fullcalendar/core'; +import { Calendar, DateInput, EventClickArg, EventSourceInput } from '@fullcalendar/core'; import dayGridPlugin from '@fullcalendar/daygrid'; import multiMonthPlugin from '@fullcalendar/multimonth'; import timeGrid from '@fullcalendar/timegrid'; +import interactionPlugin from '@fullcalendar/interaction'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -26,6 +27,7 @@ export class CalendarBox extends CollectionSubView() { _oldWheel: HTMLElement | null = null; _observer: ResizeObserver | undefined; _eventsDisposer: IReactionDisposer | undefined; + _selectDisposer: IReactionDisposer | undefined; constructor(props: SubCollectionViewProps) { super(props); @@ -38,18 +40,32 @@ export class CalendarBox extends CollectionSubView() { componentDidMount(): void { this._props.setContentViewBox?.(this); this._eventsDisposer = reaction( - () => this.calendarEvents, - events => this._calendar?.setOption('events', events), + () => ({ events: this.calendarEvents }), + ({ events }) => this._calendar?.setOption('events', events), + { fireImmediately: true } + ); + this._selectDisposer = reaction( + () => ({ initialDate: this.dateSelect }), + ({ initialDate }) => { + const state = this._calendar?.getCurrentData(); + state && + this._calendar?.dispatch({ + type: 'CHANGE_DATE', + dateMarker: state.dateEnv.createMarker(initialDate.start), + }); + setTimeout(() => (initialDate.start.toISOString() !== initialDate.end.toISOString() ? this._calendar?.select(initialDate.start, initialDate.end) : this._calendar?.select(initialDate.start))); + }, { fireImmediately: true } ); } componentWillUnmount(): void { this._eventsDisposer?.(); + this._selectDisposer?.(); } @computed get calendarEvents(): EventSourceInput | undefined { return this.childDocs.map(doc => { - const { startDate: start, endDate: end } = dateRangeStrToDates(StrCast(doc.date_range)); + const { start, end } = dateRangeStrToDates(StrCast(doc.date_range)); return { title: StrCast(doc.title), start, @@ -61,6 +77,7 @@ export class CalendarBox extends CollectionSubView() { classNames: ['mother'], // will determine the style editable: true, // subject to change in the future backgroundColor: this.eventToColor(doc), + borderColor: this.eventToColor(doc), color: 'white', extendedProps: { description: StrCast(doc.description), @@ -72,20 +89,23 @@ export class CalendarBox extends CollectionSubView() { @computed get dateRangeStrDates() { return dateRangeStrToDates(StrCast(this.Document.date_range)); } + get dateSelect() { + return dateRangeStrToDates(StrCast(this.Document.date)); + } // Choose a calendar view based on the date range @computed get calendarViewType(): CalendarView { if (this.dataDoc[this.fieldKey + '_calendarType']) return StrCast(this.dataDoc[this.fieldKey + '_calendarType']) as CalendarView; if (this.isMultiMonth) return 'multiMonth'; - const { startDate, endDate } = this.dateRangeStrDates; - if (startDate.getFullYear() !== endDate.getFullYear() || startDate.getMonth() !== endDate.getMonth()) return 'multiMonth'; - if (Math.abs(startDate.getDay() - endDate.getDay()) > 7) return 'dayGridMonth'; + const { start, end } = this.dateRangeStrDates; + if (start.getFullYear() !== end.getFullYear() || start.getMonth() !== end.getMonth()) return 'multiMonth'; + if (Math.abs(start.getDay() - end.getDay()) > 7) return 'dayGridMonth'; return 'timeGridWeek'; } // TODO: Return a different color based on the event type eventToColor(event: Doc): string { - return 'blue'; + return 'red'; } internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData) { @@ -116,32 +136,39 @@ export class CalendarBox extends CollectionSubView() { const cal = !this._calendarRef ? null : (this._calendar = new Calendar(this._calendarRef, { - plugins: [multiMonthPlugin, dayGridPlugin, timeGrid], + plugins: [multiMonthPlugin, dayGridPlugin, timeGrid, interactionPlugin], headerToolbar: { left: 'prev,next today', center: 'title', right: 'multiMonth dayGridMonth timeGridWeek timeGridDay', }, + selectable: true, initialView: this.calendarViewType === 'multiMonth' ? undefined : this.calendarViewType, - initialDate: this.dateRangeStrDates.startDate, + initialDate: this.dateSelect.start, navLinks: true, editable: false, displayEventTime: false, displayEventEnd: false, + select: info => { + const start = dateRangeStrToDates(info.startStr).start.toISOString(); + const end = dateRangeStrToDates(info.endStr).start.toISOString(); + this.dataDoc.date = start + '|' + end; + }, aspectRatio: NumCast(this.Document.width) / NumCast(this.Document.height), events: this.calendarEvents, eventClick: this.handleEventClick, })); cal?.render(); + setTimeout(() => cal?.view.calendar.select(this.dateSelect.start, this.dateSelect.end)); }; onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); render() { return ( <div - key={StrCast(this.dataDoc[this.fieldKey + '_calendarType'])} + key={this.calendarViewType} className="calendarBox" - onPointerDown={e => + onPointerDown={e => { setTimeout( action(() => { const cname = (e.nativeEvent.target as HTMLButtonElement)?.className ?? ''; @@ -150,13 +177,12 @@ export class CalendarBox extends CollectionSubView() { if (cname.includes('timeGridWeek')) this.dataDoc[this.fieldKey + '_calendarType'] = 'timeGridWeek'; if (cname.includes('timeGridDay')) this.dataDoc[this.fieldKey + '_calendarType'] = 'timeGridDay'; }) - ) - } + ); + }} style={{ width: this._props.PanelWidth() / this._props.ScreenToLocalTransform().Scale, height: this._props.PanelHeight() / this._props.ScreenToLocalTransform().Scale, transform: `scale(${this._props.ScreenToLocalTransform().Scale})`, - transformOrigin: 'top left', }} ref={r => { this.createDashEventsTarget(r); |