Skip to content

Commit 7794304

Browse files
crisbetojelbourn
authored andcommitted
fix(expansion-panel): don't handle events with modifier keys in accordion (#15750)
Fixes the accordion reacting to and preventing the default action of the home and end keys, even if they have modifiers, which could conflict with the user's shortcuts.
1 parent 3712b8f commit 7794304

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

src/material/expansion/accordion.spec.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
MatExpansionPanel,
99
MatExpansionPanelHeader,
1010
} from './index';
11-
import {dispatchKeyboardEvent} from '@angular/cdk/testing';
11+
import {dispatchKeyboardEvent, createKeyboardEvent, dispatchEvent} from '@angular/cdk/testing';
1212
import {DOWN_ARROW, UP_ARROW, HOME, END} from '@angular/cdk/keycodes';
1313
import {FocusMonitor} from '@angular/cdk/a11y';
1414

@@ -201,10 +201,31 @@ describe('MatAccordion', () => {
201201
const headers = fixture.componentInstance.headers.toArray();
202202

203203
headers.forEach(header => spyOn(header, 'focus'));
204-
dispatchKeyboardEvent(headerElements[headerElements.length - 1].nativeElement, 'keydown', HOME);
204+
const event = dispatchKeyboardEvent(
205+
headerElements[headerElements.length - 1].nativeElement, 'keydown', HOME);
205206
fixture.detectChanges();
206207

207208
expect(headers[0].focus).toHaveBeenCalledTimes(1);
209+
expect(event.defaultPrevented).toBe(true);
210+
});
211+
212+
it('should not handle the home key when it is pressed with a modifier', () => {
213+
const fixture = TestBed.createComponent(SetOfItems);
214+
fixture.detectChanges();
215+
216+
const headerElements = fixture.debugElement.queryAll(By.css('mat-expansion-panel-header'));
217+
const headers = fixture.componentInstance.headers.toArray();
218+
219+
headers.forEach(header => spyOn(header, 'focus'));
220+
const eventTarget = headerElements[headerElements.length - 1].nativeElement;
221+
const event = createKeyboardEvent('keydown', HOME, eventTarget);
222+
Object.defineProperty(event, 'altKey', {get: () => true});
223+
224+
dispatchEvent(eventTarget, event);
225+
fixture.detectChanges();
226+
227+
expect(headers[0].focus).not.toHaveBeenCalled();
228+
expect(event.defaultPrevented).toBe(false);
208229
});
209230

210231
it('should focus the last header when pressing the end key', () => {
@@ -215,10 +236,31 @@ describe('MatAccordion', () => {
215236
const headers = fixture.componentInstance.headers.toArray();
216237

217238
headers.forEach(header => spyOn(header, 'focus'));
218-
dispatchKeyboardEvent(headerElements[0].nativeElement, 'keydown', END);
239+
const event = dispatchKeyboardEvent(headerElements[0].nativeElement, 'keydown', END);
219240
fixture.detectChanges();
220241

221242
expect(headers[headers.length - 1].focus).toHaveBeenCalledTimes(1);
243+
expect(event.defaultPrevented).toBe(true);
244+
});
245+
246+
it('should not handle the end key when it is pressed with a modifier', () => {
247+
const fixture = TestBed.createComponent(SetOfItems);
248+
fixture.detectChanges();
249+
250+
const headerElements = fixture.debugElement.queryAll(By.css('mat-expansion-panel-header'));
251+
const headers = fixture.componentInstance.headers.toArray();
252+
253+
headers.forEach(header => spyOn(header, 'focus'));
254+
255+
const eventTarget = headerElements[0].nativeElement;
256+
const event = createKeyboardEvent('keydown', END, eventTarget);
257+
Object.defineProperty(event, 'altKey', {get: () => true});
258+
259+
dispatchEvent(eventTarget, event);
260+
fixture.detectChanges();
261+
262+
expect(headers[headers.length - 1].focus).not.toHaveBeenCalled();
263+
expect(event.defaultPrevented).toBe(false);
222264
});
223265

224266
});

src/material/expansion/accordion.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {Directive, Input, ContentChildren, QueryList, AfterContentInit} from '@a
1010
import {coerceBooleanProperty} from '@angular/cdk/coercion';
1111
import {CdkAccordion} from '@angular/cdk/accordion';
1212
import {FocusKeyManager} from '@angular/cdk/a11y';
13-
import {HOME, END} from '@angular/cdk/keycodes';
13+
import {HOME, END, hasModifierKey} from '@angular/cdk/keycodes';
1414
import {MAT_ACCORDION, MatAccordionBase, MatAccordionDisplayMode} from './accordion-base';
1515
import {MatExpansionPanelHeader} from './expansion-panel-header';
1616

@@ -61,11 +61,15 @@ export class MatAccordion extends CdkAccordion implements MatAccordionBase, Afte
6161
const manager = this._keyManager;
6262

6363
if (keyCode === HOME) {
64-
manager.setFirstItemActive();
65-
event.preventDefault();
64+
if (!hasModifierKey(event)) {
65+
manager.setFirstItemActive();
66+
event.preventDefault();
67+
}
6668
} else if (keyCode === END) {
67-
manager.setLastItemActive();
68-
event.preventDefault();
69+
if (!hasModifierKey(event)) {
70+
manager.setLastItemActive();
71+
event.preventDefault();
72+
}
6973
} else {
7074
this._keyManager.onKeydown(event);
7175
}

0 commit comments

Comments
 (0)