From 55a837d54e223dd368948486ae58d50b95dd4417 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 28 Nov 2016 18:53:16 +0100 Subject: [PATCH] fix(list-key-manager): prevent the default keyboard actions Calls preventDefault when handling keyboard events in the ListKeyManager. This avoids the user scrolling the page when using the arrow keys to navigate. Relates to #1999. --- src/lib/core/a11y/list-key-manager.spec.ts | 40 +++++++++++++++++++--- src/lib/core/a11y/list-key-manager.ts | 7 +++- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/lib/core/a11y/list-key-manager.spec.ts b/src/lib/core/a11y/list-key-manager.spec.ts index 918f9c049bf5..a8381aa2a72b 100644 --- a/src/lib/core/a11y/list-key-manager.spec.ts +++ b/src/lib/core/a11y/list-key-manager.spec.ts @@ -15,15 +15,23 @@ class FakeQueryList extends QueryList { } } -const DOWN_ARROW_EVENT = { keyCode: DOWN_ARROW } as KeyboardEvent; -const UP_ARROW_EVENT = { keyCode: UP_ARROW } as KeyboardEvent; -const TAB_EVENT = { keyCode: TAB } as KeyboardEvent; -const HOME_EVENT = { keyCode: HOME } as KeyboardEvent; -const END_EVENT = { keyCode: END } as KeyboardEvent; +class FakeEvent { + defaultPrevented: boolean = false; + constructor(public keyCode: number) {} + preventDefault() { + this.defaultPrevented = true; + } +} + describe('ListKeyManager', () => { let keyManager: ListKeyManager; let itemList: FakeQueryList; + let DOWN_ARROW_EVENT: KeyboardEvent; + let UP_ARROW_EVENT: KeyboardEvent; + let TAB_EVENT: KeyboardEvent; + let HOME_EVENT: KeyboardEvent; + let END_EVENT: KeyboardEvent; beforeEach(() => { itemList = new FakeQueryList(); @@ -35,6 +43,12 @@ describe('ListKeyManager', () => { keyManager = new ListKeyManager(itemList); + DOWN_ARROW_EVENT = new FakeEvent(DOWN_ARROW) as KeyboardEvent; + UP_ARROW_EVENT = new FakeEvent(UP_ARROW) as KeyboardEvent; + TAB_EVENT = new FakeEvent(TAB) as KeyboardEvent; + HOME_EVENT = new FakeEvent(HOME) as KeyboardEvent; + END_EVENT = new FakeEvent(END) as KeyboardEvent; + // first item is already focused keyManager.focusFirstItem(); @@ -166,6 +180,22 @@ describe('ListKeyManager', () => { expect(tabOutEmitted).toBe(true); }); + it('should prevent the default keyboard action', () => { + expect(DOWN_ARROW_EVENT.defaultPrevented).toBe(false); + + keyManager.onKeydown(DOWN_ARROW_EVENT); + + expect(DOWN_ARROW_EVENT.defaultPrevented).toBe(true); + }); + + it('should not prevent the default keyboard action when pressing tab', () => { + expect(TAB_EVENT.defaultPrevented).toBe(false); + + keyManager.onKeydown(TAB_EVENT); + + expect(TAB_EVENT.defaultPrevented).toBe(false); + }); + }); describe('programmatic focus', () => { diff --git a/src/lib/core/a11y/list-key-manager.ts b/src/lib/core/a11y/list-key-manager.ts index 8e447ff0c327..3be6819a31c2 100644 --- a/src/lib/core/a11y/list-key-manager.ts +++ b/src/lib/core/a11y/list-key-manager.ts @@ -54,9 +54,14 @@ export class ListKeyManager { this.focusLastItem(); break; case TAB: + // Note that we shouldn't prevent the default action on tab. this._tabOut.next(null); - break; + return; + default: + return; } + + event.preventDefault(); } /** Focuses the first enabled item in the list. */