Skip to content

Commit

Permalink
refactor(keycodes): add utilities for checking modifier keys
Browse files Browse the repository at this point in the history
Based off of the conversation in angular#13790, these changes add some utilities for dealing with modifier keys on keyboard events.
  • Loading branch information
crisbeto committed Nov 1, 2018
1 parent 28fb3ab commit 686af5b
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 9 deletions.
19 changes: 16 additions & 3 deletions src/cdk/keycodes/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package(default_visibility=["//visibility:public"])

load("//tools:defaults.bzl", "ts_library")
load("//tools:defaults.bzl", "ng_module", "ng_test_library", "ng_web_test_suite")

ts_library(
ng_module(
name = "keycodes",
module_name = "@angular/cdk/keycodes",
srcs = glob(["**/*.ts"], exclude=["**/*.spec.ts"]),
deps = ["@npm//tslib"],
)

ng_test_library(
name = "keycodes_test_sources",
srcs = glob(["**/*.spec.ts"]),
deps = [
"//src/cdk/testing",
":keycodes",
]
)

ng_web_test_suite(
name = "unit_tests",
deps = [":keycodes_test_sources"],
)
56 changes: 56 additions & 0 deletions src/cdk/keycodes/modifiers.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {createKeyboardEvent} from '@angular/cdk/testing';
import {hasModifierKey} from './modifiers';

describe('keyboard modifiers', () => {
it('should check whether the alt key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);

expect(hasModifierKey(event)).toBe(false);
Object.defineProperty(event, 'altKey', {get: () => true});
expect(hasModifierKey(event)).toBe(true);
});

it('should check whether the shift key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);

expect(hasModifierKey(event)).toBe(false);
Object.defineProperty(event, 'shiftKey', {get: () => true});
expect(hasModifierKey(event)).toBe(true);
});

it('should check whether the meta key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);

expect(hasModifierKey(event)).toBe(false);
Object.defineProperty(event, 'metaKey', {get: () => true});
expect(hasModifierKey(event)).toBe(true);
});

it('should check whether the ctrl key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);

expect(hasModifierKey(event)).toBe(false);
Object.defineProperty(event, 'ctrlKey', {get: () => true});
expect(hasModifierKey(event)).toBe(true);
});

it('should check if a particular modifier key is pressed', () => {
const event = createKeyboardEvent('keydown', 0);
Object.defineProperty(event, 'ctrlKey', {get: () => true});

expect(hasModifierKey(event, 'altKey')).toBe(false);
Object.defineProperty(event, 'altKey', {get: () => true});
expect(hasModifierKey(event, 'altKey')).toBe(true);
});

it('should check if multiple specific modifier keys are pressed', () => {
const event = createKeyboardEvent('keydown', 0);
Object.defineProperty(event, 'ctrlKey', {get: () => true});

expect(hasModifierKey(event, 'altKey', 'shiftKey')).toBe(false);
Object.defineProperty(event, 'altKey', {get: () => true});
Object.defineProperty(event, 'shiftKey', {get: () => true});
expect(hasModifierKey(event, 'altKey', 'shiftKey')).toBe(true);
});

});
21 changes: 21 additions & 0 deletions src/cdk/keycodes/modifiers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

type ModifierKey = 'altKey' | 'shiftKey' | 'ctrlKey' | 'metaKey';

/**
* Checks whether a modifier key is pressed.
* @param event Event to be checked.
*/
export function hasModifierKey(event: KeyboardEvent, ...modifiers: ModifierKey[]): boolean {
if (modifiers.length) {
return modifiers.some(modifier => event[modifier]);
}

return event.altKey || event.shiftKey || event.ctrlKey || event.metaKey;
}
1 change: 1 addition & 0 deletions src/cdk/keycodes/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
*/

export * from './keycodes';
export * from './modifiers';
6 changes: 2 additions & 4 deletions src/cdk/stepper/stepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {FocusableOption, FocusKeyManager} from '@angular/cdk/a11y';
import {Direction, Directionality} from '@angular/cdk/bidi';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {END, ENTER, HOME, SPACE} from '@angular/cdk/keycodes';
import {END, ENTER, HOME, SPACE, hasModifierKey} from '@angular/cdk/keycodes';
import {
AfterViewInit,
ChangeDetectionStrategy,
Expand Down Expand Up @@ -442,9 +442,7 @@ export class CdkStepper implements AfterViewInit, OnDestroy {
}

_onKeydown(event: KeyboardEvent) {
// TODO(crisbeto): move into a CDK utility once
// the similar PRs for other components are merged in.
const hasModifier = event.altKey || event.shiftKey || event.ctrlKey || event.metaKey;
const hasModifier = hasModifierKey(event);
const keyCode = event.keyCode;
const manager = this._keyManager;

Expand Down
4 changes: 2 additions & 2 deletions src/lib/expansion/expansion-panel-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {FocusMonitor, FocusableOption, FocusOrigin} from '@angular/cdk/a11y';
import {ENTER, SPACE} from '@angular/cdk/keycodes';
import {ENTER, SPACE, hasModifierKey} from '@angular/cdk/keycodes';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Expand Down Expand Up @@ -140,7 +140,7 @@ export class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
// Toggle for space and enter keys.
case SPACE:
case ENTER:
if (!event.altKey && !event.metaKey && !event.shiftKey && !event.ctrlKey) {
if (!hasModifierKey(event)) {
event.preventDefault();
this._toggle();
}
Expand Down

0 comments on commit 686af5b

Please sign in to comment.