Skip to content

Commit 4da9e19

Browse files
authored
fix(material/datepicker): Update strategy to handle dragging across month boundaries and/or DateAdapter implementations that do not return difference in days from compareDate (#26341)
See internal cl 489280843 for the dragging across month use case.
1 parent dffb07b commit 4da9e19

File tree

2 files changed

+122
-10
lines changed

2 files changed

+122
-10
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import {TestBed} from '@angular/core/testing';
2+
import {MatNativeDateModule} from '@angular/material/core';
3+
4+
import {JAN, FEB, MAR} from '../testing';
5+
import {
6+
MAT_DATE_RANGE_SELECTION_STRATEGY,
7+
DefaultMatCalendarRangeStrategy,
8+
} from './date-range-selection-strategy';
9+
import {DateRange} from './date-selection-model';
10+
11+
describe('DefaultMatCalendarRangeStrategy', () => {
12+
let strategy: DefaultMatCalendarRangeStrategy<Date>;
13+
14+
beforeEach(() => {
15+
TestBed.configureTestingModule({
16+
imports: [MatNativeDateModule],
17+
providers: [
18+
{provide: MAT_DATE_RANGE_SELECTION_STRATEGY, useClass: DefaultMatCalendarRangeStrategy},
19+
],
20+
});
21+
22+
strategy = TestBed.inject(
23+
MAT_DATE_RANGE_SELECTION_STRATEGY,
24+
) as DefaultMatCalendarRangeStrategy<Date>;
25+
});
26+
27+
describe('createDrag', () => {
28+
const initialRange = new DateRange(new Date(2017, FEB, 10), new Date(2017, FEB, 13));
29+
30+
it('drags the range start', () => {
31+
const rangeStart = new Date(2017, FEB, 10);
32+
33+
// Grow range.
34+
expect(strategy.createDrag(rangeStart, initialRange, new Date(2017, FEB, 9))).toEqual(
35+
new DateRange(new Date(2017, FEB, 9), new Date(2017, FEB, 13)),
36+
);
37+
expect(strategy.createDrag(rangeStart, initialRange, new Date(2016, JAN, 9))).toEqual(
38+
new DateRange(new Date(2016, JAN, 9), new Date(2017, FEB, 13)),
39+
);
40+
41+
// Shrink range.
42+
expect(strategy.createDrag(rangeStart, initialRange, new Date(2017, FEB, 11))).toEqual(
43+
new DateRange(new Date(2017, FEB, 11), new Date(2017, FEB, 13)),
44+
);
45+
46+
// Move range after end.
47+
expect(strategy.createDrag(rangeStart, initialRange, new Date(2017, FEB, 14))).toEqual(
48+
new DateRange(new Date(2017, FEB, 14), new Date(2017, FEB, 17)),
49+
);
50+
expect(strategy.createDrag(rangeStart, initialRange, new Date(2018, MAR, 14))).toEqual(
51+
new DateRange(new Date(2018, MAR, 14), new Date(2018, MAR, 17)),
52+
);
53+
});
54+
55+
it('drags the range end', () => {
56+
const rangeEnd = new Date(2017, FEB, 13);
57+
58+
// Grow range.
59+
expect(strategy.createDrag(rangeEnd, initialRange, new Date(2017, FEB, 14))).toEqual(
60+
new DateRange(new Date(2017, FEB, 10), new Date(2017, FEB, 14)),
61+
);
62+
expect(strategy.createDrag(rangeEnd, initialRange, new Date(2018, MAR, 14))).toEqual(
63+
new DateRange(new Date(2017, FEB, 10), new Date(2018, MAR, 14)),
64+
);
65+
66+
// Shrink range.
67+
expect(strategy.createDrag(rangeEnd, initialRange, new Date(2017, FEB, 12))).toEqual(
68+
new DateRange(new Date(2017, FEB, 10), new Date(2017, FEB, 12)),
69+
);
70+
71+
// Move range before start.
72+
expect(strategy.createDrag(rangeEnd, initialRange, new Date(2017, FEB, 9))).toEqual(
73+
new DateRange(new Date(2017, FEB, 6), new Date(2017, FEB, 9)),
74+
);
75+
expect(strategy.createDrag(rangeEnd, initialRange, new Date(2016, JAN, 9))).toEqual(
76+
new DateRange(new Date(2016, JAN, 6), new Date(2016, JAN, 9)),
77+
);
78+
});
79+
80+
it('drags the range middle', () => {
81+
const rangeMiddle = new Date(2017, FEB, 11);
82+
83+
// Move range earlier.
84+
expect(strategy.createDrag(rangeMiddle, initialRange, new Date(2017, FEB, 7))).toEqual(
85+
new DateRange(new Date(2017, FEB, 6), new Date(2017, FEB, 9)),
86+
);
87+
expect(strategy.createDrag(rangeMiddle, initialRange, new Date(2016, JAN, 7))).toEqual(
88+
new DateRange(new Date(2016, JAN, 6), new Date(2016, JAN, 9)),
89+
);
90+
91+
// Move range later.
92+
expect(strategy.createDrag(rangeMiddle, initialRange, new Date(2017, FEB, 15))).toEqual(
93+
new DateRange(new Date(2017, FEB, 14), new Date(2017, FEB, 17)),
94+
);
95+
expect(strategy.createDrag(rangeMiddle, initialRange, new Date(2018, MAR, 15))).toEqual(
96+
new DateRange(new Date(2018, MAR, 14), new Date(2018, MAR, 17)),
97+
);
98+
});
99+
});
100+
});

src/material/datepicker/date-range-selection-strategy.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,22 +97,34 @@ export class DefaultMatCalendarRangeStrategy<D> implements MatDateRangeSelection
9797
return null;
9898
}
9999

100-
const diff = this._dateAdapter.compareDate(newDate, dragOrigin);
101-
const isRange = this._dateAdapter.compareDate(start, end) !== 0;
100+
const adapter = this._dateAdapter;
102101

103-
if (isRange && this._dateAdapter.sameDate(dragOrigin, originalRange.start)) {
102+
const isRange = adapter.compareDate(start, end) !== 0;
103+
const diffYears = adapter.getYear(newDate) - adapter.getYear(dragOrigin);
104+
const diffMonths = adapter.getMonth(newDate) - adapter.getMonth(dragOrigin);
105+
const diffDays = adapter.getDate(newDate) - adapter.getDate(dragOrigin);
106+
107+
if (isRange && adapter.sameDate(dragOrigin, originalRange.start)) {
104108
start = newDate;
105-
if (this._dateAdapter.compareDate(newDate, end) > 0) {
106-
end = this._dateAdapter.addCalendarDays(end, diff);
109+
if (adapter.compareDate(newDate, end) > 0) {
110+
end = adapter.addCalendarYears(end, diffYears);
111+
end = adapter.addCalendarMonths(end, diffMonths);
112+
end = adapter.addCalendarDays(end, diffDays);
107113
}
108-
} else if (isRange && this._dateAdapter.sameDate(dragOrigin, originalRange.end)) {
114+
} else if (isRange && adapter.sameDate(dragOrigin, originalRange.end)) {
109115
end = newDate;
110-
if (this._dateAdapter.compareDate(newDate, start) < 0) {
111-
start = this._dateAdapter.addCalendarDays(start, diff);
116+
if (adapter.compareDate(newDate, start) < 0) {
117+
start = adapter.addCalendarYears(start, diffYears);
118+
start = adapter.addCalendarMonths(start, diffMonths);
119+
start = adapter.addCalendarDays(start, diffDays);
112120
}
113121
} else {
114-
start = this._dateAdapter.addCalendarDays(start, diff);
115-
end = this._dateAdapter.addCalendarDays(end, diff);
122+
start = adapter.addCalendarYears(start, diffYears);
123+
start = adapter.addCalendarMonths(start, diffMonths);
124+
start = adapter.addCalendarDays(start, diffDays);
125+
end = adapter.addCalendarYears(end, diffYears);
126+
end = adapter.addCalendarMonths(end, diffMonths);
127+
end = adapter.addCalendarDays(end, diffDays);
116128
}
117129

118130
return new DateRange<D>(start, end);

0 commit comments

Comments
 (0)