mirror of
https://github.com/hodgef/simple-keyboard.git
synced 2025-04-22 20:20:46 +08:00
401 lines
15 KiB
HTML
401 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<base data-ice="baseUrl" href="../../../../">
|
|
<title data-ice="title">src/lib/services/Utilities.js | simple-keyboard</title>
|
|
<link type="text/css" rel="stylesheet" href="css/style.css">
|
|
<link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
|
|
<script src="script/prettify/prettify.js"></script>
|
|
<script src="script/manual.js"></script>
|
|
<meta name="description" content="On-screen Javascript Virtual Keyboard"><meta property="twitter:card" content="summary"><meta property="twitter:title" content="simple-keyboard"><meta property="twitter:description" content="On-screen Javascript Virtual Keyboard"></head>
|
|
<body class="layout-container" data-ice="rootContainer">
|
|
|
|
<header>
|
|
<a href="./">Home</a>
|
|
|
|
<a href="identifiers.html">Reference</a>
|
|
<a href="source.html">Source</a>
|
|
|
|
<div class="search-box">
|
|
<span>
|
|
<img src="./image/search.png">
|
|
<span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
|
|
</span>
|
|
<ul class="search-result"></ul>
|
|
</div>
|
|
<a style="position:relative; top:3px;" href="https://github.com/hodgef/simple-keyboard"><img width="20px" src="./image/github.png"></a></header>
|
|
|
|
<nav class="navigation" data-ice="nav"><div>
|
|
<ul>
|
|
|
|
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#demo">demo</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/demo/App.js~App.html">App</a></span></span></li>
|
|
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-components">lib/components</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/components/Keyboard.js~SimpleKeyboard.html">SimpleKeyboard</a></span></span></li>
|
|
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-services">lib/services</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/services/KeyboardLayout.js~KeyboardLayout.html">KeyboardLayout</a></span></span></li>
|
|
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/services/PhysicalKeyboard.js~PhysicalKeyboard.html">PhysicalKeyboard</a></span></span></li>
|
|
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/services/Utilities.js~Utilities.html">Utilities</a></span></span></li>
|
|
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#lib-tests">lib/tests</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/lib/tests/TestUtility.js~TestUtility.html">TestUtility</a></span></span></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="content" data-ice="content"><h1 data-ice="title">src/lib/services/Utilities.js</h1>
|
|
<pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">/**
|
|
* Utility Service
|
|
*/
|
|
class Utilities {
|
|
/**
|
|
* Creates an instance of the Utility service
|
|
*/
|
|
constructor(simpleKeyboardInstance){
|
|
/**
|
|
* @type {object} A simple-keyboard instance
|
|
*/
|
|
this.simpleKeyboardInstance = simpleKeyboardInstance;
|
|
}
|
|
|
|
/**
|
|
* Adds default classes to a given button
|
|
*
|
|
* @param {string} button The button's layout name
|
|
* @return {string} The classes to be added to the button
|
|
*/
|
|
getButtonClass = button => {
|
|
let buttonTypeClass = (button.includes("{") && button.includes("}") && button !== '{//}') ? "functionBtn" : "standardBtn";
|
|
let buttonWithoutBraces = button.replace("{", "").replace("}", "");
|
|
let buttonNormalized = '';
|
|
|
|
if(buttonTypeClass !== "standardBtn")
|
|
buttonNormalized = ` hg-button-${buttonWithoutBraces}`;
|
|
|
|
return `hg-${buttonTypeClass}${buttonNormalized}`;
|
|
}
|
|
|
|
/**
|
|
* Default button display labels
|
|
*/
|
|
getDefaultDiplay(){
|
|
return {
|
|
'{bksp}': 'backspace',
|
|
'{backspace}': 'backspace',
|
|
'{enter}': '< enter',
|
|
'{shift}': 'shift',
|
|
'{shiftleft}': 'shift',
|
|
'{shiftright}': 'shift',
|
|
'{alt}': 'alt',
|
|
'{s}': 'shift',
|
|
'{tab}': 'tab',
|
|
'{lock}': 'caps',
|
|
'{capslock}': 'caps',
|
|
'{accept}': 'Submit',
|
|
'{space}': ' ',
|
|
'{//}': ' ',
|
|
"{esc}": "esc",
|
|
"{escape}": "esc",
|
|
"{f1}": "f1",
|
|
"{f2}": "f2",
|
|
"{f3}": "f3",
|
|
"{f4}": "f4",
|
|
"{f5}": "f5",
|
|
"{f6}": "f6",
|
|
"{f7}": "f7",
|
|
"{f8}": "f8",
|
|
"{f9}": "f9",
|
|
"{f10}": "f10",
|
|
"{f11}": "f11",
|
|
"{f12}": "f12",
|
|
'{numpaddivide}': '/',
|
|
'{numlock}': 'lock',
|
|
"{arrowup}": "↑",
|
|
"{arrowleft}": "←",
|
|
"{arrowdown}": "↓",
|
|
"{arrowright}": "→",
|
|
"{prtscr}": "print",
|
|
"{scrolllock}": "scroll",
|
|
"{pause}": "pause",
|
|
"{insert}": "ins",
|
|
"{home}": "home",
|
|
"{pageup}": "up",
|
|
"{delete}": "del",
|
|
"{end}": "end",
|
|
"{pagedown}": "down",
|
|
"{numpadmultiply}": "*",
|
|
"{numpadsubtract}": "-",
|
|
"{numpadadd}": "+",
|
|
"{numpadenter}": "enter",
|
|
"{period}": ".",
|
|
"{numpaddecimal}": ".",
|
|
"{numpad0}": "0",
|
|
"{numpad1}": "1",
|
|
"{numpad2}": "2",
|
|
"{numpad3}": "3",
|
|
"{numpad4}": "4",
|
|
"{numpad5}": "5",
|
|
"{numpad6}": "6",
|
|
"{numpad7}": "7",
|
|
"{numpad8}": "8",
|
|
"{numpad9}": "9",
|
|
};
|
|
}
|
|
/**
|
|
* Returns the display (label) name for a given button
|
|
*
|
|
* @param {string} button The button's layout name
|
|
* @param {object} display The provided display option
|
|
* @param {boolean} mergeDisplay Whether the provided param value should be merged with the default one.
|
|
*/
|
|
getButtonDisplayName = (button, display, mergeDisplay) => {
|
|
if(mergeDisplay){
|
|
display = Object.assign({}, this.getDefaultDiplay(), display);
|
|
} else {
|
|
display = display || this.getDefaultDiplay();
|
|
}
|
|
|
|
return display[button] || button;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the updated input resulting from clicking a given button
|
|
*
|
|
* @param {string} button The button's layout name
|
|
* @param {string} input The input string
|
|
* @param {object} options The simple-keyboard options object
|
|
* @param {number} caretPos The cursor's current position
|
|
*/
|
|
getUpdatedInput = (button, input, options, caretPos) => {
|
|
|
|
let output = input;
|
|
|
|
if((button === "{bksp}" || button === "{backspace}") && output.length > 0){
|
|
output = this.removeAt(output, caretPos);
|
|
|
|
} else if(button === "{space}")
|
|
output = this.addStringAt(output, " ", caretPos);
|
|
|
|
else if(button === "{tab}" && !(typeof options.tabCharOnTab === "boolean" && options.tabCharOnTab === false)){
|
|
output = this.addStringAt(output, "\t", caretPos);
|
|
|
|
} else if((button === "{enter}" || button === "{numpadenter}") && options.newLineOnEnter)
|
|
output = this.addStringAt(output, "\n", caretPos);
|
|
|
|
else if(button.includes("numpad") && Number.isInteger(Number(button[button.length - 2]))){
|
|
output = this.addStringAt(output, button[button.length - 2], caretPos);
|
|
}
|
|
else if(button === "{numpaddivide}")
|
|
output = this.addStringAt(output, '/', caretPos);
|
|
|
|
else if(button === "{numpadmultiply}")
|
|
output = this.addStringAt(output, '*', caretPos);
|
|
else if(button === "{numpadsubtract}")
|
|
output = this.addStringAt(output, '-', caretPos);
|
|
|
|
else if(button === "{numpadadd}")
|
|
output = this.addStringAt(output, '+', caretPos);
|
|
|
|
else if(button === "{numpaddecimal}")
|
|
output = this.addStringAt(output, '.', caretPos);
|
|
|
|
else if(button === "{" || button === "}")
|
|
output = this.addStringAt(output, button, caretPos);
|
|
|
|
else if(!button.includes("{") && !button.includes("}"))
|
|
output = this.addStringAt(output, button, caretPos);
|
|
|
|
return output;
|
|
}
|
|
/**
|
|
* Moves the cursor position by a given amount
|
|
*
|
|
* @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.
|
|
*/
|
|
updateCaretPos = (length, minus) => {
|
|
if(minus){
|
|
if(this.simpleKeyboardInstance.caretPosition > 0)
|
|
this.simpleKeyboardInstance.caretPosition = this.simpleKeyboardInstance.caretPosition - length
|
|
} else {
|
|
this.simpleKeyboardInstance.caretPosition = this.simpleKeyboardInstance.caretPosition + length;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a string to the input at a given position
|
|
*
|
|
* @param {string} source The source input
|
|
* @param {string} string The string to add
|
|
* @param {number} position The (cursor) position where the string should be added
|
|
*/
|
|
addStringAt(source, string, position){
|
|
let output;
|
|
|
|
if(this.simpleKeyboardInstance.options.debug){
|
|
console.log("Caret at:", position);
|
|
}
|
|
|
|
if(!position && position !== 0){
|
|
output = source + string;
|
|
} else {
|
|
output = [source.slice(0, position), string, source.slice(position)].join('');
|
|
|
|
/**
|
|
* Avoid caret position change when maxLength is set
|
|
*/
|
|
if(!this.isMaxLengthReached()){
|
|
this.updateCaretPos(string.length);
|
|
}
|
|
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* Removes an amount of characters at a given position
|
|
*
|
|
* @param {string} source The source input
|
|
* @param {number} position The (cursor) position from where the characters should be removed
|
|
*/
|
|
removeAt(source, position){
|
|
if(this.simpleKeyboardInstance.caretPosition === 0){
|
|
return source;
|
|
}
|
|
|
|
let output;
|
|
let prevTwoChars;
|
|
let emojiMatched;
|
|
let emojiMatchedReg = /([\uD800-\uDBFF][\uDC00-\uDFFF])/g;
|
|
|
|
/**
|
|
* Emojis are made out of two characters, so we must take a custom approach to trim them.
|
|
* For more info: https://mathiasbynens.be/notes/javascript-unicode
|
|
*/
|
|
if(position && position >= 0){
|
|
prevTwoChars = source.substring(position - 2, position)
|
|
emojiMatched = prevTwoChars.match(emojiMatchedReg);
|
|
|
|
if(emojiMatched){
|
|
output = source.substr(0, (position - 2)) + source.substr(position);
|
|
this.updateCaretPos(2, true);
|
|
} else {
|
|
output = source.substr(0, (position - 1)) + source.substr(position);
|
|
this.updateCaretPos(1, true);
|
|
}
|
|
} else {
|
|
prevTwoChars = source.slice(-2);
|
|
emojiMatched = prevTwoChars.match(emojiMatchedReg);
|
|
|
|
if(emojiMatched){
|
|
output = source.slice(0, -2);
|
|
this.updateCaretPos(2, true);
|
|
} else {
|
|
output = source.slice(0, -1);
|
|
this.updateCaretPos(1, true);
|
|
}
|
|
}
|
|
|
|
return output;
|
|
}
|
|
/**
|
|
* Determines whether the maxLength has been reached. This function is called when the maxLength option it set.
|
|
*
|
|
* @param {object} inputObj
|
|
* @param {object} options
|
|
* @param {string} updatedInput
|
|
*/
|
|
handleMaxLength(inputObj, options, updatedInput){
|
|
let maxLength = options.maxLength;
|
|
let currentInput = inputObj[options.inputName];
|
|
let condition = currentInput.length === maxLength;
|
|
|
|
|
|
if(
|
|
/**
|
|
* If pressing this button won't add more characters
|
|
* We exit out of this limiter function
|
|
*/
|
|
updatedInput.length <= currentInput.length
|
|
){
|
|
return false;
|
|
}
|
|
|
|
if(Number.isInteger(maxLength)){
|
|
if(options.debug){
|
|
console.log("maxLength (num) reached:", condition);
|
|
}
|
|
|
|
if(condition){
|
|
/**
|
|
* @type {boolean} Boolean value that shows whether maxLength has been reached
|
|
*/
|
|
this.maxLengthReached = true;
|
|
return true;
|
|
} else {
|
|
this.maxLengthReached = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(typeof maxLength === "object"){
|
|
let condition = currentInput.length === maxLength[options.inputName];
|
|
|
|
if(options.debug){
|
|
console.log("maxLength (obj) reached:", condition);
|
|
}
|
|
|
|
if(condition){
|
|
this.maxLengthReached = true;
|
|
return true;
|
|
} else {
|
|
this.maxLengthReached = false;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the current value of maxLengthReached
|
|
*/
|
|
isMaxLengthReached = () => {
|
|
return Boolean(this.maxLengthReached);
|
|
}
|
|
|
|
/**
|
|
* Transforms an arbitrary string to camelCase
|
|
*
|
|
* @param {string} string The string to transform.
|
|
*/
|
|
camelCase = (string) => {
|
|
return string.toLowerCase().trim().split(/[.\-_\s]/g).reduce((string, word) => string + word[0].toUpperCase() + word.slice(1));
|
|
};
|
|
|
|
/**
|
|
* Counts the number of duplicates in a given array
|
|
*
|
|
* @param {Array} array The haystack to search in
|
|
* @param {string} value The needle to search for
|
|
*/
|
|
countInArray = (array, value) => {
|
|
return array.reduce((n, x) => n + (x === value), 0);
|
|
}
|
|
|
|
}
|
|
|
|
export default Utilities;</code></pre>
|
|
|
|
</div>
|
|
|
|
<footer class="footer">
|
|
Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.1.0)</span><img src="./image/esdoc-logo-mini-black.png"></a>
|
|
</footer>
|
|
|
|
<script src="script/search_index.js"></script>
|
|
<script src="script/search.js"></script>
|
|
<script src="script/pretty-print.js"></script>
|
|
<script src="script/inherited-summary.js"></script>
|
|
<script src="script/test-summary.js"></script>
|
|
<script src="script/inner-link.js"></script>
|
|
<script src="script/patch-for-local.js"></script>
|
|
</body>
|
|
</html>
|