-
Notifications
You must be signed in to change notification settings - Fork 24.8k
/
key_events.ts
146 lines (127 loc) Β· 4.55 KB
/
key_events.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* @license
* Copyright Google Inc. 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
*/
import {Inject, Injectable, NgZone} from '@angular/core';
import {getDOM} from '../dom_adapter';
import {DOCUMENT} from '../dom_tokens';
import {EventManagerPlugin} from './event_manager';
/**
* Defines supported modifiers for key events.
*/
const MODIFIER_KEYS = ['alt', 'control', 'meta', 'shift'];
/**
* Retrieves modifiers from key-event objects.
*/
const MODIFIER_KEY_GETTERS: {[key: string]: (event: KeyboardEvent) => boolean} = {
'alt': (event: KeyboardEvent) => event.altKey,
'control': (event: KeyboardEvent) => event.ctrlKey,
'meta': (event: KeyboardEvent) => event.metaKey,
'shift': (event: KeyboardEvent) => event.shiftKey
};
/**
* @publicApi
* A browser plug-in that provides support for handling of key events in Angular.
*/
@Injectable()
export class KeyEventsPlugin extends EventManagerPlugin {
/**
* Initializes an instance of the browser plug-in.
* @param doc The document in which key events will be detected.
*/
constructor(@Inject(DOCUMENT) doc: any) { super(doc); }
/**
* Reports whether a named key event is supported.
* @param eventName The event name to query.
* @return True if the named key event is supported.
*/
supports(eventName: string): boolean { return KeyEventsPlugin.parseEventName(eventName) != null; }
/**
* Registers a handler for a specific element and key event.
* @param element The HTML element to receive event notifications.
* @param eventName The name of the key event to listen for.
* @param handler A function to call when the notification occurs. Receives the
* event object as an argument.
* @returns The key event that was registered.
*/
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
const parsedEvent = KeyEventsPlugin.parseEventName(eventName) !;
const outsideHandler =
KeyEventsPlugin.eventCallback(parsedEvent['fullKey'], handler, this.manager.getZone());
return this.manager.getZone().runOutsideAngular(() => {
return getDOM().onAndCancel(element, parsedEvent['domEventName'], outsideHandler);
});
}
static parseEventName(eventName: string): {[key: string]: string}|null {
const parts: string[] = eventName.toLowerCase().split('.');
const domEventName = parts.shift();
if ((parts.length === 0) || !(domEventName === 'keydown' || domEventName === 'keyup')) {
return null;
}
const key = KeyEventsPlugin._normalizeKey(parts.pop() !);
let fullKey = '';
MODIFIER_KEYS.forEach(modifierName => {
const index: number = parts.indexOf(modifierName);
if (index > -1) {
parts.splice(index, 1);
fullKey += modifierName + '.';
}
});
fullKey += key;
if (parts.length != 0 || key.length === 0) {
// returning null instead of throwing to let another plugin process the event
return null;
}
const result: {[k: string]: string} = {};
result['domEventName'] = domEventName;
result['fullKey'] = fullKey;
return result;
}
static getEventFullKey(event: KeyboardEvent): string {
let fullKey = '';
let key = getDOM().getEventKey(event);
key = key.toLowerCase();
if (key === ' ') {
key = 'space'; // for readability
} else if (key === '.') {
key = 'dot'; // because '.' is used as a separator in event names
}
MODIFIER_KEYS.forEach(modifierName => {
if (modifierName != key) {
const modifierGetter = MODIFIER_KEY_GETTERS[modifierName];
if (modifierGetter(event)) {
fullKey += modifierName + '.';
}
}
});
fullKey += key;
return fullKey;
}
/**
* Configures a handler callback for a key event.
* @param fullKey The event name that combines all simultaneous keystrokes.
* @param handler The function that responds to the key event.
* @param zone The zone in which the event occurred.
* @returns A callback function.
*/
static eventCallback(fullKey: any, handler: Function, zone: NgZone): Function {
return (event: any /** TODO #9100 */) => {
if (KeyEventsPlugin.getEventFullKey(event) === fullKey) {
zone.runGuarded(() => handler(event));
}
};
}
/** @internal */
static _normalizeKey(keyName: string): string {
// TODO: switch to a Map if the mapping grows too much
switch (keyName) {
case 'esc':
return 'escape';
default:
return keyName;
}
}
}