diff --git a/src/material/datepicker/date-range-selection-strategy.spec.ts b/src/material/datepicker/date-range-selection-strategy.spec.ts new file mode 100644 index 000000000000..135cb0bb5790 --- /dev/null +++ b/src/material/datepicker/date-range-selection-strategy.spec.ts @@ -0,0 +1,100 @@ +import {TestBed} from '@angular/core/testing'; +import {MatNativeDateModule} from '@angular/material/core'; + +import {JAN, FEB, MAR} from '../testing'; +import { + MAT_DATE_RANGE_SELECTION_STRATEGY, + DefaultMatCalendarRangeStrategy, +} from './date-range-selection-strategy'; +import {DateRange} from './date-selection-model'; + +describe('DefaultMatCalendarRangeStrategy', () => { + let strategy: DefaultMatCalendarRangeStrategy; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [MatNativeDateModule], + providers: [ + {provide: MAT_DATE_RANGE_SELECTION_STRATEGY, useClass: DefaultMatCalendarRangeStrategy}, + ], + }); + + strategy = TestBed.inject( + MAT_DATE_RANGE_SELECTION_STRATEGY, + ) as DefaultMatCalendarRangeStrategy; + }); + + describe('createDrag', () => { + const initialRange = new DateRange(new Date(2017, FEB, 10), new Date(2017, FEB, 13)); + + it('drags the range start', () => { + const rangeStart = new Date(2017, FEB, 10); + + // Grow range. + expect(strategy.createDrag(rangeStart, initialRange, new Date(2017, FEB, 9))).toEqual( + new DateRange(new Date(2017, FEB, 9), new Date(2017, FEB, 13)), + ); + expect(strategy.createDrag(rangeStart, initialRange, new Date(2016, JAN, 9))).toEqual( + new DateRange(new Date(2016, JAN, 9), new Date(2017, FEB, 13)), + ); + + // Shrink range. + expect(strategy.createDrag(rangeStart, initialRange, new Date(2017, FEB, 11))).toEqual( + new DateRange(new Date(2017, FEB, 11), new Date(2017, FEB, 13)), + ); + + // Move range after end. + expect(strategy.createDrag(rangeStart, initialRange, new Date(2017, FEB, 14))).toEqual( + new DateRange(new Date(2017, FEB, 14), new Date(2017, FEB, 17)), + ); + expect(strategy.createDrag(rangeStart, initialRange, new Date(2018, MAR, 14))).toEqual( + new DateRange(new Date(2018, MAR, 14), new Date(2018, MAR, 17)), + ); + }); + + it('drags the range end', () => { + const rangeEnd = new Date(2017, FEB, 13); + + // Grow range. + expect(strategy.createDrag(rangeEnd, initialRange, new Date(2017, FEB, 14))).toEqual( + new DateRange(new Date(2017, FEB, 10), new Date(2017, FEB, 14)), + ); + expect(strategy.createDrag(rangeEnd, initialRange, new Date(2018, MAR, 14))).toEqual( + new DateRange(new Date(2017, FEB, 10), new Date(2018, MAR, 14)), + ); + + // Shrink range. + expect(strategy.createDrag(rangeEnd, initialRange, new Date(2017, FEB, 12))).toEqual( + new DateRange(new Date(2017, FEB, 10), new Date(2017, FEB, 12)), + ); + + // Move range before start. + expect(strategy.createDrag(rangeEnd, initialRange, new Date(2017, FEB, 9))).toEqual( + new DateRange(new Date(2017, FEB, 6), new Date(2017, FEB, 9)), + ); + expect(strategy.createDrag(rangeEnd, initialRange, new Date(2016, JAN, 9))).toEqual( + new DateRange(new Date(2016, JAN, 6), new Date(2016, JAN, 9)), + ); + }); + + it('drags the range middle', () => { + const rangeMiddle = new Date(2017, FEB, 11); + + // Move range earlier. + expect(strategy.createDrag(rangeMiddle, initialRange, new Date(2017, FEB, 7))).toEqual( + new DateRange(new Date(2017, FEB, 6), new Date(2017, FEB, 9)), + ); + expect(strategy.createDrag(rangeMiddle, initialRange, new Date(2016, JAN, 7))).toEqual( + new DateRange(new Date(2016, JAN, 6), new Date(2016, JAN, 9)), + ); + + // Move range later. + expect(strategy.createDrag(rangeMiddle, initialRange, new Date(2017, FEB, 15))).toEqual( + new DateRange(new Date(2017, FEB, 14), new Date(2017, FEB, 17)), + ); + expect(strategy.createDrag(rangeMiddle, initialRange, new Date(2018, MAR, 15))).toEqual( + new DateRange(new Date(2018, MAR, 14), new Date(2018, MAR, 17)), + ); + }); + }); +}); diff --git a/src/material/datepicker/date-range-selection-strategy.ts b/src/material/datepicker/date-range-selection-strategy.ts index 3507138ae8cf..890a9ff617b4 100644 --- a/src/material/datepicker/date-range-selection-strategy.ts +++ b/src/material/datepicker/date-range-selection-strategy.ts @@ -97,22 +97,34 @@ export class DefaultMatCalendarRangeStrategy implements MatDateRangeSelection return null; } - const diff = this._dateAdapter.compareDate(newDate, dragOrigin); - const isRange = this._dateAdapter.compareDate(start, end) !== 0; + const adapter = this._dateAdapter; - if (isRange && this._dateAdapter.sameDate(dragOrigin, originalRange.start)) { + const isRange = adapter.compareDate(start, end) !== 0; + const diffYears = adapter.getYear(newDate) - adapter.getYear(dragOrigin); + const diffMonths = adapter.getMonth(newDate) - adapter.getMonth(dragOrigin); + const diffDays = adapter.getDate(newDate) - adapter.getDate(dragOrigin); + + if (isRange && adapter.sameDate(dragOrigin, originalRange.start)) { start = newDate; - if (this._dateAdapter.compareDate(newDate, end) > 0) { - end = this._dateAdapter.addCalendarDays(end, diff); + if (adapter.compareDate(newDate, end) > 0) { + end = adapter.addCalendarYears(end, diffYears); + end = adapter.addCalendarMonths(end, diffMonths); + end = adapter.addCalendarDays(end, diffDays); } - } else if (isRange && this._dateAdapter.sameDate(dragOrigin, originalRange.end)) { + } else if (isRange && adapter.sameDate(dragOrigin, originalRange.end)) { end = newDate; - if (this._dateAdapter.compareDate(newDate, start) < 0) { - start = this._dateAdapter.addCalendarDays(start, diff); + if (adapter.compareDate(newDate, start) < 0) { + start = adapter.addCalendarYears(start, diffYears); + start = adapter.addCalendarMonths(start, diffMonths); + start = adapter.addCalendarDays(start, diffDays); } } else { - start = this._dateAdapter.addCalendarDays(start, diff); - end = this._dateAdapter.addCalendarDays(end, diff); + start = adapter.addCalendarYears(start, diffYears); + start = adapter.addCalendarMonths(start, diffMonths); + start = adapter.addCalendarDays(start, diffDays); + end = adapter.addCalendarYears(end, diffYears); + end = adapter.addCalendarMonths(end, diffMonths); + end = adapter.addCalendarDays(end, diffDays); } return new DateRange(start, end);