You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
5.2 KiB
JavaScript
238 lines
5.2 KiB
JavaScript
'use strict';
|
|
|
|
define('settings/key', function () {
|
|
var SettingsKey;
|
|
var helper = null;
|
|
var lastKey = null;
|
|
var oldKey = null;
|
|
var keyMap = Object.freeze({
|
|
0: '',
|
|
8: 'Backspace',
|
|
9: 'Tab',
|
|
13: 'Enter',
|
|
27: 'Escape',
|
|
32: 'Space',
|
|
37: 'Left',
|
|
38: 'Up',
|
|
39: 'Right',
|
|
40: 'Down',
|
|
45: 'Insert',
|
|
46: 'Delete',
|
|
187: '=',
|
|
189: '-',
|
|
190: '.',
|
|
191: '/',
|
|
219: '[',
|
|
220: '\\',
|
|
221: ']',
|
|
});
|
|
|
|
function Key() {
|
|
this.c = false;
|
|
this.a = false;
|
|
this.s = false;
|
|
this.m = false;
|
|
this.code = 0;
|
|
this.char = '';
|
|
}
|
|
|
|
/**
|
|
Returns either a Key-Object representing the given event or null if only modification-keys got released.
|
|
@param event The event to inspect.
|
|
@returns Key | null The Key-Object the focused element should be set to.
|
|
*/
|
|
function getKey(event) {
|
|
var anyModChange = (
|
|
event.ctrlKey !== lastKey.c ||
|
|
event.altKey !== lastKey.a ||
|
|
event.shiftKey !== lastKey.s ||
|
|
event.metaKey !== lastKey.m
|
|
);
|
|
var modChange = (
|
|
event.ctrlKey +
|
|
event.altKey +
|
|
event.shiftKey +
|
|
event.metaKey -
|
|
lastKey.c -
|
|
lastKey.a -
|
|
lastKey.s -
|
|
lastKey.m
|
|
);
|
|
var key = new Key();
|
|
key.c = event.ctrlKey;
|
|
key.a = event.altKey;
|
|
key.s = event.shiftKey;
|
|
key.m = event.metaKey;
|
|
lastKey = key;
|
|
if (anyModChange) {
|
|
if (modChange < 0) {
|
|
return null;
|
|
}
|
|
key.code = oldKey.code;
|
|
key.char = oldKey.char;
|
|
} else {
|
|
key.code = event.which;
|
|
key.char = convertKeyCodeToChar(key.code);
|
|
}
|
|
oldKey = key;
|
|
return key;
|
|
}
|
|
|
|
/**
|
|
Returns the string that represents the given key-code.
|
|
@param code The key-code.
|
|
@returns String Representation of the given key-code.
|
|
*/
|
|
function convertKeyCodeToChar(code) {
|
|
code = +code;
|
|
if (code === 0) {
|
|
return '';
|
|
} else if (code >= 48 && code <= 90) {
|
|
return String.fromCharCode(code).toUpperCase();
|
|
} else if (code >= 112 && code <= 123) {
|
|
return 'F' + (code - 111);
|
|
}
|
|
return keyMap[code] || ('#' + code);
|
|
}
|
|
|
|
/**
|
|
Returns a string to identify a Key-Object.
|
|
@param key The Key-Object that should get identified.
|
|
@param human Whether to show 'Enter a key' when key-char is empty.
|
|
@param short Whether to shorten modification-names to first character.
|
|
@param separator The separator between modification-names and key-char.
|
|
@returns String The string to identify the given key-object the given way.
|
|
*/
|
|
function getKeyString(key, human, short, separator) {
|
|
var str = '';
|
|
if (!(key instanceof Key)) {
|
|
return str;
|
|
}
|
|
if (!key.char) {
|
|
if (human) {
|
|
return 'Enter a key';
|
|
}
|
|
return '';
|
|
}
|
|
if (!separator || /CtrlAShifMea#/.test(separator)) {
|
|
separator = human ? ' + ' : '+';
|
|
}
|
|
if (key.c) {
|
|
str += (short ? 'C' : 'Ctrl') + separator;
|
|
}
|
|
if (key.a) {
|
|
str += (short ? 'A' : 'Alt') + separator;
|
|
}
|
|
if (key.s) {
|
|
str += (short ? 'S' : 'Shift') + separator;
|
|
}
|
|
if (key.m) {
|
|
str += (short ? 'M' : 'Meta') + separator;
|
|
}
|
|
|
|
var out;
|
|
if (human) {
|
|
out = key.char;
|
|
} else if (key.code) {
|
|
out = '#' + key.code || '';
|
|
}
|
|
|
|
return str + out;
|
|
}
|
|
|
|
/**
|
|
Parses the given string into a Key-Object.
|
|
@param str The string to parse.
|
|
@returns Key The Key-Object that got identified by the given string.
|
|
*/
|
|
function getKeyFromString(str) {
|
|
if (str instanceof Key) {
|
|
return str;
|
|
}
|
|
var key = new Key();
|
|
var sep = /([^CtrlAShifMea#\d]+)(?:#|\d)/.exec(str);
|
|
var parts = sep != null ? str.split(sep[1]) : [str];
|
|
for (var i = 0; i < parts.length; i += 1) {
|
|
var part = parts[i];
|
|
switch (part) {
|
|
case 'C':
|
|
case 'Ctrl':
|
|
key.c = true;
|
|
break;
|
|
case 'A':
|
|
case 'Alt':
|
|
key.a = true;
|
|
break;
|
|
case 'S':
|
|
case 'Shift':
|
|
key.s = true;
|
|
break;
|
|
case 'M':
|
|
case 'Meta':
|
|
key.m = true;
|
|
break;
|
|
default:
|
|
var num = /\d+/.exec(part);
|
|
if (num != null) {
|
|
key.code = num[0];
|
|
}
|
|
key.char = convertKeyCodeToChar(key.code);
|
|
}
|
|
}
|
|
return key;
|
|
}
|
|
|
|
function handleEvent(element, event) {
|
|
event = event || window.event;
|
|
event.which = event.which || event.keyCode || event.key;
|
|
var key = getKey(event);
|
|
if (key != null) {
|
|
SettingsKey.set(element, key);
|
|
}
|
|
}
|
|
|
|
|
|
SettingsKey = {
|
|
types: ['key'],
|
|
use: function () {
|
|
helper = this.helper;
|
|
},
|
|
init: function (element) {
|
|
element.focus(function () {
|
|
oldKey = element.data('keyData') || new Key();
|
|
lastKey = new Key();
|
|
}).keydown(function (event) {
|
|
event.preventDefault();
|
|
handleEvent(element, event);
|
|
}).keyup(function (event) {
|
|
handleEvent(element, event);
|
|
});
|
|
return element;
|
|
},
|
|
set: function (element, value) {
|
|
var key = getKeyFromString(value || '');
|
|
element.data('keyData', key);
|
|
if (key.code) {
|
|
element.removeClass('alert-danger');
|
|
} else {
|
|
element.addClass('alert-danger');
|
|
}
|
|
element.val(getKeyString(key, true, false, ' + '));
|
|
},
|
|
get: function (element, trim, empty) {
|
|
var key = element.data('keyData');
|
|
var separator = element.data('split') || element.data('separator') || '+';
|
|
var short = !helper.isFalse(element.data('short'));
|
|
if (trim) {
|
|
if (empty || (key != null && key.char)) {
|
|
return getKeyString(key, false, short, separator);
|
|
}
|
|
} else if (empty || (key != null && key.code)) {
|
|
return key;
|
|
}
|
|
},
|
|
};
|
|
|
|
return SettingsKey;
|
|
});
|