Skip to content

Commit d8a2f5b

Browse files
committed
feat: add tooltip + refactor
1 parent de297ce commit d8a2f5b

File tree

2 files changed

+192
-88
lines changed

2 files changed

+192
-88
lines changed

packages/devextreme/js/__internal/scheduler/workspaces/m_work_space_year.ts

Lines changed: 127 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
/* eslint-disable class-methods-use-this */
2-
import registerComponent from '@js/core/component_registrator';
32
import type { dxElementWrapper } from '@js/core/renderer';
43
import $ from '@js/core/renderer';
54
import { noop } from '@js/core/utils/common';
65
import dateUtils from '@js/core/utils/date';
76
import type { ViewType } from '@js/ui/scheduler';
87
import { formatWeekday } from '@ts/scheduler/r1/utils/index';
98

9+
import type NotifyScheduler from '../base/m_widget_notify_scheduler';
10+
import type Scheduler from '../m_scheduler';
11+
import type { SafeAppointment } from '../types';
12+
import type { AppointmentDataAccessor } from '../utils/data_accessor/appointment_data_accessor';
1013
import { VIEWS } from '../utils/options/constants_view';
14+
import type { ResourceManager } from '../utils/resource_manager/resource_manager';
1115
import type { ListEntity } from '../view_model/types';
1216
import SchedulerWorkSpace from './m_work_space';
17+
import type { CellClickArgs, YearCalendarProperties } from './m_year_calendar';
1318
import YearCalendar from './m_year_calendar';
1419

1520
const YEAR_CLASS = 'dx-scheduler-work-space-year';
@@ -71,6 +76,10 @@ class SchedulerWorkSpaceYear extends SchedulerWorkSpace {
7176
return { left: 0, top: 0 };
7277
}
7378

79+
getScrollableContainer() {
80+
return this.$element();
81+
}
82+
7483
_getViewStartByOptions(): Date {
7584
const currentDate = this.option('currentDate') as Date;
7685
const yearStart = new Date(currentDate.getFullYear(), 0, 1);
@@ -110,18 +119,24 @@ class SchedulerWorkSpaceYear extends SchedulerWorkSpace {
110119
const firstDayOfWeek = this.option('firstDayOfWeek') as number;
111120
const hasAppointment = this._createHasAppointmentChecker();
112121
const getAppointmentColor = this._createGetAppointmentColor();
122+
const getAppointmentsForDate = this._createGetAppointmentsForDate();
123+
const showAppointmentTooltip = this._createShowAppointmentTooltip();
124+
const hideAppointmentTooltip = this._createHideAppointmentTooltip();
113125

114126
for (let month = 0; month < 12; month++) {
115127
const $calendarItem = $('<div>').addClass(YEAR_CALENDAR_ITEM_CLASS);
116128
const monthDate = new Date(currentYear, month, 1);
117129

118-
const calendarOptions: any = {
130+
const calendarOptions: YearCalendarProperties = {
119131
date: monthDate,
120132
firstDayOfWeek,
121133
showMonthLabel: true,
122134
hasAppointment,
123135
getAppointmentColor,
124-
onCellClick: (e: any) => {
136+
getAppointmentsForDate,
137+
showAppointmentTooltip,
138+
hideAppointmentTooltip,
139+
onCellClick: (e: CellClickArgs) => {
125140
this._handleYearCalendarCellClick(e);
126141
},
127142
};
@@ -136,89 +151,76 @@ class SchedulerWorkSpaceYear extends SchedulerWorkSpace {
136151
this._$dateTable.appendTo(this._$workSpace);
137152
}
138153

139-
_createHasAppointmentChecker(): (date: Date) => boolean {
140-
const notifyScheduler = this.option('notifyScheduler') as any;
141-
const scheduler = notifyScheduler?.scheduler;
142-
143-
if (!scheduler) {
144-
return () => false;
145-
}
146-
154+
_getSchedulerAndDataAccessors(): {
155+
scheduler: Scheduler;
156+
dataAccessors: AppointmentDataAccessor;
157+
} {
158+
const notifyScheduler = this.option('notifyScheduler') as NotifyScheduler;
159+
const { scheduler } = notifyScheduler;
147160
const dataAccessors = scheduler._dataAccessors;
161+
return { scheduler, dataAccessors };
162+
}
148163

149-
if (!dataAccessors) {
150-
return () => false;
151-
}
152-
153-
return (date: Date): boolean => {
154-
const dataSource = scheduler.getDataSource()?.items() || [];
155-
156-
const dayStart = new Date(date);
157-
dayStart.setHours(0, 0, 0, 0);
158-
const dayStartTime = dayStart.getTime();
159-
const dayEnd = new Date(date);
160-
dayEnd.setHours(23, 59, 59, 999);
161-
const dayEndTime = dayEnd.getTime();
162-
163-
return dataSource.some((appointment: any) => {
164-
const startDate = dataAccessors.get('startDate', appointment);
165-
const endDate = dataAccessors.get('endDate', appointment);
164+
_getDayTimeRange(date: Date): { dayStartTime: number; dayEndTime: number } {
165+
const dayStart = new Date(date);
166+
dayStart.setHours(0, 0, 0, 0);
167+
const dayStartTime = dayStart.getTime();
168+
const dayEnd = new Date(date);
169+
dayEnd.setHours(23, 59, 59, 999);
170+
const dayEndTime = dayEnd.getTime();
171+
return { dayStartTime, dayEndTime };
172+
}
166173

167-
if (!startDate || !endDate) {
168-
return false;
169-
}
174+
_appointmentIntersectsDay(
175+
appointment: SafeAppointment,
176+
dataAccessors: AppointmentDataAccessor,
177+
dayStartTime: number,
178+
dayEndTime: number,
179+
): boolean {
180+
const startDate = dataAccessors.get('startDate', appointment);
181+
const endDate = dataAccessors.get('endDate', appointment);
182+
183+
const start = new Date(startDate);
184+
const startTime = start.getTime();
185+
const end = new Date(endDate);
186+
const endTime = end.getTime();
187+
188+
return startTime <= dayEndTime && endTime >= dayStartTime;
189+
}
170190

171-
const start = new Date(startDate);
172-
const startTime = start.getTime();
173-
const end = new Date(endDate);
174-
const endTime = end.getTime();
191+
_createHasAppointmentChecker(): (date: Date) => boolean {
192+
const { scheduler, dataAccessors } = this._getSchedulerAndDataAccessors();
175193

176-
return startTime <= dayEndTime && endTime >= dayStartTime;
177-
});
194+
return (date: Date): boolean => {
195+
const dataSource = scheduler._dataSource.items() as SafeAppointment[];
196+
const { dayStartTime, dayEndTime } = this._getDayTimeRange(date);
197+
198+
return dataSource.some((appointment: SafeAppointment) => this._appointmentIntersectsDay(
199+
appointment,
200+
dataAccessors,
201+
dayStartTime,
202+
dayEndTime,
203+
));
178204
};
179205
}
180206

181207
_createGetAppointmentColor(): (date: Date) => Promise<string | undefined> {
182-
const notifyScheduler = this.option('notifyScheduler') as any;
183-
const scheduler = notifyScheduler?.scheduler;
184-
185-
if (!scheduler) {
186-
return () => Promise.resolve(undefined);
187-
}
188-
189-
const dataAccessors = scheduler._dataAccessors;
190-
const getResourceManager = this.option('getResourceManager') as any;
191-
192-
if (!dataAccessors || !getResourceManager) {
193-
return () => Promise.resolve(undefined);
194-
}
208+
const { scheduler, dataAccessors } = this._getSchedulerAndDataAccessors();
209+
const getResourceManager = this.option('getResourceManager') as () => ResourceManager;
195210

196211
return async (date: Date): Promise<string | undefined> => {
197212
try {
198-
const dataSource = scheduler.getDataSource()?.items() || [];
199-
200-
const dayStart = new Date(date);
201-
dayStart.setHours(0, 0, 0, 0);
202-
const dayStartTime = dayStart.getTime();
203-
const dayEnd = new Date(date);
204-
dayEnd.setHours(23, 59, 59, 999);
205-
const dayEndTime = dayEnd.getTime();
206-
207-
const appointment = dataSource.find((appt: any) => {
208-
const startDate = dataAccessors.get('startDate', appt);
209-
const endDate = dataAccessors.get('endDate', appt);
210-
211-
if (!startDate || !endDate) {
212-
return false;
213-
}
214-
215-
const start = new Date(startDate);
216-
const startTime = start.getTime();
217-
const end = new Date(endDate);
218-
const endTime = end.getTime();
219-
220-
return startTime <= dayEndTime && endTime >= dayStartTime;
221-
});
213+
const dataSource = scheduler._dataSource.items() as SafeAppointment[];
214+
const { dayStartTime, dayEndTime } = this._getDayTimeRange(date);
215+
216+
const appointment = dataSource.find(
217+
(appt: SafeAppointment) => this._appointmentIntersectsDay(
218+
appt,
219+
dataAccessors,
220+
dayStartTime,
221+
dayEndTime,
222+
),
223+
);
222224

223225
if (!appointment) {
224226
return undefined;
@@ -238,13 +240,59 @@ class SchedulerWorkSpaceYear extends SchedulerWorkSpace {
238240
};
239241
}
240242

243+
_createGetAppointmentsForDate() {
244+
const { scheduler, dataAccessors } = this._getSchedulerAndDataAccessors();
245+
246+
return (date: Date): SafeAppointment[] => {
247+
const dataSource = scheduler._dataSource.items() as SafeAppointment[];
248+
const { dayStartTime, dayEndTime } = this._getDayTimeRange(date);
249+
250+
return dataSource.filter((appointment: SafeAppointment) => this._appointmentIntersectsDay(
251+
appointment,
252+
dataAccessors,
253+
dayStartTime,
254+
dayEndTime,
255+
));
256+
};
257+
}
258+
259+
_createShowAppointmentTooltip() {
260+
const { scheduler } = this._getSchedulerAndDataAccessors();
261+
const getResourceManager = this.option('getResourceManager') as () => ResourceManager;
262+
263+
return (appointments: SafeAppointment[], target: dxElementWrapper) => {
264+
if (!appointments || appointments.length === 0) {
265+
return;
266+
}
267+
268+
const resourceManager = getResourceManager();
269+
const tooltipItems = appointments.map((appointment) => ({
270+
appointment,
271+
targetedAppointment: undefined,
272+
color: resourceManager.getAppointmentColor({
273+
itemData: appointment,
274+
groupIndex: 0,
275+
}),
276+
}));
277+
278+
scheduler.showAppointmentTooltipCore(target, tooltipItems);
279+
};
280+
}
281+
282+
_createHideAppointmentTooltip() {
283+
const { scheduler } = this._getSchedulerAndDataAccessors();
284+
285+
return (): void => {
286+
scheduler.hideAppointmentTooltip();
287+
};
288+
}
289+
241290
_createCellClickAction(): void {
242291
this._cellClickAction = this._createActionByOption('onCellClick', {
243292
afterExecute: (actionArgs: any) => {
244293
const args = actionArgs.args[0];
245294
if (!args.cancel) {
246-
const notifyScheduler = this.option('notifyScheduler') as any;
247-
const scheduler = notifyScheduler?.scheduler;
295+
const { scheduler } = this._getSchedulerAndDataAccessors();
248296
if (scheduler && scheduler.showAddAppointmentPopup) {
249297
scheduler.showAddAppointmentPopup(args.cellData, args.cellData.groups || {});
250298
}
@@ -253,9 +301,8 @@ class SchedulerWorkSpaceYear extends SchedulerWorkSpace {
253301
});
254302
}
255303

256-
_handleYearCalendarCellClick(e: any): void {
257-
const notifyScheduler = this.option('notifyScheduler') as any;
258-
const scheduler = notifyScheduler?.scheduler;
304+
_handleYearCalendarCellClick(e: CellClickArgs): void {
305+
const { scheduler } = this._getSchedulerAndDataAccessors();
259306

260307
const args = {
261308
cancel: false,
@@ -306,7 +353,7 @@ class SchedulerWorkSpaceYear extends SchedulerWorkSpace {
306353
this._renderView();
307354
}
308355

309-
_optionChanged(args: any): void {
356+
_optionChanged(args: Record<string, unknown>): void {
310357
const { name } = args;
311358

312359
if (name === 'currentDate' || name === 'firstDayOfWeek') {
@@ -335,6 +382,4 @@ class SchedulerWorkSpaceYear extends SchedulerWorkSpace {
335382
}
336383
}
337384

338-
registerComponent('dxSchedulerWorkSpaceYear', SchedulerWorkSpaceYear as any);
339-
340385
export default SchedulerWorkSpaceYear;

0 commit comments

Comments
 (0)