Compare commits

...
26 Commits
Author SHA1 Message Date
Francisco Hodge 38d9a635b8 Build update 2019-03-11 18:33:48 -04:00
Francisco Hodge 564aa188e4 Merge branch 'staging' 2019-03-11 18:31:04 -04:00
Francisco Hodge aadb84b8f7 npm update 2019-03-11 18:26:13 -04:00
Francisco Hodge dadad31fdd Tests update 2019-03-11 18:26:00 -04:00
Francisco Hodge 8582350774 Added stopMouseDownPropagation option 2019-03-11 18:25:51 -04:00
Francisco Hodge 287c33f498 build update 2019-03-10 19:38:38 -04:00
Francisco Hodge 1d0e985922 CI: Added dev server testing 2019-03-10 15:58:22 -04:00
Francisco Hodge a96effb570 Updated dev dependencies 2019-03-10 15:57:45 -04:00
Francisco Hodge 0bea304528 Build update 2019-03-09 21:52:44 -05:00
Francisco Hodge 652084cabb npm update 2019-03-09 21:47:49 -05:00
Francisco Hodge 39c4acba85 Tests update 2019-03-09 21:47:39 -05:00
Francisco Hodge 69b830c632 Added row button grouping functionality 2019-03-09 21:47:31 -05:00
Francisco Hodge cd909cffa8 Build update 2019-03-07 21:30:17 -05:00
Francisco Hodge 92d2b381db npm update 2019-03-07 21:26:43 -05:00
Francisco Hodge 96206d1b47 Remove PointerEvents debug message when useMouseEvents is enabled 2019-03-07 21:26:22 -05:00
Francisco Hodge 19f6ac9ac1 Build update 2019-03-07 20:53:23 -05:00
Francisco Hodge 90b67ec416 Support Utilities access through Typescript 2019-03-07 20:53:07 -05:00
Francisco Hodge 6208d5f7e1 Fixed getInput output when inputName is passed 2019-03-07 20:52:40 -05:00
Francisco Hodge bd0274415b Fixed onChangeAll callback 2019-03-07 20:51:57 -05:00
Francisco Hodge 30941f4ba0 Adding useMouseEvents option 2019-03-07 20:51:29 -05:00
Francisco Hodge 48a15e6715 Disable devDependency tracking 2019-03-07 20:49:34 -05:00
Francisco Hodge f8ee859bb0 Build update 2019-03-07 07:36:08 -05:00
Francisco Hodge 3012ce24e2 Build update 2019-03-07 07:32:24 -05:00
Francisco Hodge 6e54729f46 Tests update 2019-03-07 07:32:15 -05:00
Francisco Hodge 5ab58f2528 Using PointerEvents on browsers that support it 2019-03-07 07:32:07 -05:00
Francisco Hodge 47ddf0b1e8 Build update 2019-03-06 20:26:46 -05:00
17 changed files with 963 additions and 384 deletions
+2 -1
View File
@@ -5,8 +5,9 @@ install:
- npm install -g codecov - npm install -g codecov
- npm install - npm install
script: script:
- npm run test -- --coverage - npm run start -- --testMode
- npm run demo - npm run demo
- npm run test -- --coverage
- codecov - codecov
after_success: after_success:
- wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh - wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh
-1
View File
@@ -6,7 +6,6 @@
<a href="https://travis-ci.org/hodgef/simple-keyboard" target="_blank"><img src="https://travis-ci.org/hodgef/simple-keyboard.svg?branch=master" alt="Build Status"></a> <a href="https://travis-ci.org/hodgef/simple-keyboard" target="_blank"><img src="https://travis-ci.org/hodgef/simple-keyboard.svg?branch=master" alt="Build Status"></a>
<a href="https://codecov.io/gh/hodgef/simple-keyboard" target="_blank"><img src="https://img.shields.io/codecov/c/github/hodgef/simple-keyboard/master.svg?style=flat" alt="Coverage Status"></a> <a href="https://codecov.io/gh/hodgef/simple-keyboard" target="_blank"><img src="https://img.shields.io/codecov/c/github/hodgef/simple-keyboard/master.svg?style=flat" alt="Coverage Status"></a>
<a href="https://doc.esdoc.org/github.com/hodgef/simple-keyboard" target="_blank"><img src="https://doc.esdoc.org/github.com/hodgef/simple-keyboard/badge.svg" alt="Documentation Status"></a> <a href="https://doc.esdoc.org/github.com/hodgef/simple-keyboard" target="_blank"><img src="https://doc.esdoc.org/github.com/hodgef/simple-keyboard/badge.svg" alt="Documentation Status"></a>
<img src="https://img.shields.io/david/dev/hodgef/simple-keyboard.svg" alt="Dev dependencies">
<a href="https://www.codacy.com/app/hodgef/simple-keyboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=hodgef/simple-keyboard&amp;utm_campaign=Badge_Grade" target="_blank"><img src="https://api.codacy.com/project/badge/Grade/5778fccc6a894701853d9a1f2fb44a76" alt="Codacy Badge"></a> <a href="https://www.codacy.com/app/hodgef/simple-keyboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=hodgef/simple-keyboard&amp;utm_campaign=Badge_Grade" target="_blank"><img src="https://api.codacy.com/project/badge/Grade/5778fccc6a894701853d9a1f2fb44a76" alt="Codacy Badge"></a>
</p> </p>
</div> </div>
+2 -2
View File
@@ -1,6 +1,6 @@
/*! /*!
* *
* simple-keyboard v2.16.0 * simple-keyboard v2.20.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)
@@ -8,5 +8,5 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
*/body,html{margin:0;padding:0}.simple-keyboard{font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;width:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;box-sizing:border-box;overflow:hidden;touch-action:manipulation}.simple-keyboard .hg-row{display:-webkit-flex;display:flex}.simple-keyboard .hg-row:not(:last-child){margin-bottom:5px}.simple-keyboard .hg-row .hg-button:not(:last-child){margin-right:5px}.simple-keyboard .hg-button{display:inline-block;-webkit-flex-grow:1;flex-grow:1;cursor:pointer}.simple-keyboard .hg-button span{pointer-events:none}.simple-keyboard.hg-theme-default{background-color:rgba(0,0,0,.1);padding:5px;border-radius:5px}.simple-keyboard.hg-theme-default .hg-button{box-shadow:0 0 3px -1px rgba(0,0,0,.3);height:40px;border-radius:5px;box-sizing:border-box;padding:5px;background:#fff;border-bottom:1px solid #b5b5b5;cursor:pointer;display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center}.simple-keyboard button.hg-button{border-width:0;outline:0;font-size:inherit}.simple-keyboard.hg-theme-default:not(.hg-touch-events) .hg-button:active{background:#e4e4e4}.simple-keyboard.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:flex;-webkit-justify-content:center;justify-content:center}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadadd,.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.simple-keyboard.hg-theme-default .hg-button.hg-button-com{max-width:85px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.simple-keyboard.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px} */body,html{margin:0;padding:0}.simple-keyboard{font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;width:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;box-sizing:border-box;overflow:hidden;touch-action:manipulation}.simple-keyboard .hg-row{display:-webkit-flex;display:flex}.simple-keyboard .hg-row:not(:last-child){margin-bottom:5px}.simple-keyboard .hg-row .hg-button-container,.simple-keyboard .hg-row .hg-button:not(:last-child){margin-right:5px}.simple-keyboard .hg-row>div:last-child{margin-right:0}.simple-keyboard .hg-row .hg-button-container{display:-webkit-flex;display:flex}.simple-keyboard .hg-button{display:inline-block;-webkit-flex-grow:1;flex-grow:1;cursor:pointer}.simple-keyboard .hg-button span{pointer-events:none}.simple-keyboard.hg-theme-default{background-color:rgba(0,0,0,.1);padding:5px;border-radius:5px}.simple-keyboard.hg-theme-default .hg-button{box-shadow:0 0 3px -1px rgba(0,0,0,.3);height:40px;border-radius:5px;box-sizing:border-box;padding:5px;background:#fff;border-bottom:1px solid #b5b5b5;cursor:pointer;display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center}.simple-keyboard button.hg-button{border-width:0;outline:0;font-size:inherit}.simple-keyboard.hg-theme-default:not(.hg-touch-events) .hg-button:active{background:#e4e4e4}.simple-keyboard.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;-webkit-align-items:center;align-items:center;display:-webkit-flex;display:flex;-webkit-justify-content:center;justify-content:center}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadadd,.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.simple-keyboard.hg-theme-default .hg-button.hg-button-com{max-width:85px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.simple-keyboard.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px}
/*# sourceMappingURL=index.css.map */ /*# sourceMappingURL=index.css.map */
File diff suppressed because one or more lines are too long
+14 -1
View File
@@ -1,6 +1,6 @@
/*! /*!
* *
* simple-keyboard v2.16.0 (Non-minified build) * simple-keyboard v2.20.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)
@@ -41,6 +41,19 @@ html {
margin-right: 5px; margin-right: 5px;
} }
.simple-keyboard .hg-row .hg-button-container {
margin-right: 5px;
}
.simple-keyboard .hg-row > div:last-child {
margin-right: 0;
}
.simple-keyboard .hg-row .hg-button-container {
display: -webkit-flex;
display: flex;
}
.simple-keyboard .hg-button { .simple-keyboard .hg-button {
display: inline-block; display: inline-block;
-webkit-flex-grow: 1; -webkit-flex-grow: 1;
+10
View File
@@ -10,6 +10,11 @@ declare module 'simple-keyboard' {
} }
interface KeyboardOptions { interface KeyboardOptions {
/**
* Utilities
*/
utilities?: any;
/** /**
* Modify the keyboard layout. * Modify the keyboard layout.
*/ */
@@ -121,6 +126,11 @@ declare module 'simple-keyboard' {
*/ */
autoUseTouchEvents?: boolean; autoUseTouchEvents?: boolean;
/**
* Opt out of PointerEvents handling, falling back to the prior mouse event logic.
*/
useMouseEvents?: boolean;
/** /**
* Executes the callback function on key press. Returns button layout name (i.e.: "{shift}"). * Executes the callback function on key press. Returns button layout name (i.e.: "{shift}").
*/ */
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+188 -42
View File
@@ -1,6 +1,6 @@
/*! /*!
* *
* simple-keyboard v2.16.0 (Non-minified build) * simple-keyboard v2.20.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)
@@ -660,6 +660,13 @@
return "ontouchstart" in window || navigator.maxTouchPoints; return "ontouchstart" in window || navigator.maxTouchPoints;
} }
/** /**
* Determines whether pointer events are supported
*/ }, {
key: "pointerEventsSupported",
value: function pointerEventsSupported() {
return window.PointerEvent;
}
/**
* Bind all methods in a given class * Bind all methods in a given class
*/ }, { */ }, {
key: "camelCase", key: "camelCase",
@@ -793,15 +800,6 @@
} }
initCallback(_this.modules[name]); initCallback(_this.modules[name]);
}); });
_defineProperty(this, "getModuleProp", function(name, prop) {
if (!_this.modules[name]) {
return false;
}
return _this.modules[name][prop];
});
_defineProperty(this, "getModulesList", function() {
return Object.keys(_this.modules);
});
var keyboardDOMQuery = typeof (arguments.length <= 0 ? undefined : arguments[0]) === "string" ? arguments.length <= 0 ? undefined : arguments[0] : ".simple-keyboard"; var keyboardDOMQuery = typeof (arguments.length <= 0 ? undefined : arguments[0]) === "string" ? arguments.length <= 0 ? undefined : arguments[0] : ".simple-keyboard";
var options = Keyboard_typeof(arguments.length <= 0 ? undefined : arguments[0]) === "object" ? arguments.length <= 0 ? undefined : arguments[0] : arguments.length <= 1 ? undefined : arguments[1]; var options = Keyboard_typeof(arguments.length <= 0 ? undefined : arguments[0]) === "object" ? arguments.length <= 0 ? undefined : arguments[0] : arguments.length <= 1 ? undefined : arguments[1];
if (!options) { if (!options) {
@@ -842,6 +840,7 @@
* @property {object} inputPattern Restrains input(s) change to the defined regular expression pattern. * @property {object} inputPattern Restrains input(s) change to the defined regular expression pattern.
* @property {boolean} useTouchEvents Instructs simple-keyboard to use touch events instead of click events. * @property {boolean} useTouchEvents Instructs simple-keyboard to use touch events instead of click events.
* @property {boolean} autoUseTouchEvents Enable useTouchEvents automatically when touch device is detected. * @property {boolean} autoUseTouchEvents Enable useTouchEvents automatically when touch device is detected.
* @property {boolean} useMouseEvents Opt out of PointerEvents handling, falling back to the prior mouse event logic.
*/ 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";
@@ -941,6 +940,11 @@
*/ } */ }
if (typeof this.options.onChange === "function") { if (typeof this.options.onChange === "function") {
this.options.onChange(this.input[this.options.inputName]); this.options.onChange(this.input[this.options.inputName]);
/**
* Calling onChangeAll
*/ }
if (typeof this.options.onChangeAll === "function") {
this.options.onChangeAll(this.input);
} }
} }
if (debug) { if (debug) {
@@ -954,8 +958,16 @@
value: function handleButtonMouseDown(button, e) { value: function handleButtonMouseDown(button, e) {
var _this2 = this; var _this2 = this;
/** /**
* Handle event options
*/ if (this.options.preventMouseDownDefault) {
e.preventDefault();
}
if (this.options.stopMouseDownPropagation) {
e.stopPropagation();
/**
* @type {boolean} Whether the mouse is being held onKeyPress * @type {boolean} Whether the mouse is being held onKeyPress
*/ this.isMouseHold = true; */ }
this.isMouseHold = true;
if (this.holdInteractionTimeout) { if (this.holdInteractionTimeout) {
clearTimeout(this.holdInteractionTimeout); clearTimeout(this.holdInteractionTimeout);
} }
@@ -1040,7 +1052,7 @@
*/ if (this.options.syncInstanceInputs) { */ if (this.options.syncInstanceInputs) {
this.syncInstanceInputs(this.input); this.syncInstanceInputs(this.input);
} }
return this.input[this.options.inputName]; return this.input[inputName];
} }
/** /**
* Set the keyboards input. * Set the keyboards input.
@@ -1363,6 +1375,20 @@
} }
if (typeof this.options.beforeFirstRender === "function") { if (typeof this.options.beforeFirstRender === "function") {
this.options.beforeFirstRender(); this.options.beforeFirstRender();
/**
* Notify about PointerEvents usage
*/ }
if (this.utilities.pointerEventsSupported() && !this.options.useTouchEvents && !this.options.useMouseEvents) {
if (this.options.debug) {
console.log("Using PointerEvents as it is supported by this browser");
}
}
/**
* Notify about touch events usage
*/ if (this.options.useTouchEvents) {
if (this.options.debug) {
console.log("useTouchEvents has been enabled. Only touch events will be used.");
}
} }
} }
/** /**
@@ -1417,11 +1443,82 @@
/** /**
* Get module prop * Get module prop
*/ }, { */ }, {
key: "render", key: "getModuleProp",
value: function getModuleProp(name, prop) {
if (!this.modules[name]) {
return false;
}
return this.modules[name][prop];
}
/**
* getModulesList
*/ }, {
key: "getModulesList",
value: function getModulesList() {
return Object.keys(this.modules);
}
/**
* Parse Row DOM containers
*/ }, {
key: "parseRowDOMContainers",
value: function parseRowDOMContainers(rowDOM, rowIndex, containerStartIndexes, containerEndIndexes) {
var _this9 = this;
var rowDOMArray = Array.from(rowDOM.children);
var removedElements = 0;
if (rowDOMArray.length) {
containerStartIndexes.forEach(function(startIndex, arrIndex) {
var endIndex = containerEndIndexes[arrIndex];
/**
* If there exists a respective end index
* if end index comes after start index
*/ if (!endIndex || !(endIndex > startIndex)) {
return false;
}
/**
* Updated startIndex, endIndex
* This is since the removal of buttons to place a single button container
* results in a modified array size
*/ var updated_startIndex = startIndex - removedElements;
var updated_endIndex = endIndex - removedElements;
/**
* Create button container
*/ var containerDOM = document.createElement("div");
containerDOM.className += "hg-button-container";
var containerUID = "".concat(_this9.options.layoutName, "-r").concat(rowIndex, "c").concat(arrIndex);
containerDOM.setAttribute("data-skUID", containerUID);
/**
* Taking elements due to be inserted into container
*/ var containedElements = rowDOMArray.splice(updated_startIndex, updated_endIndex - updated_startIndex + 1);
removedElements = updated_endIndex - updated_startIndex;
/**
* Inserting elements to container
*/ containedElements.forEach(function(element) {
return containerDOM.appendChild(element);
});
/**
* Adding container at correct position within rowDOMArray
*/ rowDOMArray.splice(updated_startIndex, 0, containerDOM);
/**
* Clearing old rowDOM children structure
*/ rowDOM.innerHTML = "";
/**
* Appending rowDOM new children list
*/ rowDOMArray.forEach(function(element) {
return rowDOM.appendChild(element);
});
if (_this9.options.debug) {
console.log("rowDOMContainer", containedElements, updated_startIndex, updated_endIndex, removedElements + 1);
}
});
}
return rowDOM;
}
/** /**
* Renders rows and buttons as per options * Renders rows and buttons as per options
*/ value: function render() { */ }, {
var _this9 = this; key: "render",
value: function render() {
var _this10 = this;
/** /**
* Clear keyboard * Clear keyboard
*/ this.clear(); */ this.clear();
@@ -1437,6 +1534,8 @@
var layout = this.options.layout || services_KeyboardLayout.getDefaultLayout(); var layout = this.options.layout || services_KeyboardLayout.getDefaultLayout();
var useTouchEvents = this.options.useTouchEvents || false; var useTouchEvents = this.options.useTouchEvents || false;
var useTouchEventsClass = useTouchEvents ? "hg-touch-events" : ""; var useTouchEventsClass = useTouchEvents ? "hg-touch-events" : "";
var useMouseEvents = this.options.useMouseEvents || false;
var disableRowButtonContainers = this.options.disableRowButtonContainers;
/** /**
* Account for buttonTheme, if set * Account for buttonTheme, if set
*/ var buttonThemesParsed = Array.isArray(this.options.buttonTheme) ? this.getButtonTheme() : {}; */ var buttonThemesParsed = Array.isArray(this.options.buttonTheme) ? this.getButtonTheme() : {};
@@ -1452,38 +1551,82 @@
*/ var rowDOM = document.createElement("div"); */ var rowDOM = document.createElement("div");
rowDOM.className += "hg-row"; rowDOM.className += "hg-row";
/** /**
* Tracking container indicators in rows
*/ var containerStartIndexes = [];
var containerEndIndexes = [];
/**
* Iterating through each button in row * Iterating through each button in row
*/ rowArray.forEach(function(button, bIndex) { */ rowArray.forEach(function(button, bIndex) {
var fctBtnClass = _this9.utilities.getButtonClass(button); /**
* Check if button has a container indicator
*/ var buttonHasContainerStart = !disableRowButtonContainers && button.includes("[") && button.length > 1;
var buttonHasContainerEnd = !disableRowButtonContainers && button.includes("]") && button.length > 1;
/**
* Save container start index, if applicable
*/ if (buttonHasContainerStart) {
containerStartIndexes.push(bIndex);
/**
* Removing indicator
*/ button = button.replace(/\[/g, "");
}
if (buttonHasContainerEnd) {
containerEndIndexes.push(bIndex);
/**
* Removing indicator
*/ button = button.replace(/\]/g, "");
}
/**
* Processing button options
*/ var fctBtnClass = _this10.utilities.getButtonClass(button);
var buttonThemeClass = buttonThemesParsed[button]; var buttonThemeClass = buttonThemesParsed[button];
var buttonDisplayName = _this9.utilities.getButtonDisplayName(button, _this9.options.display, _this9.options.mergeDisplay); var buttonDisplayName = _this10.utilities.getButtonDisplayName(button, _this10.options.display, _this10.options.mergeDisplay);
/** /**
* Creating button * Creating button
*/ var buttonType = _this9.options.useButtonTag ? "button" : "div"; */ var buttonType = _this10.options.useButtonTag ? "button" : "div";
var buttonDOM = document.createElement(buttonType); var buttonDOM = document.createElement(buttonType);
buttonDOM.className += "hg-button ".concat(fctBtnClass).concat(buttonThemeClass ? " " + buttonThemeClass : ""); buttonDOM.className += "hg-button ".concat(fctBtnClass).concat(buttonThemeClass ? " " + buttonThemeClass : "");
if (useTouchEvents) { /**
buttonDOM.ontouchstart = function(e) { * Handle button click event
_this9.handleButtonClicked(button); */ /* istanbul ignore next */ if (_this10.utilities.pointerEventsSupported() && !useTouchEvents && !useMouseEvents) {
_this9.handleButtonMouseDown(button, e); /**
* Handle PointerEvents
*/ buttonDOM.onpointerdown = function(e) {
_this10.handleButtonClicked(button);
_this10.handleButtonMouseDown(button, e);
}; };
buttonDOM.ontouchend = function(e) { buttonDOM.onpointerup = function(e) {
return _this9.handleButtonMouseUp(); _this10.handleButtonMouseUp();
}; };
buttonDOM.ontouchcancel = function(e) { buttonDOM.onpointercancel = function(e) {
return _this9.handleButtonMouseUp(); return _this10.handleButtonMouseUp();
}; };
} else { } else {
buttonDOM.onclick = function() { /**
_this9.isMouseHold = false; * Fallback for browsers not supporting PointerEvents
_this9.handleButtonClicked(button); */ if (useTouchEvents) {
}; /**
buttonDOM.onmousedown = function(e) { * Handle touch events
if (_this9.options.preventMouseDownDefault) { */ buttonDOM.ontouchstart = function(e) {
e.preventDefault(); _this10.handleButtonClicked(button);
} _this10.handleButtonMouseDown(button, e);
_this9.handleButtonMouseDown(button, e); };
}; buttonDOM.ontouchend = function(e) {
return _this10.handleButtonMouseUp();
};
buttonDOM.ontouchcancel = function(e) {
return _this10.handleButtonMouseUp();
};
} else {
/**
* Handle mouse events
*/ buttonDOM.onclick = function() {
_this10.isMouseHold = false;
_this10.handleButtonClicked(button);
};
buttonDOM.onmousedown = function(e) {
_this10.handleButtonMouseDown(button, e);
};
}
} }
/** /**
* Adding identifier * Adding identifier
@@ -1491,7 +1634,7 @@
/** /**
* Adding unique id * Adding unique id
* Since there's no limit on spawning same buttons, the unique id ensures you can style every button * Since there's no limit on spawning same buttons, the unique id ensures you can style every button
*/ var buttonUID = "".concat(_this9.options.layoutName, "-r").concat(rIndex, "b").concat(bIndex); */ var buttonUID = "".concat(_this10.options.layoutName, "-r").concat(rIndex, "b").concat(bIndex);
buttonDOM.setAttribute("data-skBtnUID", buttonUID); buttonDOM.setAttribute("data-skBtnUID", buttonUID);
/** /**
* Adding display label * Adding display label
@@ -1503,17 +1646,20 @@
buttonDOM.appendChild(buttonSpanDOM); buttonDOM.appendChild(buttonSpanDOM);
/** /**
* Adding to buttonElements * Adding to buttonElements
*/ if (!_this9.buttonElements[button]) { */ if (!_this10.buttonElements[button]) {
_this9.buttonElements[button] = []; _this10.buttonElements[button] = [];
} }
_this9.buttonElements[button].push(buttonDOM); _this10.buttonElements[button].push(buttonDOM);
/** /**
* Appending button to row * Appending button to row
*/ rowDOM.appendChild(buttonDOM); */ rowDOM.appendChild(buttonDOM);
}); });
/** /**
* Parse containers in row
*/ rowDOM = _this10.parseRowDOMContainers(rowDOM, rIndex, containerStartIndexes, containerEndIndexes);
/**
* Appending row to keyboard * Appending row to keyboard
*/ _this9.keyboardDOM.appendChild(rowDOM); */ _this10.keyboardDOM.appendChild(rowDOM);
}); });
/** /**
* Calling onRender * Calling onRender
@@ -1526,7 +1672,7 @@
* Handling mouseup * Handling mouseup
*/ if (!useTouchEvents) { */ if (!useTouchEvents) {
document.onmouseup = function() { document.onmouseup = function() {
return _this9.handleButtonMouseUp(); return _this10.handleButtonMouseUp();
}; };
} }
/** /**
+322 -303
View File
File diff suppressed because it is too large Load Diff
+11 -11
View File
@@ -1,6 +1,6 @@
{ {
"name": "simple-keyboard", "name": "simple-keyboard",
"version": "2.16.0", "version": "2.20.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",
@@ -50,19 +50,19 @@
"babel-jest": "23.6.0", "babel-jest": "23.6.0",
"babel-loader": "8.0.5", "babel-loader": "8.0.5",
"babel-plugin-named-asset-import": "^0.3.1", "babel-plugin-named-asset-import": "^0.3.1",
"babel-preset-react-app": "^7.0.1", "babel-preset-react-app": "^7.0.2",
"bfj": "6.1.1", "bfj": "6.1.1",
"case-sensitive-paths-webpack-plugin": "2.2.0", "case-sensitive-paths-webpack-plugin": "2.2.0",
"chalk": "2.4.2", "chalk": "2.4.2",
"copy-webpack-plugin": "^5.0.0", "copy-webpack-plugin": "^5.0.0",
"css-loader": "2.1.0", "css-loader": "2.1.1",
"dotenv": "6.2.0", "dotenv": "6.2.0",
"dotenv-expand": "4.2.0", "dotenv-expand": "4.2.0",
"esdoc": "^1.1.0", "esdoc": "^1.1.0",
"esdoc-ecmascript-proposal-plugin": "^1.0.0", "esdoc-ecmascript-proposal-plugin": "^1.0.0",
"esdoc-standard-plugin": "^1.0.0", "esdoc-standard-plugin": "^1.0.0",
"eslint": "5.15.0", "eslint": "5.15.1",
"eslint-config-react-app": "^3.0.7", "eslint-config-react-app": "^3.0.8",
"eslint-loader": "2.1.2", "eslint-loader": "2.1.2",
"eslint-plugin-flowtype": "3.4.2", "eslint-plugin-flowtype": "3.4.2",
"eslint-plugin-import": "2.16.0", "eslint-plugin-import": "2.16.0",
@@ -78,17 +78,17 @@
"jest-resolve": "23.6.0", "jest-resolve": "23.6.0",
"mini-css-extract-plugin": "0.5.0", "mini-css-extract-plugin": "0.5.0",
"optimize-css-assets-webpack-plugin": "5.0.1", "optimize-css-assets-webpack-plugin": "5.0.1",
"pnp-webpack-plugin": "1.3.1", "pnp-webpack-plugin": "1.4.1",
"postcss-flexbugs-fixes": "4.1.0", "postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0", "postcss-loader": "3.0.0",
"postcss-preset-env": "6.6.0", "postcss-preset-env": "6.6.0",
"postcss-safe-parser": "4.0.1", "postcss-safe-parser": "4.0.1",
"prettier": "^1.16.4", "prettier": "^1.16.4",
"prettier-webpack-plugin": "^1.2.0", "prettier-webpack-plugin": "^1.2.0",
"react": "^16.8.3", "react": "^16.8.4",
"react-app-polyfill": "^0.2.1", "react-app-polyfill": "^0.2.2",
"react-dev-utils": "^7.0.3", "react-dev-utils": "^7.0.5",
"react-dom": "^16.8.3", "react-dom": "^16.8.4",
"resolve": "1.10.0", "resolve": "1.10.0",
"sass-loader": "7.1.0", "sass-loader": "7.1.0",
"style-loader": "0.23.1", "style-loader": "0.23.1",
@@ -98,7 +98,7 @@
"webpack": "4.29.6", "webpack": "4.29.6",
"webpack-dev-server": "3.2.1", "webpack-dev-server": "3.2.1",
"webpack-manifest-plugin": "2.0.4", "webpack-manifest-plugin": "2.0.4",
"workbox-webpack-plugin": "4.0.0" "workbox-webpack-plugin": "4.1.0"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app", "extends": "react-app",
+22
View File
@@ -75,6 +75,8 @@ checkBrowsers(paths.appPath, isInteractive)
// We have not found a port. // We have not found a port.
return; return;
} }
const args = process.argv;
const testMode = args[2] === "--testMode";
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name; const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port); const urls = prepareUrls(protocol, HOST, port);
@@ -99,6 +101,26 @@ checkBrowsers(paths.appPath, isInteractive)
} }
console.log(chalk.cyan('Starting the development server...\n')); console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser); openBrowser(urls.localUrlForBrowser);
/**
* Handle testMode
*/
if(testMode){
compiler.plugin('done', (stats) => {
stats = stats.toJson();
if (stats.errors && stats.errors.length > 0) {
return;
}
console.warn("App started in test mode. Closing in 5 seconds.");
let closeTimeout = setTimeout(() => {
clearTimeout(closeTimeout);
devServer.close();
process.exit();
}, 5000);
});
}
}); });
['SIGINT', 'SIGTERM'].forEach(function(sig) { ['SIGINT', 'SIGTERM'].forEach(function(sig) {
+10
View File
@@ -10,6 +10,11 @@ declare module 'simple-keyboard' {
} }
interface KeyboardOptions { interface KeyboardOptions {
/**
* Utilities
*/
utilities?: any;
/** /**
* Modify the keyboard layout. * Modify the keyboard layout.
*/ */
@@ -121,6 +126,11 @@ declare module 'simple-keyboard' {
*/ */
autoUseTouchEvents?: boolean; autoUseTouchEvents?: boolean;
/**
* Opt out of PointerEvents handling, falling back to the prior mouse event logic.
*/
useMouseEvents?: boolean;
/** /**
* Executes the callback function on key press. Returns button layout name (i.e.: "{shift}"). * Executes the callback function on key press. Returns button layout name (i.e.: "{shift}").
*/ */
+12
View File
@@ -26,6 +26,18 @@ html {
margin-right: 5px; margin-right: 5px;
} }
.simple-keyboard .hg-row .hg-button-container {
margin-right: 5px;
}
.simple-keyboard .hg-row > div:last-child {
margin-right: 0;
}
.simple-keyboard .hg-row .hg-button-container {
display: flex;
}
.simple-keyboard .hg-button { .simple-keyboard .hg-button {
display: inline-block; display: inline-block;
flex-grow: 1; flex-grow: 1;
+224 -17
View File
@@ -63,6 +63,7 @@ class SimpleKeyboard {
* @property {object} inputPattern Restrains input(s) change to the defined regular expression pattern. * @property {object} inputPattern Restrains input(s) change to the defined regular expression pattern.
* @property {boolean} useTouchEvents Instructs simple-keyboard to use touch events instead of click events. * @property {boolean} useTouchEvents Instructs simple-keyboard to use touch events instead of click events.
* @property {boolean} autoUseTouchEvents Enable useTouchEvents automatically when touch device is detected. * @property {boolean} autoUseTouchEvents Enable useTouchEvents automatically when touch device is detected.
* @property {boolean} useMouseEvents Opt out of PointerEvents handling, falling back to the prior mouse event logic.
*/ */
this.options = options; this.options = options;
this.options.layoutName = this.options.layoutName || "default"; this.options.layoutName = this.options.layoutName || "default";
@@ -207,6 +208,12 @@ class SimpleKeyboard {
*/ */
if (typeof this.options.onChange === "function") if (typeof this.options.onChange === "function")
this.options.onChange(this.input[this.options.inputName]); this.options.onChange(this.input[this.options.inputName]);
/**
* Calling onChangeAll
*/
if (typeof this.options.onChangeAll === "function")
this.options.onChangeAll(this.input);
} }
if (debug) { if (debug) {
@@ -219,6 +226,12 @@ class SimpleKeyboard {
*/ */
/* istanbul ignore next */ /* istanbul ignore next */
handleButtonMouseDown(button, e) { handleButtonMouseDown(button, e) {
/**
* Handle event options
*/
if (this.options.preventMouseDownDefault) e.preventDefault();
if (this.options.stopMouseDownPropagation) e.stopPropagation();
/** /**
* @type {boolean} Whether the mouse is being held onKeyPress * @type {boolean} Whether the mouse is being held onKeyPress
*/ */
@@ -312,7 +325,7 @@ class SimpleKeyboard {
*/ */
if (this.options.syncInstanceInputs) this.syncInstanceInputs(this.input); if (this.options.syncInstanceInputs) this.syncInstanceInputs(this.input);
return this.input[this.options.inputName]; return this.input[inputName];
} }
/** /**
@@ -717,6 +730,30 @@ class SimpleKeyboard {
if (typeof this.options.beforeFirstRender === "function") if (typeof this.options.beforeFirstRender === "function")
this.options.beforeFirstRender(); this.options.beforeFirstRender();
/**
* Notify about PointerEvents usage
*/
if (
this.utilities.pointerEventsSupported() &&
!this.options.useTouchEvents &&
!this.options.useMouseEvents
) {
if (this.options.debug) {
console.log("Using PointerEvents as it is supported by this browser");
}
}
/**
* Notify about touch events usage
*/
if (this.options.useTouchEvents) {
if (this.options.debug) {
console.log(
"useTouchEvents has been enabled. Only touch events will be used."
);
}
}
} }
/** /**
@@ -782,18 +819,104 @@ class SimpleKeyboard {
/** /**
* Get module prop * Get module prop
*/ */
getModuleProp = (name, prop) => { getModuleProp(name, prop) {
if (!this.modules[name]) return false; if (!this.modules[name]) return false;
return this.modules[name][prop]; return this.modules[name][prop];
}; }
/** /**
* getModulesList * getModulesList
*/ */
getModulesList = () => { getModulesList() {
return Object.keys(this.modules); return Object.keys(this.modules);
}; }
/**
* Parse Row DOM containers
*/
parseRowDOMContainers(
rowDOM,
rowIndex,
containerStartIndexes,
containerEndIndexes
) {
let rowDOMArray = Array.from(rowDOM.children);
let removedElements = 0;
if (rowDOMArray.length) {
containerStartIndexes.forEach((startIndex, arrIndex) => {
let endIndex = containerEndIndexes[arrIndex];
/**
* If there exists a respective end index
* if end index comes after start index
*/
if (!endIndex || !(endIndex > startIndex)) {
return false;
}
/**
* Updated startIndex, endIndex
* This is since the removal of buttons to place a single button container
* results in a modified array size
*/
let updated_startIndex = startIndex - removedElements;
let updated_endIndex = endIndex - removedElements;
/**
* Create button container
*/
let containerDOM = document.createElement("div");
containerDOM.className += "hg-button-container";
let containerUID = `${
this.options.layoutName
}-r${rowIndex}c${arrIndex}`;
containerDOM.setAttribute("data-skUID", containerUID);
/**
* Taking elements due to be inserted into container
*/
let containedElements = rowDOMArray.splice(
updated_startIndex,
updated_endIndex - updated_startIndex + 1
);
removedElements = updated_endIndex - updated_startIndex;
/**
* Inserting elements to container
*/
containedElements.forEach(element => containerDOM.appendChild(element));
/**
* Adding container at correct position within rowDOMArray
*/
rowDOMArray.splice(updated_startIndex, 0, containerDOM);
/**
* Clearing old rowDOM children structure
*/
rowDOM.innerHTML = "";
/**
* Appending rowDOM new children list
*/
rowDOMArray.forEach(element => rowDOM.appendChild(element));
if (this.options.debug) {
console.log(
"rowDOMContainer",
containedElements,
updated_startIndex,
updated_endIndex,
removedElements + 1
);
}
});
}
return rowDOM;
}
/** /**
* Renders rows and buttons as per options * Renders rows and buttons as per options
@@ -820,6 +943,8 @@ class SimpleKeyboard {
let layout = this.options.layout || KeyboardLayout.getDefaultLayout(); let layout = this.options.layout || KeyboardLayout.getDefaultLayout();
let useTouchEvents = this.options.useTouchEvents || false; let useTouchEvents = this.options.useTouchEvents || false;
let useTouchEventsClass = useTouchEvents ? "hg-touch-events" : ""; let useTouchEventsClass = useTouchEvents ? "hg-touch-events" : "";
let useMouseEvents = this.options.useMouseEvents || false;
let disableRowButtonContainers = this.options.disableRowButtonContainers;
/** /**
* Account for buttonTheme, if set * Account for buttonTheme, if set
@@ -847,10 +972,52 @@ class SimpleKeyboard {
let rowDOM = document.createElement("div"); let rowDOM = document.createElement("div");
rowDOM.className += "hg-row"; rowDOM.className += "hg-row";
/**
* Tracking container indicators in rows
*/
let containerStartIndexes = [];
let containerEndIndexes = [];
/** /**
* Iterating through each button in row * Iterating through each button in row
*/ */
rowArray.forEach((button, bIndex) => { rowArray.forEach((button, bIndex) => {
/**
* Check if button has a container indicator
*/
let buttonHasContainerStart =
!disableRowButtonContainers &&
button.includes("[") &&
button.length > 1;
let buttonHasContainerEnd =
!disableRowButtonContainers &&
button.includes("]") &&
button.length > 1;
/**
* Save container start index, if applicable
*/
if (buttonHasContainerStart) {
containerStartIndexes.push(bIndex);
/**
* Removing indicator
*/
button = button.replace(/\[/g, "");
}
if (buttonHasContainerEnd) {
containerEndIndexes.push(bIndex);
/**
* Removing indicator
*/
button = button.replace(/\]/g, "");
}
/**
* Processing button options
*/
let fctBtnClass = this.utilities.getButtonClass(button); let fctBtnClass = this.utilities.getButtonClass(button);
let buttonThemeClass = buttonThemesParsed[button]; let buttonThemeClass = buttonThemesParsed[button];
let buttonDisplayName = this.utilities.getButtonDisplayName( let buttonDisplayName = this.utilities.getButtonDisplayName(
@@ -868,22 +1035,52 @@ class SimpleKeyboard {
buttonThemeClass ? " " + buttonThemeClass : "" buttonThemeClass ? " " + buttonThemeClass : ""
}`; }`;
if (useTouchEvents) { /**
buttonDOM.ontouchstart = e => { * Handle button click event
*/
/* istanbul ignore next */
if (
this.utilities.pointerEventsSupported() &&
!useTouchEvents &&
!useMouseEvents
) {
/**
* Handle PointerEvents
*/
buttonDOM.onpointerdown = e => {
this.handleButtonClicked(button); this.handleButtonClicked(button);
this.handleButtonMouseDown(button, e); this.handleButtonMouseDown(button, e);
}; };
buttonDOM.ontouchend = e => this.handleButtonMouseUp(); buttonDOM.onpointerup = e => {
buttonDOM.ontouchcancel = e => this.handleButtonMouseUp(); this.handleButtonMouseUp();
};
buttonDOM.onpointercancel = e => this.handleButtonMouseUp();
} else { } else {
buttonDOM.onclick = () => { /**
this.isMouseHold = false; * Fallback for browsers not supporting PointerEvents
this.handleButtonClicked(button); */
}; if (useTouchEvents) {
buttonDOM.onmousedown = e => { /**
if (this.options.preventMouseDownDefault) e.preventDefault(); * Handle touch events
this.handleButtonMouseDown(button, e); */
}; buttonDOM.ontouchstart = e => {
this.handleButtonClicked(button);
this.handleButtonMouseDown(button, e);
};
buttonDOM.ontouchend = e => this.handleButtonMouseUp();
buttonDOM.ontouchcancel = e => this.handleButtonMouseUp();
} else {
/**
* Handle mouse events
*/
buttonDOM.onclick = () => {
this.isMouseHold = false;
this.handleButtonClicked(button);
};
buttonDOM.onmousedown = e => {
this.handleButtonMouseDown(button, e);
};
}
} }
/** /**
@@ -923,6 +1120,16 @@ class SimpleKeyboard {
rowDOM.appendChild(buttonDOM); rowDOM.appendChild(buttonDOM);
}); });
/**
* Parse containers in row
*/
rowDOM = this.parseRowDOMContainers(
rowDOM,
rIndex,
containerStartIndexes,
containerEndIndexes
);
/** /**
* Appending row to keyboard * Appending row to keyboard
*/ */
+135 -2
View File
@@ -186,6 +186,22 @@ it('Keyboard onChange will work', () => {
expect(output).toBe("q"); expect(output).toBe("q");
}); });
it('Keyboard onChangeAll will work', () => {
testUtil.setDOM();
let output;
let keyboard = new Keyboard({
onChangeAll: (input) => {
output = input ? input.default : null;
}
});
keyboard.getButtonElement("q").onclick();
expect(output).toBe("q");
});
it('Keyboard clearInput will work', () => { it('Keyboard clearInput will work', () => {
testUtil.setDOM(); testUtil.setDOM();
@@ -884,7 +900,9 @@ it('Keyboard handleButtonMouseDown will work', () => {
let keyboard = new Keyboard(); let keyboard = new Keyboard();
keyboard.handleButtonMouseDown("q", { keyboard.handleButtonMouseDown("q", {
target: keyboard.getButtonElement("q") target: keyboard.getButtonElement("q"),
preventDefault: () => {},
stopPropagation: () => {}
}); });
var clickEvent = document.createEvent('MouseEvents'); var clickEvent = document.createEvent('MouseEvents');
@@ -902,7 +920,9 @@ it('Keyboard handleButtonMouseDown will work with preventMouseDownDefault', () =
keyboard.options.preventMouseDownDefault = true; keyboard.options.preventMouseDownDefault = true;
keyboard.handleButtonMouseDown("q", { keyboard.handleButtonMouseDown("q", {
target: keyboard.getButtonElement("q") target: keyboard.getButtonElement("q"),
preventDefault: () => {},
stopPropagation: () => {}
}); });
var clickEvent = document.createEvent('MouseEvents'); var clickEvent = document.createEvent('MouseEvents');
@@ -1023,6 +1043,23 @@ it('Keyboard beforeFirstRender method will work', () => {
expect(timesCalled).toBe(1); expect(timesCalled).toBe(1);
}); });
it('Keyboard beforeFirstRender will show PointerEvents warning', () => {
testUtil.setDOM();
let timesCalled = 0;
window.PointerEvent = window.PointerEvent ? window.PointerEvent : () => {};
let keyboard = new Keyboard({
debug: true,
beforeFirstRender: () => {
timesCalled++;
}
});
expect(timesCalled).toBe(1);
});
it('Keyboard beforeRender method will work', () => { it('Keyboard beforeRender method will work', () => {
testUtil.setDOM(); testUtil.setDOM();
@@ -1042,4 +1079,100 @@ it('Keyboard beforeRender method will work', () => {
}); });
expect(timesCalled).toBe(2); expect(timesCalled).toBe(2);
});
it('Keyboard parseRowDOMContainers will work', () => {
testUtil.setDOM();
let keyboard = new Keyboard({
layout: {
'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} {arrowleft} [{arrowup} {arrowdown}] {arrowright}'
],
'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}'
]
}
});
let containers = Array.from(document.querySelectorAll(".hg-button-container"));
expect(containers.length).toBe(5);
keyboard.setOptions({
debug: true
});
expect(containers.length).toBe(5);
});
it('Keyboard parseRowDOMContainers will ignore empty rows', () => {
testUtil.setDOM();
let failed = false;
try {
let keyboard = new Keyboard();
keyboard.parseRowDOMContainers({
children: []
});
} catch (e) {
failed = true;
}
expect(failed).toBeFalsy();
});
it('Keyboard parseRowDOMContainers will ignore missing endIndex or endIndex before startIndex', () => {
testUtil.setDOM();
let keyboard = new Keyboard({
layout: {
'default': [
'` [1 2 3 4 5 6 7 8 9 0 - = {bksp}',
'` 1 2 3] 4 5 6 7 8 9 [0 - = {bksp}',
]
}
});
let containers = Array.from(document.querySelectorAll(".hg-button-container"));
expect(containers.length).toBe(0);
});
it('Keyboard disableRowButtonContainers will bypass parseRowDOMContainers', () => {
testUtil.setDOM();
let keyboard = new Keyboard({
disableRowButtonContainers: true,
layout: {
'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} {arrowleft} [{arrowup} {arrowdown}] {arrowright}'
],
'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}'
]
}
});
let containers = Array.from(document.querySelectorAll(".hg-button-container"));
expect(containers.length).toBe(0);
}); });
+7
View File
@@ -372,6 +372,13 @@ class Utilities {
return "ontouchstart" in window || navigator.maxTouchPoints; return "ontouchstart" in window || navigator.maxTouchPoints;
} }
/**
* Determines whether pointer events are supported
*/
pointerEventsSupported() {
return window.PointerEvent;
}
/** /**
* Bind all methods in a given class * Bind all methods in a given class
*/ */