From 66791219bf5c772134713fe85ef2dd0b81aaacd0 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Fri, 18 Aug 2017 19:52:57 +0200 Subject: [PATCH] fix(list-key-manager): increase typeahead range to include more characters As per the discussion on https://github.com/angular/material2/pull/2907#discussion_r133916040, the current typeahead setup won't cover the cases where the user is typing in an alphabet that has more characters than English. These changes update the check so that it catches any typed character (including non-alphanumeric characters). --- src/cdk/a11y/list-key-manager.spec.ts | 20 ++++++++++++++++++++ src/cdk/a11y/list-key-manager.ts | 22 ++++++++++++---------- src/cdk/keycodes/keycodes.ts | 2 ++ 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/cdk/a11y/list-key-manager.spec.ts b/src/cdk/a11y/list-key-manager.spec.ts index bba6ecf9d65d..499b5a628266 100644 --- a/src/cdk/a11y/list-key-manager.spec.ts +++ b/src/cdk/a11y/list-key-manager.spec.ts @@ -461,6 +461,26 @@ describe('Key managers', () => { expect(keyManager.activeItem).toBe(itemList.items[1]); })); + it('should handle non-letter characters', fakeAsync(() => { + itemList.items = [ + new FakeFocusable('[]'), + new FakeFocusable('321'), + new FakeFocusable('`!?') + ]; + + keyManager.onKeydown(createKeyboardEvent('keydown', 192, undefined, '`')); // types "`" + tick(debounceInterval); + expect(keyManager.activeItem).toBe(itemList.items[2]); + + keyManager.onKeydown(createKeyboardEvent('keydown', 51, undefined, '3')); // types "3" + tick(debounceInterval); + expect(keyManager.activeItem).toBe(itemList.items[1]); + + keyManager.onKeydown(createKeyboardEvent('keydown', 219, undefined, '[')); // types "[" + tick(debounceInterval); + expect(keyManager.activeItem).toBe(itemList.items[0]); + })); + }); }); diff --git a/src/cdk/a11y/list-key-manager.ts b/src/cdk/a11y/list-key-manager.ts index 1ccbedc7ce80..47fafcfa1856 100644 --- a/src/cdk/a11y/list-key-manager.ts +++ b/src/cdk/a11y/list-key-manager.ts @@ -9,7 +9,7 @@ import {QueryList} from '@angular/core'; import {Subject} from 'rxjs/Subject'; import {Subscription} from 'rxjs/Subscription'; -import {UP_ARROW, DOWN_ARROW, TAB, A, Z} from '@angular/cdk/keycodes'; +import {UP_ARROW, DOWN_ARROW, TAB, A, Z, ZERO, NINE} from '@angular/cdk/keycodes'; import {RxChain, debounceTime, filter, map, doOperator} from '@angular/cdk/rxjs'; /** @@ -107,17 +107,19 @@ export class ListKeyManager { case UP_ARROW: this.setPreviousItemActive(); break; case TAB: this.tabOut.next(); return; default: - if (event.keyCode >= A && event.keyCode <= Z) { - // Attempt to use the `event.key` which also maps it to the user's keyboard language, - // otherwise fall back to `keyCode` and `fromCharCode` which always resolve to English. - this._letterKeyStream.next(event.key ? - event.key.toLocaleUpperCase() : - String.fromCharCode(event.keyCode)); + const keyCode = event.keyCode; + + // Attempt to use the `event.key` which also maps it to the user's keyboard language, + // otherwise fall back to resolving alphanumeric characters via the keyCode. + if (event.key && event.key.length === 1) { + this._letterKeyStream.next(event.key.toLocaleUpperCase()); + } else if ((keyCode >= A && keyCode <= Z) || (keyCode >= ZERO && keyCode <= NINE)) { + this._letterKeyStream.next(String.fromCharCode(keyCode)); } - // Note that we return here, in order to avoid preventing - // the default action of non-navigational keys. - return; + // Note that we return here, in order to avoid preventing + // the default action of non-navigational keys. + return; } this._pressedLetters = []; diff --git a/src/cdk/keycodes/keycodes.ts b/src/cdk/keycodes/keycodes.ts index 312174fbd3de..d1ddf1231f03 100644 --- a/src/cdk/keycodes/keycodes.ts +++ b/src/cdk/keycodes/keycodes.ts @@ -22,3 +22,5 @@ export const BACKSPACE = 8; export const DELETE = 46; export const A = 65; export const Z = 90; +export const ZERO = 48; +export const NINE = 91;