Code optimization, added onKeyReleased. Fixes #144, #145

This commit is contained in:
Francisco Hodge 2019-07-14 11:27:18 -04:00
parent b0a7748351
commit 8ba6f879d0
27 changed files with 1024 additions and 584 deletions

View File

@ -1,6 +1,6 @@
/*! /*!
* *
* simple-keyboard v2.23.3 * simple-keyboard v2.24.0
* https://github.com/hodgef/simple-keyboard * https://github.com/hodgef/simple-keyboard
* *
* Copyright (c) Francisco Hodge (https://github.com/hodgef) * Copyright (c) Francisco Hodge (https://github.com/hodgef)

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
/*! /*!
* *
* simple-keyboard v2.23.3 (Non-minified build) * simple-keyboard v2.24.0 (Non-minified build)
* https://github.com/hodgef/simple-keyboard * https://github.com/hodgef/simple-keyboard
* *
* Copyright (c) Francisco Hodge (https://github.com/hodgef) * Copyright (c) Francisco Hodge (https://github.com/hodgef)

5
build/index.d.ts vendored
View File

@ -162,6 +162,11 @@ declare module 'simple-keyboard' {
* Executes the callback function on input change. Returns the input object with all defined inputs. * Executes the callback function on input change. Returns the input object with all defined inputs.
*/ */
onChangeAll?: (inputs: any) => any; onChangeAll?: (inputs: any) => any;
/**
* Executes the callback function on key release.
*/
onKeyReleased?: () => void;
} }
class Keyboard { class Keyboard {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
/*! /*!
* *
* simple-keyboard v2.23.3 (Non-minified build) * simple-keyboard v2.24.0 (Non-minified build)
* https://github.com/hodgef/simple-keyboard * https://github.com/hodgef/simple-keyboard
* *
* Copyright (c) Francisco Hodge (https://github.com/hodgef) * Copyright (c) Francisco Hodge (https://github.com/hodgef)
@ -151,7 +151,19 @@
__webpack_require__.r(__webpack_exports__); __webpack_require__.r(__webpack_exports__);
// EXTERNAL MODULE: ./src/lib/components/Keyboard.css // EXTERNAL MODULE: ./src/lib/components/Keyboard.css
var Keyboard = __webpack_require__(1); var Keyboard = __webpack_require__(1);
// CONCATENATED MODULE: ./src/lib/services/PhysicalKeyboard.js // CONCATENATED MODULE: ./src/lib/services/Utilities.js
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) { function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) { if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function"); throw new TypeError("Cannot call a class as a function");
@ -178,173 +190,16 @@
return Constructor; return Constructor;
} }
/** /**
* Physical Keyboard Service
*/ var PhysicalKeyboard = /* */ function() {
/**
* Creates an instance of the PhysicalKeyboard service
*/ function PhysicalKeyboard(simpleKeyboardInstance) {
_classCallCheck(this, PhysicalKeyboard);
/**
* @type {object} A simple-keyboard instance
*/ this.simpleKeyboardInstance = simpleKeyboardInstance;
/**
* Bindings
*/ this.initKeyboardListener = this.initKeyboardListener.bind(this);
this.getSimpleKeyboardLayoutKey = this.getSimpleKeyboardLayoutKey.bind(this);
/**
* Initialize key listeners
*/ this.initKeyboardListener();
}
/**
* Initializes key event listeners
*/ _createClass(PhysicalKeyboard, [ {
key: "initKeyboardListener",
value: function initKeyboardListener() {
var _this = this;
// Adding button style on keydown
document.addEventListener("keydown", function(event) {
if (_this.simpleKeyboardInstance.options.physicalKeyboardHighlight) {
var buttonPressed = _this.getSimpleKeyboardLayoutKey(event);
_this.simpleKeyboardInstance.dispatch(function(instance) {
var buttonDOM = instance.getButtonElement(buttonPressed) || instance.getButtonElement("{".concat(buttonPressed, "}"));
if (buttonDOM) {
buttonDOM.style.backgroundColor = _this.simpleKeyboardInstance.options.physicalKeyboardHighlightBgColor || "#9ab4d0";
buttonDOM.style.color = _this.simpleKeyboardInstance.options.physicalKeyboardHighlightTextColor || "white";
}
});
}
});
// Removing button style on keyup
document.addEventListener("keyup", function(event) {
if (_this.simpleKeyboardInstance.options.physicalKeyboardHighlight) {
var buttonPressed = _this.getSimpleKeyboardLayoutKey(event);
_this.simpleKeyboardInstance.dispatch(function(instance) {
var buttonDOM = instance.getButtonElement(buttonPressed) || instance.getButtonElement("{".concat(buttonPressed, "}"));
if (buttonDOM && buttonDOM.removeAttribute) {
buttonDOM.removeAttribute("style");
}
});
}
});
}
/**
* Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format
* @param {object} event The KeyboardEvent
*/ }, {
key: "getSimpleKeyboardLayoutKey",
value: function getSimpleKeyboardLayoutKey(event) {
var output;
if (event.code.includes("Numpad") || event.code.includes("Shift") || event.code.includes("Space") || event.code.includes("Backspace") || event.code.includes("Control") || event.code.includes("Alt") || event.code.includes("Meta")) {
output = event.code;
} else {
output = event.key;
}
/**
* If button is not uppercase, casting to lowercase
*/ if (output !== output.toUpperCase() || event.code[0] === "F" && Number.isInteger(Number(event.code[1])) && event.code.length <= 3) {
output = output.toLowerCase();
}
return output;
}
} ]);
return PhysicalKeyboard;
}();
/* harmony default export */ var services_PhysicalKeyboard = PhysicalKeyboard;
// CONCATENATED MODULE: ./src/lib/services/KeyboardLayout.js
function KeyboardLayout_classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function KeyboardLayout_defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) {
descriptor.writable = true;
}
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function KeyboardLayout_createClass(Constructor, protoProps, staticProps) {
if (protoProps) {
KeyboardLayout_defineProperties(Constructor.prototype, protoProps);
}
if (staticProps) {
KeyboardLayout_defineProperties(Constructor, staticProps);
}
return Constructor;
}
/**
* Keyboard Layout Service
*/ var KeyboardLayout = /* */ function() {
function KeyboardLayout() {
KeyboardLayout_classCallCheck(this, KeyboardLayout);
}
KeyboardLayout_createClass(KeyboardLayout, null, [ {
key: "getDefaultLayout",
/**
* Get default simple-keyboard layout
* @return {object} The default layout (US-QWERTY)
*/ value: function getDefaultLayout() {
return {
default: [ "` 1 2 3 4 5 6 7 8 9 0 - = {bksp}", "{tab} q w e r t y u i o p [ ] \\", "{lock} a s d f g h j k l ; ' {enter}", "{shift} z x c v b n m , . / {shift}", ".com @ {space}" ],
shift: [ "~ ! @ # $ % ^ & * ( ) _ + {bksp}", "{tab} Q W E R T Y U I O P { } |", '{lock} A S D F G H J K L : " {enter}', "{shift} Z X C V B N M < > ? {shift}", ".com @ {space}" ]
};
}
} ]);
return KeyboardLayout;
}();
/* harmony default export */ var services_KeyboardLayout = KeyboardLayout;
// CONCATENATED MODULE: ./src/lib/services/Utilities.js
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function Utilities_classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function Utilities_defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) {
descriptor.writable = true;
}
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function Utilities_createClass(Constructor, protoProps, staticProps) {
if (protoProps) {
Utilities_defineProperties(Constructor.prototype, protoProps);
}
if (staticProps) {
Utilities_defineProperties(Constructor, staticProps);
}
return Constructor;
}
/**
* Utility Service * Utility Service
*/ var Utilities = /* */ function() { */ var Utilities = /* */ function() {
/** /**
* Creates an instance of the Utility service * Creates an instance of the Utility service
*/ function Utilities(simpleKeyboardInstance) { */ function Utilities(_ref) {
Utilities_classCallCheck(this, Utilities); var getOptions = _ref.getOptions, getCaretPosition = _ref.getCaretPosition, dispatch = _ref.dispatch;
/** _classCallCheck(this, Utilities);
* @type {object} A simple-keyboard instance this.getOptions = getOptions;
*/ this.simpleKeyboardInstance = simpleKeyboardInstance; this.getCaretPosition = getCaretPosition;
this.dispatch = dispatch;
/** /**
* Bindings * Bindings
*/ Utilities.bindMethods(Utilities, this); */ Utilities.bindMethods(Utilities, this);
@ -354,7 +209,7 @@
* *
* @param {string} button The button's layout name * @param {string} button The button's layout name
* @return {string} The classes to be added to the button * @return {string} The classes to be added to the button
*/ Utilities_createClass(Utilities, [ { */ _createClass(Utilities, [ {
key: "getButtonClass", key: "getButtonClass",
value: function getButtonClass(button) { value: function getButtonClass(button) {
var buttonTypeClass = button.includes("{") && button.includes("}") && button !== "{//}" ? "functionBtn" : "standardBtn"; var buttonTypeClass = button.includes("{") && button.includes("}") && button !== "{//}" ? "functionBtn" : "standardBtn";
@ -453,12 +308,12 @@
* *
* @param {string} button The button's layout name * @param {string} button The button's layout name
* @param {string} input The input string * @param {string} input The input string
* @param {object} options The simple-keyboard options object
* @param {number} caretPos The cursor's current position * @param {number} caretPos The cursor's current position
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor * @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/ }, { */ }, {
key: "getUpdatedInput", key: "getUpdatedInput",
value: function getUpdatedInput(button, input, options, caretPos, moveCaret) { value: function getUpdatedInput(button, input, caretPos, moveCaret) {
var options = this.getOptions();
var output = input; var output = input;
if ((button === "{bksp}" || button === "{backspace}") && output.length > 0) { if ((button === "{bksp}" || button === "{backspace}") && output.length > 0) {
output = this.removeAt(output, caretPos, moveCaret); output = this.removeAt(output, caretPos, moveCaret);
@ -495,33 +350,32 @@
*/ }, { */ }, {
key: "updateCaretPos", key: "updateCaretPos",
value: function updateCaretPos(length, minus) { value: function updateCaretPos(length, minus) {
var newCaretPos = this.updateCaretPosAction(this.simpleKeyboardInstance, length, minus); var newCaretPos = this.updateCaretPosAction(length, minus);
if (this.simpleKeyboardInstance.options.syncInstanceInputs) { this.dispatch(function(instance) {
this.simpleKeyboardInstance.dispatch(function(instance) {
instance.caretPosition = newCaretPos; instance.caretPosition = newCaretPos;
}); });
} }
}
/** /**
* Action method of updateCaretPos * Action method of updateCaretPos
* *
* @param {object} instance The instance whose position should be updated
* @param {number} length Represents by how many characters the input should be moved * @param {number} length Represents by how many characters the input should be moved
* @param {boolean} minus Whether the cursor should be moved to the left or not. * @param {boolean} minus Whether the cursor should be moved to the left or not.
*/ }, { */ }, {
key: "updateCaretPosAction", key: "updateCaretPosAction",
value: function updateCaretPosAction(instance, length, minus) { value: function updateCaretPosAction(length, minus) {
var options = this.getOptions();
var caretPosition = this.getCaretPosition();
if (minus) { if (minus) {
if (instance.caretPosition > 0) { if (caretPosition > 0) {
instance.caretPosition = instance.caretPosition - length; caretPosition = caretPosition - length;
} }
} else { } else {
instance.caretPosition = instance.caretPosition + length; caretPosition = caretPosition + length;
} }
if (this.simpleKeyboardInstance.options.debug) { if (options.debug) {
console.log("Caret at:", instance.caretPosition, "(".concat(instance.keyboardDOMClass, ")")); console.log("Caret at:", caretPosition, "(".concat(this.keyboardDOMClass, ")"));
} }
return instance.caretPosition; return caretPosition;
} }
/** /**
* Adds a string to the input at a given position * Adds a string to the input at a given position
@ -557,7 +411,8 @@
*/ }, { */ }, {
key: "removeAt", key: "removeAt",
value: function removeAt(source, position, moveCaret) { value: function removeAt(source, position, moveCaret) {
if (this.simpleKeyboardInstance.caretPosition === 0) { var caretPosition = this.getCaretPosition();
if (caretPosition === 0) {
return source; return source;
} }
var output; var output;
@ -602,11 +457,11 @@
* Determines whether the maxLength has been reached. This function is called when the maxLength option it set. * Determines whether the maxLength has been reached. This function is called when the maxLength option it set.
* *
* @param {object} inputObj * @param {object} inputObj
* @param {object} options
* @param {string} updatedInput * @param {string} updatedInput
*/ }, { */ }, {
key: "handleMaxLength", key: "handleMaxLength",
value: function handleMaxLength(inputObj, options, updatedInput) { value: function handleMaxLength(inputObj, updatedInput) {
var options = this.getOptions();
var maxLength = options.maxLength; var maxLength = options.maxLength;
var currentInput = inputObj[options.inputName]; var currentInput = inputObj[options.inputName];
var condition = currentInput.length === maxLength; var condition = currentInput.length === maxLength;
@ -675,6 +530,9 @@
* *
* @param {string} string The string to transform. * @param {string} string The string to transform.
*/ value: function camelCase(string) { */ value: function camelCase(string) {
if (!string) {
return false;
}
return string.toLowerCase().trim().split(/[.\-_\s]/g).reduce(function(string, word) { return string.toLowerCase().trim().split(/[.\-_\s]/g).reduce(function(string, word) {
return word.length ? string + word[0].toUpperCase() + word.slice(1) : string; return word.length ? string + word[0].toUpperCase() + word.slice(1) : string;
}); });
@ -724,6 +582,142 @@
return Utilities; return Utilities;
}(); }();
/* harmony default export */ var services_Utilities = Utilities; /* harmony default export */ var services_Utilities = Utilities;
// CONCATENATED MODULE: ./src/lib/services/PhysicalKeyboard.js
function PhysicalKeyboard_classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function PhysicalKeyboard_defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) {
descriptor.writable = true;
}
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function PhysicalKeyboard_createClass(Constructor, protoProps, staticProps) {
if (protoProps) {
PhysicalKeyboard_defineProperties(Constructor.prototype, protoProps);
}
if (staticProps) {
PhysicalKeyboard_defineProperties(Constructor, staticProps);
}
return Constructor;
}
/**
* Physical Keyboard Service
*/ var PhysicalKeyboard_PhysicalKeyboard = /* */ function() {
/**
* Creates an instance of the PhysicalKeyboard service
*/ function PhysicalKeyboard(_ref) {
var dispatch = _ref.dispatch, getOptions = _ref.getOptions;
PhysicalKeyboard_classCallCheck(this, PhysicalKeyboard);
/**
* @type {object} A simple-keyboard instance
*/ this.dispatch = dispatch;
this.getOptions = getOptions;
/**
* Bindings
*/ services_Utilities.bindMethods(PhysicalKeyboard, this);
}
PhysicalKeyboard_createClass(PhysicalKeyboard, [ {
key: "handleHighlightKeyDown",
value: function handleHighlightKeyDown(event) {
var options = this.getOptions();
var buttonPressed = this.getSimpleKeyboardLayoutKey(event);
this.dispatch(function(instance) {
var buttonDOM = instance.getButtonElement(buttonPressed) || instance.getButtonElement("{".concat(buttonPressed, "}"));
if (buttonDOM) {
buttonDOM.style.backgroundColor = options.physicalKeyboardHighlightBgColor || "#9ab4d0";
buttonDOM.style.color = options.physicalKeyboardHighlightTextColor || "white";
}
});
}
}, {
key: "handleHighlightKeyUp",
value: function handleHighlightKeyUp(event) {
var buttonPressed = this.getSimpleKeyboardLayoutKey(event);
this.dispatch(function(instance) {
var buttonDOM = instance.getButtonElement(buttonPressed) || instance.getButtonElement("{".concat(buttonPressed, "}"));
if (buttonDOM && buttonDOM.removeAttribute) {
buttonDOM.removeAttribute("style");
}
});
}
/**
* Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format
* @param {object} event The KeyboardEvent
*/ }, {
key: "getSimpleKeyboardLayoutKey",
value: function getSimpleKeyboardLayoutKey(event) {
var output;
if (event.code.includes("Numpad") || event.code.includes("Shift") || event.code.includes("Space") || event.code.includes("Backspace") || event.code.includes("Control") || event.code.includes("Alt") || event.code.includes("Meta")) {
output = event.code;
} else {
output = event.key;
}
/**
* If button is not uppercase, casting to lowercase
*/ if (output !== output.toUpperCase() || event.code[0] === "F" && Number.isInteger(Number(event.code[1])) && event.code.length <= 3) {
output = output.toLowerCase();
}
return output;
}
} ]);
return PhysicalKeyboard;
}();
/* harmony default export */ var services_PhysicalKeyboard = PhysicalKeyboard_PhysicalKeyboard;
// CONCATENATED MODULE: ./src/lib/services/KeyboardLayout.js
function KeyboardLayout_classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function KeyboardLayout_defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) {
descriptor.writable = true;
}
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function KeyboardLayout_createClass(Constructor, protoProps, staticProps) {
if (protoProps) {
KeyboardLayout_defineProperties(Constructor.prototype, protoProps);
}
if (staticProps) {
KeyboardLayout_defineProperties(Constructor, staticProps);
}
return Constructor;
}
/**
* Keyboard Layout Service
*/ var KeyboardLayout = /* */ function() {
function KeyboardLayout() {
KeyboardLayout_classCallCheck(this, KeyboardLayout);
}
KeyboardLayout_createClass(KeyboardLayout, null, [ {
key: "getDefaultLayout",
/**
* Get default simple-keyboard layout
* @return {object} The default layout (US-QWERTY)
*/ value: function getDefaultLayout() {
return {
default: [ "` 1 2 3 4 5 6 7 8 9 0 - = {bksp}", "{tab} q w e r t y u i o p [ ] \\", "{lock} a s d f g h j k l ; ' {enter}", "{shift} z x c v b n m , . / {shift}", ".com @ {space}" ],
shift: [ "~ ! @ # $ % ^ & * ( ) _ + {bksp}", "{tab} Q W E R T Y U I O P { } |", '{lock} A S D F G H J K L : " {enter}', "{shift} Z X C V B N M < > ? {shift}", ".com @ {space}" ]
};
}
} ]);
return KeyboardLayout;
}();
/* harmony default export */ var services_KeyboardLayout = KeyboardLayout;
// CONCATENATED MODULE: ./src/lib/components/Keyboard.js // CONCATENATED MODULE: ./src/lib/components/Keyboard.js
function Keyboard_typeof(obj) { function Keyboard_typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
@ -776,6 +770,12 @@
*/ function SimpleKeyboard() { */ function SimpleKeyboard() {
var _this = this; var _this = this;
Keyboard_classCallCheck(this, SimpleKeyboard); Keyboard_classCallCheck(this, SimpleKeyboard);
this.getOptions = function() {
return _this.options;
};
this.getCaretPosition = function() {
return _this.caretPosition;
};
this.registerModule = function(name, initCallback) { this.registerModule = function(name, initCallback) {
if (!_this.modules[name]) { if (!_this.modules[name]) {
_this.modules[name] = {}; _this.modules[name] = {};
@ -789,7 +789,14 @@
/** /**
* Initializing Utilities * Initializing Utilities
*/ } */ }
this.utilities = new services_Utilities(this); this.utilities = new services_Utilities({
getOptions: this.getOptions,
getCaretPosition: this.getCaretPosition,
dispatch: this.dispatch
});
/**
* Caret position
*/ this.caretPosition = null;
/** /**
* Processing options * Processing options
*/ this.keyboardDOM = document.querySelector(keyboardDOMQuery); */ this.keyboardDOM = document.querySelector(keyboardDOMQuery);
@ -825,6 +832,7 @@
* @property {boolean} useMouseEvents Opt out of PointerEvents handling, falling back to the prior mouse event logic. * @property {boolean} useMouseEvents Opt out of PointerEvents handling, falling back to the prior mouse event logic.
* @property {function} destroy Clears keyboard listeners and DOM elements. * @property {function} destroy Clears keyboard listeners and DOM elements.
* @property {boolean} disableButtonHold Disable button hold action. * @property {boolean} disableButtonHold Disable button hold action.
* @property {function} onKeyReleased Executes the callback function on key release.
*/ this.options = options; */ this.options = options;
this.options.layoutName = this.options.layoutName || "default"; this.options.layoutName = this.options.layoutName || "default";
this.options.theme = this.options.theme || "hg-theme-default"; this.options.theme = this.options.theme || "hg-theme-default";
@ -858,6 +866,25 @@
* @type {object} Contains the DOM elements of every rendered button, the key being the button's layout name (e.g.: "{enter}"). * @type {object} Contains the DOM elements of every rendered button, the key being the button's layout name (e.g.: "{enter}").
*/ this.buttonElements = {}; */ this.buttonElements = {};
/** /**
* Simple-keyboard Instances
* This enables multiple simple-keyboard support with easier management
*/ if (!window["SimpleKeyboardInstances"]) {
window["SimpleKeyboardInstances"] = {};
}
window["SimpleKeyboardInstances"][this.utilities.camelCase(this.keyboardDOMClass)] = this;
/**
* Instance vars
*/ this.allKeyboardInstances = window["SimpleKeyboardInstances"];
this.currentInstanceName = this.utilities.camelCase(this.keyboardDOMClass);
this.keyboardInstanceNames = Object.keys(window["SimpleKeyboardInstances"]);
this.isFirstKeyboardInstance = this.keyboardInstanceNames[0] === this.currentInstanceName;
/**
* Physical Keyboard support
*/ this.physicalKeyboard = new services_PhysicalKeyboard({
dispatch: this.dispatch,
getOptions: this.getOptions
});
/**
* Rendering keyboard * Rendering keyboard
*/ if (this.keyboardDOM) { */ if (this.keyboardDOM) {
this.render(); this.render();
@ -866,26 +893,18 @@
throw new Error("KEYBOARD_DOM_ERROR"); throw new Error("KEYBOARD_DOM_ERROR");
} }
/** /**
* Saving instance
* This enables multiple simple-keyboard support with easier management
*/ if (!window["SimpleKeyboardInstances"]) {
window["SimpleKeyboardInstances"] = {};
}
window["SimpleKeyboardInstances"][this.utilities.camelCase(this.keyboardDOMClass)] = this;
/**
* Physical Keyboard support
*/ this.physicalKeyboardInterface = new services_PhysicalKeyboard(this);
/**
* Modules * Modules
*/ this.modules = {}; */ this.modules = {};
this.loadModules(); this.loadModules();
} }
/** /**
* Handles clicks made to keyboard buttons * Getters
* @param {string} button The button's layout name.
*/ Keyboard_createClass(SimpleKeyboard, [ { */ Keyboard_createClass(SimpleKeyboard, [ {
key: "handleButtonClicked", key: "handleButtonClicked",
value: function handleButtonClicked(button) { /**
* Handles clicks made to keyboard buttons
* @param {string} button The button's layout name.
*/ value: function handleButtonClicked(button) {
var debug = this.options.debug; var debug = this.options.debug;
/** /**
* Ignoring placeholder buttons * Ignoring placeholder buttons
@ -900,7 +919,7 @@
if (!this.input[this.options.inputName]) { if (!this.input[this.options.inputName]) {
this.input[this.options.inputName] = ""; this.input[this.options.inputName] = "";
} }
var updatedInput = this.utilities.getUpdatedInput(button, this.input[this.options.inputName], this.options, this.caretPosition); var updatedInput = this.utilities.getUpdatedInput(button, this.input[this.options.inputName], this.caretPosition);
if (// If input will change as a result of this button press if (// If input will change as a result of this button press
this.input[this.options.inputName] !== updatedInput && (// This pertains to the "inputPattern" option: this.input[this.options.inputName] !== updatedInput && (// This pertains to the "inputPattern" option:
// If inputPattern isn't set // If inputPattern isn't set
@ -908,10 +927,10 @@
this.options.inputPattern && this.inputPatternIsValid(updatedInput))) { this.options.inputPattern && this.inputPatternIsValid(updatedInput))) {
/** /**
* If maxLength and handleMaxLength yield true, halting * If maxLength and handleMaxLength yield true, halting
*/ if (this.options.maxLength && this.utilities.handleMaxLength(this.input, this.options, updatedInput)) { */ if (this.options.maxLength && this.utilities.handleMaxLength(this.input, updatedInput)) {
return false; return false;
} }
this.input[this.options.inputName] = this.utilities.getUpdatedInput(button, this.input[this.options.inputName], this.options, this.caretPosition, true); this.input[this.options.inputName] = this.utilities.getUpdatedInput(button, this.input[this.options.inputName], this.caretPosition, true);
if (debug) { if (debug) {
console.log("Input changed:", this.input); console.log("Input changed:", this.input);
/** /**
@ -980,6 +999,11 @@
this.isMouseHold = false; this.isMouseHold = false;
if (this.holdInteractionTimeout) { if (this.holdInteractionTimeout) {
clearTimeout(this.holdInteractionTimeout); clearTimeout(this.holdInteractionTimeout);
/**
* Calling onKeyReleased
*/ }
if (typeof this.options.onKeyReleased === "function") {
this.options.onKeyReleased();
} }
} }
/** /**
@ -1252,25 +1276,59 @@
} }
} }
/** /**
* Retrieves the current cursor position within a input or textarea (if any) * Handles simple-keyboard event listeners
*/ }, { */ }, {
key: "handleCaret", key: "setEventListeners",
value: function handleCaret() { value: function setEventListeners() {
/** /**
* Only first instance should insall the caret handling events * Only first instance should set the event listeners
*/ this.caretPosition = null; */ if (this.isFirstKeyboardInstance || !this.allKeyboardInstances) {
var simpleKeyboardInstances = window["SimpleKeyboardInstances"];
if (simpleKeyboardInstances && Object.keys(simpleKeyboardInstances)[0] === this.utilities.camelCase(this.keyboardDOMClass) || !simpleKeyboardInstances) {
if (this.options.debug) { if (this.options.debug) {
console.log("Caret handling started (".concat(this.keyboardDOMClass, ")")); console.log("Caret handling started (".concat(this.keyboardDOMClass, ")"));
} }
document.addEventListener("keyup", this.caretEventHandler); /**
document.addEventListener("mouseup", this.caretEventHandler); * Event Listeners
document.addEventListener("touchend", this.caretEventHandler); */ document.addEventListener("keyup", this.handleKeyUp);
document.addEventListener("keydown", this.handleKeyDown);
document.addEventListener("mouseup", this.handleMouseUp);
document.addEventListener("touchend", this.handleTouchEnd);
} }
} }
/** /**
* Called by {@link handleCaret} when an event that warrants a cursor position update is triggered * Event Handler: KeyUp
*/ }, {
key: "handleKeyUp",
value: function handleKeyUp(event) {
this.caretEventHandler(event);
if (this.options.physicalKeyboardHighlight) {
this.physicalKeyboard.handleHighlightKeyUp(event);
}
}
/**
* Event Handler: KeyDown
*/ }, {
key: "handleKeyDown",
value: function handleKeyDown(event) {
if (this.options.physicalKeyboardHighlight) {
this.physicalKeyboard.handleHighlightKeyDown(event);
}
}
/**
* Event Handler: MouseUp
*/ }, {
key: "handleMouseUp",
value: function handleMouseUp(event) {
this.caretEventHandler(event);
}
/**
* Event Handler: TouchEnd
*/ }, {
key: "handleTouchEnd",
value: function handleTouchEnd(event) {
this.caretEventHandler(event);
}
/**
* Called by {@link caretEventHandler} when an event that warrants a cursor position update is triggered
*/ }, { */ }, {
key: "caretEventHandler", key: "caretEventHandler",
value: function caretEventHandler(event) { value: function caretEventHandler(event) {
@ -1304,9 +1362,10 @@
value: function destroy() { value: function destroy() {
/** /**
* Remove listeners * Remove listeners
*/ document.removeEventListener("keyup", this.caretEventHandler); */ document.removeEventListener("keyup", this.handleKeyUp);
document.removeEventListener("mouseup", this.caretEventHandler); document.removeEventListener("keydown", this.handleKeyDown);
document.removeEventListener("touchend", this.caretEventHandler); document.removeEventListener("mouseup", this.handleMouseUp);
document.removeEventListener("touchend", this.handleTouchEnd);
/** /**
* Clear DOM * Clear DOM
*/ this.clear(); */ this.clear();
@ -1388,8 +1447,8 @@
console.log("".concat(this.keyboardDOMClass, " Initialized")); console.log("".concat(this.keyboardDOMClass, " Initialized"));
} }
/** /**
* Caret handling * setEventListeners
*/ this.handleCaret(); */ this.setEventListeners();
if (typeof this.options.onInit === "function") { if (typeof this.options.onInit === "function") {
this.options.onInit(); this.options.onInit();
} }
@ -1409,7 +1468,7 @@
/** /**
* Notify about PointerEvents usage * Notify about PointerEvents usage
*/ } */ }
if (this.utilities.pointerEventsSupported() && !this.options.useTouchEvents && !this.options.useMouseEvents) { if (this.isFirstKeyboardInstance && this.utilities.pointerEventsSupported() && !this.options.useTouchEvents && !this.options.useMouseEvents) {
if (this.options.debug) { if (this.options.debug) {
console.log("Using PointerEvents as it is supported by this browser"); console.log("Using PointerEvents as it is supported by this browser");
} }

109
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "simple-keyboard", "name": "simple-keyboard",
"version": "2.23.3", "version": "2.24.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -2244,7 +2244,7 @@
}, },
"util": { "util": {
"version": "0.10.3", "version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz",
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -2414,7 +2414,7 @@
}, },
"chalk": { "chalk": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4298,7 +4298,7 @@
"dependencies": { "dependencies": {
"globby": { "globby": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4311,7 +4311,7 @@
"dependencies": { "dependencies": {
"pify": { "pify": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true "dev": true
} }
@ -4974,7 +4974,7 @@
}, },
"load-json-file": { "load-json-file": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -5875,8 +5875,7 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -5897,14 +5896,12 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -5919,20 +5916,17 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -6049,8 +6043,7 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -6062,7 +6055,6 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -6077,7 +6069,6 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -6085,14 +6076,12 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -6111,7 +6100,6 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -6192,8 +6180,7 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -6205,7 +6192,6 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -6291,8 +6277,7 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -6328,7 +6313,6 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -6348,7 +6332,6 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -6392,14 +6375,12 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
} }
} }
}, },
@ -8785,9 +8766,9 @@
} }
}, },
"mixin-deep": { "mixin-deep": {
"version": "1.3.1", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true, "dev": true,
"requires": { "requires": {
"for-in": "^1.0.2", "for-in": "^1.0.2",
@ -11254,7 +11235,7 @@
}, },
"readable-stream": { "readable-stream": {
"version": "2.3.6", "version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -11429,7 +11410,7 @@
}, },
"css-select": { "css-select": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -11974,9 +11955,9 @@
"dev": true "dev": true
}, },
"set-value": { "set-value": {
"version": "2.0.0", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true, "dev": true,
"requires": { "requires": {
"extend-shallow": "^2.0.1", "extend-shallow": "^2.0.1",
@ -12038,7 +12019,7 @@
}, },
"kind-of": { "kind-of": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz",
"integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -13035,6 +13016,7 @@
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
"integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"commander": "~2.19.0", "commander": "~2.19.0",
"source-map": "~0.6.1" "source-map": "~0.6.1"
@ -13044,13 +13026,15 @@
"version": "2.19.0", "version": "2.19.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
"integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
"dev": true "dev": true,
"optional": true
}, },
"source-map": { "source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true "dev": true,
"optional": true
} }
} }
}, },
@ -13154,38 +13138,15 @@
} }
}, },
"union-value": { "union-value": {
"version": "1.0.0", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true, "dev": true,
"requires": { "requires": {
"arr-union": "^3.1.0", "arr-union": "^3.1.0",
"get-value": "^2.0.6", "get-value": "^2.0.6",
"is-extendable": "^0.1.1", "is-extendable": "^0.1.1",
"set-value": "^0.4.3" "set-value": "^2.0.1"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
} }
}, },
"uniq": { "uniq": {

View File

@ -1,6 +1,6 @@
{ {
"name": "simple-keyboard", "name": "simple-keyboard",
"version": "2.23.3", "version": "2.24.0",
"description": "On-screen Javascript Virtual Keyboard", "description": "On-screen Javascript Virtual Keyboard",
"main": "build/index.js", "main": "build/index.js",
"types": "build/index.d.ts", "types": "build/index.d.ts",
@ -126,7 +126,7 @@
"jest": { "jest": {
"collectCoverageFrom": [ "collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}", "src/**/*.{js,jsx,ts,tsx}",
"!src/lib/index.js", "!src/**/index.js",
"!src/utils/**", "!src/utils/**",
"!src/**/*.d.ts", "!src/**/*.d.ts",
"!**/tests/**" "!**/tests/**"

View File

@ -23,8 +23,6 @@
<noscript> <noscript>
You need to enable JavaScript to run this app. You need to enable JavaScript to run this app.
</noscript> </noscript>
<div id="root"> <div id="root"></div>
<div class="simple-keyboard"></div>
</div>
</body> </body>
</html> </html>

View File

@ -1,87 +0,0 @@
import Keyboard from "../lib";
import "./css/App.css";
/**
* simple-keyboard demo
*/
class App {
/**
* Instantiates the demo class
*/
constructor() {
document.addEventListener("DOMContentLoaded", this.onDOMLoaded);
/**
* Default input name
* @type {string}
*/
this.layoutName = "default";
}
/**
* Executed when the DOM is ready
*/
onDOMLoaded = () => {
/**
* Creates a new simple-keyboard instance
*/
this.keyboard = new Keyboard({
debug: true,
layoutName: this.layoutName,
onChange: input => this.onChange(input),
onKeyPress: button => this.onKeyPress(button),
newLineOnEnter: true,
physicalKeyboardHighlight: true
});
/**
* Adding preview (demo only)
*/
document.querySelector(".simple-keyboard").insertAdjacentHTML(
"beforebegin",
`
<div class="simple-keyboard-preview">
<textarea class="input"></textarea>
</div>
`
);
document.querySelector(".input").addEventListener("input", event => {
this.keyboard.setInput(event.target.value);
});
};
/**
* Handles shift functionality
*/
handleShiftButton = () => {
let layoutName = this.layoutName;
let shiftToggle = (this.layoutName =
layoutName === "default" ? "shift" : "default");
this.keyboard.setOptions({
layoutName: shiftToggle
});
};
/**
* Called when simple-keyboard input has changed
*/
onChange = input => {
document.querySelector(".input").value = input;
};
/**
* Called when a simple-keyboard key is pressed
*/
onKeyPress = button => {
console.log("Button pressed", button);
/**
* Shift functionality
*/
if (button === "{lock}" || button === "{shift}") this.handleShiftButton();
};
}
export default App;

55
src/demo/BasicDemo.js Normal file
View File

@ -0,0 +1,55 @@
import Keyboard from "../lib";
import "./css/BasicDemo.css";
const setDOM = () => {
document.querySelector("#root").innerHTML = `
<input class="input" placeholder="Tap on the virtual keyboard to start" />
<div class="simple-keyboard"></div>
`;
};
class Demo {
constructor() {
setDOM();
/**
* Demo Start
*/
this.keyboard = new Keyboard({
onChange: input => this.onChange(input),
onKeyPress: button => this.onKeyPress(button)
});
/**
* Update simple-keyboard when input is changed directly
*/
document.querySelector(".input").addEventListener("input", event => {
this.keyboard.setInput(event.target.value);
});
}
onChange(input) {
document.querySelector(".input").value = input;
console.log("Input changed", input);
}
onKeyPress(button) {
console.log("Button pressed", button);
/**
* If you want to handle the shift and caps lock buttons
*/
if (button === "{shift}" || button === "{lock}") this.handleShift();
}
handleShift() {
let currentLayout = this.keyboard.options.layoutName;
let shiftToggle = currentLayout === "default" ? "shift" : "default";
this.keyboard.setOptions({
layoutName: shiftToggle
});
}
}
export default Demo;

View File

@ -0,0 +1,157 @@
import Keyboard from "../lib";
import "./css/FullKeyboardDemo.css";
const setDOM = () => {
document.querySelector("#root").innerHTML = `
<input class="input" placeholder="Tap on the virtual keyboard to start" />
<div class="keyboardContainer">
<div class="simple-keyboard-main"></div>
<div class="controlArrows">
<div class="simple-keyboard-control"></div>
<div class="simple-keyboard-arrows"></div>
</div>
<div class="numPad">
<div class="simple-keyboard-numpad"></div>
<div class="simple-keyboard-numpadEnd"></div>
</div>
</div>
`;
};
class Demo {
constructor() {
setDOM();
/**
* Demo Start
*/
let commonKeyboardOptions = {
onChange: input => this.onChange(input),
onKeyPress: button => this.onKeyPress(button),
theme: "simple-keyboard hg-theme-default hg-layout-default",
physicalKeyboardHighlight: true,
syncInstanceInputs: true,
mergeDisplay: true,
debug: true
};
this.keyboard = new Keyboard(".simple-keyboard-main", {
...commonKeyboardOptions,
/**
* Layout by:
* Sterling Butters (https://github.com/SterlingButters)
*/
layout: {
default: [
"{escape} {f1} {f2} {f3} {f4} {f5} {f6} {f7} {f8} {f9} {f10} {f11} {f12}",
"` 1 2 3 4 5 6 7 8 9 0 - = {backspace}",
"{tab} q w e r t y u i o p [ ] \\",
"{capslock} a s d f g h j k l ; ' {enter}",
"{shiftleft} z x c v b n m , . / {shiftright}",
"{controlleft} {altleft} {metaleft} {space} {metaright} {altright}"
],
shift: [
"{escape} {f1} {f2} {f3} {f4} {f5} {f6} {f7} {f8} {f9} {f10} {f11} {f12}",
"~ ! @ # $ % ^ & * ( ) _ + {backspace}",
"{tab} Q W E R T Y U I O P { } |",
'{capslock} A S D F G H J K L : " {enter}',
"{shiftleft} Z X C V B N M < > ? {shiftright}",
"{controlleft} {altleft} {metaleft} {space} {metaright} {altright}"
]
},
display: {
"{escape}": "esc ⎋",
"{tab}": "tab ⇥",
"{backspace}": "backspace ⌫",
"{enter}": "enter ↵",
"{capslock}": "caps lock ⇪",
"{shiftleft}": "shift ⇧",
"{shiftright}": "shift ⇧",
"{controlleft}": "ctrl ⌃",
"{controlright}": "ctrl ⌃",
"{altleft}": "alt ⌥",
"{altright}": "alt ⌥",
"{metaleft}": "cmd ⌘",
"{metaright}": "cmd ⌘"
}
});
this.keyboardControlPad = new Keyboard(".simple-keyboard-control", {
...commonKeyboardOptions,
layout: {
default: [
"{prtscr} {scrolllock} {pause}",
"{insert} {home} {pageup}",
"{delete} {end} {pagedown}"
]
}
});
this.keyboardArrows = new Keyboard(".simple-keyboard-arrows", {
...commonKeyboardOptions,
layout: {
default: ["{arrowup}", "{arrowleft} {arrowdown} {arrowright}"]
}
});
this.keyboardNumPad = new Keyboard(".simple-keyboard-numpad", {
...commonKeyboardOptions,
layout: {
default: [
"{numlock} {numpaddivide} {numpadmultiply}",
"{numpad7} {numpad8} {numpad9}",
"{numpad4} {numpad5} {numpad6}",
"{numpad1} {numpad2} {numpad3}",
"{numpad0} {numpaddecimal}"
]
}
});
this.keyboardNumPadEnd = new Keyboard(".simple-keyboard-numpadEnd", {
...commonKeyboardOptions,
layout: {
default: ["{numpadsubtract}", "{numpadadd}", "{numpadenter}"]
}
});
document.querySelector(".input").addEventListener("input", event => {
let input = document.querySelector(".input").value;
this.keyboard.setInput(input);
});
}
onChange(input) {
document.querySelector(".input").value = input;
this.keyboard.setInput(input);
console.log("Input changed", input);
}
onKeyPress(button) {
console.log("Button pressed", button);
/**
* If you want to handle the shift and caps lock buttons
*/
if (
button === "{shift}" ||
button === "{shiftleft}" ||
button === "{shiftright}" ||
button === "{capslock}"
)
this.handleShift();
}
handleShift() {
let currentLayout = this.keyboard.options.layoutName;
let shiftToggle = currentLayout === "default" ? "shift" : "default";
this.keyboard.setOptions({
layoutName: shiftToggle
});
}
}
export default Demo;

View File

@ -1,33 +0,0 @@
#root {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue",
Helvetica, Arial, "Lucida Grande", sans-serif;
max-width: 850px;
margin: 0 auto;
padding-top: 20px;
}
#root .simple-keyboard-preview {
background: rgba(0, 0, 0, 0.8);
border: 20px solid rgba(0, 0, 0, 0.1);
height: 200px;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
padding: 10px;
box-sizing: border-box;
}
#root .input {
color: rgba(255, 255, 255, 0.9);
background: transparent;
border: none;
outline: none;
font-family: monospace;
width: 100%;
height: 100%;
font-size: 18px;
}
.simple-keyboard.hg-layout-custom {
border-top-left-radius: 0px;
border-top-right-radius: 0px;
}

View File

@ -0,0 +1,12 @@
input {
width: 100%;
height: 100px;
padding: 20px;
font-size: 20px;
border: none;
box-sizing: border-box;
}
.simple-keyboard {
max-width: 850px;
}

View File

@ -0,0 +1,132 @@
input {
width: 100%;
height: 100px;
padding: 20px;
font-size: 20px;
border: none;
box-sizing: border-box;
}
.keyboardContainer {
display: flex;
background-color: rgba(0, 0, 0, 0.1);
justify-content: center;
width: 1024px;
border-radius: 5px;
}
.simple-keyboard.hg-theme-default {
display: inline-block;
}
.simple-keyboard-main.simple-keyboard {
width: 640px;
min-width: 640px;
background: none;
}
.simple-keyboard-main.simple-keyboard .hg-row:first-child {
margin-bottom: 10px;
}
.simple-keyboard-arrows.simple-keyboard {
align-self: flex-end;
background: none;
}
.simple-keyboard .hg-button.selectedButton {
background: rgba(5, 25, 70, 0.53);
color: white;
}
.simple-keyboard .hg-button.emptySpace {
pointer-events: none;
background: none;
border: none;
box-shadow: none;
}
.simple-keyboard-arrows .hg-row {
justify-content: center;
}
.simple-keyboard-arrows .hg-button {
width: 50px;
flex-grow: 0;
justify-content: center;
display: flex;
align-items: center;
}
.controlArrows {
display: flex;
align-items: center;
justify-content: space-between;
flex-flow: column;
}
.simple-keyboard-control.simple-keyboard {
background: none;
}
.simple-keyboard-control.simple-keyboard .hg-row:first-child {
margin-bottom: 10px;
}
.simple-keyboard-control .hg-button {
width: 50px;
flex-grow: 0;
justify-content: center;
display: flex;
align-items: center;
}
.numPad {
display: flex;
align-items: flex-end;
}
.simple-keyboard-numpad.simple-keyboard {
background: none;
}
.simple-keyboard-numpad.simple-keyboard {
width: 160px;
}
.simple-keyboard-numpad.simple-keyboard .hg-button {
width: 50px;
justify-content: center;
display: flex;
align-items: center;
}
.simple-keyboard-numpadEnd.simple-keyboard {
width: 50px;
background: none;
margin: 0;
padding: 5px 5px 5px 0;
}
.simple-keyboard-numpadEnd.simple-keyboard .hg-button {
align-items: center;
justify-content: center;
display: flex;
}
.simple-keyboard-numpadEnd .hg-button.hg-standardBtn.hg-button-plus {
height: 85px;
}
.simple-keyboard-numpadEnd.simple-keyboard .hg-button.hg-button-enter {
height: 85px;
}
.simple-keyboard.hg-theme-default .hg-button.hg-selectedButton {
background: rgba(5, 25, 70, 0.53);
color: white;
}
.hg-button.hg-functionBtn.hg-button-space {
width: 350px;
}

3
src/demo/css/index.css Normal file
View File

@ -0,0 +1,3 @@
#root {
padding: 0px 40px;
}

View File

@ -1,6 +1,17 @@
import App from "./App"; import "./css/index.css";
/** /**
* Initializing demo * Demos
*/ */
new App(); import BasicDemo from "./BasicDemo";
//import FullKeyboardDemo from "./FullKeyboardDemo";
/**
* Selected demo
*/
const SELECTED_DEMO = BasicDemo;
/**
* Bootstrap
*/
new SELECTED_DEMO();

View File

@ -1,20 +1,18 @@
import TestUtility from '../../utils/TestUtility'; import TestUtility from '../../utils/TestUtility';
import Index from '../index'; import BasicDemo from '../BasicDemo';
import App from '../App';
let testUtil = new TestUtility(); let testUtil = new TestUtility();
it('Demo will load', () => { it('Demo will load', () => {
testUtil.setDOM(); testUtil.setDOM();
let demo = new App(); let demo = new BasicDemo();
}); });
it('Demo onDOMLoaded will work', () => { it('Demo onDOMLoaded will work', () => {
testUtil.setDOM(); testUtil.setDOM();
let demo = new App(); let demo = new BasicDemo();
demo.onDOMLoaded();
expect(demo.keyboard).toBeTruthy(); expect(demo.keyboard).toBeTruthy();
}); });
@ -22,8 +20,7 @@ it('Demo onDOMLoaded will work', () => {
it('Demo onChange will work', () => { it('Demo onChange will work', () => {
testUtil.setDOM(); testUtil.setDOM();
let demo = new App(); let demo = new BasicDemo();
demo.onDOMLoaded();
demo.onChange("test"); demo.onChange("test");
@ -33,8 +30,7 @@ it('Demo onChange will work', () => {
it('Demo onChange will work', () => { it('Demo onChange will work', () => {
testUtil.setDOM(); testUtil.setDOM();
let demo = new App(); let demo = new BasicDemo();
demo.onDOMLoaded();
demo.keyboard.getButtonElement("q").onclick(); demo.keyboard.getButtonElement("q").onclick();
@ -44,8 +40,7 @@ it('Demo onChange will work', () => {
it('Demo input change will work', () => { it('Demo input change will work', () => {
testUtil.setDOM(); testUtil.setDOM();
let demo = new App(); let demo = new BasicDemo();
demo.onDOMLoaded();
document.body.querySelector('.input').value = "test"; document.body.querySelector('.input').value = "test";
document.body.querySelector('.input').dispatchEvent(new Event('input')); document.body.querySelector('.input').dispatchEvent(new Event('input'));
@ -56,8 +51,7 @@ it('Demo input change will work', () => {
it('Demo handleShiftButton will work', () => { it('Demo handleShiftButton will work', () => {
testUtil.setDOM(); testUtil.setDOM();
let demo = new App(); let demo = new BasicDemo();
demo.onDOMLoaded();
demo.keyboard.getButtonElement("{shift}")[0].onclick(); demo.keyboard.getButtonElement("{shift}")[0].onclick();
expect(demo.keyboard.options.layoutName).toBe("shift"); expect(demo.keyboard.options.layoutName).toBe("shift");

View File

@ -0,0 +1,62 @@
import TestUtility from '../../utils/TestUtility';
import FullKeyboardDemo from '../FullKeyboardDemo';
let testUtil = new TestUtility();
it('Demo will load', () => {
testUtil.setDOM();
let demo = new FullKeyboardDemo();
});
it('Demo onDOMLoaded will work', () => {
testUtil.setDOM();
let demo = new FullKeyboardDemo();
expect(demo.keyboard).toBeTruthy();
});
it('Demo onChange will work', () => {
testUtil.setDOM();
let demo = new FullKeyboardDemo();
demo.onChange("test");
expect(document.body.querySelector('.input').value).toBe("test");
});
it('Demo onChange will work', () => {
testUtil.setDOM();
let demo = new FullKeyboardDemo();
demo.keyboard.getButtonElement("q").onclick();
expect(document.body.querySelector('.input').value).toBe("q");
});
it('Demo input change will work', () => {
testUtil.setDOM();
let demo = new FullKeyboardDemo();
document.body.querySelector('.input').value = "test";
document.body.querySelector('.input').dispatchEvent(new Event('input'));
expect(demo.keyboard.getInput()).toBe("test");
expect(demo.keyboardNumPad.getInput()).toBe("test");
});
it('Demo handleShiftButton will work', () => {
testUtil.setDOM();
let demo = new FullKeyboardDemo();
demo.keyboard.getButtonElement("{shiftleft}").onclick();
expect(demo.keyboard.options.layoutName).toBe("shift");
demo.keyboard.getButtonElement("{shiftright}").onclick();
expect(demo.keyboard.options.layoutName).toBe("default");
});

View File

@ -162,6 +162,11 @@ declare module 'simple-keyboard' {
* Executes the callback function on input change. Returns the input object with all defined inputs. * Executes the callback function on input change. Returns the input object with all defined inputs.
*/ */
onChangeAll?: (inputs: any) => any; onChangeAll?: (inputs: any) => any;
/**
* Executes the callback function on key release.
*/
onKeyReleased?: () => void;
} }
class Keyboard { class Keyboard {

View File

@ -27,7 +27,16 @@ class SimpleKeyboard {
/** /**
* Initializing Utilities * Initializing Utilities
*/ */
this.utilities = new Utilities(this); this.utilities = new Utilities({
getOptions: this.getOptions,
getCaretPosition: this.getCaretPosition,
dispatch: this.dispatch
});
/**
* Caret position
*/
this.caretPosition = null;
/** /**
* Processing options * Processing options
@ -66,6 +75,7 @@ class SimpleKeyboard {
* @property {boolean} useMouseEvents Opt out of PointerEvents handling, falling back to the prior mouse event logic. * @property {boolean} useMouseEvents Opt out of PointerEvents handling, falling back to the prior mouse event logic.
* @property {function} destroy Clears keyboard listeners and DOM elements. * @property {function} destroy Clears keyboard listeners and DOM elements.
* @property {boolean} disableButtonHold Disable button hold action. * @property {boolean} disableButtonHold Disable button hold action.
* @property {function} onKeyReleased Executes the callback function on key release.
*/ */
this.options = options; this.options = options;
this.options.layoutName = this.options.layoutName || "default"; this.options.layoutName = this.options.layoutName || "default";
@ -112,16 +122,7 @@ class SimpleKeyboard {
this.buttonElements = {}; this.buttonElements = {};
/** /**
* Rendering keyboard * Simple-keyboard Instances
*/
if (this.keyboardDOM) this.render();
else {
console.warn(`"${keyboardDOMQuery}" was not found in the DOM.`);
throw new Error("KEYBOARD_DOM_ERROR");
}
/**
* Saving instance
* This enables multiple simple-keyboard support with easier management * This enables multiple simple-keyboard support with easier management
*/ */
if (!window["SimpleKeyboardInstances"]) if (!window["SimpleKeyboardInstances"])
@ -131,10 +132,31 @@ class SimpleKeyboard {
this.utilities.camelCase(this.keyboardDOMClass) this.utilities.camelCase(this.keyboardDOMClass)
] = this; ] = this;
/**
* Instance vars
*/
this.allKeyboardInstances = window["SimpleKeyboardInstances"];
this.currentInstanceName = this.utilities.camelCase(this.keyboardDOMClass);
this.keyboardInstanceNames = Object.keys(window["SimpleKeyboardInstances"]);
this.isFirstKeyboardInstance =
this.keyboardInstanceNames[0] === this.currentInstanceName;
/** /**
* Physical Keyboard support * Physical Keyboard support
*/ */
this.physicalKeyboardInterface = new PhysicalKeyboard(this); this.physicalKeyboard = new PhysicalKeyboard({
dispatch: this.dispatch,
getOptions: this.getOptions
});
/**
* Rendering keyboard
*/
if (this.keyboardDOM) this.render();
else {
console.warn(`"${keyboardDOMQuery}" was not found in the DOM.`);
throw new Error("KEYBOARD_DOM_ERROR");
}
/** /**
* Modules * Modules
@ -143,6 +165,12 @@ class SimpleKeyboard {
this.loadModules(); this.loadModules();
} }
/**
* Getters
*/
getOptions = () => this.options;
getCaretPosition = () => this.caretPosition;
/** /**
* Handles clicks made to keyboard buttons * Handles clicks made to keyboard buttons
* @param {string} button The button's layout name. * @param {string} button The button's layout name.
@ -167,7 +195,6 @@ class SimpleKeyboard {
let updatedInput = this.utilities.getUpdatedInput( let updatedInput = this.utilities.getUpdatedInput(
button, button,
this.input[this.options.inputName], this.input[this.options.inputName],
this.options,
this.caretPosition this.caretPosition
); );
@ -185,7 +212,7 @@ class SimpleKeyboard {
*/ */
if ( if (
this.options.maxLength && this.options.maxLength &&
this.utilities.handleMaxLength(this.input, this.options, updatedInput) this.utilities.handleMaxLength(this.input, updatedInput)
) { ) {
return false; return false;
} }
@ -193,7 +220,6 @@ class SimpleKeyboard {
this.input[this.options.inputName] = this.utilities.getUpdatedInput( this.input[this.options.inputName] = this.utilities.getUpdatedInput(
button, button,
this.input[this.options.inputName], this.input[this.options.inputName],
this.options,
this.caretPosition, this.caretPosition,
true true
); );
@ -272,6 +298,12 @@ class SimpleKeyboard {
handleButtonMouseUp() { handleButtonMouseUp() {
this.isMouseHold = false; this.isMouseHold = false;
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout); if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
/**
* Calling onKeyReleased
*/
if (typeof this.options.onKeyReleased === "function")
this.options.onKeyReleased();
} }
/** /**
@ -584,33 +616,63 @@ class SimpleKeyboard {
} }
/** /**
* Retrieves the current cursor position within a input or textarea (if any) * Handles simple-keyboard event listeners
*/ */
handleCaret() { setEventListeners() {
/** /**
* Only first instance should insall the caret handling events * Only first instance should set the event listeners
*/ */
this.caretPosition = null; if (this.isFirstKeyboardInstance || !this.allKeyboardInstances) {
let simpleKeyboardInstances = window["SimpleKeyboardInstances"];
if (
(simpleKeyboardInstances &&
Object.keys(simpleKeyboardInstances)[0] ===
this.utilities.camelCase(this.keyboardDOMClass)) ||
!simpleKeyboardInstances
) {
if (this.options.debug) { if (this.options.debug) {
console.log(`Caret handling started (${this.keyboardDOMClass})`); console.log(`Caret handling started (${this.keyboardDOMClass})`);
} }
document.addEventListener("keyup", this.caretEventHandler); /**
document.addEventListener("mouseup", this.caretEventHandler); * Event Listeners
document.addEventListener("touchend", this.caretEventHandler); */
document.addEventListener("keyup", this.handleKeyUp);
document.addEventListener("keydown", this.handleKeyDown);
document.addEventListener("mouseup", this.handleMouseUp);
document.addEventListener("touchend", this.handleTouchEnd);
} }
} }
/** /**
* Called by {@link handleCaret} when an event that warrants a cursor position update is triggered * Event Handler: KeyUp
*/
handleKeyUp(event) {
this.caretEventHandler(event);
if (this.options.physicalKeyboardHighlight) {
this.physicalKeyboard.handleHighlightKeyUp(event);
}
}
/**
* Event Handler: KeyDown
*/
handleKeyDown(event) {
if (this.options.physicalKeyboardHighlight) {
this.physicalKeyboard.handleHighlightKeyDown(event);
}
}
/**
* Event Handler: MouseUp
*/
handleMouseUp(event) {
this.caretEventHandler(event);
}
/**
* Event Handler: TouchEnd
*/
handleTouchEnd(event) {
this.caretEventHandler(event);
}
/**
* Called by {@link caretEventHandler} when an event that warrants a cursor position update is triggered
*/ */
caretEventHandler(event) { caretEventHandler(event) {
let targetTagName; let targetTagName;
@ -657,9 +719,10 @@ class SimpleKeyboard {
/** /**
* Remove listeners * Remove listeners
*/ */
document.removeEventListener("keyup", this.caretEventHandler); document.removeEventListener("keyup", this.handleKeyUp);
document.removeEventListener("mouseup", this.caretEventHandler); document.removeEventListener("keydown", this.handleKeyDown);
document.removeEventListener("touchend", this.caretEventHandler); document.removeEventListener("mouseup", this.handleMouseUp);
document.removeEventListener("touchend", this.handleTouchEnd);
/** /**
* Clear DOM * Clear DOM
@ -763,9 +826,9 @@ class SimpleKeyboard {
} }
/** /**
* Caret handling * setEventListeners
*/ */
this.handleCaret(); this.setEventListeners();
if (typeof this.options.onInit === "function") this.options.onInit(); if (typeof this.options.onInit === "function") this.options.onInit();
} }
@ -788,6 +851,7 @@ class SimpleKeyboard {
* Notify about PointerEvents usage * Notify about PointerEvents usage
*/ */
if ( if (
this.isFirstKeyboardInstance &&
this.utilities.pointerEventsSupported() && this.utilities.pointerEventsSupported() &&
!this.options.useTouchEvents && !this.options.useTouchEvents &&
!this.options.useMouseEvents !this.options.useMouseEvents

View File

@ -1243,3 +1243,56 @@ it('Keyboard disableButtonHold will work', () => {
expect(keyboard.options.disableButtonHold).toBe(true); expect(keyboard.options.disableButtonHold).toBe(true);
}); });
it('Keyboard caretEventHandler will be triggered on mouseup and ontouchend', () => {
testUtil.setDOM();
let keyboard = new Keyboard({
disableCaretPositioning: true
});
keyboard.caretPosition = 6;
document.dispatchEvent(new MouseEvent('mouseup', {
target: {
tagName: "input"
}
}));
expect(keyboard.caretPosition).toBe(null);
keyboard.setOptions({
disableCaretPositioning: false
})
keyboard.caretPosition = 10;
document.dispatchEvent(new TouchEvent('touchend', {
target: {
tagName: "input"
}
}));
expect(keyboard.caretPosition).toBe(10);
});
it('Keyboard onKeyReleased will work', () => {
testUtil.setDOM();
let pressed = false;
let firedTimes = 0;
let keyboard = new Keyboard({
onKeyReleased: () => {
pressed = true;
firedTimes++;
},
debug: true
});
keyboard.getButtonElement("q").onpointerdown();
keyboard.getButtonElement("q").onpointerup();
expect(pressed).toBeTruthy();
expect(firedTimes).toBe(1);
});

View File

@ -1,3 +1,5 @@
import Utilities from "../services/Utilities";
/** /**
* Physical Keyboard Service * Physical Keyboard Service
*/ */
@ -5,58 +7,41 @@ class PhysicalKeyboard {
/** /**
* Creates an instance of the PhysicalKeyboard service * Creates an instance of the PhysicalKeyboard service
*/ */
constructor(simpleKeyboardInstance) { constructor({ dispatch, getOptions }) {
/** /**
* @type {object} A simple-keyboard instance * @type {object} A simple-keyboard instance
*/ */
this.simpleKeyboardInstance = simpleKeyboardInstance; this.dispatch = dispatch;
this.getOptions = getOptions;
/** /**
* Bindings * Bindings
*/ */
this.initKeyboardListener = this.initKeyboardListener.bind(this); Utilities.bindMethods(PhysicalKeyboard, this);
this.getSimpleKeyboardLayoutKey = this.getSimpleKeyboardLayoutKey.bind(
this
);
/**
* Initialize key listeners
*/
this.initKeyboardListener();
} }
/** handleHighlightKeyDown(event) {
* Initializes key event listeners let options = this.getOptions();
*/
initKeyboardListener() {
// Adding button style on keydown
document.addEventListener("keydown", event => {
if (this.simpleKeyboardInstance.options.physicalKeyboardHighlight) {
let buttonPressed = this.getSimpleKeyboardLayoutKey(event); let buttonPressed = this.getSimpleKeyboardLayoutKey(event);
this.simpleKeyboardInstance.dispatch(instance => { this.dispatch(instance => {
let buttonDOM = let buttonDOM =
instance.getButtonElement(buttonPressed) || instance.getButtonElement(buttonPressed) ||
instance.getButtonElement(`{${buttonPressed}}`); instance.getButtonElement(`{${buttonPressed}}`);
if (buttonDOM) { if (buttonDOM) {
buttonDOM.style.backgroundColor = buttonDOM.style.backgroundColor =
this.simpleKeyboardInstance.options options.physicalKeyboardHighlightBgColor || "#9ab4d0";
.physicalKeyboardHighlightBgColor || "#9ab4d0";
buttonDOM.style.color = buttonDOM.style.color =
this.simpleKeyboardInstance.options options.physicalKeyboardHighlightTextColor || "white";
.physicalKeyboardHighlightTextColor || "white";
} }
}); });
} }
});
// Removing button style on keyup handleHighlightKeyUp(event) {
document.addEventListener("keyup", event => {
if (this.simpleKeyboardInstance.options.physicalKeyboardHighlight) {
let buttonPressed = this.getSimpleKeyboardLayoutKey(event); let buttonPressed = this.getSimpleKeyboardLayoutKey(event);
this.simpleKeyboardInstance.dispatch(instance => { this.dispatch(instance => {
let buttonDOM = let buttonDOM =
instance.getButtonElement(buttonPressed) || instance.getButtonElement(buttonPressed) ||
instance.getButtonElement(`{${buttonPressed}}`); instance.getButtonElement(`{${buttonPressed}}`);
@ -66,8 +51,6 @@ class PhysicalKeyboard {
} }
}); });
} }
});
}
/** /**
* Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format * Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format

View File

@ -5,11 +5,10 @@ class Utilities {
/** /**
* Creates an instance of the Utility service * Creates an instance of the Utility service
*/ */
constructor(simpleKeyboardInstance) { constructor({ getOptions, getCaretPosition, dispatch }) {
/** this.getOptions = getOptions;
* @type {object} A simple-keyboard instance this.getCaretPosition = getCaretPosition;
*/ this.dispatch = dispatch;
this.simpleKeyboardInstance = simpleKeyboardInstance;
/** /**
* Bindings * Bindings
@ -125,11 +124,11 @@ class Utilities {
* *
* @param {string} button The button's layout name * @param {string} button The button's layout name
* @param {string} input The input string * @param {string} input The input string
* @param {object} options The simple-keyboard options object
* @param {number} caretPos The cursor's current position * @param {number} caretPos The cursor's current position
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor * @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/ */
getUpdatedInput(button, input, options, caretPos, moveCaret) { getUpdatedInput(button, input, caretPos, moveCaret) {
let options = this.getOptions();
let output = input; let output = input;
if ( if (
@ -187,43 +186,34 @@ class Utilities {
* @param {boolean} minus Whether the cursor should be moved to the left or not. * @param {boolean} minus Whether the cursor should be moved to the left or not.
*/ */
updateCaretPos(length, minus) { updateCaretPos(length, minus) {
let newCaretPos = this.updateCaretPosAction( let newCaretPos = this.updateCaretPosAction(length, minus);
this.simpleKeyboardInstance,
length,
minus
);
if (this.simpleKeyboardInstance.options.syncInstanceInputs) { this.dispatch(instance => {
this.simpleKeyboardInstance.dispatch(instance => {
instance.caretPosition = newCaretPos; instance.caretPosition = newCaretPos;
}); });
} }
}
/** /**
* Action method of updateCaretPos * Action method of updateCaretPos
* *
* @param {object} instance The instance whose position should be updated
* @param {number} length Represents by how many characters the input should be moved * @param {number} length Represents by how many characters the input should be moved
* @param {boolean} minus Whether the cursor should be moved to the left or not. * @param {boolean} minus Whether the cursor should be moved to the left or not.
*/ */
updateCaretPosAction(instance, length, minus) { updateCaretPosAction(length, minus) {
let options = this.getOptions();
let caretPosition = this.getCaretPosition();
if (minus) { if (minus) {
if (instance.caretPosition > 0) if (caretPosition > 0) caretPosition = caretPosition - length;
instance.caretPosition = instance.caretPosition - length;
} else { } else {
instance.caretPosition = instance.caretPosition + length; caretPosition = caretPosition + length;
} }
if (this.simpleKeyboardInstance.options.debug) { if (options.debug) {
console.log( console.log("Caret at:", caretPosition, `(${this.keyboardDOMClass})`);
"Caret at:",
instance.caretPosition,
`(${instance.keyboardDOMClass})`
);
} }
return instance.caretPosition; return caretPosition;
} }
/** /**
@ -263,7 +253,9 @@ class Utilities {
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor * @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/ */
removeAt(source, position, moveCaret) { removeAt(source, position, moveCaret) {
if (this.simpleKeyboardInstance.caretPosition === 0) { let caretPosition = this.getCaretPosition();
if (caretPosition === 0) {
return source; return source;
} }
@ -306,10 +298,10 @@ class Utilities {
* Determines whether the maxLength has been reached. This function is called when the maxLength option it set. * Determines whether the maxLength has been reached. This function is called when the maxLength option it set.
* *
* @param {object} inputObj * @param {object} inputObj
* @param {object} options
* @param {string} updatedInput * @param {string} updatedInput
*/ */
handleMaxLength(inputObj, options, updatedInput) { handleMaxLength(inputObj, updatedInput) {
let options = this.getOptions();
let maxLength = options.maxLength; let maxLength = options.maxLength;
let currentInput = inputObj[options.inputName]; let currentInput = inputObj[options.inputName];
let condition = currentInput.length === maxLength; let condition = currentInput.length === maxLength;
@ -399,6 +391,8 @@ class Utilities {
* @param {string} string The string to transform. * @param {string} string The string to transform.
*/ */
camelCase(string) { camelCase(string) {
if (!string) return false;
return string return string
.toLowerCase() .toLowerCase()
.trim() .trim()

View File

@ -31,7 +31,7 @@ it('Keyboard {bksp} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{bksp}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{bksp}", "test");
expect(output).toBe("tes"); expect(output).toBe("tes");
}); });
@ -41,7 +41,7 @@ it('Keyboard {space} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{space}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{space}", "test");
expect(output).toBe("test "); expect(output).toBe("test ");
}); });
@ -51,7 +51,7 @@ it('Keyboard {tab} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{tab}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{tab}", "test");
expect(output).toBe("test\t"); expect(output).toBe("test\t");
}); });
@ -63,7 +63,7 @@ it('Keyboard {tab} button will work with tabCharOnTab:false', () => {
tabCharOnTab: false tabCharOnTab: false
}); });
let output = keyboard.utilities.getUpdatedInput("{tab}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{tab}", "test");
expect(output).toBe("test"); expect(output).toBe("test");
}); });
@ -73,7 +73,7 @@ it('Keyboard {enter} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{enter}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{enter}", "test");
expect(output).toBe("test"); expect(output).toBe("test");
}); });
@ -85,7 +85,7 @@ it('Keyboard {enter} button will work with newLineOnEnter:true', () => {
newLineOnEnter: true newLineOnEnter: true
}); });
let output = keyboard.utilities.getUpdatedInput("{enter}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{enter}", "test");
expect(output).toBe("test\n"); expect(output).toBe("test\n");
}); });
@ -96,7 +96,7 @@ it('Keyboard {numpadX} buttons will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
for(let i = 0;i<=9;i++){ for(let i = 0;i<=9;i++){
let output = keyboard.utilities.getUpdatedInput(`{numpad${i}}`, "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput(`{numpad${i}}`, "test");
expect(output).toBe(`test${i}`); expect(output).toBe(`test${i}`);
} }
}); });
@ -106,7 +106,7 @@ it('Keyboard {numpaddivide} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{numpaddivide}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{numpaddivide}", "test");
expect(output).toBe("test/"); expect(output).toBe("test/");
}); });
@ -116,7 +116,7 @@ it('Keyboard {numpadmultiply} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{numpadmultiply}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{numpadmultiply}", "test");
expect(output).toBe("test*"); expect(output).toBe("test*");
}); });
@ -126,7 +126,7 @@ it('Keyboard {numpadsubtract} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{numpadsubtract}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{numpadsubtract}", "test");
expect(output).toBe("test-"); expect(output).toBe("test-");
}); });
@ -136,7 +136,7 @@ it('Keyboard {numpadadd} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{numpadadd}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{numpadadd}", "test");
expect(output).toBe("test+"); expect(output).toBe("test+");
}); });
@ -146,7 +146,7 @@ it('Keyboard {numpadadd} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{numpadadd}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{numpadadd}", "test");
expect(output).toBe("test+"); expect(output).toBe("test+");
}); });
@ -156,7 +156,7 @@ it('Keyboard {numpaddecimal} button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{numpaddecimal}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{numpaddecimal}", "test");
expect(output).toBe("test."); expect(output).toBe("test.");
}); });
@ -172,7 +172,7 @@ it('Keyboard custom function buttons will work', () => {
} }
}); });
let output = keyboard.utilities.getUpdatedInput("{randombuttontest}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{randombuttontest}", "test");
expect(output).toBe("test"); expect(output).toBe("test");
expect(keyboard.getButtonElement("{randombuttontest}").onclick).toBeTruthy(); expect(keyboard.getButtonElement("{randombuttontest}").onclick).toBeTruthy();
@ -183,7 +183,7 @@ it('Keyboard "{" button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("{", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("{", "test");
expect(output).toBe("test{"); expect(output).toBe("test{");
}); });
@ -193,7 +193,7 @@ it('Keyboard "}" button will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
let output = keyboard.utilities.getUpdatedInput("}", "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput("}", "test");
expect(output).toBe("test}"); expect(output).toBe("test}");
}); });
@ -205,7 +205,7 @@ it('Keyboard standard button will affect input', () => {
for (let i = 65; i <= 90; i++) { for (let i = 65; i <= 90; i++) {
let char = String.fromCharCode(i); let char = String.fromCharCode(i);
let output = keyboard.utilities.getUpdatedInput(char, "test", keyboard.options); let output = keyboard.utilities.getUpdatedInput(char, "test");
expect(output).toBe(`test${char}`); expect(output).toBe(`test${char}`);
} }
}); });
@ -213,8 +213,9 @@ it('Keyboard standard button will affect input', () => {
it('Keyboard updateCaretPos will work with minus', () => { it('Keyboard updateCaretPos will work with minus', () => {
testUtil.setDOM(); testUtil.setDOM();
let keyboard = new Keyboard(); let keyboard = new Keyboard({
keyboard.options.syncInstanceInputs = true; syncInstanceInputs: true
});
keyboard.caretPosition = 5; keyboard.caretPosition = 5;
keyboard.utilities.updateCaretPos(2, true); keyboard.utilities.updateCaretPos(2, true);
@ -282,7 +283,7 @@ it('Keyboard addStringAt will respect maxLength', () => {
keyboard.setInput("test"); keyboard.setInput("test");
keyboard.caretPosition = 4; keyboard.caretPosition = 4;
keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq") keyboard.utilities.handleMaxLength(keyboard.input, "testq")
keyboard.utilities.addStringAt("test", "q", 4); keyboard.utilities.addStringAt("test", "q", 4);
expect(keyboard.caretPosition).toBe(4); expect(keyboard.caretPosition).toBe(4);
@ -297,7 +298,7 @@ it('Keyboard handleMaxLength will exit out on same updatedInput', () => {
keyboard.setInput("test"); keyboard.setInput("test");
let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "test") let output = keyboard.utilities.handleMaxLength(keyboard.input, "test")
expect(output).toBeFalsy(); expect(output).toBeFalsy();
}); });
@ -313,7 +314,7 @@ it('Keyboard handleMaxLength will work with object maxLength', () => {
keyboard.setInput("test"); keyboard.setInput("test");
let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); let output = keyboard.utilities.handleMaxLength(keyboard.input, "testq");
expect(output).toBeTruthy(); expect(output).toBeTruthy();
}); });
@ -330,7 +331,7 @@ it('Keyboard handleMaxLength will work with object maxLength and debug', () => {
keyboard.setInput("test"); keyboard.setInput("test");
let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); let output = keyboard.utilities.handleMaxLength(keyboard.input, "testq");
expect(output).toBeTruthy(); expect(output).toBeTruthy();
}); });
@ -346,7 +347,7 @@ it('Keyboard handleMaxLength will return false if obj maxLength not reached', ()
keyboard.setInput("test"); keyboard.setInput("test");
let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); let output = keyboard.utilities.handleMaxLength(keyboard.input, "testq");
expect(output).toBeFalsy(); expect(output).toBeFalsy();
}); });
@ -361,7 +362,7 @@ it('Keyboard handleMaxLength will work without debug', () => {
keyboard.setInput("test"); keyboard.setInput("test");
let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); let output = keyboard.utilities.handleMaxLength(keyboard.input, "testq");
expect(output).toBeTruthy(); expect(output).toBeTruthy();
}); });
@ -376,7 +377,7 @@ it('Keyboard handleMaxLength will work with numeric maxLength', () => {
keyboard.setInput("test"); keyboard.setInput("test");
let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); let output = keyboard.utilities.handleMaxLength(keyboard.input, "testq");
expect(output).toBeFalsy(); expect(output).toBeFalsy();
}); });
@ -390,7 +391,7 @@ it('Keyboard handleMaxLength wont work with non numeric or object maxLength', ()
keyboard.setInput("test"); keyboard.setInput("test");
let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); let output = keyboard.utilities.handleMaxLength(keyboard.input, "testq");
expect(output).toBeFalsy(); expect(output).toBeFalsy();
}); });
@ -405,7 +406,7 @@ it('Keyboard handleMaxLength wont work with non numeric or object maxLength (wit
keyboard.setInput("test"); keyboard.setInput("test");
let output = keyboard.utilities.handleMaxLength(keyboard.input, keyboard.options, "testq"); let output = keyboard.utilities.handleMaxLength(keyboard.input, "testq");
expect(output).toBeFalsy(); expect(output).toBeFalsy();
}); });
@ -484,3 +485,9 @@ it('Keyboard will work with custom (and weird) class', () => {
let keyboard = new Keyboard(".my--weird--class"); let keyboard = new Keyboard(".my--weird--class");
expect(keyboard.keyboardDOMClass).toBe("my--weird--class"); expect(keyboard.keyboardDOMClass).toBe("my--weird--class");
}); });
it('Keyboard camelCase will work with empty strings', () => {
testUtil.setDOM();
let keyboard = new Keyboard();
expect(keyboard.utilities.camelCase()).toBeFalsy();
});

View File

@ -7,9 +7,14 @@ export default class TestUtility {
*/ */
setDOM = (divClass) => { setDOM = (divClass) => {
this.clear(); this.clear();
const div = document.createElement('div'); const wrapperDOM = document.createElement('div');
div.className += divClass || "simple-keyboard"; wrapperDOM.setAttribute("id", "root");
document.body.appendChild(div);
const keyboardDOM = document.createElement('div');
keyboardDOM.className = divClass || "simple-keyboard";
wrapperDOM.appendChild(keyboardDOM);
document.body.appendChild(wrapperDOM);
} }
/** /**