mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-08 15:51:16 +08:00
fix(datetime): switching month and year accounts for day (#25996)
resolves #25585
This commit is contained in:
@ -45,6 +45,7 @@ import {
|
|||||||
getPreviousWeek,
|
getPreviousWeek,
|
||||||
getPreviousYear,
|
getPreviousYear,
|
||||||
getStartOfWeek,
|
getStartOfWeek,
|
||||||
|
validateParts,
|
||||||
} from './utils/manipulation';
|
} from './utils/manipulation';
|
||||||
import {
|
import {
|
||||||
clampDate,
|
clampDate,
|
||||||
@ -583,6 +584,19 @@ export class Datetime implements ComponentInterface {
|
|||||||
private setActiveParts = (parts: DatetimeParts, removeDate = false) => {
|
private setActiveParts = (parts: DatetimeParts, removeDate = false) => {
|
||||||
const { multiple, activePartsClone, highlightActiveParts } = this;
|
const { multiple, activePartsClone, highlightActiveParts } = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When setting the active parts, it is possible
|
||||||
|
* to set invalid data. For example,
|
||||||
|
* when updating January 31 to February,
|
||||||
|
* February 31 does not exist. As a result
|
||||||
|
* we need to validate the active parts and
|
||||||
|
* ensure that we are only setting valid dates.
|
||||||
|
* Additionally, we need to update the working parts
|
||||||
|
* too in the event that the validated parts are different.
|
||||||
|
*/
|
||||||
|
const validatedParts = validateParts(parts);
|
||||||
|
this.setWorkingParts(validatedParts);
|
||||||
|
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
/**
|
/**
|
||||||
* We read from activePartsClone here because valueChanged() only updates that,
|
* We read from activePartsClone here because valueChanged() only updates that,
|
||||||
@ -595,20 +609,20 @@ export class Datetime implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
const activePartsArray = Array.isArray(activePartsClone) ? activePartsClone : [activePartsClone];
|
const activePartsArray = Array.isArray(activePartsClone) ? activePartsClone : [activePartsClone];
|
||||||
if (removeDate) {
|
if (removeDate) {
|
||||||
this.activeParts = activePartsArray.filter((p) => !isSameDay(p, parts));
|
this.activeParts = activePartsArray.filter((p) => !isSameDay(p, validatedParts));
|
||||||
} else if (highlightActiveParts) {
|
} else if (highlightActiveParts) {
|
||||||
this.activeParts = [...activePartsArray, parts];
|
this.activeParts = [...activePartsArray, validatedParts];
|
||||||
} else {
|
} else {
|
||||||
/**
|
/**
|
||||||
* If highlightActiveParts is false, that means we just have a
|
* If highlightActiveParts is false, that means we just have a
|
||||||
* default value of today in activeParts; we need to replace that
|
* default value of today in activeParts; we need to replace that
|
||||||
* rather than adding to it since it's just a placeholder.
|
* rather than adding to it since it's just a placeholder.
|
||||||
*/
|
*/
|
||||||
this.activeParts = [parts];
|
this.activeParts = [validatedParts];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.activeParts = {
|
this.activeParts = {
|
||||||
...parts,
|
...validatedParts,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
48
core/src/components/datetime/test/datetime.e2e.ts
Normal file
48
core/src/components/datetime/test/datetime.e2e.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
test.describe('datetime: switching months with different number of days', () => {
|
||||||
|
test.beforeEach(async ({ page, skip }) => {
|
||||||
|
skip.rtl();
|
||||||
|
skip.mode('ios');
|
||||||
|
|
||||||
|
await page.setContent(`
|
||||||
|
<ion-datetime locale="en-US" presentation="date" value="2022-01-31"></ion-datetime>
|
||||||
|
`);
|
||||||
|
|
||||||
|
await page.waitForSelector('.datetime-ready');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should switch the calendar header when moving to a month with a different number of days', async ({ page }) => {
|
||||||
|
const monthYearToggle = page.locator('ion-datetime .calendar-month-year');
|
||||||
|
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
|
||||||
|
|
||||||
|
await expect(monthYearToggle).toContainText('January 2022');
|
||||||
|
|
||||||
|
await monthYearToggle.click();
|
||||||
|
await page.waitForChanges();
|
||||||
|
|
||||||
|
// February
|
||||||
|
await monthColumnItems.nth(1).click();
|
||||||
|
await page.waitForChanges();
|
||||||
|
|
||||||
|
await expect(monthYearToggle).toContainText('February 2022');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should adjust the selected day when moving to a month with a different number of days', async ({ page }) => {
|
||||||
|
const monthYearToggle = page.locator('ion-datetime .calendar-month-year');
|
||||||
|
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
|
||||||
|
const datetime = page.locator('ion-datetime');
|
||||||
|
const ionChange = await page.spyOnEvent('ionChange');
|
||||||
|
|
||||||
|
await monthYearToggle.click();
|
||||||
|
await page.waitForChanges();
|
||||||
|
|
||||||
|
// February
|
||||||
|
await monthColumnItems.nth(1).click();
|
||||||
|
|
||||||
|
await ionChange.next();
|
||||||
|
await expect(ionChange).toHaveReceivedEventTimes(1);
|
||||||
|
await expect(datetime).toHaveJSProperty('value', '2022-02-28');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -339,3 +339,27 @@ export const calculateHourFromAMPM = (currentParts: DatetimeParts, newAMPM: 'am'
|
|||||||
|
|
||||||
return newHour;
|
return newHour;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates parts to ensure that month and day
|
||||||
|
* values are valid. For days that do not exist,
|
||||||
|
* the closest valid day is used.
|
||||||
|
*/
|
||||||
|
export const validateParts = (parts: DatetimeParts): DatetimeParts => {
|
||||||
|
const { month, day, year } = parts;
|
||||||
|
const partsCopy = { ...parts };
|
||||||
|
|
||||||
|
const numDays = getNumDaysInMonth(month, year);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the max number of days
|
||||||
|
* is greater than the day we want
|
||||||
|
* to set, update the DatetimeParts
|
||||||
|
* day field to be the max days.
|
||||||
|
*/
|
||||||
|
if (day !== null && numDays < day) {
|
||||||
|
partsCopy.day = numDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
return partsCopy;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user