Skip to content

Commit 158ab75

Browse files
Tucchhaasjbur
andauthored
Scheduler: T1310544 — scrollTo does not take offset into account (#32160)
Co-authored-by: Sergio Bur <sjbur.dev@gmail.com>
1 parent ebe3449 commit 158ab75

4 files changed

Lines changed: 175 additions & 48 deletions

File tree

e2e/testcafe-devextreme/tests/scheduler/common/scrollTo.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,91 @@ test('ScrollTo works correctly in timeline RTL (native, sync header/workspace)',
230230
height: 580,
231231
rtlEnabled: true,
232232
}));
233+
234+
[
235+
// startDayHour: 6:00, endDayHour: 18:00
236+
{
237+
offset: 0,
238+
targetDate: new Date(2021, 1, 3, 4, 0),
239+
expectedDate: new Date(2021, 1, 3, 6, 0),
240+
},
241+
{
242+
offset: 0,
243+
targetDate: new Date(2021, 1, 3, 12, 0),
244+
expectedDate: new Date(2021, 1, 3, 12, 0),
245+
},
246+
{
247+
offset: 0,
248+
targetDate: new Date(2021, 1, 3, 20, 0),
249+
expectedDate: new Date(2021, 1, 3, 18, 0),
250+
},
251+
252+
// startDayHour: 18:00, endDayHour: next day 6:00
253+
{
254+
offset: 720,
255+
targetDate: new Date(2021, 1, 3, 10, 0),
256+
expectedDate: new Date(2021, 1, 3, 6, 0),
257+
},
258+
{
259+
offset: 720,
260+
targetDate: new Date(2021, 1, 3, 20, 0),
261+
expectedDate: new Date(2021, 1, 3, 20, 0),
262+
},
263+
{
264+
offset: 720,
265+
targetDate: new Date(2021, 1, 4, 1, 0),
266+
expectedDate: new Date(2021, 1, 4, 1, 0),
267+
},
268+
{
269+
offset: 720,
270+
targetDate: new Date(2021, 1, 4, 7, 0),
271+
expectedDate: new Date(2021, 1, 4, 6, 0),
272+
},
273+
274+
// startDayHour: prev day 18:00, endDayHour: 6:00
275+
{
276+
offset: -720,
277+
targetDate: new Date(2021, 1, 3, 16, 0),
278+
expectedDate: new Date(2021, 1, 3, 18, 0),
279+
},
280+
{
281+
offset: -720,
282+
targetDate: new Date(2021, 1, 3, 21, 0),
283+
expectedDate: new Date(2021, 1, 3, 21, 0),
284+
},
285+
{
286+
offset: -720,
287+
targetDate: new Date(2021, 1, 4, 3, 0),
288+
expectedDate: new Date(2021, 1, 4, 3, 0),
289+
},
290+
{
291+
offset: -720,
292+
targetDate: new Date(2021, 1, 3, 7, 0),
293+
expectedDate: new Date(2021, 1, 3, 6, 0),
294+
},
295+
].forEach(({ offset, targetDate, expectedDate }) => {
296+
test(`scrollTo should scroll to date with offset=${offset}, targetDate=${targetDate.toString()} (T1310544)`, async (t) => {
297+
const scheduler = new Scheduler('#container');
298+
299+
await scheduler.scrollTo(targetDate);
300+
301+
const cellData = await scheduler.getCellDataAtViewportCenter();
302+
303+
await t
304+
.expect(expectedDate.getTime()).gte(cellData.startDate.getTime())
305+
// eslint-disable-next-line spellcheck/spell-checker
306+
.expect(expectedDate.getTime()).lte(cellData.endDate.getTime());
307+
}).before(async () => createScheduler({
308+
dataSource: [],
309+
views: [{
310+
type: 'timelineWeek',
311+
offset,
312+
cellDuration: 60,
313+
}],
314+
currentView: 'timelineWeek',
315+
currentDate: new Date(2021, 1, 2),
316+
startDayHour: 6,
317+
endDayHour: 18,
318+
height: 580,
319+
}));
320+
});

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

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,26 +1407,20 @@ class SchedulerWorkSpace extends Widget<WorkspaceOptionsInternal> {
14071407
return (this.$element() as any).find(`.${GROUP_HEADER_CLASS}`);
14081408
}
14091409

1410-
_getScrollCoordinates(hours, minutes, date, groupIndex?: any, allDay?: any) {
1410+
_getScrollCoordinates(date, groupIndex?: any, allDay?: any) {
14111411
const currentDate = date || new Date(this.option('currentDate'));
1412-
const startDayHour = this.option('startDayHour');
1413-
const endDayHour = this.option('endDayHour');
14141412

1415-
if (hours < startDayHour) {
1416-
hours = startDayHour;
1417-
}
1413+
const cell = this.viewDataProvider.findGlobalCellPosition(currentDate, groupIndex, allDay, true);
14181414

1419-
if (hours >= endDayHour) {
1420-
hours = endDayHour - 1;
1415+
if (!cell) {
1416+
return undefined;
14211417
}
14221418

1423-
currentDate.setHours(hours, minutes, 0, 0);
1424-
1425-
const cell = this.viewDataProvider.findGlobalCellPosition(currentDate, groupIndex, allDay);
1419+
currentDate.setHours(cell.cellData.startDate.getHours(), currentDate.getMinutes(), 0, 0);
14261420

14271421
return this.virtualScrollingDispatcher.calculateCoordinatesByDataAndPosition(
1428-
cell?.cellData,
1429-
cell?.position,
1422+
cell.cellData,
1423+
cell.position,
14301424
currentDate,
14311425
isDateAndTimeView(this.type as any),
14321426
this.viewDirection === 'vertical',
@@ -1833,7 +1827,11 @@ class SchedulerWorkSpace extends Widget<WorkspaceOptionsInternal> {
18331827
: 0;
18341828
const isScrollToAllDay = allDay && this.isAllDayPanelVisible;
18351829

1836-
const coordinates = this._getScrollCoordinates(date.getHours(), date.getMinutes(), date, groupIndex, isScrollToAllDay);
1830+
const coordinates = this._getScrollCoordinates(date, groupIndex, isScrollToAllDay);
1831+
1832+
if (!coordinates) {
1833+
return;
1834+
}
18371835

18381836
const scrollable = this.getScrollable();
18391837
const $scrollable = scrollable.$element();
@@ -1865,8 +1863,9 @@ class SchedulerWorkSpace extends Widget<WorkspaceOptionsInternal> {
18651863
}
18661864

18671865
_isValidScrollDate(date, throwWarning = true) {
1868-
const min = this.getStartViewDate();
1869-
const max = this.getEndViewDate();
1866+
const viewOffset = this.option('viewOffset') as number;
1867+
const min = new Date(this.getStartViewDate().getTime() + viewOffset);
1868+
const max = new Date(this.getEndViewDate().getTime() + viewOffset);
18701869

18711870
if (date < min || date > max) {
18721871
throwWarning && errors.log('W1008', date);

packages/devextreme/js/__internal/scheduler/workspaces/view_model/m_view_data_provider.ts

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -282,51 +282,67 @@ export default class ViewDataProvider {
282282
return startDate < groupEndDate && endDate > groupStartDate;
283283
}
284284

285-
findGlobalCellPosition(date, groupIndex = 0, allDay = false) {
285+
findGlobalCellPosition(date, groupIndex = 0, allDay = false, findClosest = false) {
286286
const { completeViewDataMap } = this;
287287

288288
const showAllDayPanel = this._options.isAllDayPanelVisible;
289289

290+
let resultDiff = Number.MAX_VALUE;
291+
let resultCellData: ViewCellData | undefined;
292+
let resultCellColumnIndex = -1;
293+
let resultCellRowIndex = -1;
294+
295+
const getCellPosition = (columnIndex: number, rowIndex: number) => ({
296+
columnIndex,
297+
rowIndex: showAllDayPanel && !this._options.isVerticalGrouping
298+
? rowIndex - 1
299+
: rowIndex,
300+
});
301+
290302
for (let rowIndex = 0; rowIndex < completeViewDataMap.length; rowIndex += 1) {
291303
const currentRow = completeViewDataMap[rowIndex];
292304

293305
for (let columnIndex = 0; columnIndex < currentRow.length; columnIndex += 1) {
294306
const cellData = currentRow[columnIndex];
295307
const {
296-
startDate: currentStartDate,
297-
endDate: currentEndDate,
298-
groupIndex: currentGroupIndex,
299-
allDay: currentAllDay,
308+
startDate: cellStartDate,
309+
endDate: cellEndDate,
310+
groupIndex: cellGroupIndex,
311+
allDay: cellAllDay,
300312
} = cellData;
301313

302-
if (groupIndex === currentGroupIndex
303-
&& allDay === Boolean(currentAllDay)
304-
&& this._compareDatesAndAllDay(date, currentStartDate, currentEndDate, allDay)) {
314+
if (groupIndex !== cellGroupIndex || allDay !== Boolean(cellAllDay)) {
315+
continue;
316+
}
317+
318+
const isDateInCell = allDay
319+
? dateUtils.sameDate(date, cellStartDate)
320+
: date >= cellStartDate && date < cellEndDate;
321+
322+
if (isDateInCell) {
305323
return {
306-
position: {
307-
columnIndex,
308-
rowIndex: showAllDayPanel && !this._options.isVerticalGrouping
309-
? rowIndex - 1
310-
: rowIndex,
311-
},
324+
position: getCellPosition(columnIndex, rowIndex),
312325
cellData,
313326
};
314327
}
328+
329+
const diff = Math.abs(date.getTime() - cellStartDate.getTime());
330+
331+
if (findClosest && diff < resultDiff) {
332+
resultDiff = diff;
333+
resultCellData = cellData;
334+
resultCellColumnIndex = columnIndex;
335+
resultCellRowIndex = rowIndex;
336+
}
315337
}
316338
}
317339

318-
return undefined;
319-
}
320-
321-
private _compareDatesAndAllDay(
322-
date: Date,
323-
cellStartDate: Date,
324-
cellEndDate: Date,
325-
allDay: boolean,
326-
): boolean {
327-
return allDay
328-
? dateUtils.sameDate(date, cellStartDate)
329-
: date >= cellStartDate && date < cellEndDate;
340+
return resultCellData
341+
? {
342+
position: getCellPosition(resultCellColumnIndex, resultCellRowIndex),
343+
cellData: resultCellData,
344+
}
345+
: undefined;
330346
}
331347

332348
getSkippedDaysCount(groupIndex, startDate, endDate, daysCount) {

packages/testcafe-models/scheduler/index.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,28 @@ export default class Scheduler extends Widget {
163163
return cells.filter(`.${CLASS.focusedCell}`);
164164
}
165165

166+
getCellDataAtViewportCenter(): any {
167+
const { getInstance } = this;
168+
169+
return ClientFunction(
170+
() => {
171+
const instance = getInstance() as any;
172+
const workSpace = instance.getWorkSpace();
173+
const scrollable = workSpace.getScrollable();
174+
const scrollLeft = scrollable.scrollLeft();
175+
const scrollTop = scrollable.scrollTop();
176+
const centerX = scrollLeft + scrollable.$element().width() / 2;
177+
const centerY = scrollTop + scrollable.$element().height() / 2;
178+
179+
const cellElement = workSpace.getCellByCoordinates({ top: centerY, left: centerX }, false);
180+
const cellData = workSpace.getCellData(cellElement);
181+
182+
return cellData;
183+
},
184+
{ dependencies: { getInstance } }
185+
)();
186+
}
187+
166188
getSelectedCells(isAllDay = false): Selector {
167189
const cells = isAllDay ? this.allDayTableCells : this.dateTableCells;
168190

@@ -197,13 +219,15 @@ export default class Scheduler extends Widget {
197219

198220
scrollTo(date: Date, group?: Record<string, unknown>, allDay?: boolean): Promise<any> {
199221
const { getInstance } = this;
200-
const scrollTo = (): any => (getInstance() as any).scrollTo(date, group, allDay);
201222

202-
return ClientFunction(scrollTo, {
203-
dependencies: {
204-
date, group, allDay, getInstance,
205-
},
206-
})();
223+
return ClientFunction(
224+
() => {
225+
const instance = getInstance() as any;
226+
instance.scrollTo(date, group, allDay);
227+
}, {
228+
dependencies: { date, group, allDay, getInstance },
229+
}
230+
)();
207231
}
208232

209233
hideAppointmentTooltip(): Promise<any> {

0 commit comments

Comments
 (0)