Skip to content

Commit f4ec259

Browse files
Merge remote-tracking branch 'origin/25_2' into 25_2-endpoints-anti-forgery-dev
2 parents 25c90e7 + 35e9a2d commit f4ec259

14 files changed

Lines changed: 310 additions & 103 deletions
Loading
Loading
Loading
Loading
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { createScreenshotsComparer } from 'devextreme-screenshot-comparer';
2+
import Scheduler from 'devextreme-testcafe-models/scheduler';
3+
import { insertStylesheetRulesToPage } from '../../../../../helpers/domUtils';
4+
import { createWidget } from '../../../../../helpers/createWidget';
5+
import url from '../../../../../helpers/getPageUrl';
6+
import { testScreenshot } from '../../../../../helpers/themeUtils';
7+
8+
fixture.disablePageReloads`Scheduler: Current Time Indication: Shader with Virtual Scrolling`
9+
.page(url(__dirname, '../../../../container.html'))
10+
.beforeEach(async (t) => {
11+
await t.resizeWindow(2560, 600);
12+
});
13+
14+
const style = `
15+
.dx-scheduler-date-time-shader-top::before,
16+
.dx-scheduler-date-time-shader-bottom::before,
17+
.dx-scheduler-timeline .dx-scheduler-date-time-shader::before,
18+
.dx-scheduler-date-time-shader-all-day {
19+
background-color: red !important;
20+
}`;
21+
22+
const resources = [
23+
{ text: 'Room 1', id: 1, color: '#cb6bb2' },
24+
{ text: 'Room 2', id: 2, color: '#56ca85' },
25+
{ text: 'Room 3', id: 3, color: '#1e90ff' },
26+
{ text: 'Room 4', id: 4, color: '#ff9747' },
27+
{ text: 'Room 5', id: 5, color: '#ff6a00' },
28+
{ text: 'Room 6', id: 6, color: '#ffc0cb' },
29+
];
30+
31+
test('Should render shader correct with virtual scrolling without current time indicator', async (t) => {
32+
const scheduler = new Scheduler('#container');
33+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
34+
35+
await testScreenshot(
36+
t,
37+
takeScreenshot,
38+
'shader-virtual-scrolling-week-start.png',
39+
);
40+
41+
await scheduler.scrollTo(new Date(2025, 9, 15, 17, 30), { roomId: 6 });
42+
43+
await testScreenshot(
44+
t,
45+
takeScreenshot,
46+
'shader-virtual-scrolling-week-end.png',
47+
);
48+
49+
await t.expect(compareResults.isValid())
50+
.ok(compareResults.errorMessages());
51+
}).before(async () => {
52+
await insertStylesheetRulesToPage(style);
53+
54+
await createWidget('dxScheduler', {
55+
dataSource: [],
56+
currentView: 'week',
57+
views: ['week'],
58+
groups: ['roomId'],
59+
resources: [{ fieldExpr: 'roomId', dataSource: resources, label: 'Room' }],
60+
startDayHour: 8,
61+
endDayHour: 18,
62+
currentDate: new Date(2025, 9, 15),
63+
height: 400,
64+
shadeUntilCurrentTime: true,
65+
scrolling: { mode: 'virtual' },
66+
});
67+
});
68+
69+
test('Should render shader correctly with virtual scrolling and current time indicator', async (t) => {
70+
const scheduler = new Scheduler('#container');
71+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
72+
73+
await testScreenshot(
74+
t,
75+
takeScreenshot,
76+
'shader-virtual-scrolling-week-start-with-current-time-indicator.png',
77+
);
78+
79+
await scheduler.scrollTo(new Date(2025, 9, 15, 17, 30), { roomId: 6 });
80+
81+
await testScreenshot(
82+
t,
83+
takeScreenshot,
84+
'shader-virtual-scrolling-week-end-with-current-time-indicator.png',
85+
);
86+
87+
await t.expect(compareResults.isValid())
88+
.ok(compareResults.errorMessages());
89+
}).before(async () => {
90+
await insertStylesheetRulesToPage(style);
91+
92+
await createWidget('dxScheduler', {
93+
dataSource: [],
94+
currentView: 'week',
95+
views: ['week'],
96+
groups: ['roomId'],
97+
resources: [{ fieldExpr: 'roomId', dataSource: resources, label: 'Room' }],
98+
startDayHour: 8,
99+
endDayHour: 18,
100+
currentDate: new Date(2025, 9, 15),
101+
indicatorTime: new Date(2025, 9, 15, 17, 30),
102+
height: 400,
103+
shadeUntilCurrentTime: true,
104+
scrolling: { mode: 'virtual' },
105+
});
106+
});

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/shaders/m_current_time_shader_vertical.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class VerticalCurrentTimeShader extends CurrentTimeShader {
3535

3636
_renderShaderParts(groupCount, shaderHeight, maxHeight, isSolidShader) {
3737
for (let i = 0; i < groupCount; i++) {
38-
const shaderWidth = this._getShaderWidth(i);
38+
const shaderWidth = this._getShaderWidth();
3939
this._renderTopShader(this._$shader, shaderHeight, shaderWidth, i);
4040

4141
!isSolidShader && this._renderBottomShader(this._$shader, maxHeight, shaderHeight, shaderWidth, i);
@@ -45,7 +45,7 @@ class VerticalCurrentTimeShader extends CurrentTimeShader {
4545
}
4646

4747
_renderGroupedByDateShaderParts(groupCount, shaderHeight, maxHeight, isSolidShader) {
48-
const shaderWidth = this._getShaderWidth(0);
48+
const shaderWidth = this._getShaderWidth();
4949
let bottomShaderWidth = shaderWidth - this._workSpace.getCellWidth();
5050

5151
if (shaderHeight < 0) {
@@ -116,8 +116,8 @@ class VerticalCurrentTimeShader extends CurrentTimeShader {
116116
return this._workSpace.getGroupedStrategy().getShaderMaxHeight();
117117
}
118118

119-
_getShaderWidth(i) {
120-
return this._workSpace.getGroupedStrategy().getShaderWidth(i);
119+
_getShaderWidth() {
120+
return this._workSpace.getGroupedStrategy().getShaderWidth();
121121
}
122122

123123
clean() {

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

Lines changed: 15 additions & 41 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',
@@ -1563,31 +1557,6 @@ class SchedulerWorkSpace extends Widget<WorkspaceOptionsInternal> {
15631557
return DATE_TABLE_MIN_CELL_WIDTH;
15641558
}
15651559

1566-
getRoundedCellWidth(groupIndex, startIndex, cellCount) {
1567-
if (groupIndex < 0 || !hasWindow()) {
1568-
return 0;
1569-
}
1570-
1571-
const $row = (this.$element() as any).find(`.${DATE_TABLE_ROW_CLASS}`).eq(0);
1572-
let width = 0;
1573-
const $cells = $row.find(`.${DATE_TABLE_CELL_CLASS}`);
1574-
const totalCellCount = this._getCellCount() * groupIndex;
1575-
1576-
cellCount = cellCount || this._getCellCount();
1577-
1578-
if (!isDefined(startIndex)) {
1579-
startIndex = totalCellCount;
1580-
}
1581-
1582-
for (let i = startIndex; i < totalCellCount + cellCount; i++) {
1583-
const element = $($cells).eq(i).get(0);
1584-
const elementWidth = element ? getBoundingRect(element).width : 0;
1585-
width += elementWidth;
1586-
}
1587-
1588-
return width / (totalCellCount + cellCount - startIndex);
1589-
}
1590-
15911560
// Mappings
15921561
getCellWidth() {
15931562
return getCellWidth(this.getDOMElementsMetaData());
@@ -1833,7 +1802,11 @@ class SchedulerWorkSpace extends Widget<WorkspaceOptionsInternal> {
18331802
: 0;
18341803
const isScrollToAllDay = allDay && this.isAllDayPanelVisible;
18351804

1836-
const coordinates = this._getScrollCoordinates(date.getHours(), date.getMinutes(), date, groupIndex, isScrollToAllDay);
1805+
const coordinates = this._getScrollCoordinates(date, groupIndex, isScrollToAllDay);
1806+
1807+
if (!coordinates) {
1808+
return;
1809+
}
18371810

18381811
const scrollable = this.getScrollable();
18391812
const $scrollable = scrollable.$element();
@@ -1865,8 +1838,9 @@ class SchedulerWorkSpace extends Widget<WorkspaceOptionsInternal> {
18651838
}
18661839

18671840
_isValidScrollDate(date, throwWarning = true) {
1868-
const min = this.getStartViewDate();
1869-
const max = this.getEndViewDate();
1841+
const viewOffset = this.option('viewOffset') as number;
1842+
const min = new Date(this.getStartViewDate().getTime() + viewOffset);
1843+
const max = new Date(this.getEndViewDate().getTime() + viewOffset);
18701844

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

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,17 @@ class HorizontalGroupedStrategy {
142142

143143
_calculateOffset(groupIndex) {
144144
const indicatorStartPosition = this._workSpace.getIndicatorOffset(groupIndex);
145-
const offset = this._workSpace._getCellCount() * this._workSpace.getRoundedCellWidth(groupIndex - 1, 0) * groupIndex;
145+
const offset = this._workSpace._getCellCount() * this._workSpace.getCellWidth() * groupIndex;
146146

147147
return indicatorStartPosition + offset;
148148
}
149149

150150
_calculateGroupByDateOffset(groupIndex) {
151-
return this._workSpace.getIndicatorOffset(0) * this._workSpace._getGroupCount() + this._workSpace.getRoundedCellWidth(groupIndex - 1, 0) * groupIndex;
151+
return this._workSpace.getIndicatorOffset(0) * this._workSpace._getGroupCount() + this._workSpace.getCellWidth() * groupIndex;
152152
}
153153

154154
getShaderOffset(i, width) {
155-
const offset = this._workSpace._getCellCount() * this._workSpace.getRoundedCellWidth(i - 1) * i;
155+
const offset = this._workSpace._getCellCount() * this._workSpace.getCellWidth() * i;
156156
return this._workSpace.option('rtlEnabled') ? getBoundingRect(this._workSpace._dateTableScrollable.$content().get(0)).width - offset - this._workSpace.getTimePanelWidth() - width : offset;
157157
}
158158

@@ -170,8 +170,8 @@ class HorizontalGroupedStrategy {
170170
return getBoundingRect(this._workSpace._dateTableScrollable.$content().get(0)).height;
171171
}
172172

173-
getShaderWidth(i) {
174-
return this._workSpace.getIndicationWidth(i);
173+
getShaderWidth() {
174+
return this._workSpace.getIndicationWidth();
175175
}
176176

177177
getScrollableScrollTop(allDay) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ class VerticalGroupedStrategy {
159159
}
160160

161161
getShaderWidth() {
162-
return this._workSpace.getIndicationWidth(0);
162+
return this._workSpace.getIndicationWidth();
163163
}
164164

165165
getScrollableScrollTop() {

0 commit comments

Comments
 (0)