feat(keyEvents): support for <div (keyup.enter)="callback()">
This commit adds a plugin for the event manager, to allow a key name to be appended to the event name (for keyup and keydown events), so that the callback is only called for that key. Here are some examples: (keydown.shift.enter) (keyup.space) (keydown.control.shift.a) (keyup.f1) Key names mostly follow the DOM Level 3 event key values: http://www.w3.org/TR/DOM-Level-3-Events-key/#key-value-tables There are some limitations to be worked on (cf details in https://github.com/angular/angular/pull/1136) but for now, this implementation is reliable for the following keys (by "reliable" I mean compatible with Chrome and Firefox and not depending on the keyboard layout): - alt, control, shift, meta (those keys can be combined with other keys) - tab, enter, backspace, pause, scrolllock, capslock, numlock - insert, delete, home, end, pageup, pagedown - arrowup, arrowdown, arrowleft, arrowright - latin letters (a-z), function keys (f1-f12) - numbers on the numeric keypad (but those keys are not correctly simulated by Chromedriver) There is a sample to play with in examples/src/key_events/. close #523 close #1136
This commit is contained in:
93
modules/angular2/src/render/dom/events/key_events.js
vendored
Normal file
93
modules/angular2/src/render/dom/events/key_events.js
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {isPresent, isBlank, StringWrapper, RegExpWrapper, BaseException, NumberWrapper} from 'angular2/src/facade/lang';
|
||||
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {EventManagerPlugin} from './event_manager';
|
||||
|
||||
var modifierKeys = ['alt', 'control', 'meta', 'shift'];
|
||||
var modifierKeyGetters = {
|
||||
'alt': (event) => event.altKey,
|
||||
'control': (event) => event.ctrlKey,
|
||||
'meta': (event) => event.metaKey,
|
||||
'shift': (event) => event.shiftKey
|
||||
}
|
||||
|
||||
export class KeyEventsPlugin extends EventManagerPlugin {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
supports(eventName: string): boolean {
|
||||
return isPresent(KeyEventsPlugin.parseEventName(eventName));
|
||||
}
|
||||
|
||||
addEventListener(element, eventName: string, handler: Function,
|
||||
shouldSupportBubble: boolean) {
|
||||
var parsedEvent = KeyEventsPlugin.parseEventName(eventName);
|
||||
|
||||
var outsideHandler = KeyEventsPlugin.eventCallback(element, shouldSupportBubble,
|
||||
StringMapWrapper.get(parsedEvent, 'fullKey'), handler, this.manager.getZone());
|
||||
|
||||
this.manager.getZone().runOutsideAngular(() => {
|
||||
DOM.on(element, StringMapWrapper.get(parsedEvent, 'domEventName'), outsideHandler);
|
||||
});
|
||||
}
|
||||
|
||||
static parseEventName(eventName: string) /* {'domEventName': string, 'fullKey': string} */ {
|
||||
eventName = eventName.toLowerCase();
|
||||
var parts = eventName.split('.');
|
||||
var domEventName = ListWrapper.removeAt(parts, 0);
|
||||
if ((parts.length === 0) || !(StringWrapper.equals(domEventName, 'keydown') || StringWrapper.equals(domEventName, 'keyup'))) {
|
||||
return null;
|
||||
}
|
||||
var key = ListWrapper.removeLast(parts);
|
||||
|
||||
var fullKey = '';
|
||||
ListWrapper.forEach(modifierKeys, (modifierName) => {
|
||||
if (ListWrapper.contains(parts, modifierName)) {
|
||||
ListWrapper.remove(parts, modifierName);
|
||||
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;
|
||||
}
|
||||
|
||||
return {
|
||||
'domEventName': domEventName,
|
||||
'fullKey': fullKey
|
||||
};
|
||||
}
|
||||
|
||||
static getEventFullKey(event): string {
|
||||
var fullKey = '';
|
||||
var key = DOM.getEventKey(event);
|
||||
key = key.toLowerCase();
|
||||
if (StringWrapper.equals(key, ' ')) {
|
||||
key = 'space'; // for readability
|
||||
} else if (StringWrapper.equals(key, '.')) {
|
||||
key = 'dot'; // because '.' is used as a separator in event names
|
||||
}
|
||||
ListWrapper.forEach(modifierKeys, (modifierName) => {
|
||||
if (modifierName != key) {
|
||||
var modifierGetter = StringMapWrapper.get(modifierKeyGetters, modifierName);
|
||||
if (modifierGetter(event)) {
|
||||
fullKey += modifierName + '.';
|
||||
}
|
||||
}
|
||||
});
|
||||
fullKey += key;
|
||||
return fullKey;
|
||||
}
|
||||
|
||||
static eventCallback(element, shouldSupportBubble, fullKey, handler, zone) {
|
||||
return (event) => {
|
||||
var correctElement = shouldSupportBubble || event.target === element;
|
||||
if (correctElement && KeyEventsPlugin.getEventFullKey(event) === fullKey) {
|
||||
zone.run(() => handler(event));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user