Skip to content

Commit

Permalink
fix(autocomplete): don't block default arrow keys when using modifiers
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
crisbeto committed Jun 29, 2018
1 parent 8dfce58 commit 976f41c
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 7 deletions.
9 changes: 6 additions & 3 deletions src/cdk/testing/event-objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@ export function createTouchEvent(type: string, pageX = 0, pageY = 0) {
/** Dispatches a keydown event from an element. */
export function createKeyboardEvent(type: string, keyCode: number, target?: Element, key?: string) {
let event = document.createEvent('KeyboardEvent') as any;
// Firefox does not support `initKeyboardEvent`, but supports `initKeyEvent`.
let initEventFn = (event.initKeyEvent || event.initKeyboardEvent).bind(event);
let originalPreventDefault = event.preventDefault;

initEventFn(type, true, true, window, 0, 0, 0, 0, 0, keyCode);
// Firefox does not support `initKeyboardEvent`, but supports `initKeyEvent`.
if (event.initKeyEvent) {
event.initKeyEvent(type, true, true, window, 0, 0, 0, 0, 0, keyCode);
} else {
event.initKeyboardEvent(type, true, true, window, 0, key, 0, '', false);
}

// Webkit Browsers don't set the keyCode when calling the init function.
// See related bug https://bugs.webkit.org/show_bug.cgi?id=16735
Expand Down
9 changes: 5 additions & 4 deletions src/lib/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,15 +336,16 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
event.preventDefault();
} else {
const prevActiveItem = this.autocomplete._keyManager.activeItem;
const isArrowKey = keyCode === UP_ARROW || keyCode === DOWN_ARROW;
const isVerticalArrowKey = keyCode === UP_ARROW || keyCode === DOWN_ARROW;
const hasModifier = event.ctrlKey || event.altKey || event.metaKey || event.shiftKey;

if (this.panelOpen || keyCode === TAB) {
if ((isVerticalArrowKey && !hasModifier) || keyCode === TAB) {
this.autocomplete._keyManager.onKeydown(event);
} else if (isArrowKey && this._canOpen()) {
} else if (isVerticalArrowKey && this._canOpen()) {
this.openPanel();
}

if (isArrowKey || this.autocomplete._keyManager.activeItem !== prevActiveItem) {
if (isVerticalArrowKey || this.autocomplete._keyManager.activeItem !== prevActiveItem) {
this._scrollToOption();
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/lib/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,18 @@ describe('MatAutocomplete', () => {
expect(!!trigger.activeOption).toBe(false, 'Expected no active options.');
}));

it('should not prevent the default action when a modifier key is pressed', () => {
['metaKey', 'ctrlKey', 'altKey', 'shiftKey'].forEach(name => {
const event = createKeyboardEvent('keydown', DOWN_ARROW);
Object.defineProperty(event, name, {get: () => true});

fixture.componentInstance.trigger._handleKeydown(event);
fixture.detectChanges();

expect(event.defaultPrevented).toBe(false, `Expected autocompete not to block ${name} key`);
});
});

});

describe('option groups', () => {
Expand Down

0 comments on commit 976f41c

Please sign in to comment.