Skip to content

Calendar: Should not switch to earliest date if same value is set programmatically (T1279950) #29358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/devextreme/js/__internal/core/utils/m_date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,26 @@ const sameCentury = function (date1, date2) {
return date1 && date2 && startCenturyDate1 === startCenturyDate2;
};

const sameDatesArrays = (arr1: Date[], arr2: Date[]): boolean => {
if (!Array.isArray(arr1) || !Array.isArray(arr2) || arr1.length !== arr2.length) {
return false;
}

return arr1.every((date1, index) => {
const date2 = arr2[index];

if ([date1, date2].some((date) => date !== null && !(date instanceof Date))) {
return false;
}

if (date1 instanceof Date && date2 instanceof Date) {
return sameDate(date1, date2);
}

return date1 === date2;
});
};

function getFirstDecadeInCentury(date) {
return date && date.getFullYear() - date.getFullYear() % 100;
}
Expand Down Expand Up @@ -768,6 +788,7 @@ const dateUtils = {
sameDecade,
sameCentury,
sameView,
sameDatesArrays,
getDifferenceInMonth,
getDifferenceInMonthForCells,
getFirstYearInDecade,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class CalendarMultiSelectionStrategy extends CalendarSelectionStrategy {
}

getDefaultCurrentDate() {
const dates = this.dateOption('value').filter((value) => value);
const dates = this.dateOption('value').filter(Boolean);
return this._getLowestDateInArray(dates);
}

Expand Down
10 changes: 8 additions & 2 deletions packages/devextreme/js/__internal/ui/calendar/m_calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1608,11 +1608,17 @@ class Calendar<
this._correctZoomLevel();
this._updateButtonsVisibility();
break;
case 'value':
this._selectionStrategy.processValueChanged(value, previousValue);
case 'value': {
const isSameValue = dateUtils.sameDatesArrays(value, previousValue);

if (!isSameValue) {
this._selectionStrategy.processValueChanged(value, previousValue);
}

this._setSubmitValue(value);
super._optionChanged(args);
break;
}
case 'viewsCount':
this._refreshViews();
this._renderNavigator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1773,3 +1773,50 @@ QUnit.module('intervalsOverlap', () => {
}), 'Intervals overlaps');
});
});

QUnit.module('sameDatesArrays', () => {
QUnit.test('Empty arrays', function(assert) {
assert.ok(dateUtils.sameDatesArrays([], []), 'empty arrays are equal');
});

QUnit.test('Arrays of different length', function(assert) {
assert.notOk(dateUtils.sameDatesArrays([], [new Date(2025, 1, 1)]), 'arrays of different length are not equal');
});

QUnit.test('Non-arrays', function(assert) {
assert.notOk(dateUtils.sameDatesArrays(null, null), 'both null arguments are not array');
assert.notOk(dateUtils.sameDatesArrays(null, new Date(2025, 1, 1)), 'first null is not an array');
assert.notOk(dateUtils.sameDatesArrays(new Date(2025, 1, 1), null), 'second null is not an array');
assert.notOk(dateUtils.sameDatesArrays('string', 'string'), 'strings are not arrays');
});

QUnit.test('Same arrays with valid dates', function(assert) {
const arr1 = [new Date(2025, 1, 1), new Date(2025, 2, 1)];
const arr2 = [new Date(2025, 1, 1), new Date(2025, 2, 1)];
assert.ok(dateUtils.sameDatesArrays(arr1, arr2), 'arrays with same dates are equal');
});

QUnit.test('Same arrays with null dates', function(assert) {
const arr1 = [new Date(2025, 1, 1), null];
const arr2 = [new Date(2025, 1, 1), null];
assert.ok(dateUtils.sameDatesArrays(arr1, arr2), 'arrays with same empty dates are equal');
});

QUnit.test('Different arrays with valid dates', function(assert) {
const arr1 = [new Date(2025, 1, 1), new Date(2025, 2, 1)];
const arr2 = [new Date(2025, 1, 1), new Date(2025, 3, 1)];
assert.notOk(dateUtils.sameDatesArrays(arr1, arr2), 'arrays with different dates are not equal');
});

QUnit.test('Different arrays with null dates', function(assert) {
const arr1 = [null, new Date(2025, 2, 1)];
const arr2 = [new Date(2025, 2, 1), null];
assert.notOk(dateUtils.sameDatesArrays(arr1, arr2), 'arrays with different empty dates are not equal');
});

QUnit.test('Arrays with non-null and non-Date values', function(assert) {
const arr1 = ['string'];
const arr2 = ['string'];
assert.notOk(dateUtils.sameDatesArrays(arr1, arr2), 'arrays with strings are not equal dates');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,46 @@ QUnit.module('Views integration', {

assert.strictEqual($contouredCell.length, 0, 'there is no contoured date cell');
});

QUnit.test('should not navigate view after new date UI select, even in React controlled mode (T1279950)', function(assert) {
this.calendar.option({
selectionMode: 'multiple',
value: [new Date(2025, 1, 10), new Date(2025, 2, 10)],
});

const calendar = this.calendar;
const $nextMonthButton = this.$element.find(toSelector(CALENDAR_NAVIGATOR_NEXT_MONTH_CLASS));

assert.ok(
dateUtils.sameMonth(calendar.option('currentDate'), new Date(2025, 1, 10)),
'initially navigated to the earliest date'
);

$($nextMonthButton).trigger('dxclick');

assert.ok(
dateUtils.sameMonth(calendar.option('currentDate'), new Date(2025, 2, 10)),
'navigated to the next month'
);

calendar.option('value', [new Date(2025, 1, 10), new Date(2025, 2, 10)]);

assert.ok(
dateUtils.sameMonth(calendar.option('currentDate'), new Date(2025, 2, 10)),
'did not navigate back to the earliest date'
);

const $cell = this.$element.find('*[data-value="2025/03/10"]');

$cell.trigger('dxclick');

assert.strictEqual(this.calendar.option('value').length, 1, 'deselected correctly');

assert.ok(
dateUtils.sameMonth(calendar.option('currentDate'), new Date(2025, 2, 10)),
'did not navigate back to the earliest date after deseleting'
);
});
});


Expand Down
Loading