Skip to content

Commit b35f8b3

Browse files
committed
fix(expansion-panel): don't handle events with modifier keys in accordion
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 b35f8b3

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)