Skip to content

Commit fb35c71

Browse files
authored
Scheduler: Restore recurrence appointment focus after edit recurrence appointment popup closed (#31135)
1 parent 037b82a commit fb35c71

File tree

4 files changed

+55
-5
lines changed

4 files changed

+55
-5
lines changed

packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ export class PopupModel {
118118
return cancelButton;
119119
};
120120

121+
getCloseButton = (): HTMLButtonElement => {
122+
const closeButton = this.element.querySelector('.dx-closebutton.dx-button') as HTMLButtonElement;
123+
if (!closeButton) {
124+
throw new Error('Close button not found');
125+
}
126+
return closeButton;
127+
};
128+
121129
getFormEditor = (fieldName: string): HTMLElement | null => {
122130
const form = this.getForm();
123131
if (form === null) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import {
2+
afterEach, describe, expect, it, jest,
3+
} from '@jest/globals';
4+
5+
import { createScheduler } from './__tests__/__mock__/create_scheduler';
6+
import { setupSchedulerTestEnvironment } from './__tests__/__mock__/m_mock_scheduler';
7+
8+
describe('Recurrence focus restore', () => {
9+
afterEach(() => {
10+
jest.useRealTimers();
11+
});
12+
13+
it('should restore focus on appointment after closing recurrence dialog and allow reopening with Enter', async () => {
14+
setupSchedulerTestEnvironment();
15+
16+
const { POM, keydown } = await createScheduler({
17+
timeZone: 'Etc/UTC',
18+
dataSource: [{
19+
text: 'Recurring meeting',
20+
startDate: new Date('2021-02-02T09:00:00.000Z'),
21+
endDate: new Date('2021-02-02T10:00:00.000Z'),
22+
recurrenceRule: 'FREQ=DAILY',
23+
}],
24+
currentDate: new Date('2021-02-02T10:00:00.000Z'),
25+
});
26+
jest.useFakeTimers();
27+
28+
const appointment = POM.getAppointment('Recurring meeting');
29+
const appointmentEl = appointment.element as HTMLElement;
30+
31+
appointmentEl.focus();
32+
keydown(appointmentEl, 'Enter');
33+
34+
POM.popup.getCloseButton().click();
35+
jest.runAllTimers();
36+
37+
expect(appointmentEl.classList.contains('dx-state-focused')).toBe(true);
38+
});
39+
});

packages/devextreme/js/__internal/scheduler/m_scheduler.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,9 @@ class Scheduler extends SchedulerOptionsBaseWidget {
15831583
],
15841584
popupOptions: {
15851585
wrapperAttr: { class: POPUP_DIALOG_CLASS },
1586+
onHidden: () => {
1587+
this._appointments?.focus();
1588+
},
15861589
},
15871590
} as any);
15881591

packages/devextreme/js/__internal/ui/dialog.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { getHeight, getWidth } from '@js/core/utils/size';
1111
import { isDefined, isPlainObject } from '@js/core/utils/type';
1212
import { value as getViewport } from '@js/core/utils/view_port';
1313
import { getWindow } from '@js/core/utils/window';
14+
import type { EventInfo } from '@js/events';
1415
import type { ClickEvent, Properties as ButtonProperties } from '@js/ui/button';
1516
import type {
1617
alert as alertFunc,
@@ -152,10 +153,6 @@ export const custom = (params: DialogParams): BaseDialog => {
152153
eventsEngine.trigger($firstButton, 'focus');
153154
};
154155

155-
const onHidden: PopupProperties['onHidden'] = (e) => {
156-
$(e.element).remove();
157-
};
158-
159156
const animation = {
160157
show: {
161158
type: 'pop',
@@ -240,7 +237,6 @@ export const custom = (params: DialogParams): BaseDialog => {
240237
height: 'auto',
241238
ignoreChildEvents: false,
242239
onContentReady,
243-
onHidden,
244240
onHiding: (): void => { deferred.reject(); },
245241
onShowing,
246242
onShown,
@@ -258,6 +254,10 @@ export const custom = (params: DialogParams): BaseDialog => {
258254
const options = {
259255
...configuration,
260256
...popupOptions,
257+
onHidden: (e: EventInfo<Popup>): void => {
258+
$(e.element).remove();
259+
popupOptions?.onHidden?.(e);
260+
},
261261
};
262262

263263
// @ts-expect-error Incorrect constructor usage

0 commit comments

Comments
 (0)