Skip to content

Commit 976f41c

Browse files
committed
fix(autocomplete): don't block default arrow keys when using modifiers
Currently we hijack all up/down arrow key events, however this interferes with keyboard shortcuts such as shift + up arrow for marking all of the text. These changes stop intercepting the arrow keys, if they're used with a modifier. These changes also fix an issue where all the mocked out key events had the `metaKey` set to `true` on some browsers.
1 parent 8dfce58 commit 976f41c

File tree

3 files changed

+23
-7
lines changed

3 files changed

+23
-7
lines changed

src/cdk/testing/event-objects.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,14 @@ export function createTouchEvent(type: string, pageX = 0, pageY = 0) {
5151
/** Dispatches a keydown event from an element. */
5252
export function createKeyboardEvent(type: string, keyCode: number, target?: Element, key?: string) {
5353
let event = document.createEvent('KeyboardEvent') as any;
54-
// Firefox does not support `initKeyboardEvent`, but supports `initKeyEvent`.
55-
let initEventFn = (event.initKeyEvent || event.initKeyboardEvent).bind(event);
5654
let originalPreventDefault = event.preventDefault;
5755

58-
initEventFn(type, true, true, window, 0, 0, 0, 0, 0, keyCode);
56+
// Firefox does not support `initKeyboardEvent`, but supports `initKeyEvent`.
57+
if (event.initKeyEvent) {
58+
event.initKeyEvent(type, true, true, window, 0, 0, 0, 0, 0, keyCode);
59+
} else {
60+
event.initKeyboardEvent(type, true, true, window, 0, key, 0, '', false);
61+
}
5962

6063
// Webkit Browsers don't set the keyCode when calling the init function.
6164
// See related bug https://bugs.webkit.org/show_bug.cgi?id=16735

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,15 +336,16 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
336336
event.preventDefault();
337337
} else {
338338
const prevActiveItem = this.autocomplete._keyManager.activeItem;
339-
const isArrowKey = keyCode === UP_ARROW || keyCode === DOWN_ARROW;
339+
const isVerticalArrowKey = keyCode === UP_ARROW || keyCode === DOWN_ARROW;
340+
const hasModifier = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;
340341

341-
if (this.panelOpen || keyCode === TAB) {
342+
if ((isVerticalArrowKey && !hasModifier) || keyCode === TAB) {
342343
this.autocomplete._keyManager.onKeydown(event);
343-
} else if (isArrowKey && this._canOpen()) {
344+
} else if (isVerticalArrowKey && this._canOpen()) {
344345
this.openPanel();
345346
}
346347

347-
if (isArrowKey || this.autocomplete._keyManager.activeItem !== prevActiveItem) {
348+
if (isVerticalArrowKey || this.autocomplete._keyManager.activeItem !== prevActiveItem) {
348349
this._scrollToOption();
349350
}
350351
}

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,18 @@ describe('MatAutocomplete', () => {
11481148
expect(!!trigger.activeOption).toBe(false, 'Expected no active options.');
11491149
}));
11501150

1151+
it('should not prevent the default action when a modifier key is pressed', () => {
1152+
['metaKey', 'ctrlKey', 'altKey', 'shiftKey'].forEach(name => {
1153+
const event = createKeyboardEvent('keydown', DOWN_ARROW);
1154+
Object.defineProperty(event, name, {get: () => true});
1155+
1156+
fixture.componentInstance.trigger._handleKeydown(event);
1157+
fixture.detectChanges();
1158+
1159+
expect(event.defaultPrevented).toBe(false, `Expected autocompete not to block ${name} key`);
1160+
});
1161+
});
1162+
11511163
});
11521164

11531165
describe('option groups', () => {

0 commit comments

Comments
 (0)