159 lines
5.1 KiB
JavaScript
159 lines
5.1 KiB
JavaScript
(function(window, document) {
|
|
var KeyEvent = function(data, type) {
|
|
this.keyCode = 'keyCode' in data ? data.keyCode : 0;
|
|
this.charCode = 'charCode' in data ? data.charCode : 0;
|
|
|
|
var modifiers = 'modifiers' in data ? data.modifiers : [];
|
|
|
|
this.ctrlKey = false;
|
|
this.metaKey = false;
|
|
this.altKey = false;
|
|
this.shiftKey = false;
|
|
|
|
for (var i = 0; i < modifiers.length; i++) {
|
|
this[modifiers[i] + 'Key'] = true;
|
|
}
|
|
|
|
this.type = type || 'keypress';
|
|
};
|
|
|
|
KeyEvent.prototype.toNative = function() {
|
|
var event = document.createEventObject ? document.createEventObject() : document.createEvent('Events');
|
|
|
|
if (event.initEvent) {
|
|
event.initEvent(this.type, true, true);
|
|
}
|
|
|
|
event.keyCode = this.keyCode;
|
|
event.which = this.charCode || this.keyCode;
|
|
event.shiftKey = this.shiftKey;
|
|
event.metaKey = this.metaKey;
|
|
event.altKey = this.altKey;
|
|
event.ctrlKey = this.ctrlKey;
|
|
|
|
return event;
|
|
};
|
|
|
|
KeyEvent.prototype.fire = function(element) {
|
|
var event = this.toNative();
|
|
if (element.dispatchEvent) {
|
|
element.dispatchEvent(event);
|
|
return;
|
|
}
|
|
|
|
element.fireEvent('on' + this.type, event);
|
|
};
|
|
|
|
// simulates complete key event as if the user pressed the key in the browser
|
|
// triggers a keydown, then a keypress, then a keyup
|
|
KeyEvent.simulate = function(charCode, keyCode, modifiers, element, repeat, options) {
|
|
if (modifiers === undefined) {
|
|
modifiers = [];
|
|
}
|
|
|
|
if (element === undefined) {
|
|
element = document;
|
|
}
|
|
|
|
if (repeat === undefined) {
|
|
repeat = 1;
|
|
}
|
|
|
|
if (options === undefined) {
|
|
options = {};
|
|
}
|
|
|
|
// Re-target the element so that `event.target` becomes the shadow host. See:
|
|
// https://developers.google.com/web/fundamentals/web-components/shadowdom#events
|
|
// This is a bit of a lie because true events would re-target the event target both for
|
|
// closed and open shadow trees. `KeyEvent` is not a true event and will fire the event
|
|
// directly from the shadow host for closed shadow trees. For open trees, this would make
|
|
// the tests fail as the actual event that will be eventually dispatched would have an
|
|
// incorrect `Event.composedPath()` starting with the shadow host instead of the
|
|
// initial event target.
|
|
if (options.shadowHost && options.shadowHost.shadowRoot === null) {
|
|
// closed shadow dom
|
|
element = options.shadowHost;
|
|
}
|
|
|
|
var modifierToKeyCode = {
|
|
'shift': 16,
|
|
'ctrl': 17,
|
|
'alt': 18,
|
|
'meta': 91
|
|
};
|
|
|
|
// if the key is a modifier then take it out of the regular
|
|
// keypress/keydown
|
|
if (keyCode == 16 || keyCode == 17 || keyCode == 18 || keyCode == 91) {
|
|
repeat = 0;
|
|
}
|
|
|
|
var modifiersToInclude = [];
|
|
var keyEvents = [];
|
|
|
|
// modifiers would go down first
|
|
for (var i = 0; i < modifiers.length; i++) {
|
|
modifiersToInclude.push(modifiers[i]);
|
|
keyEvents.push(new KeyEvent({
|
|
charCode: 0,
|
|
keyCode: modifierToKeyCode[modifiers[i]],
|
|
modifiers: modifiersToInclude
|
|
}, 'keydown'));
|
|
}
|
|
|
|
// @todo factor in duration for these
|
|
while (repeat > 0) {
|
|
keyEvents.push(new KeyEvent({
|
|
charCode: 0,
|
|
keyCode: keyCode,
|
|
modifiers: modifiersToInclude
|
|
}, 'keydown'));
|
|
|
|
keyEvents.push(new KeyEvent({
|
|
charCode: charCode,
|
|
keyCode: charCode,
|
|
modifiers: modifiersToInclude
|
|
}, 'keypress'));
|
|
|
|
repeat--;
|
|
}
|
|
|
|
keyEvents.push(new KeyEvent({
|
|
charCode: 0,
|
|
keyCode: keyCode,
|
|
modifiers: modifiersToInclude
|
|
}, 'keyup'));
|
|
|
|
// now lift up the modifier keys
|
|
for (i = 0; i < modifiersToInclude.length; i++) {
|
|
var modifierKeyCode = modifierToKeyCode[modifiersToInclude[i]];
|
|
modifiersToInclude.splice(i, 1);
|
|
keyEvents.push(new KeyEvent({
|
|
charCode: 0,
|
|
keyCode: modifierKeyCode,
|
|
modifiers: modifiersToInclude
|
|
}, 'keyup'));
|
|
}
|
|
|
|
for (i = 0; i < keyEvents.length; i++) {
|
|
// console.log('firing', keyEvents[i].type, keyEvents[i].keyCode, keyEvents[i].charCode);
|
|
keyEvents[i].fire(element);
|
|
}
|
|
};
|
|
|
|
window.KeyEvent = KeyEvent;
|
|
|
|
// expose as a common js module
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = KeyEvent;
|
|
}
|
|
|
|
// expose KeyEvent as an AMD module
|
|
if (typeof define === 'function' && define.amd) {
|
|
define(function() {
|
|
return KeyEvent;
|
|
});
|
|
}
|
|
}) (typeof window !== 'undefined' ? window : null, typeof window !== 'undefined' ? document : null);
|