Commit 3a8a3a99 authored by Wen Wei Li's avatar Wen Wei Li

modify the v_keyboard

parent 9801126e
...@@ -2,24 +2,58 @@ from flask import Flask,request,render_template,jsonify,redirect, url_for, sessi ...@@ -2,24 +2,58 @@ from flask import Flask,request,render_template,jsonify,redirect, url_for, sessi
import json import json
import os import os
import requests import requests
from wifi import Cell,Scheme
from wireless import Wireless
from flask_bootstrap import Bootstrap from flask_bootstrap import Bootstrap
app = Flask(__name__) app = Flask(__name__)
bootstrap = Bootstrap(app) bootstrap = Bootstrap(app)
recent_dir = os.path.abspath(os.path.dirname(__file__)) recent_dir = os.path.abspath(os.path.dirname(__file__))
wifi_list = []
wifi_name_list = []
def wifi_scan():
wireless = Wireless()
cells = Cell.all('wlan0')
for cell in cells:
wifi_list.append(cell)
wifi_name_list.append(cell.ssid)
def is_encrypted(ssid):
for i in wifi_list:
if i.ssid==ssid:
return i.encrypted
return None
def connect_wifi(ssid, password):
ret = wireless.connect(ssid,password)
if ret == False:
print("Error : Cannot Connect to Wifi {}".format(ssid))
else:
print("Success")
#
@app.route('/') @app.route('/')
def main(): def main():
return render_template('demo.html') return render_template('demo.html')
@app.route('/initial')
def initial():
return 'HTTP OK'
@app.route('/wifi_configure') @app.route('/wifi_configure')
def wifi_configure(): def wifi_configure():
return 'HTTP OK' wifi_scan()
return render_template('wifi.html', data=wifi_name_list)
@app.route('/wifi_pass') @app.route('/wifi_pass')
def wifi_pass(): def wifi_pass():
return render_template('index.html')
if __name__ == '__main__': if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True) app.run(host='0.0.0.0', port=8080, debug=True)
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="#111">
<path d="M7.4 4.4V2.5c0-1.4-1.1-2.5-2.5-2.5c-1.4 0-2.5 1.1-2.5 2.5v1.9 c-0.7 0-1.2 0.5-1.2 1.2v3.1C1.3 9.4 1.8 10 2.5 10h4.9c0.7 0 1.2-0.6 1.2-1.2V5.6 C8.7 4.9 8.1 4.4 7.4 4.4z M5.3 7.4v1.0c0 0.2-0.1 0.3-0.3 0.3c-0.2 0-0.3-0.1-0.3-0.3V7.4 c-0.2-0.1-0.3-0.3-0.3-0.5c0-0.3 0.3-0.6 0.6-0.6c0.3 0 0.6 0.3 0.6 0.6 C5.6 7.1 5.5 7.3 5.3 7.4z M6.2 4.4H3.7V2.5c0-0.7 0.5-1.2 1.2-1.2c0.7 0 1.2 0.6 1.2 1.2 V4.4z"/>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="#111">
<path d="M8.7,4.4H7.5H5.0v-1.9c0-1.4-1.1-2.5-2.5-2.5c-1.4,0-2.5,1.1-2.5,2.5v1.9h1.2 v-1.9c0-0.7,0.6-1.2,1.2-1.2s1.2,0.6,1.2,1.2v1.9c-0.7,0-1.2,0.6-1.2,1.2V8.8 c0,0.7,0.6,1.2,1.2,1.2h5.0C9.4,10,10,9.4,10,8.8V5.6C10,5.0,9.4,4.4,8.8,4.4z M6.6,7.4v1.0 c0,0.2-0.1,0.3-0.3,0.3S6.0,8.6,6.0,8.4V7.4c-0.2-0.1-0.3-0.3-0.3-0.5c0-0.3,0.3-0.6,0.6-0.6 S6.9,6.6,6.9,6.9C6.9,7.1,6.8,7.3,6.6,7.4z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill:#888">
<g>
<path style="fill:none;stroke:#888" d="M 0.5,4.5 15.5,4.5 15.5,15.5 0.5,15.5 Z"></path>
<rect width="2" height="2" x="2" y="6"></rect>
<rect width="2" height="2" x="5" y="6"></rect>
<rect width="2" height="2" x="8" y="6"></rect>
<path d="m 11,6 3,0 0,5 -2,0 0,-3 -1,0 z"></path>
<rect width="2" height="2" x="12" y="12"></rect>
<rect width="6" height="2" x="5" y="12"></rect>
<rect width="2" height="2" x="9" y="9"></rect>
<rect width="2" height="2" x="6" y="9"></rect>
<rect width="2" height="2" x="2" y="12"></rect>
<rect width="3" height="2" x="2" y="9"></rect>
</g>
</svg>
\ No newline at end of file
/* *** keyboard light theme ***
for when jQuery UI themes are not being used
See https://jsfiddle.net/Mottie/jsh0377k/
*/
.ui-keyboard {
/* adjust overall keyboard size using "font-size" */
font-size: 14px;
text-align: center;
background: #fefefe;
border: 1px solid #aaa;
padding: 4px;
/* include the following setting to place the
keyboard at the bottom of the browser window */
width: 100%;
height: auto;
left: 0px;
top: auto;
bottom: 0px;
position: fixed;
white-space: nowrap;
overflow-x: auto;
/* see issue #484 */
-ms-touch-action: manipulation;
touch-action: manipulation;
}
.ui-keyboard-has-focus {
z-index: 16001;
}
.ui-keyboard-button {
border: 1px solid #aaa;
padding: 0 0.5em;
margin: 1px;
min-width: 3em;
height: 3em;
line-height: 3em;
vertical-align: top;
font-family: Helvetica, Arial, sans-serif;
color: #333;
text-align: center;
border-radius: 5px;
-webkit-box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
background: white;
background-image: -webkit-linear-gradient(-90deg, white 0%, #e3e3e3 100%);
background-image: linear-gradient(-90deg, white 0%, #e3e3e3 100%);
cursor: pointer;
overflow: hidden;
-moz-user-focus: ignore;
}
.ui-keyboard-button:not([disabled]):hover {
background: #eee;
background-image: -webkit-linear-gradient(-90deg, #f2f2f2 0%, #d3d3d3 100%);
background-image: linear-gradient(-90deg, #f2f2f2 0%, #d3d3d3 100%);
}
.ui-keyboard-button:not([disabled]):active {
background: #ddd;
background-image: -webkit-linear-gradient(-90deg, #e5e5e5 0%, #d3d3d3 100%);
background-image: linear-gradient(-90deg, #e5e5e5 0%, #d3d3d3 100%);
}
.ui-keyboard-button span {
display: block;
width: 100%;
font-size: 1.2em;
text-align: center;
}
/* make action keys extra-wide */
.ui-keyboard-actionkey:not(.ui-keyboard-dec):not(.ui-keyboard-combo) {
min-width: 6em;
}
.ui-keyboard-space {
width: 15em;
}
.ui-keyboard-actionkey:not(.ui-keyboard-dec):not(.ui-keyboard-combo) span {
font-size: 0.8em;
position: relative;
top: -1em;
left: -1.6em;
}
.ui-keyboard-placeholder {
color: #888;
}
/* disabled or readonly inputs, or use input[disabled='disabled'] { color: #f00; } */
.ui-keyboard-nokeyboard {
color: #888;
border-color: #888;
}
.ui-keyboard-spacer {
display: inline-block;
width: 1px;
height: 0;
cursor: default;
}
.ui-keyboard-NBSP span, .ui-keyboard-ZWSP span, .ui-keyboard-ZWNJ span, .ui-keyboard-ZWJ span,
.ui-keyboard-LRM span, .ui-keyboard-RLM span {
font-size: 0.5em;
line-height: 1.5em;
white-space: normal;
}
/* combo key styling - toggles diacritics on/off */
.ui-keyboard-button.ui-keyboard-combo.ui-state-default {
-webkit-box-shadow: 1px 1px 3px 0 rgba(213, 133, 18, 0.5);
box-shadow: 1px 1px 3px 0 rgba(213, 133, 18, 0.5);
border-color: #d58512;
}
.ui-keyboard-button.ui-keyboard-combo.ui-state-active {
-webkit-box-shadow: 1px 1px 3px 0 rgba(38, 154, 188, 0.5);
box-shadow: 1px 1px 3px 0 rgba(38, 154, 188, 0.5);
border-color: #269abc;
}
/* (in)valid inputs */
button.ui-keyboard-accept.ui-keyboard-valid-input {
-webkit-box-shadow: 1px 1px 3px 0 rgba(57, 132, 57, 0.5);
box-shadow: 1px 1px 3px 0 rgba(57, 132, 57, 0.5);
border-color: #398439;
}
button.ui-keyboard-accept.ui-keyboard-valid-input:not([disabled]):hover {
border-color: #4cae4c;
}
button.ui-keyboard-accept.ui-keyboard-invalid-input {
-webkit-box-shadow: 1px 1px 3px 0 rgba(172, 41, 37, 0.5);
box-shadow: 1px 1px 3px 0 rgba(172, 41, 37, 0.5);
border-color: #ac2925;
}
button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover {
border-color: #d43f3a;
}
/* unlocked icon (keyboard enabled) */
button.ui-keyboard-toggle span {
width: .9em;
height: .9em;
display: inline-block;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
/* light theme unlocked icon - fill: #111 */
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==');
}
/* locked icon (keyboard disabled) */
button.ui-keyboard-toggle.ui-keyboard-disabled span {
/* light theme locked icon - fill: #111 */
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=');
}
.ui-keyboard.ui-keyboard-disabled button:not(.ui-keyboard-toggle), .ui-keyboard.ui-keyboard-disabled input {
opacity: 0.5;
}
/*** Alt-Keys Popup extension ***/
/* clickable overlay on top of keyboard to hide the popup */
.ui-keyboard-overlay {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: rgba(238, 238, 238, 0.5);
}
/* the actual popup styling, class names from the css.container option are also added */
.ui-keyboard-popup {
display: inline-block;
/* default buttons are 2em wide + .1em margin on either side (set in .ui-keyboard-button definition);
so use multiples of 2.2em for a max-width if you don't want any extra white space on the sides,
e.g. 5 buttons * 2.2em = 11em, 6 buttons * 2.2em = 13.2em, etc */
max-width: 22em;
/* 10 buttons */
}
.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button {
/* Disable keys under overlay while popup is open - see #654 */
pointer-events: none;
}
/*** Caret extension definition ***/
/* margin-top => is added to the caret height (top & bottom) */
.ui-keyboard-caret {
background: #c00;
width: 1px;
margin-top: 3px;
}
/*** Extender keyboard extension ***/
div.ui-keyboard-extender {
margin-left: 5px;
margin-right: 10px;
}
button.ui-keyboard-extender span {
width: .9em;
height: .9em;
display: inline-block;
margin-bottom: 3px;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
/* light theme extender icon - fill: #111 */
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6IzExMSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzExMSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+');
}
/* *** keyboard dark theme ***
for when jQuery UI themes are not being used
See https://jsfiddle.net/Mottie/6dmqhLvh/
*/
.ui-keyboard {
/* adjust overall keyboard size using "font-size" */
font-size: 14px;
text-align: center;
background: #282828;
border: 1px solid #484848;
padding: 4px;
/* include the following setting to place the
keyboard at the bottom of the browser window */
width: 100%;
height: auto;
left: 0px;
top: auto;
bottom: 0px;
position: fixed;
white-space: nowrap;
overflow-x: auto;
/* see issue #484 */
-ms-touch-action: manipulation;
touch-action: manipulation;
}
.ui-keyboard-has-focus {
z-index: 16001;
}
.ui-keyboard-button {
border: 1px solid #404040;
padding: 0 0.5em;
margin: 1px;
min-width: 3em;
height: 3em;
line-height: 3em;
vertical-align: top;
font-family: Helvetica, Arial, sans-serif;
color: #eee;
text-align: center;
border-radius: 5px;
-webkit-box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
background: #444;
background-image: -webkit-linear-gradient(-90deg, #444 0%, #333 100%);
background-image: linear-gradient(-90deg, #444 0%, #333 100%);
cursor: pointer;
overflow: hidden;
-moz-user-focus: ignore;
}
.ui-keyboard-button:not([disabled]):hover {
background: #eee;
background-image: -webkit-linear-gradient(-90deg, #4f4f4f 0%, #444 100%);
background-image: linear-gradient(-90deg, #4f4f4f 0%, #444 100%);
}
.ui-keyboard-button:not([disabled]):active {
background: #ddd;
background-image: -webkit-linear-gradient(-90deg, #555 0%, #5f5f5f 100%);
background-image: linear-gradient(-90deg, #555 0%, #5f5f5f 100%);
}
.ui-keyboard-button span {
display: block;
width: 100%;
font-size: 1.2em;
text-align: center;
}
/* make action keys extra-wide */
.ui-keyboard-actionkey:not(.ui-keyboard-dec):not(.ui-keyboard-combo) {
min-width: 6em;
}
.ui-keyboard-space {
width: 15em;
}
.ui-keyboard-actionkey:not(.ui-keyboard-dec):not(.ui-keyboard-combo) span {
font-size: 0.8em;
position: relative;
top: -1em;
left: -1.6em;
}
.ui-keyboard-placeholder {
color: #888;
}
/* disabled or readonly inputs, or use input[disabled='disabled'] { color: #f00; } */
.ui-keyboard-nokeyboard {
color: #888;
border-color: #888;
}
.ui-keyboard-spacer {
display: inline-block;
width: 1px;
height: 0;
cursor: default;
}
.ui-keyboard-NBSP span, .ui-keyboard-ZWSP span, .ui-keyboard-ZWNJ span, .ui-keyboard-ZWJ span,
.ui-keyboard-LRM span, .ui-keyboard-RLM span {
font-size: 0.5em;
line-height: 1.5em;
white-space: normal;
}
/* combo key styling - toggles diacritics on/off */
.ui-keyboard-button.ui-keyboard-combo.ui-state-default {
-webkit-box-shadow: 1px 1px 3px 0 rgba(213, 133, 18, 0.5);
box-shadow: 1px 1px 3px 0 rgba(213, 133, 18, 0.5);
border-color: #d58512;
}
.ui-keyboard-button.ui-keyboard-combo.ui-state-active {
-webkit-box-shadow: 1px 1px 3px 0 rgba(38, 154, 188, 0.5);
box-shadow: 1px 1px 3px 0 rgba(38, 154, 188, 0.5);
border-color: #269abc;
}
/* (in)valid inputs */
button.ui-keyboard-accept.ui-keyboard-valid-input {
-webkit-box-shadow: 1px 1px 3px 0 rgba(57, 132, 57, 0.5);
box-shadow: 1px 1px 3px 0 rgba(57, 132, 57, 0.5);
border-color: #398439;
}
button.ui-keyboard-accept.ui-keyboard-valid-input:not([disabled]):hover {
border-color: #4cae4c;
}
button.ui-keyboard-accept.ui-keyboard-invalid-input {
-webkit-box-shadow: 1px 1px 3px 0 rgba(172, 41, 37, 0.5);
box-shadow: 1px 1px 3px 0 rgba(172, 41, 37, 0.5);
border-color: #ac2925;
}
button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover {
border-color: #d43f3a;
}
/* unlocked icon (keyboard enabled) */
button.ui-keyboard-toggle span {
width: .9em;
height: .9em;
display: inline-block;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
/* dark theme unlocked icon - fill: #eee */
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==');
}
/* locked icon (keyboard disabled) */
button.ui-keyboard-toggle.ui-keyboard-disabled span {
/* dark theme locked icon - fill: #eee */
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=');
}
.ui-keyboard.ui-keyboard-disabled button:not(.ui-keyboard-toggle), .ui-keyboard.ui-keyboard-disabled input {
opacity: 0.5;
}
/*** Alt-Keys Popup extension ***/
/* clickable overlay on top of keyboard to hide the popup */
.ui-keyboard-overlay {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: rgba(0, 0, 0, 0.5);
}
/* the actual popup styling, class names from the css.container option are also added */
.ui-keyboard-popup {
display: inline-block;
/* default buttons are 2em wide + .1em margin on either side (set in .ui-keyboard-button definition);
so use multiples of 2.2em for a max-width if you don't want any extra white space on the sides,
e.g. 5 buttons * 2.2em = 11em, 6 buttons * 2.2em = 13.2em, etc */
max-width: 22em;
/* 10 buttons */
}
.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button {
/* Disable keys under overlay while popup is open - see #654 */
pointer-events: none;
}
/*** Caret extension definition ***/
/* margin-top => is added to the caret height (top & bottom) */
.ui-keyboard-caret {
background: #c00;
width: 1px;
margin-top: 3px;
}
/*** Extender keyboard extension ***/
div.ui-keyboard-extender {
margin-left: 5px;
margin-right: 10px;
}
button.ui-keyboard-extender span {
width: .9em;
height: .9em;
display: inline-block;
margin-bottom: 3px;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
/* dark theme extender icon - fill: #eee */
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6I2VlZSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VlZSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+');
}
/* basic previewKeyset setup - modify as desired */
.ui-keyboard-keyset .ui-keyboard-button {
position: relative;
}
/* show mini-shift keyset with normal keyset */
.ui-keyboard-keyset-normal .ui-keyboard-button::after {
content: attr(data-shift);
font-size: 0.6em;
color: #999;
position: absolute;
top: -1em;
left: 2px;
z-index: 200;
}
/* show mini-normal keyset with shift keyset */
.ui-keyboard-keyset-shift .ui-keyboard-button::after {
content: attr(data-normal);
font-size: 0.6em;
color: #999;
position: absolute;
top: -1em;
left: 2px;
z-index: 200;
}
/* show mini-normal keyset with alt keyset */
.ui-keyboard-keyset-alt .ui-keyboard-button::after {
content: attr(data-alt-shift);
font-size: 0.6em;
color: #999;
position: absolute;
top: -1em;
left: 2px;
z-index: 200;
}
/* show mini-alt-shift keyset with alt-shift keyset */
.ui-keyboard-keyset-alt-shift .ui-keyboard-button::after {
content: attr(data-alt);
font-size: 0.6em;
color: #999;
position: absolute;
top: -1em;
left: 2px;
z-index: 200;
}
/* keyboard - jQuery UI Widget */ /*!
.ui-keyboard { *
text-align: center; * simple-keyboard v2.28.42
padding: .3em; * https://github.com/hodgef/simple-keyboard
position: absolute; *
left: 0; * Copyright (c) Francisco Hodge (https://github.com/hodgef)
top: 0; *
z-index: 16000; * This source code is licensed under the MIT license found in the
/* see issue #484 */ * LICENSE file in the root directory of this source tree.
-ms-touch-action: manipulation; *
touch-action: manipulation; */
} .hg-theme-default {
.ui-keyboard-has-focus { width: 100%;
z-index: 16001; -webkit-user-select: none;
} -moz-user-select: none;
.ui-keyboard div { -ms-user-select: none;
font-size: 1.1em; user-select: none;
} box-sizing: border-box;
.ui-keyboard[contenteditable] { overflow: hidden;
white-space: pre; touch-action: manipulation
} }
.ui-keyboard-button { .hg-theme-default .hg-button span {
height: 2em; pointer-events: none
min-width: 2em; }
margin: .1em;
cursor: pointer; .hg-theme-default button.hg-button {
overflow: hidden; border-width: 0;
line-height: 2em; outline: 0;
-moz-user-focus: ignore; font-size: inherit
} }
.ui-keyboard-button span {
padding: 0; .hg-theme-default {
margin: 0; font-family: HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif;
white-space: nowrap; background-color: #ececec;
display: inline-block; padding: 5px;
} border-radius: 5px
.ui-keyboard-button-endrow { }
clear: left;
} .hg-theme-default .hg-button {
.ui-keyboard-space { display: inline-block;
width: 15em; flex-grow: 1
} }
/* see http://nicolasgallagher.com/another-css-image-replacement-technique/ */
.ui-keyboard-space span, .ui-keyboard-empty span { .hg-theme-default .hg-row {
font: 0/0 a; display: flex
text-shadow: none; }
color: transparent;
} .hg-theme-default .hg-row:not(:last-child) {
.ui-keyboard-preview-wrapper { margin-bottom: 5px
text-align: center; }
position: relative;
overflow: hidden; .hg-theme-default .hg-row .hg-button-container,
} .hg-theme-default .hg-row .hg-button:not(:last-child) {
/* width is calculated in IE, since 99% = 99% full browser width =( */ margin-right: 5px
.ui-keyboard-preview { }
text-align: left;
margin: 0 0 3px 0; .hg-theme-default .hg-row>div:last-child {
display: inline; margin-right: 0
width: 99%; }
}
.ui-keyboard-keyset { .hg-theme-default .hg-row .hg-button-container {
text-align: center; display: flex
white-space: nowrap; }
}
.ui-keyboard-input { .hg-theme-default .hg-button {
text-align: left; box-shadow: 0 0 3px -1px rgba(0, 0, 0, .3);
} height: 40px;
.ui-keyboard-input-current { border-radius: 5px;
-moz-box-shadow: 0 0 5px #4d90fe; box-sizing: border-box;
-webkit-box-shadow: 0 0 5px #4d90fe; padding: 5px;
box-shadow: 0 0 5px #4d90fe; background: #fff;
} border-bottom: 1px solid #b5b5b5;
.ui-keyboard-placeholder { cursor: pointer;
color: #888; display: flex;
} align-items: center;
/* disabled or readonly inputs, or use justify-content: center;
input[disabled='disabled'] { color: #f00; } */ -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
.ui-keyboard-nokeyboard { }
color: #888;
border-color: #888; .hg-theme-default .hg-button.hg-activeButton {
} background: #efefef
.ui-keyboard-spacer { }
display: inline-block;
width: 1px; .hg-theme-default.hg-layout-numeric .hg-button {
height: 0; width: 33.3%;
cursor: default; height: 60px;
} align-items: center;
display: flex;
.ui-keyboard-NBSP span, .ui-keyboard-ZWSP span, .ui-keyboard-ZWNJ span, justify-content: center
.ui-keyboard-ZWJ span, .ui-keyboard-LRM span, .ui-keyboard-RLM span { }
font-size: 0.5em;
line-height: 1.5em; .hg-theme-default .hg-button.hg-button-numpadadd,
white-space: normal; .hg-theme-default .hg-button.hg-button-numpadenter {
} height: 85px
}
/* combo key styling - toggles diacritics on/off */
.ui-keyboard-button.ui-keyboard-combo.ui-state-default { .hg-theme-default .hg-button.hg-button-numpad0 {
border-color: #ffaf0f; width: 105px
} }
/* (in)valid inputs */ .hg-theme-default .hg-button.hg-button-com {
button.ui-keyboard-accept.ui-keyboard-valid-input { max-width: 85px
border-color: #0c0; }
background: #080;
color: #fff; .hg-theme-default .hg-button.hg-standardBtn.hg-button-at {
} max-width: 45px
button.ui-keyboard-accept.ui-keyboard-valid-input:not([disabled]):hover { }
background: #0a0;
} .hg-theme-default .hg-button.hg-selectedButton {
button.ui-keyboard-accept.ui-keyboard-invalid-input { background: rgba(5, 25, 70, .53);
border-color: #c00; color: #fff
background: #800; }
color: #fff;
opacity: 0.5; .hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"] {
filter: alpha(opacity=50); max-width: 82px
} }
button.ui-keyboard-accept.ui-keyboard-invalid-input:not([disabled]):hover {
background: #a00; .hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"] {
} max-width: 60px
}
/*** Caret extension definition ***/
/* margin-top => is added to the caret height (top & bottom) */ /*# sourceMappingURL=index.css.map */
.ui-keyboard-caret { \ No newline at end of file
background: #c00;
width: 1px;
margin-top: 3px;
}
/*** jQuery Mobile definitions ***/
/* jQuery Mobile styles - need wider buttons because of font size and
text-overflow:ellipsis */
div.ui-body.ui-keyboard button.ui-keyboard-button.ui-btn {
padding: 0.5em 1em;
border-color: transparent;
}
.ui-body .ui-keyboard-button {
width: 3em;
height: 3em;
display: inline-block;
}
.ui-body .ui-keyboard-widekey {
width: 5.5em;
}
.ui-body .ui-keyboard-space {
width: 15em;
}
.ui-body .ui-keyboard-space span {
visibility: hidden; /* hides the ellipsis */
}
.ui-body .ui-keyboard-keyset {
line-height: 0.5em;
}
.ui-body input.ui-input-text, .ui-body textarea.ui-input-text {
width: 95%;
}
/* over-ride padding set by mobile ui theme - needed because the mobile script
wraps button text with several more spans */
.ui-body .ui-btn-inner {
height: 2em;
padding: 0.2em 0;
margin: 0;
}
.ui-body .ui-btn {
margin: 0;
font-size: 13px; /* mobile default size is 13px */
}
/* override Bootstrap excessive button padding */
button.ui-keyboard-button.btn {
padding: 1px 6px;
}
/* enable/disable icons */
button.ui-keyboard-toggle span {
width: .8em;
height: .8em;
display: inline-block;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
}
/* unlocked icon (keyboard enabled) */
button.ui-keyboard-toggle span {
/* light theme unlocked icon - fill: #111 */
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==);
}
.ui-keyboard-dark-theme button.ui-keyboard-toggle span {
/* dark theme unlocked icon - fill: #eee */
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTguNyw0LjRINy41SDUuMHYtMS45YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40LDAtMi41LDEuMS0yLjUsMi41djEuOWgxLjIgdi0xLjljMC0wLjcsMC42LTEuMiwxLjItMS4yczEuMiwwLjYsMS4yLDEuMnYxLjljLTAuNywwLTEuMiwwLjYtMS4yLDEuMlY4LjggYzAsMC43LDAuNiwxLjIsMS4yLDEuMmg1LjBDOS40LDEwLDEwLDkuNCwxMCw4LjhWNS42QzEwLDUuMCw5LjQsNC40LDguOCw0LjR6IE02LjYsNy40djEuMCBjMCwwLjItMC4xLDAuMy0wLjMsMC4zUzYuMCw4LjYsNi4wLDguNFY3LjRjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zLDAuMy0wLjYsMC42LTAuNiBTNi45LDYuNiw2LjksNi45QzYuOSw3LjEsNi44LDcuMyw2LjYsNy40eiIvPjwvc3ZnPg==);
}
/* locked icon (keyboard disabled) */
button.ui-keyboard-toggle.ui-keyboard-disabled span {
/* light theme locked icon - fill: #111 */
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iIzExMSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=);
}
.ui-keyboard-dark-theme button.ui-keyboard-toggle.ui-keyboard-disabled span {
/* dark theme locked icon - fill: #eee */
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgZmlsbD0iI2VlZSI+PHBhdGggZD0iTTcuNCA0LjRWMi41YzAtMS40LTEuMS0yLjUtMi41LTIuNWMtMS40IDAtMi41IDEuMS0yLjUgMi41djEuOSBjLTAuNyAwLTEuMiAwLjUtMS4yIDEuMnYzLjFDMS4zIDkuNCAxLjggMTAgMi41IDEwaDQuOWMwLjcgMCAxLjItMC42IDEuMi0xLjJWNS42IEM4LjcgNC45IDguMSA0LjQgNy40IDQuNHogTTUuMyA3LjR2MS4wYzAgMC4yLTAuMSAwLjMtMC4zIDAuM2MtMC4yIDAtMC4zLTAuMS0wLjMtMC4zVjcuNCBjLTAuMi0wLjEtMC4zLTAuMy0wLjMtMC41YzAtMC4zIDAuMy0wLjYgMC42LTAuNmMwLjMgMCAwLjYgMC4zIDAuNiAwLjYgQzUuNiA3LjEgNS41IDcuMyA1LjMgNy40eiBNNi4yIDQuNEgzLjdWMi41YzAtMC43IDAuNS0xLjIgMS4yLTEuMmMwLjcgMCAxLjIgMC42IDEuMiAxLjIgVjQuNHoiLz48L3N2Zz4=);
}
.ui-keyboard.ui-keyboard-disabled button:not(.ui-keyboard-toggle),
.ui-keyboard.ui-keyboard-disabled input {
opacity: 0.5;
}
/*** Alt-Keys Popup extension ***/
/* clickable overlay on top of keyboard to hide the popup */
.ui-keyboard-overlay {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: rgba(0, 0, 0, 0.5);
}
/* the actual popup styling, class names from the css.container option are also
added */
.ui-keyboard-popup {
display: inline-block;
/* default buttons are 2em wide + .1em margin on either side (set in
.ui-keyboard-button definition); so use multiples of 2.2em for a max-width
if you don't want any extra white space on the sides, e.g.
5 buttons * 2.2em = 11em,
6 buttons * 2.2em = 13.2em, etc
*/
max-width: 22em; /* 10 buttons */
}
.ui-keyboard.ui-keyboard-popup-open .ui-keyboard-keyset .ui-keyboard-button {
/* Disable keys under overlay while popup is open - see #654 */
pointer-events: none;
}
/*** Extender keyboard extension ***/
div.ui-keyboard-extender {
margin-left: 5px;
}
button.ui-keyboard-extender span {
width: .9em;
height: .9em;
display: inline-block;
margin-bottom: 3px;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
/* light theme extender icon - fill: #111 */
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6IzExMSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzExMSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+);
}
.ui-keyboard-dark-theme button.ui-keyboard-extender span {
/* dark theme extender icon - fill: #eee */
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgc3R5bGU9ImZpbGw6I2VlZSI+PGc+PHBhdGggc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VlZSIgZD0iTSAwLjUsNC41IDE1LjUsNC41IDE1LjUsMTUuNSAwLjUsMTUuNSBaIj48L3BhdGg+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iMiIgeT0iNiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjYiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSI4IiB5PSI2Ij48L3JlY3Q+PHBhdGggZD0ibSAxMSw2IDMsMCAwLDUgLTIsMCAwLC0zIC0xLDAgeiI+PC9wYXRoPjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjEyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSI2IiBoZWlnaHQ9IjIiIHg9IjUiIHk9IjEyIj48L3JlY3Q+PHJlY3Qgd2lkdGg9IjIiIGhlaWdodD0iMiIgeD0iOSIgeT0iOSI+PC9yZWN0PjxyZWN0IHdpZHRoPSIyIiBoZWlnaHQ9IjIiIHg9IjYiIHk9IjkiPjwvcmVjdD48cmVjdCB3aWR0aD0iMiIgaGVpZ2h0PSIyIiB4PSIyIiB5PSIxMiI+PC9yZWN0PjxyZWN0IHdpZHRoPSIzIiBoZWlnaHQ9IjIiIHg9IjIiIHk9IjkiPjwvcmVjdD48L2c+PC9zdmc+);
}
/* Media Queries (optimized for jQuery UI themes;
may be slightly off in jQuery Mobile themes) */
/* 240 x 320 (small phone) */
@media all and (max-width: 319px) {
.ui-keyboard div {
font-size: 9px;
}
.ui-keyboard .ui-keyboard-input {
font-size: 12px;
}
/* I don't own an iPhone so I have no idea how small this really is... is it
even clickable with your finger? */
.ui-body .ui-btn {
margin: 0;
font-size: 9px;
}
.ui-body .ui-keyboard-button {
width: 1.8em;
height: 2.5em;
}
.ui-body .ui-keyboard-widekey {
width: 4em;
}
.ui-body .ui-keyboard-space {
width: 8em;
}
.ui-body .ui-btn-inner {
height: 2.5em;
padding: 0.3em 0;
}
}
/* 320 x 480 (iPhone) */
@media all and (min-width: 320px) and (max-width: 479px) {
.ui-keyboard div {
font-size: 9px;
}
.ui-keyboard .ui-keyboard-input {
font-size: 14px;
}
/* I don't own an iPhone so I have no idea how small this really is... is it
even clickable with your finger? */
.ui-body .ui-btn {
margin: 0;
font-size: 11px;
}
.ui-body .ui-keyboard-button {
width: 1.8em;
height: 3em;
}
.ui-body .ui-keyboard-widekey {
width: 4.5em;
}
.ui-body .ui-keyboard-space {
width: 10em;
}
.ui-body .ui-btn-inner {
height: 3em;
padding: 0.7em 0;
}
}
/* 480 x 640 (small tablet) */
@media all and (min-width: 480px) and (max-width: 767px) {
.ui-keyboard div {
font-size: 13px;
}
.ui-keyboard .ui-keyboard-input {
font-size: 14px;
}
.ui-body .ui-btn {
margin: 0;
font-size: 10px;
}
.ui-body .ui-keyboard-button {
height: 2.5em;
}
.ui-body .ui-btn-inner {
height: 2.5em;
padding: 0.5em 0;
}
}
.inline {
display:inline-grid;
}
.input {
width: auto;
height: 50px;
}
.btn{
width:auto;
height: 50px;
}
/* caret "after" content visible outside of keyboard popup */
.ui-keyboard-preview-wrapper {
overflow: visible;
}
/* add caret character preview popup */
.ui-keyboard-caret:after {
content: attr(data-character);
background: red;
color: white;
font-family: Verdana, Tahoma, Segoe, sans-serif;
font-size: 1.1em;
min-width: 1em;
position: absolute;
z-index: 100;
top: -1.4em;
left: -.5em;
}
/* for password, set font to monospace to ensure caret stays lined up */
input[type=password] {
font-family: monospace !important;
}
/* jsFiddle demo stuff */
body {
margin-top: 50px;
font-size: 12px;
}
#wrap {
display: block;
margin: 0 auto;
width: 200px;
}
.spacer {
height: 20px;
}
import "./Keyboard.css";
// Services
import { getDefaultLayout } from "../services/KeyboardLayout";
import PhysicalKeyboard from "../services/PhysicalKeyboard";
import Utilities from "../services/Utilities";
/**
* Root class for simple-keyboard
* This class:
* - Parses the options
* - Renders the rows and buttons
* - Handles button functionality
*/
class SimpleKeyboard {
/**
* Creates an instance of SimpleKeyboard
* @param {Array} params If first parameter is a string, it is considered the container class. The second parameter is then considered the options object. If first parameter is an object, it is considered the options object.
*/
constructor(...params) {
const { keyboardDOMClass, keyboardDOM, options = {} } = this.handleParams(
params
);
/**
* Initializing Utilities
*/
this.utilities = new Utilities({
getOptions: this.getOptions,
getCaretPosition: this.getCaretPosition,
dispatch: this.dispatch
});
/**
* Caret position
*/
this.caretPosition = null;
/**
* Processing options
*/
this.keyboardDOM = keyboardDOM;
/**
* @type {object}
* @property {object} layout Modify the keyboard layout.
* @property {string} layoutName Specifies which layout should be used.
* @property {object} display Replaces variable buttons (such as {bksp}) with a human-friendly name (e.g.: “backspace”).
* @property {boolean} mergeDisplay By default, when you set the display property, you replace the default one. This setting merges them instead.
* @property {string} theme A prop to add your own css classes to the keyboard wrapper. You can add multiple classes separated by a space.
* @property {array} buttonTheme A prop to add your own css classes to one or several buttons.
* @property {array} buttonAttributes A prop to add your own attributes to one or several buttons.
* @property {boolean} debug Runs a console.log every time a key is pressed. Displays the buttons pressed and the current input.
* @property {boolean} newLineOnEnter Specifies whether clicking the “ENTER” button will input a newline (\n) or not.
* @property {boolean} tabCharOnTab Specifies whether clicking the “TAB” button will input a tab character (\t) or not.
* @property {string} inputName Allows you to use a single simple-keyboard instance for several inputs.
* @property {number} maxLength Restrains all of simple-keyboard inputs to a certain length. This should be used in addition to the input element’s maxlengthattribute.
* @property {object} maxLength Restrains simple-keyboard’s individual inputs to a certain length. This should be used in addition to the input element’s maxlengthattribute.
* @property {boolean} syncInstanceInputs When set to true, this option synchronizes the internal input of every simple-keyboard instance.
* @property {boolean} physicalKeyboardHighlight Enable highlighting of keys pressed on physical keyboard.
* @property {boolean} preventMouseDownDefault Calling preventDefault for the mousedown events keeps the focus on the input.
* @property {boolean} stopMouseDownPropagation Stops pointer down events on simple-keyboard buttons from bubbling to parent elements.
* @property {string} physicalKeyboardHighlightTextColor Define the text color that the physical keyboard highlighted key should have.
* @property {string} physicalKeyboardHighlightBgColor Define the background color that the physical keyboard highlighted key should have.
* @property {function(button: string):string} onKeyPress Executes the callback function on key press. Returns button layout name (i.e.: “{shift}”).
* @property {function(input: string):string} onChange Executes the callback function on input change. Returns the current input’s string.
* @property {function} onRender Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
* @property {function} onInit Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
* @property {function(inputs: object):object} onChangeAll Executes the callback function on input change. Returns the input object with all defined inputs.
* @property {boolean} useButtonTag Render buttons as a button element instead of a div element.
* @property {boolean} disableCaretPositioning A prop to ensure characters are always be added/removed at the end of the string.
* @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} 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.
* @property {function} destroy Clears keyboard listeners and DOM elements.
* @property {boolean} disableButtonHold Disable button hold action.
* @property {function} onKeyReleased Executes the callback function on key release.
* @property {array} modules Module classes to be loaded by simple-keyboard.
*/
this.options = options;
this.options.layoutName = this.options.layoutName || "default";
this.options.theme = this.options.theme || "hg-theme-default";
this.options.inputName = this.options.inputName || "default";
this.options.preventMouseDownDefault =
this.options.preventMouseDownDefault || false;
/**
* @type {object} Classes identifying loaded plugins
*/
this.keyboardPluginClasses = "";
/**
* Bindings
*/
Utilities.bindMethods(SimpleKeyboard, this);
/**
* simple-keyboard uses a non-persistent internal input to keep track of the entered string (the variable `keyboard.input`).
* This removes any dependency to input DOM elements. You can type and directly display the value in a div element, for example.
* @example
* // To get entered input
* const input = keyboard.getInput();
*
* // To clear entered input.
* keyboard.clearInput();
*
* @type {object}
* @property {object} default Default SimpleKeyboard internal input.
* @property {object} myInputName Example input that can be set through `options.inputName:"myInputName"`.
*/
this.input = {};
this.input[this.options.inputName] = "";
/**
* @type {string} DOM class of the keyboard wrapper, normally "simple-keyboard" by default.
*/
this.keyboardDOMClass = keyboardDOMClass;
/**
* @type {object} Contains the DOM elements of every rendered button, the key being the button's layout name (e.g.: "{enter}").
*/
this.buttonElements = {};
/**
* Simple-keyboard Instances
* This enables multiple simple-keyboard support with easier management
*/
if (!window["SimpleKeyboardInstances"])
window["SimpleKeyboardInstances"] = {};
this.currentInstanceName = this.utilities.camelCase(this.keyboardDOMClass);
window["SimpleKeyboardInstances"][this.currentInstanceName] = this;
/**
* Instance vars
*/
this.allKeyboardInstances = window["SimpleKeyboardInstances"];
this.keyboardInstanceNames = Object.keys(window["SimpleKeyboardInstances"]);
this.isFirstKeyboardInstance =
this.keyboardInstanceNames[0] === this.currentInstanceName;
/**
* Physical Keyboard support
*/
this.physicalKeyboard = new PhysicalKeyboard({
dispatch: this.dispatch,
getOptions: this.getOptions
});
/**
* Rendering keyboard
*/
if (this.keyboardDOM) this.render();
else {
console.warn(`".${keyboardDOMClass}" was not found in the DOM.`);
throw new Error("KEYBOARD_DOM_ERROR");
}
/**
* Modules
*/
this.modules = {};
this.loadModules();
}
/**
* parseParams
*/
handleParams = params => {
let keyboardDOMClass;
let keyboardDOM;
let options;
/**
* If first parameter is a string:
* Consider it as an element's class
*/
if (typeof params[0] === "string") {
keyboardDOMClass = params[0].split(".").join("");
keyboardDOM = document.querySelector(`.${keyboardDOMClass}`);
options = params[1];
/**
* If first parameter is an HTMLDivElement
* Consider it as the keyboard DOM element
*/
} else if (params[0] instanceof HTMLDivElement) {
/**
* This element must have a class, otherwise throw
*/
if (!params[0].className) {
console.warn("Any DOM element passed as parameter must have a class.");
throw new Error("KEYBOARD_DOM_CLASS_ERROR");
}
keyboardDOMClass = params[0].className.split(" ")[0];
keyboardDOM = params[0];
options = params[1];
/**
* Otherwise, search for .simple-keyboard DOM element
*/
} else {
keyboardDOMClass = "simple-keyboard";
keyboardDOM = document.querySelector(`.${keyboardDOMClass}`);
options = params[0];
}
return {
keyboardDOMClass,
keyboardDOM,
options
};
};
/**
* Getters
*/
getOptions = () => this.options;
getCaretPosition = () => this.caretPosition;
/**
* Handles clicks made to keyboard buttons
* @param {string} button The button's layout name.
*/
handleButtonClicked(button) {
const debug = this.options.debug;
/**
* Ignoring placeholder buttons
*/
if (button === "{//}") return false;
/**
* Calling onKeyPress
*/
if (typeof this.options.onKeyPress === "function")
this.options.onKeyPress(button);
if (!this.input[this.options.inputName])
this.input[this.options.inputName] = "";
const updatedInput = this.utilities.getUpdatedInput(
button,
this.input[this.options.inputName],
this.caretPosition
);
if (
// If input will change as a result of this button press
this.input[this.options.inputName] !== updatedInput &&
// This pertains to the "inputPattern" option:
// If inputPattern isn't set
(!this.options.inputPattern ||
// Or, if it is set and if the pattern is valid - we proceed.
(this.options.inputPattern && this.inputPatternIsValid(updatedInput)))
) {
/**
* If maxLength and handleMaxLength yield true, halting
*/
if (
this.options.maxLength &&
this.utilities.handleMaxLength(this.input, updatedInput)
) {
return false;
}
this.input[this.options.inputName] = this.utilities.getUpdatedInput(
button,
this.input[this.options.inputName],
this.caretPosition,
true
);
if (debug) console.log("Input changed:", this.input);
/**
* Enforce syncInstanceInputs, if set
*/
if (this.options.syncInstanceInputs) this.syncInstanceInputs();
/**
* Calling onChange
*/
if (typeof this.options.onChange === "function")
this.options.onChange(this.input[this.options.inputName]);
/**
* Calling onChangeAll
*/
if (typeof this.options.onChangeAll === "function")
this.options.onChangeAll(this.input);
}
if (debug) {
console.log("Key pressed:", button);
}
}
/**
* Handles button mousedown
*/
/* istanbul ignore next */
handleButtonMouseDown(button, e) {
/**
* Handle event options
*/
if (this.options.preventMouseDownDefault) e.preventDefault();
if (this.options.stopMouseDownPropagation) e.stopPropagation();
/**
* Add active class
*/
if (e) e.target.classList.add(this.activeButtonClass);
/**
* @type {boolean} Whether the mouse is being held onKeyPress
*/
this.isMouseHold = true;
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
if (this.holdTimeout) clearTimeout(this.holdTimeout);
/**
* @type {object} Time to wait until a key hold is detected
*/
if (!this.options.disableButtonHold) {
this.holdTimeout = setTimeout(() => {
if (
this.isMouseHold &&
((!button.includes("{") && !button.includes("}")) ||
button === "{delete}" ||
button === "{backspace}" ||
button === "{bksp}" ||
button === "{space}" ||
button === "{tab}")
) {
if (this.options.debug) console.log("Button held:", button);
this.handleButtonHold(button, e);
}
clearTimeout(this.holdTimeout);
}, 500);
}
}
/**
* Handles button mouseup
*/
handleButtonMouseUp(button) {
/**
* Remove active class
*/
this.recurseButtons(buttonElement => {
buttonElement.classList.remove(this.activeButtonClass);
});
this.isMouseHold = false;
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
/**
* Calling onKeyReleased
*/
if (button && typeof this.options.onKeyReleased === "function")
this.options.onKeyReleased(button);
}
/**
* Handles container mousedown
*/
handleKeyboardContainerMouseDown(e) {
/**
* Handle event options
*/
if (this.options.preventMouseDownDefault) e.preventDefault();
}
/**
* Handles button hold
*/
/* istanbul ignore next */
handleButtonHold(button) {
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
/**
* @type {object} Timeout dictating the speed of key hold iterations
*/
this.holdInteractionTimeout = setTimeout(() => {
if (this.isMouseHold) {
this.handleButtonClicked(button);
this.handleButtonHold(button);
} else {
clearTimeout(this.holdInteractionTimeout);
}
}, 100);
}
/**
* Send a command to all simple-keyboard instances (if you have several instances).
*/
syncInstanceInputs() {
this.dispatch(instance => {
instance.replaceInput(this.input);
instance.caretPosition = this.caretPosition;
});
}
/**
* Clear the keyboard’s input.
* @param {string} [inputName] optional - the internal input to select
*/
clearInput(inputName) {
inputName = inputName || this.options.inputName;
this.input[inputName] = "";
/**
* Reset caretPosition
*/
this.caretPosition = 0;
/**
* Enforce syncInstanceInputs, if set
*/
if (this.options.syncInstanceInputs) this.syncInstanceInputs();
}
/**
* Get the keyboard’s input (You can also get it from the onChange prop).
* @param {string} [inputName] optional - the internal input to select
*/
getInput(inputName) {
inputName = inputName || this.options.inputName;
/**
* Enforce syncInstanceInputs, if set
*/
if (this.options.syncInstanceInputs) this.syncInstanceInputs();
return this.input[inputName];
}
/**
* Set the keyboard’s input.
* @param {string} input the input value
* @param {string} inputName optional - the internal input to select
*/
setInput(input, inputName) {
inputName = inputName || this.options.inputName;
this.input[inputName] = input;
/**
* Enforce syncInstanceInputs, if set
*/
if (this.options.syncInstanceInputs) this.syncInstanceInputs();
}
/**
* Replace the input object (`keyboard.input`)
* @param {object} inputObj The input object
*/
replaceInput(inputObj) {
this.input = inputObj;
}
/**
* Set new option or modify existing ones after initialization.
* @param {object} options The options to set
*/
setOptions(options) {
options = options || {};
this.options = Object.assign(this.options, options);
/**
* Some option changes require adjustments before re-render
*/
this.onSetOptions(options);
/**
* Rendering
*/
this.render();
}
/**
* Executing actions depending on changed options
* @param {object} options The options to set
*/
onSetOptions(options) {
if (options.inputName) {
/**
* inputName changed. This requires a caretPosition reset
*/
if (this.options.debug) {
console.log("inputName changed. caretPosition reset.");
}
this.caretPosition = null;
}
}
/**
* Remove all keyboard rows and reset keyboard values.
* Used internally between re-renders.
*/
clear() {
this.keyboardDOM.innerHTML = "";
this.keyboardDOM.className = this.keyboardDOMClass;
this.buttonElements = {};
}
/**
* Send a command to all simple-keyboard instances at once (if you have multiple instances).
* @param {function(instance: object, key: string)} callback Function to run on every instance
*/
dispatch(callback) {
if (!window["SimpleKeyboardInstances"]) {
console.warn(
`SimpleKeyboardInstances is not defined. Dispatch cannot be called.`
);
throw new Error("INSTANCES_VAR_ERROR");
}
return Object.keys(window["SimpleKeyboardInstances"]).forEach(key => {
callback(window["SimpleKeyboardInstances"][key], key);
});
}
/**
* Adds/Modifies an entry to the `buttonTheme`. Basically a way to add a class to a button.
* @param {string} buttons List of buttons to select (separated by a space).
* @param {string} className Classes to give to the selected buttons (separated by space).
*/
addButtonTheme(buttons, className) {
if (!className || !buttons) return false;
buttons.split(" ").forEach(button => {
className.split(" ").forEach(classNameItem => {
if (!this.options.buttonTheme) this.options.buttonTheme = [];
let classNameFound = false;
/**
* If class is already defined, we add button to class definition
*/
this.options.buttonTheme.map(buttonTheme => {
if (buttonTheme.class.split(" ").includes(classNameItem)) {
classNameFound = true;
const buttonThemeArray = buttonTheme.buttons.split(" ");
if (!buttonThemeArray.includes(button)) {
classNameFound = true;
buttonThemeArray.push(button);
buttonTheme.buttons = buttonThemeArray.join(" ");
}
}
return buttonTheme;
});
/**
* If class is not defined, we create a new entry
*/
if (!classNameFound) {
this.options.buttonTheme.push({
class: classNameItem,
buttons: buttons
});
}
});
});
this.render();
}
/**
* Removes/Amends an entry to the `buttonTheme`. Basically a way to remove a class previously added to a button through buttonTheme or addButtonTheme.
* @param {string} buttons List of buttons to select (separated by a space).
* @param {string} className Classes to give to the selected buttons (separated by space).
*/
removeButtonTheme(buttons, className) {
/**
* When called with empty parameters, remove all button themes
*/
if (!buttons && !className) {
this.options.buttonTheme = [];
this.render();
return false;
}
/**
* If buttons are passed and buttonTheme has items
*/
if (
buttons &&
Array.isArray(this.options.buttonTheme) &&
this.options.buttonTheme.length
) {
const buttonArray = buttons.split(" ");
buttonArray.forEach(button => {
this.options.buttonTheme.map((buttonTheme, index) => {
/**
* If className is set, we affect the buttons only for that class
* Otherwise, we afect all classes
*/
if (
(className && className.includes(buttonTheme.class)) ||
!className
) {
const filteredButtonArray = buttonTheme.buttons
.split(" ")
.filter(item => item !== button);
/**
* If buttons left, return them, otherwise, remove button Theme
*/
if (filteredButtonArray.length) {
buttonTheme.buttons = filteredButtonArray.join(" ");
} else {
this.options.buttonTheme.splice(index, 1);
buttonTheme = null;
}
}
return buttonTheme;
});
});
this.render();
}
}
/**
* Get the DOM Element of a button. If there are several buttons with the same name, an array of the DOM Elements is returned.
* @param {string} button The button layout name to select
*/
getButtonElement(button) {
let output;
const buttonArr = this.buttonElements[button];
if (buttonArr) {
if (buttonArr.length > 1) {
output = buttonArr;
} else {
output = buttonArr[0];
}
}
return output;
}
/**
* This handles the "inputPattern" option
* by checking if the provided inputPattern passes
*/
inputPatternIsValid(inputVal) {
const inputPatternRaw = this.options.inputPattern;
let inputPattern;
/**
* Check if input pattern is global or targeted to individual inputs
*/
if (inputPatternRaw instanceof RegExp) {
inputPattern = inputPatternRaw;
} else {
inputPattern = inputPatternRaw[this.options.inputName];
}
if (inputPattern && inputVal) {
const didInputMatch = inputPattern.test(inputVal);
if (this.options.debug) {
console.log(
`inputPattern ("${inputPattern}"): ${
didInputMatch ? "passed" : "did not pass!"
}`
);
}
return didInputMatch;
} else {
/**
* inputPattern doesn't seem to be set for the current input, or input is empty. Pass.
*/
return true;
}
}
/**
* Handles simple-keyboard event listeners
*/
setEventListeners() {
/**
* Only first instance should set the event listeners
*/
if (this.isFirstKeyboardInstance || !this.allKeyboardInstances) {
if (this.options.debug) {
console.log(`Caret handling started (${this.keyboardDOMClass})`);
}
/**
* Event Listeners
*/
document.addEventListener("keyup", this.handleKeyUp);
document.addEventListener("keydown", this.handleKeyDown);
document.addEventListener("mouseup", this.handleMouseUp);
document.addEventListener("touchend", this.handleTouchEnd);
}
}
/**
* 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 setEventListeners} when an event that warrants a cursor position update is triggered
*/
caretEventHandler(event) {
let targetTagName;
if (event.target.tagName) {
targetTagName = event.target.tagName.toLowerCase();
}
this.dispatch(instance => {
if (instance.isMouseHold) {
instance.isMouseHold = false;
}
if (
(targetTagName === "textarea" || targetTagName === "input") &&
!instance.options.disableCaretPositioning
) {
/**
* Tracks current cursor position
* As keys are pressed, text will be added/removed at that position within the input.
*/
instance.caretPosition = event.target.selectionStart;
if (instance.options.debug) {
console.log(
"Caret at: ",
event.target.selectionStart,
event.target.tagName.toLowerCase(),
`(${instance.keyboardDOMClass})`
);
}
} else if (instance.options.disableCaretPositioning) {
/**
* If we toggled off disableCaretPositioning, we must ensure caretPosition doesn't persist once reactivated.
*/
instance.caretPosition = null;
}
});
}
/**
* Execute an operation on each button
*/
recurseButtons(fn) {
if (!fn) return false;
Object.keys(this.buttonElements).forEach(buttonName =>
this.buttonElements[buttonName].forEach(fn)
);
}
/**
* Destroy keyboard listeners and DOM elements
*/
destroy() {
if (this.options.debug)
console.log(
`Destroying simple-keyboard instance: ${this.currentInstanceName}`
);
/**
* Remove document listeners
*/
document.removeEventListener("keyup", this.handleKeyUp);
document.removeEventListener("keydown", this.handleKeyDown);
document.removeEventListener("mouseup", this.handleMouseUp);
document.removeEventListener("touchend", this.handleTouchEnd);
document.onpointerup = null;
document.ontouchend = null;
document.ontouchcancel = null;
document.onmouseup = null;
/**
* Remove buttons
*/
let deleteButton = buttonElement => {
buttonElement.onpointerdown = null;
buttonElement.onpointerup = null;
buttonElement.onpointercancel = null;
buttonElement.ontouchstart = null;
buttonElement.ontouchend = null;
buttonElement.ontouchcancel = null;
buttonElement.onclick = null;
buttonElement.onmousedown = null;
buttonElement.onmouseup = null;
buttonElement.remove();
buttonElement = null;
};
this.recurseButtons(deleteButton);
this.recurseButtons = null;
deleteButton = null;
/**
* Remove wrapper events
*/
this.keyboardDOM.onpointerdown = null;
this.keyboardDOM.ontouchstart = null;
this.keyboardDOM.onmousedown = null;
/**
* Clearing keyboard wrapper
*/
this.clear();
/**
* Remove instance
*/
window["SimpleKeyboardInstances"][this.currentInstanceName] = null;
delete window["SimpleKeyboardInstances"][this.currentInstanceName];
/**
* Reset initialized flag
*/
this.initialized = false;
}
/**
* Process buttonTheme option
*/
getButtonThemeClasses(button) {
const buttonTheme = this.options.buttonTheme;
let buttonClasses = [];
if (Array.isArray(buttonTheme)) {
buttonTheme.forEach(themeObj => {
if (
themeObj.class &&
typeof themeObj.class === "string" &&
themeObj.buttons &&
typeof themeObj.buttons === "string"
) {
const themeObjClasses = themeObj.class.split(" ");
const themeObjButtons = themeObj.buttons.split(" ");
if (themeObjButtons.includes(button)) {
buttonClasses = [...buttonClasses, ...themeObjClasses];
}
} else {
console.warn(
`Incorrect "buttonTheme". Please check the documentation.`,
themeObj
);
}
});
}
return buttonClasses;
}
/**
* Process buttonAttributes option
*/
setDOMButtonAttributes(button, callback) {
const buttonAttributes = this.options.buttonAttributes;
if (Array.isArray(buttonAttributes)) {
buttonAttributes.forEach(attrObj => {
if (
attrObj.attribute &&
typeof attrObj.attribute === "string" &&
attrObj.value &&
typeof attrObj.value === "string" &&
attrObj.buttons &&
typeof attrObj.buttons === "string"
) {
const attrObjButtons = attrObj.buttons.split(" ");
if (attrObjButtons.includes(button)) {
callback(attrObj.attribute, attrObj.value);
}
} else {
console.warn(
`Incorrect "buttonAttributes". Please check the documentation.`,
attrObj
);
}
});
}
}
onTouchDeviceDetected() {
/**
* Processing autoTouchEvents
*/
this.processAutoTouchEvents();
/**
* Disabling contextual window on touch devices
*/
this.disableContextualWindow();
}
/**
* Disabling contextual window for hg-button
*/
/* istanbul ignore next */
disableContextualWindow() {
window.oncontextmenu = event => {
if (event.target.classList.contains("hg-button")) {
event.preventDefault();
event.stopPropagation();
return false;
}
};
}
/**
* Process autoTouchEvents option
*/
processAutoTouchEvents() {
if (this.options.autoUseTouchEvents) {
this.options.useTouchEvents = true;
if (this.options.debug) {
console.log(
`autoUseTouchEvents: Touch device detected, useTouchEvents enabled.`
);
}
}
}
/**
* Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
*/
onInit() {
if (this.options.debug) {
console.log(`${this.keyboardDOMClass} Initialized`);
}
/**
* setEventListeners
*/
this.setEventListeners();
if (typeof this.options.onInit === "function") this.options.onInit();
}
/**
* Executes the callback function before a simple-keyboard render.
*/
beforeFirstRender() {
/**
* Performing actions when touch device detected
*/
if (this.utilities.isTouchDevice()) {
this.onTouchDeviceDetected();
}
if (typeof this.options.beforeFirstRender === "function")
this.options.beforeFirstRender();
/**
* Notify about PointerEvents usage
*/
if (
this.isFirstKeyboardInstance &&
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."
);
}
}
}
/**
* Executes the callback function before a simple-keyboard render.
*/
beforeRender() {
if (typeof this.options.beforeRender === "function")
this.options.beforeRender();
}
/**
* Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
*/
onRender() {
if (typeof this.options.onRender === "function") this.options.onRender();
}
/**
* Executes the callback function once all modules have been loaded
*/
onModulesLoaded() {
if (typeof this.options.onModulesLoaded === "function")
this.options.onModulesLoaded();
}
/**
* Register module
*/
registerModule = (name, initCallback) => {
if (!this.modules[name]) this.modules[name] = {};
initCallback(this.modules[name]);
};
/**
* Load modules
*/
loadModules() {
if (Array.isArray(this.options.modules)) {
this.options.modules.forEach(KeyboardModule => {
const keyboardModule = new KeyboardModule();
/* istanbul ignore next */
if (
keyboardModule.constructor.name &&
keyboardModule.constructor.name !== "Function"
) {
const classStr = `module-${this.utilities.camelCase(
keyboardModule.constructor.name
)}`;
this.keyboardPluginClasses =
this.keyboardPluginClasses + ` ${classStr}`;
}
keyboardModule.init(this);
});
this.keyboardPluginClasses =
this.keyboardPluginClasses + " modules-loaded";
this.render();
this.onModulesLoaded();
}
}
/**
* Get module prop
*/
getModuleProp(name, prop) {
if (!this.modules[name]) return false;
return this.modules[name][prop];
}
/**
* getModulesList
*/
getModulesList() {
return Object.keys(this.modules);
}
/**
* Parse Row DOM containers
*/
parseRowDOMContainers(
rowDOM,
rowIndex,
containerStartIndexes,
containerEndIndexes
) {
const rowDOMArray = Array.from(rowDOM.children);
let removedElements = 0;
if (rowDOMArray.length) {
containerStartIndexes.forEach((startIndex, arrIndex) => {
const 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
*/
const updated_startIndex = startIndex - removedElements;
const updated_endIndex = endIndex - removedElements;
/**
* Create button container
*/
const containerDOM = document.createElement("div");
containerDOM.className += "hg-button-container";
const containerUID = `${this.options.layoutName}-r${rowIndex}c${arrIndex}`;
containerDOM.setAttribute("data-skUID", containerUID);
/**
* Taking elements due to be inserted into container
*/
const 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;
}
/**
* getKeyboardClassString
*/
getKeyboardClassString = (...baseDOMClasses) => {
const keyboardClasses = [this.keyboardDOMClass, ...baseDOMClasses].filter(
DOMClass => !!DOMClass
);
return keyboardClasses.join(" ");
};
/**
* Renders rows and buttons as per options
*/
render() {
/**
* Clear keyboard
*/
this.clear();
/**
* Calling beforeFirstRender
*/
if (!this.initialized) {
this.beforeFirstRender();
}
/**
* Calling beforeRender
*/
this.beforeRender();
const layoutClass = `hg-layout-${this.options.layoutName}`;
const layout = this.options.layout || getDefaultLayout();
const useTouchEvents = this.options.useTouchEvents || false;
const useTouchEventsClass = useTouchEvents ? "hg-touch-events" : "";
const useMouseEvents = this.options.useMouseEvents || false;
const disableRowButtonContainers = this.options.disableRowButtonContainers;
/**
* Adding themeClass, layoutClass to keyboardDOM
*/
this.keyboardDOM.className = this.getKeyboardClassString(
this.options.theme,
layoutClass,
this.keyboardPluginClasses,
useTouchEventsClass
);
/**
* Iterating through each row
*/
layout[this.options.layoutName].forEach((row, rIndex) => {
const rowArray = row.split(" ");
/**
* Creating empty row
*/
let rowDOM = document.createElement("div");
rowDOM.className += "hg-row";
/**
* Tracking container indicators in rows
*/
const containerStartIndexes = [];
const containerEndIndexes = [];
/**
* Iterating through each button in row
*/
rowArray.forEach((button, bIndex) => {
/**
* Check if button has a container indicator
*/
const buttonHasContainerStart =
!disableRowButtonContainers &&
button.includes("[") &&
button.length > 1;
const 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
*/
const fctBtnClass = this.utilities.getButtonClass(button);
const buttonDisplayName = this.utilities.getButtonDisplayName(
button,
this.options.display,
this.options.mergeDisplay
);
/**
* Creating button
*/
const buttonType = this.options.useButtonTag ? "button" : "div";
const buttonDOM = document.createElement(buttonType);
buttonDOM.className += `hg-button ${fctBtnClass}`;
/**
* Adding buttonTheme
*/
buttonDOM.classList.add(...this.getButtonThemeClasses(button));
/**
* Adding buttonAttributes
*/
this.setDOMButtonAttributes(button, (attribute, value) => {
buttonDOM.setAttribute(attribute, value);
});
this.activeButtonClass = "hg-activeButton";
/**
* Handle button click event
*/
/* istanbul ignore next */
if (
this.utilities.pointerEventsSupported() &&
!useTouchEvents &&
!useMouseEvents
) {
/**
* Handle PointerEvents
*/
buttonDOM.onpointerdown = e => {
this.handleButtonClicked(button);
this.handleButtonMouseDown(button, e);
};
buttonDOM.onpointerup = () => {
this.handleButtonMouseUp(button);
};
buttonDOM.onpointercancel = () => {
this.handleButtonMouseUp(button);
};
} else {
/**
* Fallback for browsers not supporting PointerEvents
*/
if (useTouchEvents) {
/**
* Handle touch events
*/
buttonDOM.ontouchstart = e => {
this.handleButtonClicked(button);
this.handleButtonMouseDown(button, e);
};
buttonDOM.ontouchend = () => {
this.handleButtonMouseUp(button);
};
buttonDOM.ontouchcancel = () => {
this.handleButtonMouseUp(button);
};
} else {
/**
* Handle mouse events
*/
buttonDOM.onclick = () => {
this.isMouseHold = false;
this.handleButtonClicked(button);
};
buttonDOM.onmousedown = e => {
this.handleButtonMouseDown(button, e);
};
buttonDOM.onmouseup = () => {
this.handleButtonMouseUp(button);
};
}
}
/**
* Adding identifier
*/
buttonDOM.setAttribute("data-skBtn", button);
/**
* Adding unique id
* Since there's no limit on spawning same buttons, the unique id ensures you can style every button
*/
const buttonUID = `${this.options.layoutName}-r${rIndex}b${bIndex}`;
buttonDOM.setAttribute("data-skBtnUID", buttonUID);
/**
* Adding button label to button
*/
const buttonSpanDOM = document.createElement("span");
buttonSpanDOM.innerHTML = buttonDisplayName;
buttonDOM.appendChild(buttonSpanDOM);
/**
* Adding to buttonElements
*/
if (!this.buttonElements[button]) this.buttonElements[button] = [];
this.buttonElements[button].push(buttonDOM);
/**
* Appending button to row
*/
rowDOM.appendChild(buttonDOM);
});
/**
* Parse containers in row
*/
rowDOM = this.parseRowDOMContainers(
rowDOM,
rIndex,
containerStartIndexes,
containerEndIndexes
);
/**
* Appending row to keyboard
*/
this.keyboardDOM.appendChild(rowDOM);
});
/**
* Calling onRender
*/
this.onRender();
if (!this.initialized) {
/**
* Ensures that onInit and beforeFirstRender are only called once per instantiation
*/
this.initialized = true;
/**
* Handling parent events
*/
/* istanbul ignore next */
if (
this.utilities.pointerEventsSupported() &&
!useTouchEvents &&
!useMouseEvents
) {
document.onpointerup = () => this.handleButtonMouseUp();
this.keyboardDOM.onpointerdown = e =>
this.handleKeyboardContainerMouseDown(e);
} else if (useTouchEvents) {
/**
* Handling ontouchend, ontouchcancel
*/
document.ontouchend = () => this.handleButtonMouseUp();
document.ontouchcancel = () => this.handleButtonMouseUp();
this.keyboardDOM.ontouchstart = e =>
this.handleKeyboardContainerMouseDown(e);
} else if (!useTouchEvents) {
/**
* Handling mouseup
*/
document.onmouseup = () => this.handleButtonMouseUp();
this.keyboardDOM.onmousedown = e =>
this.handleKeyboardContainerMouseDown(e);
}
/**
* Calling onInit
*/
this.onInit();
}
}
}
export default SimpleKeyboard;
import ('./Keyboard.js')
let Keyboard = window.SimpleKeyboard.default;
let myKeyboard = new Keyboard({
onChange: input => onChange(input),
onKeyPress: button => onKeyPress(button)
});
function onChange(input) {
document.querySelector(".input").value = input;
console.log("Input changed", input);
}
function onKeyPress(button) {
console.log("Button pressed", button);
}
/*** This file is dynamically generated ***
█████▄ ▄████▄ █████▄ ▄████▄ ██████ ███████▄ ▄████▄ █████▄ ██ ██████ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██
█████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀
*/
/*! jQuery UI Virtual Keyboard (1.30.1) - ALL Extensions + Mousewheel */
/*! jQuery UI Virtual Keyboard Alt Key Popup v2.0.0 *//*
* for Keyboard v1.18+ only (2018-04-19)
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
* Note: Use of `event.key` requires a modern browser
* (https://caniuse.com/#feat=keyboardevent-key)
*/
/* jshint browser:true, jquery:true, unused:false */
/* global require:false, define:false, module:false */
;( function( factory ) {
if ( typeof define === 'function' && define.amd ) {
define( [ 'jquery' ], factory );
} else if (
typeof module === 'object' &&
typeof module.exports === 'object'
) {
module.exports = factory( require( 'jquery' ) );
} else {
factory( jQuery );
}
}( function( $ ) {
'use strict';
var $keyboard = $.keyboard;
$.extend( $keyboard.css, {
altKeyPopup : 'ui-keyboard-popup',
altKeyOverlay : 'ui-keyboard-overlay',
altKeyPopupOpen : 'ui-keyboard-popup-open'
});
$keyboard.altKeys = $.extend({
a : '\u00e5 \u00e6 \u0101 \u0103 \u0105 \u00e0 \u00e1 \u00e2 \u00e3 \u00e4', // å æ ā ă ą à á â ã ä
A : '\u00c5 \u00c6 \u0100 \u0102 \u0104 \u00c0 \u00c1 \u00c2 \u00c3 \u00c4', // Å Æ Ā Ă Ą À Á Â Ã Ä
c : '\u00e7 \u0107 \u0109 \u010b \u010d', // ç ć ĉ ċ č
C : '\u00c7 \u0106 \u0108 \u010a \u010c', // Ç Ć Ĉ Ċ Č
d : '\u010f \u00f0 \u010f', // ď ð ď
D : '\u010e \u00d0 \u010e', // Ď Ð Ď
e : '\u0117 \u0119 \u0115 \u011b \u0259 \u00e8 \u00e9 \u00ea \u00eb \u0113', // ė ę ĕ ě ə è é ê ë ē
E : '\u0116 \u0118 \u0114 \u011a \u018e \u00c8 \u00c9 \u00ca \u00cb \u0112', // Ė Ę Ĕ Ě Ǝ È É Ê Ë Ē
g : '\u0123 \u011f \u011d \u0121', // ģ ğ ĝ ġ
G : '\u0122 \u011e \u011c \u0120', // Ģ Ğ Ĝ Ġ
h : '\u0125 \u0127', // ĥ ħ
H : '\u0124 \u0126', // Ĥ Ħ
i : '\u0131 \u012f \u012b \u00ef \u00ee \u00ed \u00ec \u0129 \u012d', // ı į ī ï î í ì ĩ ĭ
I : '\u0130 \u012e \u012a \u00cf \u00ce \u00cd \u00cc \u0128 \u012c', // İ Į Ī Ï Î Í Ì Ĩ Ĭ
j : '\u0135', // ĵ
J : '\u0134', // Ĵ
k : '\u0137', // ķ
K : '\u0136', // Ķ
l : '\u0141 \u013d \u013b \u0139 \u013f', // Ł Ľ Ļ Ĺ Ŀ
L : '\u0142 \u013e \u013c \u013a \u0140', // ł ľ ļ ĺ ŀ
n : '\u0149 \u0148 \u0146 \u0144 \u00f1', // ʼn ň ņ ń ñ
N : '\u0149 \u0147 \u0145 \u0143 \u00d1', // ʼn Ň Ņ Ń Ñ
o : '\u0153 \u0151 \u00f8 \u00f6 \u00f5 \u00f4 \u00f3 \u00f2 \u014d \u014f', // œ ő ø ö õ ô ó ò ō ŏ
O : '\u0152 \u0150 \u00d8 \u00d6 \u00d5 \u00d4 \u00d3 \u00d2 \u014c \u014e', // Œ Ő Ø Ö Õ Ô Ó Ò Ō Ŏ
r : '\u0155 \u0159 \u0157', // ŕ ř ŗ
R : '\u0154 \u0158 \u0156', // Ŕ Ř Ŗ
s : '\u015b \u0161 \u015f \u00df \u00a7 \u015d', // ś š ş ß § ŝ
S : '\u015a \u0160 \u015e \u1e9e \u00a7 \u015c', // Ś Š Ş ẞ § Ŝ
t : '\u00fe \u0165 \u021b \u0163 \u0167', // þ ť ț ţ ŧ
T : '\u00de \u0164 \u021a \u0162 \u0166', // Þ Ť Ț Ţ Ŧ
u : '\u0173 \u0171 \u016f \u016b \u00fc \u00fb \u00fa \u00f9 \u0169 \u016d', // ų ű ů ū ü û ú ù ũ ŭ
U : '\u0172 \u0170 \u016e \u016a \u00dc \u00db \u00da \u00d9 \u0168 \u016c', // Ų Ű Ů Ū Ü Û Ú Ù Ũ Ŭ
w : '\u0175', // ŵ
W : '\u0174', // Ŵ
y : '\u00fd', // ý
Y : '\u00dd', // Ý
z : '\u017a \u017c \u017e', // ź ż ž
Z : '\u0179 \u017b \u017d', // Ź Ż Ž
'!' : '\u00a1', // ¡
'$' : '\u20ac \u00a3 \u00a4 \u00a5 \u00a2 \u20a1 \u20b1 \u20a9 \u20b9 \u20aa \u20ad \u20ae \u20a6 \u20a4', // €£¤¥¢₡₱₩₹₪₭₮₦₤
'?' : '\u00bf', // ¿
"'" : '\u3008 \u300c \u300e \u201c', // 〈 「 『 “
'"' : '\u3009 \u300d \u300f \u201d', // 〉 」 』 ”
'(' : '\u300a \u3010 \u3014', // « 【 〔
')' : '\u300b \u3011 \u3015' // » 】 〕
}, $keyboard.altKeys );
$.fn.addAltKeyPopup = function( options ) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
// time to hold down a button in ms to trigger a popup
holdTime : 500,
// events triggered when popup is visible & hidden
popupVisible : 'popup-visible',
popupHidden : 'popup-hidden',
popupPosition : null
};
return this.each( function() {
// make sure a keyboard is attached
var base = $( this ).data( 'keyboard' );
if (!base) { return; }
// variables
base.altkeypopup_options = $.extend(
{},
defaults,
base.altkeypopup_options, // restore prev options on layout update
options
);
// already initialized
if ( base.altkeypopup_namespace ) {
return base.altkeypopup_setup();
}
base.altkeypopup_namespace = base.namespace + 'AltKeyPopup';
base.extensionNamespace.push( base.altkeypopup_namespace );
base.altkeypopup_setup = function() {
var timer,
start = 'mousedown touchstart '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' ),
end = 'mouseup touchend touchcancel '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' );
// force disable repeat keys
base.options.repeatRate = 0;
// add hold key functionality for popups
base
.unbindButton( base.altkeypopup_namespace )
.bindButton( start, function() {
clearTimeout( timer );
var $key = $( this ),
key = $key.attr( 'data-value' ) || '',
delay = base.altkeypopup_options.holdTime;
if ( key in $keyboard.altKeys ) {
if (delay) {
timer = setTimeout( function() {
base.altKeyPopup_popup( key, $key );
}, delay );
} else {
// holdTime set to zero.. don't use a setTimeout
base.altKeyPopup_popup( key, $key );
}
}
})
.bindButton( end, function() {
clearTimeout( timer );
});
base.altkeypopup_blockingFlag = false;
base.$preview
.unbind(
'keypress keydown keyup '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' )
.trim()
)
.bind(
'keypress keydown keyup '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' ),
function( event ) {
if ( event.type === 'keyup' ) {
clearTimeout( timer );
base.altkeypopup_blockingFlag = false;
return event.key !== 'Escape';
}
var layout = $keyboard.builtLayouts[ base.layout ],
$key = $( event.target ),
origKey = event.key,
key = event.key;
if ( event.type === 'keydown' && key in $keyboard.altKeys ) {
// Compare typed key to prevent blocking issues reported in #664
if ( base.altkeypopup_blockingFlag === origKey ) {
return false;
}
base.altkeypopup_blockingFlag = origKey;
// return true on initial keydown or keypress never fires
// then return false to prevent repeat key
return true;
}
if ( base.altkeypopup_blockingFlag ) {
// find mapped key, if any
if (
layout.hasMappedKeys &&
layout.mappedKeys.hasOwnProperty( key )
) {
key = layout.mappedKeys[ key ];
}
if ( key in $keyboard.altKeys ) {
clearTimeout( timer );
timer = setTimeout( function() {
if ( base.altkeypopup_blockingFlag === origKey ) {
base.altKeyPopup_popup( key, $key );
}
}, base.altkeypopup_options.holdTime );
}
return true;
}
}
);
};
base.altKeyPopup_close = function() {
base.altkeypopup_blockingFlag = false;
base.altKeyPopup_$overlay = null;
setTimeout(function() {
if (base.$keyboard.length) {
base.$keyboard.removeClass($keyboard.css.altKeyPopupOpen);
var $el = base.$keyboard.find( '.' + $keyboard.css.altKeyOverlay );
if ($el) {
$el.remove();
}
}
}, 1);
$( document ).unbind( base.altkeypopup_namespace );
base.$preview.focus();
// restore ignoreEsc option
base.options.ignoreEsc = base.altKeyPopup_savedIgnoreEsc;
// trigger popup hidden event
base.$el.trigger( base.altkeypopup_options.popupHidden, [ base ] );
};
base.altKeyPopup_popup = function( key, $key ) {
if ( base.$keyboard.find( '.' + $keyboard.css.altKeyOverlay ).length ) {
return;
}
var keys, $container, $keys, positionHoriz, positionVert, top,
popupWidth, popupHeight, evts,
kbcss = $keyboard.css,
data = {
$kb : base.$keyboard,
kbWidth : base.$keyboard.outerWidth(),
kbHeight : base.$keyboard.outerHeight(),
$key : $key
};
// overlay keyboard
base.altKeyPopup_$overlay =
$( '<div class="' + kbcss.altKeyOverlay + '" />' )
.css({
width : data.kbWidth,
height: data.kbHeight
})
.appendTo( base.$keyboard )
.bind( 'click touchstart', function() {
base.altKeyPopup_close();
});
evts = 'inactive hidden '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' );
base.$keyboard.addClass($keyboard.css.altKeyPopupOpen);
base.$el.unbind( evts ).bind( evts, function() {
base.altKeyPopup_close();
});
// remove character added when key was initially pressed, unless it
// was a backspace key
if ( key !== 'bksp' ) {
$keyboard.keyaction.bksp( base );
}
// make popup; use the same classes as the keyboard container
$container = $(
'<div class="' + kbcss.altKeyPopup + ' ' +
base.options.css.container + '" />'
);
keys = $keyboard.altKeys[ key ].split( /\s+/ );
// make popup keys
base.buildRow( $container, 0, keys, [] );
// add popup & add bindings
$keys = $container
.appendTo( base.altKeyPopup_$overlay )
.children()
.bind( 'mousedown touchstart', function() {
// action/value now processed by core functions
base.altKeyPopup_close();
})
.bind( 'mouseover mouseleave', function( event ){
// remove hover from physical keyboard highlighted key
$keys.removeClass( base.options.css.buttonHover );
if ( event.type !== 'mouseleave' ) {
$( this ).addClass( base.options.css.buttonHover );
}
});
// popup opened... add key highlight
base.altKeyPopup_navigate( true ); // init
// set ignoreEsc to allow escape to ONLY close the popup
base.altKeyPopup_savedIgnoreEsc = base.options.ignoreEsc;
base.options.ignoreEsc = true;
$( document )
.unbind( base.altkeypopup_namespace )
.bind( 'keydown' + base.altkeypopup_namespace, function() {
// keep home & end from scrolling the page
return false;
})
.bind( 'keyup' + base.altkeypopup_namespace, function( event ) {
if ( event.key === 'Escape' ) {
event.which = 0; // prevent escClose from closing the keyboard
base.altKeyPopup_close();
} else {
base.altKeyPopup_navigate( event );
}
return false;
});
data.$popup = $container;
popupWidth = $container.outerWidth();
// position popup within $keyboard container
positionHoriz = $key.position().left - popupWidth / 2;
if ( positionHoriz + popupWidth > data.kbWidth ) {
positionHoriz = data.kbWidth - popupWidth;
if ( positionHoriz < 0 ) {
$container.css({
width : data.kbWidth,
height : 'auto'
});
}
}
positionVert = $key.position().top - $key.outerHeight() - 5;
popupHeight = $container.outerHeight();
// find top of keyset (don't cover up the preview input)
top = base.$keyboard.find( '.' + kbcss.keySet ).position().top;
if ( positionVert + popupHeight > data.kbHeight ) {
positionVert = data.kbHeight - popupHeight;
if ( positionVert < top ) {
$container.css({
height : data.popupHeight,
width : 'auto'
});
}
}
data.popupWidth = $container.outerWidth();
data.popupHeight = $container.outerHeight();
data.popupLeft = positionHoriz < 0 ? 0 : positionHoriz;
data.popupTop = positionVert < top ? top : positionVert;
$container.css({
position : 'absolute',
left : data.popupLeft,
top : data.popupTop
});
// adjust position as needed using popupPosition callback function
if ( typeof base.altkeypopup_options.popupPosition === 'function' ) {
base.altkeypopup_options.popupPosition(base, data);
}
base.$preview.blur();
// trigger popup visible event
base.$el.trigger( base.altkeypopup_options.popupVisible, [ base ] );
};
base.altKeyPopup_navigate = function( event ) {
var indx,
kbcss = $keyboard.css,
k = $keyboard.navigationKeys,
hover = base.options.css.buttonHover,
$keys = base.$keyboard
.find( '.' + kbcss.altKeyPopup )
.find( '.' + kbcss.keyButton ),
max = $keys.length - 1;
// popup visible, add key highlight
if ( event === true ) {
$keys.eq( 0 ).addClass( hover );
base.altKeyPopup_currentIndex = 0;
return;
}
indx = base.altKeyPopup_currentIndex;
if ( event.key === 'Enter' ) {
base.insertText( $keys.eq( indx ).attr( 'data-value' ) );
base.altKeyPopup_close();
return true;
}
switch( event.key ) {
case 'End': indx = max; break;
case 'Home': indx = 0; break;
case 'ArrowLeft': indx -= 1; break;
case 'ArrowRight': indx += 1; break;
}
if ( indx < 0 ) { indx = 0; }
if ( indx > max ) { indx = max; }
base.altKeyPopup_currentIndex = indx;
$keys
.removeClass( hover )
.eq( indx )
.addClass( hover );
};
// visible event is fired before this extension is initialized, so check!
if ( base.options.alwaysOpen && base.isVisible() ) {
base.altkeypopup_setup();
}
// setup altkey popup
base.$el
.unbind(
$keyboard.events.kbBeforeVisible + base.altkeypopup_namespace
)
.bind(
$keyboard.events.kbBeforeVisible + base.altkeypopup_namespace,
function() {
base.altkeypopup_setup();
}
);
});
};
}));
/*! jQuery UI Virtual Keyboard Autocomplete v1.11.4 *//*
* for Keyboard v1.18+ only (2018-01-10)
*
* By Rob Garrison (Mottie)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to get
* the jQuery UI Autocomplete widget to work seamlessly
*
* Requires:
* jQuery
* jQuery UI & css
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .autocomplete(options)
* .addAutoComplete();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .autocomplete(options) // jQuery UI autocomplete
* .addAutoComplete(); // this keyboard extension
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.fn.addAutocomplete = function(options) {
var defaults = {
position : {
of : null,
my : 'right top',
at : 'left top',
collision: 'flip'
},
events: 'autocomplete',
data: ''
};
return this.each(function() {
// make sure a keyboard is attached
var o, namespace,
base = $(this).data('keyboard');
if (!base) { return; }
namespace = base.namespace + 'Autocomplete';
base.autocomplete_namespace = namespace;
base.extensionNamespace.push( namespace );
// Setup
base.autocomplete_init = function() {
// variables
o = base.autocomplete_options = $.extend( true, {}, defaults, options );
var events = o.events || o.data || 'autocomplete';
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible()) {
base.autocomplete_setup();
}
base.$el
.unbind(namespace)
.bind($.keyboard.events.kbVisible + namespace, function() {
base.autocomplete_setup();
})
.bind($.keyboard.events.kbHidden + namespace, function() {
base.$el[o.data || 'autocomplete']('close');
})
.bind($.keyboard.events.kbChange + namespace, function() {
if (base.hasAutocomplete && base.isVisible()) {
base.$el.val(base.$preview.val());
}
})
.bind(events + 'open' + namespace, function() {
if (base.hasAutocomplete) {
// default to $keyboard if no position.of defined
var position = $.extend( {}, o.position );
// refresh base.$keyboard (it gets destroyed after use); fixes #382
position.of = position.of || base.$keyboard;
// reposition autocomplete window next to the keyboard
base.$autocomplete.menu.element.position( position );
}
})
.bind(events + 'select' + namespace, function(e, ui) {
base.autocomplete_getVal(ui.item);
});
};
base.autocomplete_getVal = function(val) {
var v;
switch (typeof val) {
case 'string':
v = val || '';
break;
case 'object':
v = val.label || val.value || '';
break;
default:
v = base.preview && base.preview.value || base.el.value;
}
v = v.toString();
if (base.hasAutocomplete && v !== '') {
// fallback to original input if undefined, see #520
(base.$preview || base.$el)
.val( v )
.focus();
// see issue #95 - thanks banku!
base.last.start = v.length;
base.last.end = v.length;
base.last.val = v;
}
};
base.autocomplete_update = function(event) {
clearTimeout( base.$autocomplete.searching );
base.$autocomplete.searching = setTimeout(function() {
// only search if the value has changed
if ( base.$autocomplete.term !== base.$autocomplete.element.val() ) {
base.$autocomplete.selectedItem = null;
base.$autocomplete.search( null, event );
}
}, base.$autocomplete.options.delay );
};
base.autocomplete_navKeys = {
8: 'backSpace',
9: 'tab',
13: 'enter',
20: 'capsLock',
27: 'escape',
32: 'space',
33: 'pageup',
34: 'pagedown',
35: 'end',
36: 'home',
37: 'left',
38: 'up',
39: 'right',
40: 'down',
45: 'insert',
46: 'delete'
};
// set up after keyboard is visible
base.autocomplete_setup = function() {
var key;
// look for autocomplete
base.$autocomplete = base.$el.data(base.autocomplete_options.data) ||
// data changes based on jQuery UI version
base.$el.data('uiAutocomplete') ||
base.$el.data('ui-autocomplete') ||
base.$el.data('autocomplete');
base.hasAutocomplete = (typeof(base.$autocomplete) === 'undefined') ?
false : (base.$autocomplete.options.disabled) ? false : true;
// only bind to keydown once
if (base.hasAutocomplete) {
base.$preview.bind('keydown' + namespace + ' keypress' + namespace, function(event) {
// send keys to the autocomplete widget (arrow, pageup/down, etc)
if (base.$preview && event.namespace !== base.$autocomplete.eventNamespace) {
event.namespace = base.$autocomplete.eventNamespace.slice(1);
key = base.autocomplete_navKeys[event.which];
if (key) {
if (base.el !== base.preview) {
base.$el.triggerHandler(event);
if (key === 'enter') {
// update preview with the selected item
setTimeout(function(){
if (base.$autocomplete) {
base.$preview.val(base.$autocomplete.selectedItem.value);
base.$preview.focus();
}
}, 100);
}
}
} else {
// only search when a non-navigation key is pressed
base.autocomplete_update(event);
}
}
});
var events = 'mouseup mousedown mouseleave touchstart touchend touchcancel '
.split(' ')
.join(namespace + ' ');
base.bindButton(events, function(event) {
base.autocomplete_update(event);
});
}
if (!base.escCloseCallback.autocomplete) {
base.escCloseCallback.autocomplete = base.checkAutocompleteMenu;
}
};
base.checkAutocompleteMenu = function($target) {
// prevent selecting an item in autocomplete from closing keyboard
// return a "shouldStayOpen" boolean state for this extension
return base.hasAutocomplete &&
$target.closest('ul').hasClass('ui-autocomplete');
};
base.autocomplete_destroy = function() {
clearTimeout(base.$autocomplete.searching);
base.hasAutocomplete = false;
base.$el.unbind(namespace);
if (base.$preview) {
base.$preview.unbind(namespace);
base.unbindButton(namespace);
}
delete base.$autocomplete;
};
base.autocomplete_init();
});
};
}));
/*! jQuery UI Virtual Keyboard Virtual Caret v1.1.5 (beta) *//*
* for Keyboard v1.18+ only (2/20/2016)
* modified from https://github.com/component/textarea-caret-position
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
* CSS changes
* NOTE: caret margin-top => is added to the caret height (top & bottom)
* .ui-keyboard-preview-wrapper { position: relative; overflow: hidden; }
* .ui-keyboard-caret { background: red; width: 1px; margin-top: 3px; }
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;( function( factory ) {
if ( typeof define === 'function' && define.amd ) {
define( [ 'jquery' ], factory );
} else if ( typeof module === 'object' && typeof module.exports === 'object' ) {
module.exports = factory( require( 'jquery' ) );
} else {
factory( jQuery );
}
}( function( $ ) {
'use strict';
var $keyboard = $.keyboard;
$keyboard.firefox = typeof window.mozInnerScreenX !== 'undefined';
$.extend( $keyboard.css, {
caret : 'ui-keyboard-caret',
caretMirror : 'ui-keyboard-mirror-div'
});
$.fn.addCaret = function( options ) {
var defaults = {
caretClass : '',
// *** for future use ***
// data-attribute containing the character(s) next to the caret
charAttr : 'data-character',
// # character(s) next to the caret (can be negative for RTL)
charIndex : 1,
offsetX : 0,
offsetY : 0,
adjustHt : 0
};
return this.each( function() {
// make sure a keyboard is attached
var o, namespace,
kbevents = $keyboard.events,
base = $( this ).data( 'keyboard' );
if ( !base ) { return; }
// variables
o = base.caret_options = $.extend( {}, defaults, options );
namespace = base.caret_namespace = base.namespace + 'caret';
base.extensionNamespace.push( namespace );
// modified from https://github.com/component/textarea-caret-position
// The properties that we copy into a mirrored div.
// Note that some browsers, such as Firefox,
// do not concatenate properties, i.e. padding-top, bottom etc. -> padding,
// so we have to do every single property specifically.
base.textareaCaretProperties = [
'direction', 'boxSizing', 'width', 'height', 'overflowX', 'overflowY',
'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'borderStyle',
'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft',
'fontStyle', 'fontVariant', 'fontWeight', 'fontStretch', 'fontSize', 'fontSizeAdjust',
'lineHeight', 'fontFamily', 'textAlign', 'textTransform', 'textIndent', 'textDecoration',
'letterSpacing', 'wordSpacing', 'tabSize', 'MozTabSize'
];
base.caret_setup = function() {
var kbcss = $keyboard.css,
events = 'keyup keypress mouseup mouseleave '.split( ' ' ).join( namespace + ' ' ),
style = 'position:absolute;visibility:hidden;top:-9999em;left:-9999em;' +
'white-space:pre-wrap;z-index:-10;' +
( base.preview.nodeName === 'INPUT' ? '' : 'word-wrap:break-word;' );
// add mirrored div
base.$keyboard.find( '.' + kbcss.caretMirror ).remove();
base.caret_$div = $( '<div class="' + kbcss.caretMirror + '" style="' + style + '">' )
.appendTo( base.$keyboard );
// remove caret, just-in-case
if (base.$caret) { base.$caret.remove(); }
base.$caret = $( '<div class="' + kbcss.caret + ' ' + o.caretClass + '" style="position:absolute;">' )
.insertAfter( base.$preview );
base.$el
.unbind( kbevents.kbChange + namespace )
.bind( kbevents.kbChange + namespace, function() {
base.findCaretPos();
});
base.$preview
.unbind( events )
.bind( events, function() {
base.findCaretPos();
});
};
// getCaretCoordinatesFn = function (element, position, recalculate) {
base.findCaretPos = function() {
if ( !base.caret_$div ) { return; }
var style, computed, margin, pos, position, txt, span, offset,
element = base.preview,
fontWidth = parseFloat( base.$preview.css('fontSize') ),
isInput = element.nodeName === 'INPUT',
div = base.caret_$div[0];
style = div.style;
// getComputedStyle with null - fixes #384
computed = window.getComputedStyle ? getComputedStyle( element, null ) : element.currentStyle;
// get caret position based on text-direction
pos = $keyboard.caret( base.$preview );
position = Math[ computed.direction === 'ltr' ? 'max' : 'min' ]( pos.start, pos.end );
// transfer the element's properties to the div
base.textareaCaretProperties.forEach(function ( prop ) {
style[ prop ] = computed[ prop ];
});
if ( $keyboard.firefox ) {
// Firefox adds 2 pixels to the padding - https://bugzilla.mozilla.org/show_bug.cgi?id=753662
style.width = parseInt( computed.width, 10 ) - 2 + 'px';
// Firefox lies about the overflow property for textareas:
// https://bugzilla.mozilla.org/show_bug.cgi?id=984275
if ( element.scrollHeight > parseInt( computed.height, 10 ) ) {
style.overflowY = 'scroll';
}
}
// for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'
// style.overflow = 'hidden';
style.width = parseInt( isInput ? element.scrollWidth : computed.width, 10 ) +
// add 2em extra width if it's an input to prevent wrap
( isInput ? fontWidth * 2 : 0 ) + 'px';
div.textContent = element.value.substring( 0, position );
// the second special handling for input type="text" vs textarea:
// spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037
if ( element.nodeName === 'INPUT' ) {
div.textContent = div.textContent.replace( /\x20/g, '\xa0' );
}
span = document.createElement( 'span' );
// Wrapping must be replicated *exactly*, including when a long word gets
// onto the next line, with whitespace at the end of the line before (#7).
// The *only* reliable way to do that is to copy the *entire* rest of the
// textarea's content into the <span> created at the caret position.
// for inputs, just '.' would be enough, but why bother?
// || because a completely empty faux span doesn't render at all
// changed to zero-width space due to inaccuracy when textAlign = center; see #436
span.textContent = element.value.substring( position ) || '\u200b';
div.appendChild( span );
offset = $(span).position();
// adjust for 2em added to width moves caret, use half; see #436
pos = style.textAlign === 'center' ? fontWidth : 0;
base.caretPos = {
top: offset.top + parseInt( computed.borderTopWidth, 10 ) + o.offsetY,
left: offset.left + parseInt( computed.borderLeftWidth, 10 ) + o.offsetX - pos
};
// make caret height = font-size + any margin-top x2 added by the css
margin = parseInt( base.$caret.css( 'margin-top' ), 10 );
style = Math.round( fontWidth + margin * 2 ) + o.adjustHt;
offset = base.$preview.position();
base.$caret.css({
top: offset.top - element.scrollTop + base.caretPos.top - margin,
left: offset.left - element.scrollLeft + base.caretPos.left,
height: style
});
txt = element.value.substring( position, position + o.charIndex ).replace(/\s/, '\xa0' ) || '\xa0';
base.$caret.attr( o.charAttr, txt );
};
// setup caret when keyboard is visible
base.$el
.unbind( namespace )
.bind( kbevents.kbBeforeVisible + namespace, function() {
base.caret_setup();
})
.bind( kbevents.kbVisible + namespace, function() {
base.findCaretPos();
})
.bind( kbevents.kbHidden + namespace, function() {
// unbind events in case usePreview: false; see #376
var events = 'keyup keypress mouseup mouseleave '.split( ' ' ).join( namespace + ' ' );
base.$preview.unbind( events );
base.$caret.remove();
base.$caret = null;
base.caret_$div = null;
});
// visible event is fired before this extension is initialized, so check!
if ( base.options.alwaysOpen && base.isVisible() ) {
base.caret_setup();
base.findCaretPos();
}
});
};
}));
/*! jQuery UI Virtual Keyboard Extender v1.0.3 *//*
* for Keyboard v1.18+ only (12/5/2015)
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;( function( factory ) {
if ( typeof define === 'function' && define.amd ) {
define( [ 'jquery' ], factory );
} else if ( typeof module === 'object' && typeof module.exports === 'object' ) {
module.exports = factory( require( 'jquery' ) );
} else {
factory( jQuery );
}
}( function( $ ) {
'use strict';
var $keyboard = $.keyboard;
$keyboard.css.extender = 'ui-keyboard-extender';
$keyboard.language.en.display.extender = ' :toggle_numpad';
$keyboard.layouts.numpad = {
'normal' : [
'{clear} / * -',
'7 8 9 +',
'4 5 6 %',
'1 2 3 =',
'0 {dec} {left} {right}'
]
};
// add {extender} keyaction
$keyboard.keyaction.extender = function( base ) {
base.extender_toggle();
return false;
};
$.fn.addExtender = function(options) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
layout : 'numpad',
showing : false,
reposition : true
};
return this.each( function() {
var base = $( this ).data( 'keyboard' );
// make sure a keyboard is attached
if ( !base ) { return; }
// variables
base.extender_options = $.extend(
{},
defaults,
base.extender_options, // restore prev options on layout update
options
);
// already initialized & switching layouts
if ( base.extender_namespace ) {
return base.extender_layoutSwitcher();
}
base.extender_namespace = base.namespace + 'extender';
base.extensionNamespace.push( base.extender_namespace );
base.extender_layoutSwitcher = function() {
base.extender_lastKeyset = base.last.keyset;
base.extender_bindEvents( false );
base.$el.one( $keyboard.events.kbBeforeVisible, function() {
// preserve active keysets; redraw resets them - see #510
base.shiftActive = base.extender_lastKeyset[ 0 ];
base.altActive = base.extender_lastKeyset[ 1 ];
base.metaActive = base.extender_lastKeyset[ 2 ];
base.showKeySet();
base.extender_setup();
base.extender_bindEvents();
});
base.redraw();
};
base.extender_bindEvents = function( bind ) {
var event = $keyboard.events.kbBeforeVisible + base.extender_namespace;
// setup extender
base.$el.unbind( event );
if ( bind !== false ) {
base.$el.bind( event, function() {
base.extender_setup();
});
}
};
base.extender_setup = function() {
var $extender,
layout = base.extender_options.layout;
if ( typeof $keyboard.builtLayouts[ layout ] === 'undefined' ) {
base.buildKeyboard( layout );
}
$extender = $keyboard.builtLayouts[ layout ].$keyboard
// only use the "normal" layout in the extender
.find( '.' + $keyboard.css.keySet + '-normal' )
.clone();
$extender
.removeClass()
.removeAttr( 'name' )
.addClass( $keyboard.css.extender )
.children( 'button' )
.removeAttr( 'data-pos' );
// show extender using inline-block - allows the removal of css float
$extender[ 0 ].style.display = base.extender_options.showing ?
'inline-block' :
'none';
// remove previous extender... just-in-case
base.$keyboard.find( 'div.' + $keyboard.css.extender ).remove();
base.$keyboard.append( $extender );
base.extender_toggle( base.extender_options.showing );
base.bindKeys();
};
base.extender_toggle = function( set ) {
base.extender_options.showing = typeof set === 'undefined' ?
!base.extender_options.showing : set;
base.$keyboard
.find( 'button.' + $keyboard.css.extender )
.toggleClass(
base.options.css.buttonActive,
base.extender_options.showing
)
.end()
.find( 'div.' + $keyboard.css.extender )[ 0 ].style.display =
base.extender_options.showing ? 'inline-block' : 'none';
// force keyboard reposition
if ( base.extender_options.reposition ) {
$( window ).trigger( 'resize' );
}
};
// visible event is fired before this extension is initialized, so check!
if ( base.options.alwaysOpen && base.isVisible() ) {
base.extender_setup();
}
base.extender_bindEvents();
});
};
}));
/*! jQuery UI Virtual Keyboard for jQuery Mobile Themes v1.4.1 *//*
* for Keyboard v1.18+ (updated 7/7/2015)
*
* By Rob Garrison (aka Mottie & Fudgey)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to apply
* the necessary themes to make the keyboard compatible with
* jQuery Mobile themes
*
* Requires:
* jQuery - http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js
* jQuery Mobile - http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js
* jQuery Mobile themes - http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .addMobile(mobile-options);
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .addMobile(mobile-options); // this keyboard extension
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
$.fn.addMobile = function(options){
var o, defaults = {
// keyboard wrapper theme
container : { theme:'b', cssClass:'ui-body' },
// keyboard duplicate input
input : { theme:'b', cssClass:'' },
// theme added to all regular buttons
buttonMarkup : { theme:'b', cssClass:'ui-btn', shadow:'true', corners:'true' },
// theme added to all buttons when they are being hovered
buttonHover : { theme:'b', cssClass:'ui-btn-hover' },
// theme added to action buttons (e.g. tab, shift, accept, cancel);
// parameters here will override the settings in the buttonMarkup
buttonAction : { theme:'b', cssClass:'ui-btn-active' },
// theme added to button when it is active (e.g. shift is down)
// All extra parameters will be ignored
buttonActive : { theme:'b', cssClass:'ui-btn-active' },
// if more than 3 mobile themes are used, add them here
allThemes : 'a b c'
};
return this.each(function(){
var base = $(this).data('keyboard');
// Stop if no keyboard attached or if jQuery Mobile isn't loaded
if (!base || typeof($.fn.textinput) === 'undefined') { return; }
base.mobile_options = o = $.extend(true, {}, defaults, options);
// create a list of theme class names to remove
base.mobile_themes = $.trim(
(' ' + o.allThemes).split(' ').join(' ' + o.buttonMarkup.cssClass + '-') +
(' ' + o.allThemes).split(' ').join(' ' + o.buttonAction.cssClass + '-') +
(' ' + o.allThemes).split(' ').join(' ' + o.buttonActive.cssClass + '-')
);
// save original action class because it gets removed when this theme switches swatches
if (typeof base.options.mobile_savedActiveClass === 'undefined') {
base.options.mobile_savedActiveClass = '' + base.options.css.buttonActive;
}
// Setup
base.mobile_init = function() {
var namespace = base.namespace + 'Mobile';
// Add theme to input - if not already done through the markup
$('.' + $.keyboard.css.input).textinput();
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible) {
base.mobile_setup();
}
base.extensionNamespace.push( namespace );
// Setup mobile theme on keyboard once it is visible.
// Note: There is a 10ms delay after the keyboard is displayed before it actually fires 'visible.keyboard'.
// Since we are restyling here, the user will experience FlashOfUnstyledContent (FOUC).
// This is avoided by first setting the visibility to hidden, then after the mobile styles are applied we
// set it visible.
base.$el
.unbind(namespace)
.bind($.keyboard.events.kbBeforeVisible + namespace, function() {
if ( base && base.el.active && base.$keyboard.length ) {
base.$keyboard.css('visibility', 'hidden');
}
})
.bind($.keyboard.events.kbVisible + namespace, function() {
if ( base && base.el.active && base.$keyboard.length ) {
base.mobile_setup();
base.$keyboard.css('visibility', 'visible');
base.$preview.focus();
}
});
};
base.mobile_setup = function(){
var p,
kbcss = $.keyboard.css,
opts = base.options,
themes = base.mobile_themes;
base.mobile_$actionKeys = base.$keyboard.find('.' + base.options.css.buttonAction);
opts.css.buttonActive = opts.mobile_savedActiveClass + ' ' + base.modOptions(o.buttonActive, o.buttonMarkup);
base.$keyboard
// 'ui-body ui-body-a' classes to apply swatch theme
.addClass( base.modOptions(o.container, o.container) )
// preview input
.find('.' + kbcss.preview)
// removing 'ui-widget-content' will prevent jQuery UI theme from applying to the keyboard
.removeClass('ui-widget ui-widget-content')
.addClass( base.modOptions(o.input, o.input) ).end()
// apply jQuery Mobile button markup
// removed call to jQuery Mobile buttonMarkup function; replaced with base.modOptions
.find('button')
.removeClass( $.trim('ui-corner-all ui-state-default ' + themes) )
.addClass( base.modOptions(o.buttonMarkup, o.buttonMarkup) )
.not( base.mobile_$actionKeys )
.hover(function(){
$(this)
.removeClass( themes )
.addClass( base.modOptions(o.buttonHover, o.buttonMarkup) );
},function(){
$(this)
.removeClass( themes + ' ' + o.buttonHover.cssClass )
.addClass( base.modOptions(o.buttonMarkup, o.buttonMarkup) );
});
base.mobile_$actionKeys
.removeClass( themes )
.addClass( base.modOptions(o.buttonAction, o.buttonMarkup) );
// update keyboard width if preview is showing... after applying mobile theme
if (base.msie && base.$preview[0] !== base.el) {
base.$preview.hide();
base.$keyboard.css('width','');
base.width = base.$keyboard.outerWidth();
// add about 1em to input width for extra padding
base.$keyboard.width(base.width + parseInt(base.$preview.css('fontSize'),10));
base.$preview.width(base.width);
base.$preview.show();
}
// adjust keyboard position after applying mobile theme
if ($.ui && $.ui.position) {
p = opts.position;
p.of = p.of || base.$el.data('keyboardPosition') || base.$el;
p.collision = p.collision || 'flipfit flipfit';
base.$keyboard.position(p);
}
};
base.modOptions = function(t, btn){
var css = ' ' + ( t.cssClass || '' );
// Using this instead of the jQuery Mobile buttonMarkup because it is expecting <a>'s instead of <button>
// theme:'a', shadow:'true', inline:'true', corners:'false'
return css + ' ' + (btn && btn.cssClass ? btn.cssClass + '-' + (t.theme || '') : '') +
(t.shadow == 'true' ? ' ui-shadow' : '') + // eslint-disable-line eqeqeq
(t.corners == 'true' ? ' ui-corner-all' : ''); // eslint-disable-line eqeqeq
};
base.mobile_init();
});
};
}));
/*! jQuery UI Virtual Keyboard Navigation v1.7.0 *//*
* for Keyboard v1.18+ only (updated 2019-05-02)
*
* By Rob Garrison (aka Mottie & Fudgey)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to navigate
* the virtual keyboard keys using the arrow, page, home and end keys
* Using this extension WILL prevent keyboard navigation inside of all
* input and textareas
*
* Requires:
* jQuery
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .addNavigation();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .addNavigation(); // this keyboard extension
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.keyboard = $.keyboard || {};
$.keyboard.navigationKeys = {
// all keys
toggle : 112, // toggle key; F1 = 112 (event.which value for function 1 key)
enter : 13,
pageup : 33,
pagedown : 34,
end : 35,
home : 36,
left : 37,
up : 38,
right : 39,
down : 40,
// move caret WITH navigate toggle active
caretrt : 45, // Insert key
caretlt : 46, // delete key
// ** custom navigationKeys functions **
// move caret without navigate toggle active
caretright : function(kb) {
$.keyboard.keyaction.right(kb);
},
caretleft : function(kb) {
$.keyboard.keyaction.left(kb);
}
};
$.fn.addNavigation = function(options) {
return this.each(function() {
// make sure a keyboard is attached
var o, k,
base = $(this).data('keyboard'),
opts = base.options,
defaults = {
position : [0,0], // set start position [row-number, key-index]
toggleMode : false, // true = navigate the virtual keyboard, false = navigate in input/textarea
focusClass : 'hasFocus',// css class added when toggle mode is on
toggleKey : null, // defaults to $.keyboard.navigationKeys.toggle value
rowLooping : false // when you are at the left end position and hit the left cursor, you will appear at the other end
},
kbevents = $.keyboard.events,
kbcss = $.keyboard.css;
if (!base) { return; }
base.navigation_options = o = $.extend({}, defaults, options);
base.navigation_keys = k = $.extend({}, $.keyboard.navigationKeys);
base.navigation_namespace = base.namespace + 'Nav';
base.extensionNamespace.push( base.navigation_namespace );
// save navigation settings - disabled when the toggled
base.saveNav = [ base.options.tabNavigation, base.options.enterNavigation ];
base.allNavKeys = $.map(k, function(v) { return v; });
// Setup
base.navigation_init = function() {
base.$keyboard.toggleClass(o.focusClass, o.toggleMode)
.find('.' + kbcss.keySet + ':visible')
.find('.' + kbcss.keyButton + '[data-pos="' + o.position[0] + ',' + o.position[1] + '"]')
.addClass(opts.css.buttonHover);
base.$preview
.unbind(base.navigation_namespace)
.bind('keydown' + base.navigation_namespace,function(e) {
return base.checkKeys(e.which);
});
};
base.checkKeys = function(key, disable) {
if (typeof(key) === 'undefined' || !base.isVisible()) {
return;
}
var k = base.navigation_keys;
if (key === ( o.toggleKey || k.toggle ) || disable) {
o.toggleMode = (disable) ? false : !o.toggleMode;
base.options.tabNavigation = (o.toggleMode) ? false : base.saveNav[0];
base.options.enterNavigation = (o.toggleMode) ? false : base.saveNav[1];
}
base.$keyboard.toggleClass(o.focusClass, o.toggleMode);
if ( o.toggleMode && key === k.enter ) {
base.$keyboard
.find('.' + kbcss.keySet + ':visible')
.find('.' + kbcss.keyButton + '[data-pos="' + o.position[0] + ',' + o.position[1] + '"]')
.trigger(kbevents.kbRepeater);
return false;
}
if ( o.toggleMode && $.inArray(key, base.allNavKeys) >= 0 ) {
base.navigateKeys(key);
return false;
}
};
base.getMaxIndex = function(vis, row) {
return vis.find('.' + kbcss.keyButton + '[data-pos^="' + row + ',"]').length - 1;
};
base.leftNavigateKey = function(indx, maxIndx) {
var rowLooping = base.navigation_options.rowLooping;
var newIndx = indx - 1;
return newIndx >= 0 ? newIndx :
rowLooping ? maxIndx : 0 ;
};
base.rightNavigateKey = function(indx, maxIndx) {
var rowLooping = base.navigation_options.rowLooping;
var newIndx = indx + 1;
return newIndx <= maxIndx ? newIndx :
rowLooping ? 0 : maxIndx ;
};
base.navigateKeys = function(key, row, indx) {
if (!base.isVisible()) {
return;
}
indx = typeof indx === 'number' ? indx : o.position[1];
row = typeof row === 'number' ? row : o.position[0];
var nextMaxIndx,
vis = base.$keyboard.find('.' + kbcss.keySet + ':visible'),
maxRow = vis.find('.' + kbcss.endRow).length - 1,
maxIndx = base.getMaxIndex(vis, row),
p = base.last,
l = base.$preview.val().length,
k = base.navigation_keys;
switch(key) {
case k.pageup : row = 0; break; // pageUp
case k.pagedown : row = maxRow; break; // pageDown
case k.end : indx = maxIndx; break; // End
case k.home : indx = 0; break; // Home
case k.left : indx = base.leftNavigateKey(indx, maxIndx); break; // Left
case k.up :
row += (row > 0) ? -1 : 0;
nextMaxIndx = base.getMaxIndex(vis, row);
indx = indx === maxIndx ? nextMaxIndx : indx;
break; // Up
case k.right : indx = base.rightNavigateKey(indx, maxIndx); break; // Right
case k.down :
row += (row + 1 > maxRow) ? 0 : 1;
nextMaxIndx = base.getMaxIndex(vis, row);
indx = indx === maxIndx ? nextMaxIndx : indx;
break; // Down
case k.caretrt : p.start++; break; // caret right
case k.caretlt : p.start--; break; // caret left
}
// move caret
if (key === k.caretrt || key === k.caretlt) {
p.start = p.start < 0 ? 0 : p.start > l ? l : p.start;
base.last.start = base.last.end = p.end = p.start;
$.keyboard.caret( base.$preview, base.last );
}
// get max index of new row
maxIndx = base.getMaxIndex(vis, row);
if (indx > maxIndx) { indx = maxIndx; }
vis.find('.' + opts.css.buttonHover).removeClass(opts.css.buttonHover);
vis.find('.' + kbcss.keyButton + '[data-pos="' + row + ',' + indx + '"]').addClass(opts.css.buttonHover);
o.position = [ row, indx ];
};
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible()) {
base.$keyboard.find('.' + opts.css.buttonHover).removeClass(opts.css.buttonHover);
base.navigation_init();
}
// navigation bindings
base.$el
.unbind(base.navigation_namespace)
.bind(kbevents.kbVisible, function() {
base.$keyboard.find('.' + opts.css.buttonHover).removeClass(opts.css.buttonHover);
base.navigation_init();
})
.bind(kbevents.kbInactive + ' ' + kbevents.kbHidden, function(e) {
base.checkKeys(e.which, true); // disable toggle mode & revert navigation options
})
.bind(kbevents.kbKeysetChange, function() {
base.navigateKeys(null);
})
.bind('navigate navigateTo', function(e, row, indx) {
var key;
// no row given, check if it's a navigation key or keyaction
row = isNaN(row) ? row.toLowerCase() : row;
if (row in base.navigation_keys) {
key = base.navigation_keys[row];
if (isNaN(key) && key in $.keyboard.keyaction) {
// defined navigation_keys string name is a defined keyaction
$.keyboard.keyaction[key]( base, this, e );
} else if (typeof key === 'function') {
// custom function defined in navigation_keys
key(base);
} else {
// key (e.which value) is defined in navigation_keys
base.checkKeys(key);
}
} else if ( typeof row === 'string' && row in $.keyboard.keyaction ) {
// navigate called directly with a keyaction name
$.keyboard.keyaction[row]( base, this, e );
} else {
base.navigateKeys(null, row, indx);
}
});
});
};
}));
/*! jQuery UI Virtual Keyboard previewKeyset v1.1.1 *//*
* for Keyboard v1.18+ only (updated 7/7/2015)
*
* By Rob Garrison (aka Mottie & Fudgey)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to add a preview
* of other keysets to the main keyboard.
*
* Requires:
* jQuery
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .previewKeyset();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .previewKeyset(); // this keyboard extension
*
*/
/* jshint browser:true, jquery:true, unused:false */
/* global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.keyboard = $.keyboard || {};
$.fn.previewKeyset = function( options ) {
return this.each( function() {
// make sure a keyboard is attached
var base = $( this ).data( 'keyboard' ),
namespace = base.namespace + 'Preview',
defaults = {
sets : [ 'normal', 'shift', 'alt', 'alt-shift' ]
};
if ( !base ) { return; }
base.previewKeyset_options = $.extend( {}, defaults, options );
base.extensionNamespace.push( namespace );
base.previewKeyset = function() {
var kbcss = $.keyboard.css,
sets = base.previewKeyset_options.sets,
// only target option defined sets
$sets = base.$keyboard.find( '.' + kbcss.keySet ).filter( '[name="' + sets.join('"],[name="') + '"]' );
if ( $sets.length > 1 ) {
// start with normal keyset & find all non-action buttons
$sets.eq( 0 ).find( '.' + kbcss.keyButton ).not( '.' + kbcss.keyAction ).each(function(){
var indx, nam,
data = {},
len = sets.length,
// find all keys with the same position
$sibs = $sets.find( 'button[data-pos="' + $(this).attr('data-pos') + '"]' );
for ( indx = 0; indx < len; indx++ ) {
nam = $sibs.eq( indx ).parent().attr( 'name' );
if ( $.inArray( nam, sets ) >= 0 ) {
data[ 'data-' + nam ] = $sibs.eq( indx ).find( '.' + kbcss.keyText ).text();
}
}
$sibs.attr( data );
});
}
};
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible()) {
base.previewKeyset();
} else {
base.$el
.unbind($.keyboard.events.kbBeforeVisible + namespace)
.bind($.keyboard.events.kbBeforeVisible + namespace, function() {
base.previewKeyset();
});
}
});
};
}));
/*! jQuery UI Virtual Keyboard Scramble Extension v1.8.0 *//*
* for Keyboard v1.18+ (updated 2019-05-02)
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to scramble the
* specified keyboard keys
*
* Requires:
* jQuery v1.4.4+
* Keyboard v1.17.14+ - https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .addScramble();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .addScramble(); // this keyboard extension
*
*/
/* jshint browser:true, jquery:true, unused:false */
/* global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.keyboard = $.keyboard || {};
$.fn.addScramble = function(options) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
// keys to randomize
targetKeys : /[a-z\d]/i,
// randomize by row, otherwise randomize all keys
byRow : true,
// if true, randomize one keyset & duplicate
byKeySet : false,
// if true, randomize only once on keyboard visible
randomizeOnce : true,
// if true, randomize after user input;
// only `targetKeys` cause a new randomization
randomizeInput : false,
// initialization callback function
init : null, // function(keyboard){}
// use the same scrambled keyboard for all targetted keyboards
// not fully implemented!
sameForAll : false
};
return this.each(function() {
// make sure a keyboard is attached
var o,
base = $(this).data('keyboard'),
namespace = base.namespace + 'Scramble',
opts = base.options;
if (!base || base.scramble_options) { return; }
o = base.scramble_options = $.extend({}, defaults, options);
base.extensionNamespace.push( namespace );
// save create callback
o.orig_create = opts.create;
base.scramble_setup = function($keyboard) {
var $sets, set, $keys, key, index, tmp,
rowIndex, keyboardmap, map, keyboard, row;
$sets = $keyboard.find('.' + $.keyboard.css.keySet);
if ($keyboard.length) {
if (o.byKeySet) {
$sets = $sets.eq(0);
}
for (set = 0; set < $sets.length; set++) {
/*jshint loopfunc:true */
$keys = $sets.eq(set);
rowIndex = 0;
row = [];
map = [];
keyboardmap = [];
keyboard = [];
$keys.children('button, span, br').each(function() {
if (this.tagName === 'BR') {
if (o.byRow) {
row.push(this);
map.push(false);
keyboard[rowIndex] = row;
keyboardmap[rowIndex] = map;
row = [];
map = [];
rowIndex++;
} else {
keyboard[rowIndex] = this;
keyboardmap[rowIndex] = false;
rowIndex++;
}
} else {
tmp = $(this).attr('data-value') || '';
tmp = tmp.length === 1 && o.targetKeys.test(tmp) ? tmp : false;
if (o.byRow) {
row.push(this);
map.push (tmp);
} else {
keyboard[rowIndex] = this;
keyboardmap[rowIndex] = tmp;
rowIndex++;
}
}
});
// remove original <br> elements
$keys.find('.' + $.keyboard.css.endRow).remove();
// re-map keys
if (!o.byRow) {
row = base.shuffle( keyboard, keyboardmap );
for (key = 0; key < row.length; key++) {
$keys.append(row[key]);
}
} else {
for (index = 0; index < keyboard.length; index++) {
row = base.shuffle( keyboard[index], keyboardmap[index] );
for (key = 0; key < row.length; key++) {
$keys.append(row[key]);
}
}
}
}
if (o.byKeySet) {
$keyboard = base.realign($keyboard);
}
return $keyboard;
}
};
// get a random uint from 0 ... max-1
base.getRandomUInt = function(max) {
var cryptoObj = window.crypto || window.msCrypto;
if (cryptoObj !== undefined) {
var random_array = new Uint32Array(1);
cryptoObj.getRandomValues(random_array);
return random_array[0] % max;
}
// fallback
return Math.floor(Math.random() * max);
};
// modified from Fisher-Yates shuffle ( http://bost.ocks.org/mike/shuffle/ )
// to allow not shuffling specifically mapped array elements
base.shuffle = function(array, map) {
var swap, random,
index = array.length;
// While there remain elements to shuffle...
while (index > 0) {
// Pick a remaining element...
random = base.getRandomUInt(index);
if (map[index - 1] === false) {
index--;
}
// skip elements that are mapped to false
if (map[index - 1] !== false && map[random] !== false) {
// And swap it with the current element
index--;
swap = array[index];
array[index] = array[random];
array[random] = swap;
}
}
return array;
};
// make other keysets "line-up" with scrambled keyset
base.realign = function($keyboard) {
var selector, typ, pos,
$sets = $keyboard.find('.' + $.keyboard.css.keySet),
$orig = $sets.eq(0);
$sets = $sets.filter(':gt(0)');
$orig.children().each(function(i, cell) {
typ = cell.tagName === 'BR';
pos = $(cell).attr('data-pos');
/*jshint loopfunc:true */
$sets.each(function(j, k) {
selector = typ ? 'br:first' : 'button[data-pos="' + pos + '"]';
$(k).find(selector).appendTo( k );
});
});
return $keyboard;
};
base.setScrambleLayout = function() {
// scrambled layout already initialized
if (!/^scrambled/.test(opts.layout)) {
base.orig_layout = opts.layout;
var savedLayout = savedLayout || 'scrambled' + Math.round(Math.random() * 10000);
opts.layout = o.sameForAll ? savedLayout : 'scrambled' + Math.round(Math.random() * 10000);
}
};
// create scrambled keyboard layout
opts.create = function() {
var layout = opts.layout;
$.keyboard.builtLayouts[layout] = {
mappedKeys : {},
acceptedKeys : [],
$keyboard : null
};
base.layout = opts.layout = base.orig_layout;
// build original layout, if not already built, e.g. "qwerty"
base.buildKeyboard( base.layout, true );
base.layout = opts.layout = layout;
// clone, scramble then save layout
$.keyboard.builtLayouts[layout] = $.extend(true, {}, $.keyboard.builtLayouts[base.orig_layout]);
if ( o.randomizeOnce ) {
$.keyboard.builtLayouts[layout].$keyboard =
base.scramble_setup( $.keyboard.builtLayouts[base.orig_layout].$keyboard.clone() );
}
base.$keyboard = $.keyboard.builtLayouts[layout].$keyboard;
// randomize after every input - see #522
if ( o.randomizeInput ) {
base.$el
.unbind($.keyboard.events.kbChange + namespace)
.bind($.keyboard.events.kbChange + namespace, function(e, kb) {
if ( o.targetKeys.test( kb.last.key ) ) {
// prevent hover class flash on previous key after scramble
kb.$keyboard
.find('.' + opts.css.buttonHover)
.removeClass(opts.css.buttonHover);
kb.$keyboard = kb.scramble_setup(kb.$keyboard);
// now make sure the key under the mouse is highlighted
$(document.elementFromPoint(e.clientX, e.clientY)).trigger('mouseenter');
}
});
} else if ( !o.randomizeOnce ) {
base.$el
.unbind($.keyboard.events.kbBeforeVisible + namespace)
.bind($.keyboard.events.kbBeforeVisible + namespace, function(e, kb) {
kb.$keyboard = kb.scramble_setup(kb.$keyboard);
});
}
if ( typeof o.orig_create === 'function' ) {
o.orig_create( base );
}
};
base.setScrambleLayout();
// special case when keyboard is set to always be open
if (opts.alwaysOpen && base.$keyboard.length) {
setTimeout(function() {
var built = $.keyboard.builtLayouts;
base.$keyboard = base.scramble_setup(base.$keyboard);
base.setScrambleLayout();
if (typeof built[opts.layout] === 'undefined') {
built[opts.layout] = {
mappedKeys : $.extend({}, built[base.layout].mappedKeys),
acceptedKeys : $.extend([], built[base.layout].acceptedKeys),
$keyboard : base.$keyboard.clone()
};
}
if (typeof o.init === 'function') {
o.init(base);
}
}, 0);
} else {
if (typeof o.init === 'function') {
o.init(base);
}
}
});
};
}));
/*! jQuery UI Virtual Keyboard Typing Simulator v1.12.0 *//*
* for Keyboard v1.18+ only (2019-05-02)
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to simulate
* typing for tutorials or whatever else use you can find
*
* Requires:
* jQuery
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .addTyping(typing-options);
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options)
* .addTyping(typing-options);
*
* Basic Usage:
* // To disable manual typing on the virtual keyboard, just set "showTyping"
* // option to false
* $('#keyboard-input').keyboard(options).addTyping({ showTyping: false });
*
* // Change the default typing delay (time the virtual keyboard highlights the
* // manually typed key) - default = 250 milliseconds
* $('#keyboard-input').keyboard(options).addTyping({ delay: 500 });
*
* // get keyboard object, open it, then start typing simulation
* $('#keyboard-input').getkeyboard().reveal().typeIn('Hello World', 700);
*
* // get keyboard object, open it, type in "This is a test" with 700ms delay
* // between types, then accept & close the keyboard
* $('#keyboard-input')
* .getkeyboard()
* .reveal()
* .typeIn('This is a test', 700, function(keyboard) {
* keyboard.accept();
* });
*/
/* More Examples:
* $('#inter').getkeyboard().reveal().typeIn('\tHello \b\n\tWorld', 500);
* $('#meta')
* .getkeyboard().reveal()
* .typeIn('abCDd11123\u2648\u2649\u264A\u264B', 700, function() {
* alert('all done!');
* });
*/
/* jshint browser:true, jquery:true, unused:false */
/* global require:false, define:false, module:false */
;( function( factory ) {
if ( typeof define === 'function' && define.amd ) {
define( ['jquery'], factory );
} else if (
typeof module === 'object' &&
typeof module.exports === 'object'
) {
module.exports = factory( require( 'jquery' ) );
} else {
factory( jQuery );
}
}( function( $ ) {
$.fn.addTyping = function( options ) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
showTyping : true,
lockTypeIn : false,
delay : 250,
hoverDelay : 250
},
$keyboard = $.keyboard;
return this.each( function() {
// make sure a keyboard is attached
var o, base = $( this ).data( 'keyboard' );
if ( !base ) {
return;
}
// variables
o = base.typing_options = $.extend( {}, defaults, options );
base.typing_keymap = {
' ' : 'space',
'"' : '34',
"'" : '39',
'&nbsp;' : 'space',
'\b' : 'bksp', // delete character to the left
'{b}' : 'bksp',
'{d}' : 'del', // delete character to the right
'{l}' : 'left', // move caret left
'{r}' : 'right', // move caret right
'\n' : 'enter',
'\r' : 'enter',
'{e}' : 'enter',
'\t' : 'tab',
'{t}' : 'tab'
};
base.typing_xref = {
8 : 'bksp',
9 : 'tab',
13 : 'enter',
32 : 'space',
37 : 'left',
39 : 'right',
46 : 'del'
};
base.typing_event = false;
base.typing_namespace = base.namespace + 'typing';
base.extensionNamespace.push( base.typing_namespace );
// save lockInput setting
o.savedLockInput = base.options.lockInput;
base.typing_setup_reset = function() {
var kbevents = $keyboard.events,
namespace = base.typing_namespace,
events = [ kbevents.kbHidden, kbevents.kbInactive, '' ]
.join( namespace + ' ' );
// reset "typeIn" when keyboard is closed
base.$el
.unbind( namespace )
.bind( events, function() {
base.typing_reset();
});
base
.unbindButton( namespace )
.bindButton( 'mousedown' + namespace, function() {
base.typing_reset();
});
};
base.typing_setup = function() {
var namespace = base.typing_namespace;
base.typing_setup_reset();
base.$el
.bind( $keyboard.events.kbBeforeVisible + namespace, function() {
base.typing_setup();
});
base.$preview
.unbind( namespace )
.bind( 'keyup' + namespace, function( e ) {
if ( o.init && o.lockTypeIn || !o.showTyping ) {
return false;
}
if ( e.which >= 37 && e.which <=40 ) {
return; // ignore arrow keys
}
if ( e.which === 16 ) {
base.shiftActive = false;
}
if ( e.which === 18 ) {
base.altActive = false;
}
if ( e.which === 16 || e.which === 18 ) {
base.showSet();
// Alt key will shift focus to the menu - doesn't work in Windows
setTimeout( function() {
if (base.$preview) {
base.$preview.focus();
}
}, 200 );
return;
}
})
// change keyset when either shift or alt is held down
.bind( 'keydown' + namespace, function( e ) {
if ( o.init && o.lockTypeIn || !o.showTyping ) {
return false;
}
e.temp = false; // prevent repetitive calls while keydown repeats.
if ( e.which === 16 ) {
e.temp = !base.shiftActive; base.shiftActive = true;
}
// it should be ok to reset e.temp, since both alt and shift will
// call this function separately
if ( e.which === 18 ) {
e.temp = !base.altActive; base.altActive = true;
}
if ( e.temp ) {
base.showSet();
base.$preview.focus(); // Alt shift focus to the menu
}
base.typing_event = true;
// Simulate key press for tab and backspace since they don't fire
// the keypress event
if ( base.typing_xref[ e.which ] ) {
base.typing_findKey( '', e ); // pass event object
}
})
.bind( 'keypress' + namespace, function( e ) {
if ( o.init && o.lockTypeIn ) {
return false;
}
// Simulate key press on virtual keyboard
if ( base.typing_event && !base.options.lockInput ) {
base.typing_reset();
base.typing_event = true;
base.typing_findKey( '', e ); // pass event object
}
});
};
base.typing_reset = function() {
base.typing_event = o.init = false;
o.text = '';
o.len = o.current = 0;
base.options.lockInput = o.savedLockInput;
// clearTimeout( base.typing_timer );
};
// Store typing text
base.typeIn = function( txt, delay, callback, e ) {
if ( !base.isVisible() ) {
// keyboard was closed
clearTimeout( base.typing_timer );
base.typing_reset();
return;
}
if ( !base.typing_event ) {
if ( o.init !== true ) {
o.init = true;
base.options.lockInput = o.lockTypeIn;
o.text = txt || o.text || '';
o.len = o.text.length;
o.delay = delay || o.delay;
o.current = 0; // position in text string
if ( callback ) {
o.callback = callback;
}
}
// function that loops through and types each character
txt = o.text.substring( o.current, ++o.current );
// add support for curly-wrapped single character: {l}, {r}, {d}, etc.
if (
txt === '{' &&
o.text.substring( o.current + 1, o.current + 2 ) === '}'
) {
txt += o.text.substring( o.current, o.current += 2 );
}
base.typing_findKey( txt, e );
} else if ( typeof txt === 'undefined' ) {
// typeIn called by user input
base.typing_event = false;
base.options.lockInput = o.savedLockInput;
return;
}
};
base.typing_findKey = function( txt, e ) {
var tar, m, n, k, key, ks, meta, set,
kbcss = $keyboard.css,
mappedKeys = $keyboard.builtLayouts[base.layout].mappedKeys;
// stop if keyboard is closed
if ( !base.isOpen || !base.$keyboard.length ) {
return;
}
ks = base.$keyboard.find( '.' + kbcss.keySet );
k = txt in base.typing_keymap ? base.typing_keymap[ txt ] : txt;
// typing_event is true when typing on the actual keyboard - look for
// actual key; All of this breaks when the CapLock is on... unable to
// find a cross-browser method that works.
tar = '.' + kbcss.keyButton + '[data-action="' + k + '"]';
if ( base.typing_event && e ) {
// xref used for keydown
// ( 46 = delete in keypress & period on keydown )
if (
e.type !== 'keypress' &&
base.typing_xref.hasOwnProperty( e.keyCode || e.which )
) {
// special named keys: bksp, tab and enter
tar = '.' +
kbcss.keyPrefix +
base.processName( base.typing_xref[ e.keyCode || e.which ] );
} else {
m = String.fromCharCode( e.charCode || e.which );
tar = ( mappedKeys.hasOwnProperty( m ) ) ?
'.' + kbcss.keyButton + '[data-value="' +
mappedKeys[ m ].replace(/"/g, '\\"') + '"]' :
'.' + kbcss.keyPrefix + base.processName( m );
}
}
// find key
key = ks.filter( ':visible' ).find( tar );
if ( key.length ) {
// key is visible, simulate typing
base.typing_simulateKey( key, txt, e );
} else {
// key not found, check if it is in the keymap
// (tab, space, enter, etc)
if ( base.typing_event ) {
key = ks.find( tar );
} else {
// key not found, check if it is in the keymap
// (tab, space, enter, etc)
n = txt in base.typing_keymap ?
base.typing_keymap[ txt ] :
base.processName( txt );
// find actual key on keyboard
key = ks.find( '.' + kbcss.keyPrefix + n );
}
// find the keyset
set = key.closest( '.' + kbcss.keySet );
// figure out which keyset the key is in then simulate clicking on
// that meta key, then on the key
if ( set.attr('name' ) ) {
if ( o.showTyping ) {
// get meta key name
meta = set.attr( 'name' );
// show correct key set
base.shiftActive = /shift/.test( meta );
base.altActive = /alt/.test( meta );
base.metaActive = base.last.keyset[ 2 ] = /\bmeta/.test(meta) ?
( meta ).match(/meta[\w-]+/)[0] : false;
base.showSet( base.metaActive );
}
// Add the key
base.typing_simulateKey( key, txt, e );
} else {
if ( !base.typing_event ) {
// Key doesn't exist on the keyboard, so just enter it
if (
txt in base.typing_keymap &&
base.typing_keymap[txt] in $keyboard.keyaction
) {
$keyboard.keyaction[ base.typing_keymap[ txt ] ]( base, key, e );
} else {
base.insertText( txt );
}
base.checkCombos();
base.$el.trigger( $keyboard.events.kbChange, [ base, base.el ] );
}
}
}
if ( o.current <= o.len && o.len !== 0 ) {
if ( !base.isVisible() ) {
return; // keyboard was closed, abort!!
}
base.typing_timer = setTimeout( function() {
base.typeIn();
}, o.delay );
} else if ( o.len !== 0 ) {
// o.len is zero when the user typed on the actual keyboard during
// simulation
base.typing_reset();
if ( typeof o.callback === 'function' ) {
// ensure all typing animation is done before the callback
base.typing_timer = setTimeout( function() {
// if the user typed during the key simulation, the "o" variable
// may sometimes be undefined
if ( typeof o.callback === 'function' ) {
o.callback( base );
}
}, o.delay );
}
return;
} else {
base.typing_reset();
}
};
// mouseover the key, add the text directly, then mouseout on the key
base.typing_simulateKey = function( el, txt, e ) {
var len = el.length;
if ( !base.isVisible() ) {
return;
}
if ( o.showTyping && len ) {
el.filter( ':visible' ).trigger( 'mouseenter' + base.namespace );
if ( o.showTyping && len ) {
setTimeout( function() {
el.trigger( 'mouseleave' + base.namespace );
}, Math.min( o.hoverDelay, o.delay ) );
}
}
if ( !base.typing_event ) {
// delay required or initial tab does not get added
// in the main demo (international keyboard)
setTimeout( function() {
if (
txt in base.typing_keymap &&
base.typing_keymap[ txt ] in $keyboard.keyaction
) {
e = e || $.Event( 'keypress' );
e.target = el; // "Enter" checks for the e.target
$keyboard.keyaction[ base.typing_keymap[ txt ] ]( base, el, e );
} else {
base.insertText( txt );
}
base.checkCombos();
base.$el.trigger( $keyboard.events.kbChange, [ base, base.el ] );
}, o.delay/3 );
}
};
// visible event is fired before this extension is initialized, so check!
if ( o.showTyping && base.options.alwaysOpen && base.isVisible() ) {
base.typing_setup();
} else {
// capture and simulate typing
base.$el
.unbind( $keyboard.events.kbBeforeVisible + base.typing_namespace )
.bind( $keyboard.events.kbBeforeVisible + base.typing_namespace, function() {
if ( o.showTyping ) {
base.typing_setup();
} else {
base.typing_setup_reset();
}
});
}
});
};
}));
/* Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
* Licensed under the MIT License (LICENSE.txt).
*
* Version: 3.1.12
*
* Requires: jQuery 1.2.2+
*/
/*! Mousewheel version: 3.1.12 * (c) 2014 Brandon Aaron * MIT License */
(function (factory) {
if ( typeof define === 'function' && define.amd ) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS style for Browserify
module.exports = factory;
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
slice = Array.prototype.slice,
nullLowestDeltaTimeout, lowestDelta;
if ( $.event.fixHooks ) {
for ( var i = toFix.length; i; ) {
$.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
}
}
var special = $.event.special.mousewheel = {
version: '3.1.12',
setup: function() {
if ( this.addEventListener ) {
for ( var i = toBind.length; i; ) {
this.addEventListener( toBind[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
// Store the line height and page height for this particular element
$.data(this, 'mousewheel-line-height', special.getLineHeight(this));
$.data(this, 'mousewheel-page-height', special.getPageHeight(this));
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i = toBind.length; i; ) {
this.removeEventListener( toBind[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
// Clean up the data we added to the element
$.removeData(this, 'mousewheel-line-height');
$.removeData(this, 'mousewheel-page-height');
},
getLineHeight: function(elem) {
var $elem = $(elem),
$parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
if (!$parent.length) {
$parent = $('body');
}
return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
},
getPageHeight: function(elem) {
return $(elem).height();
},
settings: {
adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
normalizeOffset: true // calls getBoundingClientRect for each event
}
};
$.fn.extend({
mousewheel: function(fn) {
return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
},
unmousewheel: function(fn) {
return this.unbind('mousewheel', fn);
}
});
function handler(event) {
var orgEvent = event || window.event,
args = slice.call(arguments, 1),
delta = 0,
deltaX = 0,
deltaY = 0,
absDelta = 0,
offsetX = 0,
offsetY = 0;
event = $.event.fix(orgEvent);
event.type = 'mousewheel';
// Old school scrollwheel delta
if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; }
if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; }
if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; }
if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }
// Firefox < 17 horizontal scrolling related to DOMMouseScroll event
if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaX = deltaY * -1;
deltaY = 0;
}
// Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
delta = deltaY === 0 ? deltaX : deltaY;
// New school wheel delta (wheel event)
if ( 'deltaY' in orgEvent ) {
deltaY = orgEvent.deltaY * -1;
delta = deltaY;
}
if ( 'deltaX' in orgEvent ) {
deltaX = orgEvent.deltaX;
if ( deltaY === 0 ) { delta = deltaX * -1; }
}
// No change actually happened, no reason to go any further
if ( deltaY === 0 && deltaX === 0 ) { return; }
// Need to convert lines and pages to pixels if we aren't already in pixels
// There are three delta modes:
// * deltaMode 0 is by pixels, nothing to do
// * deltaMode 1 is by lines
// * deltaMode 2 is by pages
if ( orgEvent.deltaMode === 1 ) {
var lineHeight = $.data(this, 'mousewheel-line-height');
delta *= lineHeight;
deltaY *= lineHeight;
deltaX *= lineHeight;
} else if ( orgEvent.deltaMode === 2 ) {
var pageHeight = $.data(this, 'mousewheel-page-height');
delta *= pageHeight;
deltaY *= pageHeight;
deltaX *= pageHeight;
}
// Store lowest absolute delta to normalize the delta values
absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
if ( !lowestDelta || absDelta < lowestDelta ) {
lowestDelta = absDelta;
// Adjust older deltas if necessary
if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
lowestDelta /= 40;
}
}
// Adjust older deltas if necessary
if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
// Divide all the things by 40!
delta /= 40;
deltaX /= 40;
deltaY /= 40;
}
// Get a whole, normalized value for the deltas
delta = Math[ delta >= 1 ? 'floor' : 'ceil' ](delta / lowestDelta);
deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
// Normalise offsetX and offsetY properties
if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
var boundingRect = this.getBoundingClientRect();
offsetX = event.clientX - boundingRect.left;
offsetY = event.clientY - boundingRect.top;
}
// Add information to the event object
event.deltaX = deltaX;
event.deltaY = deltaY;
event.deltaFactor = lowestDelta;
event.offsetX = offsetX;
event.offsetY = offsetY;
// Go ahead and set deltaMode to 0 since we converted to pixels
// Although this is a little odd since we overwrite the deltaX/Y
// properties with normalized deltas.
event.deltaMode = 0;
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
// Clearout lowestDelta after sometime to better
// handle multiple device types that give different
// a different lowestDelta
// Ex: trackpad = 3 and mouse wheel = 120
if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
function nullLowestDelta() {
lowestDelta = null;
}
function shouldAdjustOldDeltas(orgEvent, absDelta) {
// If this is an older event and the delta is divisable by 120,
// then we are assuming that the browser is treating this as an
// older mouse wheel event and that we should divide the deltas
// by 40 to try and get a more usable deltaFactor.
// Side note, this actually impacts the reported scroll distance
// in older browsers and can cause scrolling to be slower than native.
// Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
}
}));
/*! jQuery UI Virtual Keyboard Alt Key Popup v2.0.0 *//*
* for Keyboard v1.18+ only (2018-04-19)
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
* Note: Use of `event.key` requires a modern browser
* (https://caniuse.com/#feat=keyboardevent-key)
*/
/* jshint browser:true, jquery:true, unused:false */
/* global require:false, define:false, module:false */
;( function( factory ) {
if ( typeof define === 'function' && define.amd ) {
define( [ 'jquery' ], factory );
} else if (
typeof module === 'object' &&
typeof module.exports === 'object'
) {
module.exports = factory( require( 'jquery' ) );
} else {
factory( jQuery );
}
}( function( $ ) {
'use strict';
var $keyboard = $.keyboard;
$.extend( $keyboard.css, {
altKeyPopup : 'ui-keyboard-popup',
altKeyOverlay : 'ui-keyboard-overlay',
altKeyPopupOpen : 'ui-keyboard-popup-open'
});
$keyboard.altKeys = $.extend({
a : '\u00e5 \u00e6 \u0101 \u0103 \u0105 \u00e0 \u00e1 \u00e2 \u00e3 \u00e4', // å æ ā ă ą à á â ã ä
A : '\u00c5 \u00c6 \u0100 \u0102 \u0104 \u00c0 \u00c1 \u00c2 \u00c3 \u00c4', // Å Æ Ā Ă Ą À Á Â Ã Ä
c : '\u00e7 \u0107 \u0109 \u010b \u010d', // ç ć ĉ ċ č
C : '\u00c7 \u0106 \u0108 \u010a \u010c', // Ç Ć Ĉ Ċ Č
d : '\u010f \u00f0 \u010f', // ď ð ď
D : '\u010e \u00d0 \u010e', // Ď Ð Ď
e : '\u0117 \u0119 \u0115 \u011b \u0259 \u00e8 \u00e9 \u00ea \u00eb \u0113', // ė ę ĕ ě ə è é ê ë ē
E : '\u0116 \u0118 \u0114 \u011a \u018e \u00c8 \u00c9 \u00ca \u00cb \u0112', // Ė Ę Ĕ Ě Ǝ È É Ê Ë Ē
g : '\u0123 \u011f \u011d \u0121', // ģ ğ ĝ ġ
G : '\u0122 \u011e \u011c \u0120', // Ģ Ğ Ĝ Ġ
h : '\u0125 \u0127', // ĥ ħ
H : '\u0124 \u0126', // Ĥ Ħ
i : '\u0131 \u012f \u012b \u00ef \u00ee \u00ed \u00ec \u0129 \u012d', // ı į ī ï î í ì ĩ ĭ
I : '\u0130 \u012e \u012a \u00cf \u00ce \u00cd \u00cc \u0128 \u012c', // İ Į Ī Ï Î Í Ì Ĩ Ĭ
j : '\u0135', // ĵ
J : '\u0134', // Ĵ
k : '\u0137', // ķ
K : '\u0136', // Ķ
l : '\u0141 \u013d \u013b \u0139 \u013f', // Ł Ľ Ļ Ĺ Ŀ
L : '\u0142 \u013e \u013c \u013a \u0140', // ł ľ ļ ĺ ŀ
n : '\u0149 \u0148 \u0146 \u0144 \u00f1', // ʼn ň ņ ń ñ
N : '\u0149 \u0147 \u0145 \u0143 \u00d1', // ʼn Ň Ņ Ń Ñ
o : '\u0153 \u0151 \u00f8 \u00f6 \u00f5 \u00f4 \u00f3 \u00f2 \u014d \u014f', // œ ő ø ö õ ô ó ò ō ŏ
O : '\u0152 \u0150 \u00d8 \u00d6 \u00d5 \u00d4 \u00d3 \u00d2 \u014c \u014e', // Œ Ő Ø Ö Õ Ô Ó Ò Ō Ŏ
r : '\u0155 \u0159 \u0157', // ŕ ř ŗ
R : '\u0154 \u0158 \u0156', // Ŕ Ř Ŗ
s : '\u015b \u0161 \u015f \u00df \u00a7 \u015d', // ś š ş ß § ŝ
S : '\u015a \u0160 \u015e \u1e9e \u00a7 \u015c', // Ś Š Ş ẞ § Ŝ
t : '\u00fe \u0165 \u021b \u0163 \u0167', // þ ť ț ţ ŧ
T : '\u00de \u0164 \u021a \u0162 \u0166', // Þ Ť Ț Ţ Ŧ
u : '\u0173 \u0171 \u016f \u016b \u00fc \u00fb \u00fa \u00f9 \u0169 \u016d', // ų ű ů ū ü û ú ù ũ ŭ
U : '\u0172 \u0170 \u016e \u016a \u00dc \u00db \u00da \u00d9 \u0168 \u016c', // Ų Ű Ů Ū Ü Û Ú Ù Ũ Ŭ
w : '\u0175', // ŵ
W : '\u0174', // Ŵ
y : '\u00fd', // ý
Y : '\u00dd', // Ý
z : '\u017a \u017c \u017e', // ź ż ž
Z : '\u0179 \u017b \u017d', // Ź Ż Ž
'!' : '\u00a1', // ¡
'$' : '\u20ac \u00a3 \u00a4 \u00a5 \u00a2 \u20a1 \u20b1 \u20a9 \u20b9 \u20aa \u20ad \u20ae \u20a6 \u20a4', // €£¤¥¢₡₱₩₹₪₭₮₦₤
'?' : '\u00bf', // ¿
"'" : '\u3008 \u300c \u300e \u201c', // 〈 「 『 “
'"' : '\u3009 \u300d \u300f \u201d', // 〉 」 』 ”
'(' : '\u300a \u3010 \u3014', // « 【 〔
')' : '\u300b \u3011 \u3015' // » 】 〕
}, $keyboard.altKeys );
$.fn.addAltKeyPopup = function( options ) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
// time to hold down a button in ms to trigger a popup
holdTime : 500,
// events triggered when popup is visible & hidden
popupVisible : 'popup-visible',
popupHidden : 'popup-hidden',
popupPosition : null
};
return this.each( function() {
// make sure a keyboard is attached
var base = $( this ).data( 'keyboard' );
if (!base) { return; }
// variables
base.altkeypopup_options = $.extend(
{},
defaults,
base.altkeypopup_options, // restore prev options on layout update
options
);
// already initialized
if ( base.altkeypopup_namespace ) {
return base.altkeypopup_setup();
}
base.altkeypopup_namespace = base.namespace + 'AltKeyPopup';
base.extensionNamespace.push( base.altkeypopup_namespace );
base.altkeypopup_setup = function() {
var timer,
start = 'mousedown touchstart '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' ),
end = 'mouseup touchend touchcancel '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' );
// force disable repeat keys
base.options.repeatRate = 0;
// add hold key functionality for popups
base
.unbindButton( base.altkeypopup_namespace )
.bindButton( start, function() {
clearTimeout( timer );
var $key = $( this ),
key = $key.attr( 'data-value' ) || '',
delay = base.altkeypopup_options.holdTime;
if ( key in $keyboard.altKeys ) {
if (delay) {
timer = setTimeout( function() {
base.altKeyPopup_popup( key, $key );
}, delay );
} else {
// holdTime set to zero.. don't use a setTimeout
base.altKeyPopup_popup( key, $key );
}
}
})
.bindButton( end, function() {
clearTimeout( timer );
});
base.altkeypopup_blockingFlag = false;
base.$preview
.unbind(
'keypress keydown keyup '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' )
.trim()
)
.bind(
'keypress keydown keyup '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' ),
function( event ) {
if ( event.type === 'keyup' ) {
clearTimeout( timer );
base.altkeypopup_blockingFlag = false;
return event.key !== 'Escape';
}
var layout = $keyboard.builtLayouts[ base.layout ],
$key = $( event.target ),
origKey = event.key,
key = event.key;
if ( event.type === 'keydown' && key in $keyboard.altKeys ) {
// Compare typed key to prevent blocking issues reported in #664
if ( base.altkeypopup_blockingFlag === origKey ) {
return false;
}
base.altkeypopup_blockingFlag = origKey;
// return true on initial keydown or keypress never fires
// then return false to prevent repeat key
return true;
}
if ( base.altkeypopup_blockingFlag ) {
// find mapped key, if any
if (
layout.hasMappedKeys &&
layout.mappedKeys.hasOwnProperty( key )
) {
key = layout.mappedKeys[ key ];
}
if ( key in $keyboard.altKeys ) {
clearTimeout( timer );
timer = setTimeout( function() {
if ( base.altkeypopup_blockingFlag === origKey ) {
base.altKeyPopup_popup( key, $key );
}
}, base.altkeypopup_options.holdTime );
}
return true;
}
}
);
};
base.altKeyPopup_close = function() {
base.altkeypopup_blockingFlag = false;
base.altKeyPopup_$overlay = null;
setTimeout(function() {
if (base.$keyboard.length) {
base.$keyboard.removeClass($keyboard.css.altKeyPopupOpen);
var $el = base.$keyboard.find( '.' + $keyboard.css.altKeyOverlay );
if ($el) {
$el.remove();
}
}
}, 1);
$( document ).unbind( base.altkeypopup_namespace );
base.$preview.focus();
// restore ignoreEsc option
base.options.ignoreEsc = base.altKeyPopup_savedIgnoreEsc;
// trigger popup hidden event
base.$el.trigger( base.altkeypopup_options.popupHidden, [ base ] );
};
base.altKeyPopup_popup = function( key, $key ) {
if ( base.$keyboard.find( '.' + $keyboard.css.altKeyOverlay ).length ) {
return;
}
var keys, $container, $keys, positionHoriz, positionVert, top,
popupWidth, popupHeight, evts,
kbcss = $keyboard.css,
data = {
$kb : base.$keyboard,
kbWidth : base.$keyboard.outerWidth(),
kbHeight : base.$keyboard.outerHeight(),
$key : $key
};
// overlay keyboard
base.altKeyPopup_$overlay =
$( '<div class="' + kbcss.altKeyOverlay + '" />' )
.css({
width : data.kbWidth,
height: data.kbHeight
})
.appendTo( base.$keyboard )
.bind( 'click touchstart', function() {
base.altKeyPopup_close();
});
evts = 'inactive hidden '
.split( ' ' )
.join( base.altkeypopup_namespace + ' ' );
base.$keyboard.addClass($keyboard.css.altKeyPopupOpen);
base.$el.unbind( evts ).bind( evts, function() {
base.altKeyPopup_close();
});
// remove character added when key was initially pressed, unless it
// was a backspace key
if ( key !== 'bksp' ) {
$keyboard.keyaction.bksp( base );
}
// make popup; use the same classes as the keyboard container
$container = $(
'<div class="' + kbcss.altKeyPopup + ' ' +
base.options.css.container + '" />'
);
keys = $keyboard.altKeys[ key ].split( /\s+/ );
// make popup keys
base.buildRow( $container, 0, keys, [] );
// add popup & add bindings
$keys = $container
.appendTo( base.altKeyPopup_$overlay )
.children()
.bind( 'mousedown touchstart', function() {
// action/value now processed by core functions
base.altKeyPopup_close();
})
.bind( 'mouseover mouseleave', function( event ){
// remove hover from physical keyboard highlighted key
$keys.removeClass( base.options.css.buttonHover );
if ( event.type !== 'mouseleave' ) {
$( this ).addClass( base.options.css.buttonHover );
}
});
// popup opened... add key highlight
base.altKeyPopup_navigate( true ); // init
// set ignoreEsc to allow escape to ONLY close the popup
base.altKeyPopup_savedIgnoreEsc = base.options.ignoreEsc;
base.options.ignoreEsc = true;
$( document )
.unbind( base.altkeypopup_namespace )
.bind( 'keydown' + base.altkeypopup_namespace, function() {
// keep home & end from scrolling the page
return false;
})
.bind( 'keyup' + base.altkeypopup_namespace, function( event ) {
if ( event.key === 'Escape' ) {
event.which = 0; // prevent escClose from closing the keyboard
base.altKeyPopup_close();
} else {
base.altKeyPopup_navigate( event );
}
return false;
});
data.$popup = $container;
popupWidth = $container.outerWidth();
// position popup within $keyboard container
positionHoriz = $key.position().left - popupWidth / 2;
if ( positionHoriz + popupWidth > data.kbWidth ) {
positionHoriz = data.kbWidth - popupWidth;
if ( positionHoriz < 0 ) {
$container.css({
width : data.kbWidth,
height : 'auto'
});
}
}
positionVert = $key.position().top - $key.outerHeight() - 5;
popupHeight = $container.outerHeight();
// find top of keyset (don't cover up the preview input)
top = base.$keyboard.find( '.' + kbcss.keySet ).position().top;
if ( positionVert + popupHeight > data.kbHeight ) {
positionVert = data.kbHeight - popupHeight;
if ( positionVert < top ) {
$container.css({
height : data.popupHeight,
width : 'auto'
});
}
}
data.popupWidth = $container.outerWidth();
data.popupHeight = $container.outerHeight();
data.popupLeft = positionHoriz < 0 ? 0 : positionHoriz;
data.popupTop = positionVert < top ? top : positionVert;
$container.css({
position : 'absolute',
left : data.popupLeft,
top : data.popupTop
});
// adjust position as needed using popupPosition callback function
if ( typeof base.altkeypopup_options.popupPosition === 'function' ) {
base.altkeypopup_options.popupPosition(base, data);
}
base.$preview.blur();
// trigger popup visible event
base.$el.trigger( base.altkeypopup_options.popupVisible, [ base ] );
};
base.altKeyPopup_navigate = function( event ) {
var indx,
kbcss = $keyboard.css,
k = $keyboard.navigationKeys,
hover = base.options.css.buttonHover,
$keys = base.$keyboard
.find( '.' + kbcss.altKeyPopup )
.find( '.' + kbcss.keyButton ),
max = $keys.length - 1;
// popup visible, add key highlight
if ( event === true ) {
$keys.eq( 0 ).addClass( hover );
base.altKeyPopup_currentIndex = 0;
return;
}
indx = base.altKeyPopup_currentIndex;
if ( event.key === 'Enter' ) {
base.insertText( $keys.eq( indx ).attr( 'data-value' ) );
base.altKeyPopup_close();
return true;
}
switch( event.key ) {
case 'End': indx = max; break;
case 'Home': indx = 0; break;
case 'ArrowLeft': indx -= 1; break;
case 'ArrowRight': indx += 1; break;
}
if ( indx < 0 ) { indx = 0; }
if ( indx > max ) { indx = max; }
base.altKeyPopup_currentIndex = indx;
$keys
.removeClass( hover )
.eq( indx )
.addClass( hover );
};
// visible event is fired before this extension is initialized, so check!
if ( base.options.alwaysOpen && base.isVisible() ) {
base.altkeypopup_setup();
}
// setup altkey popup
base.$el
.unbind(
$keyboard.events.kbBeforeVisible + base.altkeypopup_namespace
)
.bind(
$keyboard.events.kbBeforeVisible + base.altkeypopup_namespace,
function() {
base.altkeypopup_setup();
}
);
});
};
}));
/*! jQuery UI Virtual Keyboard Autocomplete v1.11.4 *//*
* for Keyboard v1.18+ only (2018-01-10)
*
* By Rob Garrison (Mottie)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to get
* the jQuery UI Autocomplete widget to work seamlessly
*
* Requires:
* jQuery
* jQuery UI & css
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .autocomplete(options)
* .addAutoComplete();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .autocomplete(options) // jQuery UI autocomplete
* .addAutoComplete(); // this keyboard extension
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.fn.addAutocomplete = function(options) {
var defaults = {
position : {
of : null,
my : 'right top',
at : 'left top',
collision: 'flip'
},
events: 'autocomplete',
data: ''
};
return this.each(function() {
// make sure a keyboard is attached
var o, namespace,
base = $(this).data('keyboard');
if (!base) { return; }
namespace = base.namespace + 'Autocomplete';
base.autocomplete_namespace = namespace;
base.extensionNamespace.push( namespace );
// Setup
base.autocomplete_init = function() {
// variables
o = base.autocomplete_options = $.extend( true, {}, defaults, options );
var events = o.events || o.data || 'autocomplete';
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible()) {
base.autocomplete_setup();
}
base.$el
.unbind(namespace)
.bind($.keyboard.events.kbVisible + namespace, function() {
base.autocomplete_setup();
})
.bind($.keyboard.events.kbHidden + namespace, function() {
base.$el[o.data || 'autocomplete']('close');
})
.bind($.keyboard.events.kbChange + namespace, function() {
if (base.hasAutocomplete && base.isVisible()) {
base.$el.val(base.$preview.val());
}
})
.bind(events + 'open' + namespace, function() {
if (base.hasAutocomplete) {
// default to $keyboard if no position.of defined
var position = $.extend( {}, o.position );
// refresh base.$keyboard (it gets destroyed after use); fixes #382
position.of = position.of || base.$keyboard;
// reposition autocomplete window next to the keyboard
base.$autocomplete.menu.element.position( position );
}
})
.bind(events + 'select' + namespace, function(e, ui) {
base.autocomplete_getVal(ui.item);
});
};
base.autocomplete_getVal = function(val) {
var v;
switch (typeof val) {
case 'string':
v = val || '';
break;
case 'object':
v = val.label || val.value || '';
break;
default:
v = base.preview && base.preview.value || base.el.value;
}
v = v.toString();
if (base.hasAutocomplete && v !== '') {
// fallback to original input if undefined, see #520
(base.$preview || base.$el)
.val( v )
.focus();
// see issue #95 - thanks banku!
base.last.start = v.length;
base.last.end = v.length;
base.last.val = v;
}
};
base.autocomplete_update = function(event) {
clearTimeout( base.$autocomplete.searching );
base.$autocomplete.searching = setTimeout(function() {
// only search if the value has changed
if ( base.$autocomplete.term !== base.$autocomplete.element.val() ) {
base.$autocomplete.selectedItem = null;
base.$autocomplete.search( null, event );
}
}, base.$autocomplete.options.delay );
};
base.autocomplete_navKeys = {
8: 'backSpace',
9: 'tab',
13: 'enter',
20: 'capsLock',
27: 'escape',
32: 'space',
33: 'pageup',
34: 'pagedown',
35: 'end',
36: 'home',
37: 'left',
38: 'up',
39: 'right',
40: 'down',
45: 'insert',
46: 'delete'
};
// set up after keyboard is visible
base.autocomplete_setup = function() {
var key;
// look for autocomplete
base.$autocomplete = base.$el.data(base.autocomplete_options.data) ||
// data changes based on jQuery UI version
base.$el.data('uiAutocomplete') ||
base.$el.data('ui-autocomplete') ||
base.$el.data('autocomplete');
base.hasAutocomplete = (typeof(base.$autocomplete) === 'undefined') ?
false : (base.$autocomplete.options.disabled) ? false : true;
// only bind to keydown once
if (base.hasAutocomplete) {
base.$preview.bind('keydown' + namespace + ' keypress' + namespace, function(event) {
// send keys to the autocomplete widget (arrow, pageup/down, etc)
if (base.$preview && event.namespace !== base.$autocomplete.eventNamespace) {
event.namespace = base.$autocomplete.eventNamespace.slice(1);
key = base.autocomplete_navKeys[event.which];
if (key) {
if (base.el !== base.preview) {
base.$el.triggerHandler(event);
if (key === 'enter') {
// update preview with the selected item
setTimeout(function(){
if (base.$autocomplete) {
base.$preview.val(base.$autocomplete.selectedItem.value);
base.$preview.focus();
}
}, 100);
}
}
} else {
// only search when a non-navigation key is pressed
base.autocomplete_update(event);
}
}
});
var events = 'mouseup mousedown mouseleave touchstart touchend touchcancel '
.split(' ')
.join(namespace + ' ');
base.bindButton(events, function(event) {
base.autocomplete_update(event);
});
}
if (!base.escCloseCallback.autocomplete) {
base.escCloseCallback.autocomplete = base.checkAutocompleteMenu;
}
};
base.checkAutocompleteMenu = function($target) {
// prevent selecting an item in autocomplete from closing keyboard
// return a "shouldStayOpen" boolean state for this extension
return base.hasAutocomplete &&
$target.closest('ul').hasClass('ui-autocomplete');
};
base.autocomplete_destroy = function() {
clearTimeout(base.$autocomplete.searching);
base.hasAutocomplete = false;
base.$el.unbind(namespace);
if (base.$preview) {
base.$preview.unbind(namespace);
base.unbindButton(namespace);
}
delete base.$autocomplete;
};
base.autocomplete_init();
});
};
}));
/*! jQuery UI Virtual Keyboard Virtual Caret v1.1.5 (beta) *//*
* for Keyboard v1.18+ only (2/20/2016)
* modified from https://github.com/component/textarea-caret-position
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
* CSS changes
* NOTE: caret margin-top => is added to the caret height (top & bottom)
* .ui-keyboard-preview-wrapper { position: relative; overflow: hidden; }
* .ui-keyboard-caret { background: red; width: 1px; margin-top: 3px; }
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;( function( factory ) {
if ( typeof define === 'function' && define.amd ) {
define( [ 'jquery' ], factory );
} else if ( typeof module === 'object' && typeof module.exports === 'object' ) {
module.exports = factory( require( 'jquery' ) );
} else {
factory( jQuery );
}
}( function( $ ) {
'use strict';
var $keyboard = $.keyboard;
$keyboard.firefox = typeof window.mozInnerScreenX !== 'undefined';
$.extend( $keyboard.css, {
caret : 'ui-keyboard-caret',
caretMirror : 'ui-keyboard-mirror-div'
});
$.fn.addCaret = function( options ) {
var defaults = {
caretClass : '',
// *** for future use ***
// data-attribute containing the character(s) next to the caret
charAttr : 'data-character',
// # character(s) next to the caret (can be negative for RTL)
charIndex : 1,
offsetX : 0,
offsetY : 0,
adjustHt : 0
};
return this.each( function() {
// make sure a keyboard is attached
var o, namespace,
kbevents = $keyboard.events,
base = $( this ).data( 'keyboard' );
if ( !base ) { return; }
// variables
o = base.caret_options = $.extend( {}, defaults, options );
namespace = base.caret_namespace = base.namespace + 'caret';
base.extensionNamespace.push( namespace );
// modified from https://github.com/component/textarea-caret-position
// The properties that we copy into a mirrored div.
// Note that some browsers, such as Firefox,
// do not concatenate properties, i.e. padding-top, bottom etc. -> padding,
// so we have to do every single property specifically.
base.textareaCaretProperties = [
'direction', 'boxSizing', 'width', 'height', 'overflowX', 'overflowY',
'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'borderStyle',
'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft',
'fontStyle', 'fontVariant', 'fontWeight', 'fontStretch', 'fontSize', 'fontSizeAdjust',
'lineHeight', 'fontFamily', 'textAlign', 'textTransform', 'textIndent', 'textDecoration',
'letterSpacing', 'wordSpacing', 'tabSize', 'MozTabSize'
];
base.caret_setup = function() {
var kbcss = $keyboard.css,
events = 'keyup keypress mouseup mouseleave '.split( ' ' ).join( namespace + ' ' ),
style = 'position:absolute;visibility:hidden;top:-9999em;left:-9999em;' +
'white-space:pre-wrap;z-index:-10;' +
( base.preview.nodeName === 'INPUT' ? '' : 'word-wrap:break-word;' );
// add mirrored div
base.$keyboard.find( '.' + kbcss.caretMirror ).remove();
base.caret_$div = $( '<div class="' + kbcss.caretMirror + '" style="' + style + '">' )
.appendTo( base.$keyboard );
// remove caret, just-in-case
if (base.$caret) { base.$caret.remove(); }
base.$caret = $( '<div class="' + kbcss.caret + ' ' + o.caretClass + '" style="position:absolute;">' )
.insertAfter( base.$preview );
base.$el
.unbind( kbevents.kbChange + namespace )
.bind( kbevents.kbChange + namespace, function() {
base.findCaretPos();
});
base.$preview
.unbind( events )
.bind( events, function() {
base.findCaretPos();
});
};
// getCaretCoordinatesFn = function (element, position, recalculate) {
base.findCaretPos = function() {
if ( !base.caret_$div ) { return; }
var style, computed, margin, pos, position, txt, span, offset,
element = base.preview,
fontWidth = parseFloat( base.$preview.css('fontSize') ),
isInput = element.nodeName === 'INPUT',
div = base.caret_$div[0];
style = div.style;
// getComputedStyle with null - fixes #384
computed = window.getComputedStyle ? getComputedStyle( element, null ) : element.currentStyle;
// get caret position based on text-direction
pos = $keyboard.caret( base.$preview );
position = Math[ computed.direction === 'ltr' ? 'max' : 'min' ]( pos.start, pos.end );
// transfer the element's properties to the div
base.textareaCaretProperties.forEach(function ( prop ) {
style[ prop ] = computed[ prop ];
});
if ( $keyboard.firefox ) {
// Firefox adds 2 pixels to the padding - https://bugzilla.mozilla.org/show_bug.cgi?id=753662
style.width = parseInt( computed.width, 10 ) - 2 + 'px';
// Firefox lies about the overflow property for textareas:
// https://bugzilla.mozilla.org/show_bug.cgi?id=984275
if ( element.scrollHeight > parseInt( computed.height, 10 ) ) {
style.overflowY = 'scroll';
}
}
// for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'
// style.overflow = 'hidden';
style.width = parseInt( isInput ? element.scrollWidth : computed.width, 10 ) +
// add 2em extra width if it's an input to prevent wrap
( isInput ? fontWidth * 2 : 0 ) + 'px';
div.textContent = element.value.substring( 0, position );
// the second special handling for input type="text" vs textarea:
// spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037
if ( element.nodeName === 'INPUT' ) {
div.textContent = div.textContent.replace( /\x20/g, '\xa0' );
}
span = document.createElement( 'span' );
// Wrapping must be replicated *exactly*, including when a long word gets
// onto the next line, with whitespace at the end of the line before (#7).
// The *only* reliable way to do that is to copy the *entire* rest of the
// textarea's content into the <span> created at the caret position.
// for inputs, just '.' would be enough, but why bother?
// || because a completely empty faux span doesn't render at all
// changed to zero-width space due to inaccuracy when textAlign = center; see #436
span.textContent = element.value.substring( position ) || '\u200b';
div.appendChild( span );
offset = $(span).position();
// adjust for 2em added to width moves caret, use half; see #436
pos = style.textAlign === 'center' ? fontWidth : 0;
base.caretPos = {
top: offset.top + parseInt( computed.borderTopWidth, 10 ) + o.offsetY,
left: offset.left + parseInt( computed.borderLeftWidth, 10 ) + o.offsetX - pos
};
// make caret height = font-size + any margin-top x2 added by the css
margin = parseInt( base.$caret.css( 'margin-top' ), 10 );
style = Math.round( fontWidth + margin * 2 ) + o.adjustHt;
offset = base.$preview.position();
base.$caret.css({
top: offset.top - element.scrollTop + base.caretPos.top - margin,
left: offset.left - element.scrollLeft + base.caretPos.left,
height: style
});
txt = element.value.substring( position, position + o.charIndex ).replace(/\s/, '\xa0' ) || '\xa0';
base.$caret.attr( o.charAttr, txt );
};
// setup caret when keyboard is visible
base.$el
.unbind( namespace )
.bind( kbevents.kbBeforeVisible + namespace, function() {
base.caret_setup();
})
.bind( kbevents.kbVisible + namespace, function() {
base.findCaretPos();
})
.bind( kbevents.kbHidden + namespace, function() {
// unbind events in case usePreview: false; see #376
var events = 'keyup keypress mouseup mouseleave '.split( ' ' ).join( namespace + ' ' );
base.$preview.unbind( events );
base.$caret.remove();
base.$caret = null;
base.caret_$div = null;
});
// visible event is fired before this extension is initialized, so check!
if ( base.options.alwaysOpen && base.isVisible() ) {
base.caret_setup();
base.findCaretPos();
}
});
};
}));
/*! jQuery UI Virtual Keyboard Extender v1.0.3 *//*
* for Keyboard v1.18+ only (12/5/2015)
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;( function( factory ) {
if ( typeof define === 'function' && define.amd ) {
define( [ 'jquery' ], factory );
} else if ( typeof module === 'object' && typeof module.exports === 'object' ) {
module.exports = factory( require( 'jquery' ) );
} else {
factory( jQuery );
}
}( function( $ ) {
'use strict';
var $keyboard = $.keyboard;
$keyboard.css.extender = 'ui-keyboard-extender';
$keyboard.language.en.display.extender = ' :toggle_numpad';
$keyboard.layouts.numpad = {
'normal' : [
'{clear} / * -',
'7 8 9 +',
'4 5 6 %',
'1 2 3 =',
'0 {dec} {left} {right}'
]
};
// add {extender} keyaction
$keyboard.keyaction.extender = function( base ) {
base.extender_toggle();
return false;
};
$.fn.addExtender = function(options) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
layout : 'numpad',
showing : false,
reposition : true
};
return this.each( function() {
var base = $( this ).data( 'keyboard' );
// make sure a keyboard is attached
if ( !base ) { return; }
// variables
base.extender_options = $.extend(
{},
defaults,
base.extender_options, // restore prev options on layout update
options
);
// already initialized & switching layouts
if ( base.extender_namespace ) {
return base.extender_layoutSwitcher();
}
base.extender_namespace = base.namespace + 'extender';
base.extensionNamespace.push( base.extender_namespace );
base.extender_layoutSwitcher = function() {
base.extender_lastKeyset = base.last.keyset;
base.extender_bindEvents( false );
base.$el.one( $keyboard.events.kbBeforeVisible, function() {
// preserve active keysets; redraw resets them - see #510
base.shiftActive = base.extender_lastKeyset[ 0 ];
base.altActive = base.extender_lastKeyset[ 1 ];
base.metaActive = base.extender_lastKeyset[ 2 ];
base.showKeySet();
base.extender_setup();
base.extender_bindEvents();
});
base.redraw();
};
base.extender_bindEvents = function( bind ) {
var event = $keyboard.events.kbBeforeVisible + base.extender_namespace;
// setup extender
base.$el.unbind( event );
if ( bind !== false ) {
base.$el.bind( event, function() {
base.extender_setup();
});
}
};
base.extender_setup = function() {
var $extender,
layout = base.extender_options.layout;
if ( typeof $keyboard.builtLayouts[ layout ] === 'undefined' ) {
base.buildKeyboard( layout );
}
$extender = $keyboard.builtLayouts[ layout ].$keyboard
// only use the "normal" layout in the extender
.find( '.' + $keyboard.css.keySet + '-normal' )
.clone();
$extender
.removeClass()
.removeAttr( 'name' )
.addClass( $keyboard.css.extender )
.children( 'button' )
.removeAttr( 'data-pos' );
// show extender using inline-block - allows the removal of css float
$extender[ 0 ].style.display = base.extender_options.showing ?
'inline-block' :
'none';
// remove previous extender... just-in-case
base.$keyboard.find( 'div.' + $keyboard.css.extender ).remove();
base.$keyboard.append( $extender );
base.extender_toggle( base.extender_options.showing );
base.bindKeys();
};
base.extender_toggle = function( set ) {
base.extender_options.showing = typeof set === 'undefined' ?
!base.extender_options.showing : set;
base.$keyboard
.find( 'button.' + $keyboard.css.extender )
.toggleClass(
base.options.css.buttonActive,
base.extender_options.showing
)
.end()
.find( 'div.' + $keyboard.css.extender )[ 0 ].style.display =
base.extender_options.showing ? 'inline-block' : 'none';
// force keyboard reposition
if ( base.extender_options.reposition ) {
$( window ).trigger( 'resize' );
}
};
// visible event is fired before this extension is initialized, so check!
if ( base.options.alwaysOpen && base.isVisible() ) {
base.extender_setup();
}
base.extender_bindEvents();
});
};
}));
/*! jQuery UI Virtual Keyboard for jQuery Mobile Themes v1.4.1 *//*
* for Keyboard v1.18+ (updated 7/7/2015)
*
* By Rob Garrison (aka Mottie & Fudgey)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to apply
* the necessary themes to make the keyboard compatible with
* jQuery Mobile themes
*
* Requires:
* jQuery - http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js
* jQuery Mobile - http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js
* jQuery Mobile themes - http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .addMobile(mobile-options);
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .addMobile(mobile-options); // this keyboard extension
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
$.fn.addMobile = function(options){
var o, defaults = {
// keyboard wrapper theme
container : { theme:'b', cssClass:'ui-body' },
// keyboard duplicate input
input : { theme:'b', cssClass:'' },
// theme added to all regular buttons
buttonMarkup : { theme:'b', cssClass:'ui-btn', shadow:'true', corners:'true' },
// theme added to all buttons when they are being hovered
buttonHover : { theme:'b', cssClass:'ui-btn-hover' },
// theme added to action buttons (e.g. tab, shift, accept, cancel);
// parameters here will override the settings in the buttonMarkup
buttonAction : { theme:'b', cssClass:'ui-btn-active' },
// theme added to button when it is active (e.g. shift is down)
// All extra parameters will be ignored
buttonActive : { theme:'b', cssClass:'ui-btn-active' },
// if more than 3 mobile themes are used, add them here
allThemes : 'a b c'
};
return this.each(function(){
var base = $(this).data('keyboard');
// Stop if no keyboard attached or if jQuery Mobile isn't loaded
if (!base || typeof($.fn.textinput) === 'undefined') { return; }
base.mobile_options = o = $.extend(true, {}, defaults, options);
// create a list of theme class names to remove
base.mobile_themes = $.trim(
(' ' + o.allThemes).split(' ').join(' ' + o.buttonMarkup.cssClass + '-') +
(' ' + o.allThemes).split(' ').join(' ' + o.buttonAction.cssClass + '-') +
(' ' + o.allThemes).split(' ').join(' ' + o.buttonActive.cssClass + '-')
);
// save original action class because it gets removed when this theme switches swatches
if (typeof base.options.mobile_savedActiveClass === 'undefined') {
base.options.mobile_savedActiveClass = '' + base.options.css.buttonActive;
}
// Setup
base.mobile_init = function() {
var namespace = base.namespace + 'Mobile';
// Add theme to input - if not already done through the markup
$('.' + $.keyboard.css.input).textinput();
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible) {
base.mobile_setup();
}
base.extensionNamespace.push( namespace );
// Setup mobile theme on keyboard once it is visible.
// Note: There is a 10ms delay after the keyboard is displayed before it actually fires 'visible.keyboard'.
// Since we are restyling here, the user will experience FlashOfUnstyledContent (FOUC).
// This is avoided by first setting the visibility to hidden, then after the mobile styles are applied we
// set it visible.
base.$el
.unbind(namespace)
.bind($.keyboard.events.kbBeforeVisible + namespace, function() {
if ( base && base.el.active && base.$keyboard.length ) {
base.$keyboard.css('visibility', 'hidden');
}
})
.bind($.keyboard.events.kbVisible + namespace, function() {
if ( base && base.el.active && base.$keyboard.length ) {
base.mobile_setup();
base.$keyboard.css('visibility', 'visible');
base.$preview.focus();
}
});
};
base.mobile_setup = function(){
var p,
kbcss = $.keyboard.css,
opts = base.options,
themes = base.mobile_themes;
base.mobile_$actionKeys = base.$keyboard.find('.' + base.options.css.buttonAction);
opts.css.buttonActive = opts.mobile_savedActiveClass + ' ' + base.modOptions(o.buttonActive, o.buttonMarkup);
base.$keyboard
// 'ui-body ui-body-a' classes to apply swatch theme
.addClass( base.modOptions(o.container, o.container) )
// preview input
.find('.' + kbcss.preview)
// removing 'ui-widget-content' will prevent jQuery UI theme from applying to the keyboard
.removeClass('ui-widget ui-widget-content')
.addClass( base.modOptions(o.input, o.input) ).end()
// apply jQuery Mobile button markup
// removed call to jQuery Mobile buttonMarkup function; replaced with base.modOptions
.find('button')
.removeClass( $.trim('ui-corner-all ui-state-default ' + themes) )
.addClass( base.modOptions(o.buttonMarkup, o.buttonMarkup) )
.not( base.mobile_$actionKeys )
.hover(function(){
$(this)
.removeClass( themes )
.addClass( base.modOptions(o.buttonHover, o.buttonMarkup) );
},function(){
$(this)
.removeClass( themes + ' ' + o.buttonHover.cssClass )
.addClass( base.modOptions(o.buttonMarkup, o.buttonMarkup) );
});
base.mobile_$actionKeys
.removeClass( themes )
.addClass( base.modOptions(o.buttonAction, o.buttonMarkup) );
// update keyboard width if preview is showing... after applying mobile theme
if (base.msie && base.$preview[0] !== base.el) {
base.$preview.hide();
base.$keyboard.css('width','');
base.width = base.$keyboard.outerWidth();
// add about 1em to input width for extra padding
base.$keyboard.width(base.width + parseInt(base.$preview.css('fontSize'),10));
base.$preview.width(base.width);
base.$preview.show();
}
// adjust keyboard position after applying mobile theme
if ($.ui && $.ui.position) {
p = opts.position;
p.of = p.of || base.$el.data('keyboardPosition') || base.$el;
p.collision = p.collision || 'flipfit flipfit';
base.$keyboard.position(p);
}
};
base.modOptions = function(t, btn){
var css = ' ' + ( t.cssClass || '' );
// Using this instead of the jQuery Mobile buttonMarkup because it is expecting <a>'s instead of <button>
// theme:'a', shadow:'true', inline:'true', corners:'false'
return css + ' ' + (btn && btn.cssClass ? btn.cssClass + '-' + (t.theme || '') : '') +
(t.shadow == 'true' ? ' ui-shadow' : '') + // eslint-disable-line eqeqeq
(t.corners == 'true' ? ' ui-corner-all' : ''); // eslint-disable-line eqeqeq
};
base.mobile_init();
});
};
}));
/*! jQuery UI Virtual Keyboard Navigation v1.7.0 *//*
* for Keyboard v1.18+ only (updated 2019-05-02)
*
* By Rob Garrison (aka Mottie & Fudgey)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to navigate
* the virtual keyboard keys using the arrow, page, home and end keys
* Using this extension WILL prevent keyboard navigation inside of all
* input and textareas
*
* Requires:
* jQuery
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .addNavigation();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .addNavigation(); // this keyboard extension
*
*/
/*jshint browser:true, jquery:true, unused:false */
/*global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.keyboard = $.keyboard || {};
$.keyboard.navigationKeys = {
// all keys
toggle : 112, // toggle key; F1 = 112 (event.which value for function 1 key)
enter : 13,
pageup : 33,
pagedown : 34,
end : 35,
home : 36,
left : 37,
up : 38,
right : 39,
down : 40,
// move caret WITH navigate toggle active
caretrt : 45, // Insert key
caretlt : 46, // delete key
// ** custom navigationKeys functions **
// move caret without navigate toggle active
caretright : function(kb) {
$.keyboard.keyaction.right(kb);
},
caretleft : function(kb) {
$.keyboard.keyaction.left(kb);
}
};
$.fn.addNavigation = function(options) {
return this.each(function() {
// make sure a keyboard is attached
var o, k,
base = $(this).data('keyboard'),
opts = base.options,
defaults = {
position : [0,0], // set start position [row-number, key-index]
toggleMode : false, // true = navigate the virtual keyboard, false = navigate in input/textarea
focusClass : 'hasFocus',// css class added when toggle mode is on
toggleKey : null, // defaults to $.keyboard.navigationKeys.toggle value
rowLooping : false // when you are at the left end position and hit the left cursor, you will appear at the other end
},
kbevents = $.keyboard.events,
kbcss = $.keyboard.css;
if (!base) { return; }
base.navigation_options = o = $.extend({}, defaults, options);
base.navigation_keys = k = $.extend({}, $.keyboard.navigationKeys);
base.navigation_namespace = base.namespace + 'Nav';
base.extensionNamespace.push( base.navigation_namespace );
// save navigation settings - disabled when the toggled
base.saveNav = [ base.options.tabNavigation, base.options.enterNavigation ];
base.allNavKeys = $.map(k, function(v) { return v; });
// Setup
base.navigation_init = function() {
base.$keyboard.toggleClass(o.focusClass, o.toggleMode)
.find('.' + kbcss.keySet + ':visible')
.find('.' + kbcss.keyButton + '[data-pos="' + o.position[0] + ',' + o.position[1] + '"]')
.addClass(opts.css.buttonHover);
base.$preview
.unbind(base.navigation_namespace)
.bind('keydown' + base.navigation_namespace,function(e) {
return base.checkKeys(e.which);
});
};
base.checkKeys = function(key, disable) {
if (typeof(key) === 'undefined' || !base.isVisible()) {
return;
}
var k = base.navigation_keys;
if (key === ( o.toggleKey || k.toggle ) || disable) {
o.toggleMode = (disable) ? false : !o.toggleMode;
base.options.tabNavigation = (o.toggleMode) ? false : base.saveNav[0];
base.options.enterNavigation = (o.toggleMode) ? false : base.saveNav[1];
}
base.$keyboard.toggleClass(o.focusClass, o.toggleMode);
if ( o.toggleMode && key === k.enter ) {
base.$keyboard
.find('.' + kbcss.keySet + ':visible')
.find('.' + kbcss.keyButton + '[data-pos="' + o.position[0] + ',' + o.position[1] + '"]')
.trigger(kbevents.kbRepeater);
return false;
}
if ( o.toggleMode && $.inArray(key, base.allNavKeys) >= 0 ) {
base.navigateKeys(key);
return false;
}
};
base.getMaxIndex = function(vis, row) {
return vis.find('.' + kbcss.keyButton + '[data-pos^="' + row + ',"]').length - 1;
};
base.leftNavigateKey = function(indx, maxIndx) {
var rowLooping = base.navigation_options.rowLooping;
var newIndx = indx - 1;
return newIndx >= 0 ? newIndx :
rowLooping ? maxIndx : 0 ;
};
base.rightNavigateKey = function(indx, maxIndx) {
var rowLooping = base.navigation_options.rowLooping;
var newIndx = indx + 1;
return newIndx <= maxIndx ? newIndx :
rowLooping ? 0 : maxIndx ;
};
base.navigateKeys = function(key, row, indx) {
if (!base.isVisible()) {
return;
}
indx = typeof indx === 'number' ? indx : o.position[1];
row = typeof row === 'number' ? row : o.position[0];
var nextMaxIndx,
vis = base.$keyboard.find('.' + kbcss.keySet + ':visible'),
maxRow = vis.find('.' + kbcss.endRow).length - 1,
maxIndx = base.getMaxIndex(vis, row),
p = base.last,
l = base.$preview.val().length,
k = base.navigation_keys;
switch(key) {
case k.pageup : row = 0; break; // pageUp
case k.pagedown : row = maxRow; break; // pageDown
case k.end : indx = maxIndx; break; // End
case k.home : indx = 0; break; // Home
case k.left : indx = base.leftNavigateKey(indx, maxIndx); break; // Left
case k.up :
row += (row > 0) ? -1 : 0;
nextMaxIndx = base.getMaxIndex(vis, row);
indx = indx === maxIndx ? nextMaxIndx : indx;
break; // Up
case k.right : indx = base.rightNavigateKey(indx, maxIndx); break; // Right
case k.down :
row += (row + 1 > maxRow) ? 0 : 1;
nextMaxIndx = base.getMaxIndex(vis, row);
indx = indx === maxIndx ? nextMaxIndx : indx;
break; // Down
case k.caretrt : p.start++; break; // caret right
case k.caretlt : p.start--; break; // caret left
}
// move caret
if (key === k.caretrt || key === k.caretlt) {
p.start = p.start < 0 ? 0 : p.start > l ? l : p.start;
base.last.start = base.last.end = p.end = p.start;
$.keyboard.caret( base.$preview, base.last );
}
// get max index of new row
maxIndx = base.getMaxIndex(vis, row);
if (indx > maxIndx) { indx = maxIndx; }
vis.find('.' + opts.css.buttonHover).removeClass(opts.css.buttonHover);
vis.find('.' + kbcss.keyButton + '[data-pos="' + row + ',' + indx + '"]').addClass(opts.css.buttonHover);
o.position = [ row, indx ];
};
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible()) {
base.$keyboard.find('.' + opts.css.buttonHover).removeClass(opts.css.buttonHover);
base.navigation_init();
}
// navigation bindings
base.$el
.unbind(base.navigation_namespace)
.bind(kbevents.kbVisible, function() {
base.$keyboard.find('.' + opts.css.buttonHover).removeClass(opts.css.buttonHover);
base.navigation_init();
})
.bind(kbevents.kbInactive + ' ' + kbevents.kbHidden, function(e) {
base.checkKeys(e.which, true); // disable toggle mode & revert navigation options
})
.bind(kbevents.kbKeysetChange, function() {
base.navigateKeys(null);
})
.bind('navigate navigateTo', function(e, row, indx) {
var key;
// no row given, check if it's a navigation key or keyaction
row = isNaN(row) ? row.toLowerCase() : row;
if (row in base.navigation_keys) {
key = base.navigation_keys[row];
if (isNaN(key) && key in $.keyboard.keyaction) {
// defined navigation_keys string name is a defined keyaction
$.keyboard.keyaction[key]( base, this, e );
} else if (typeof key === 'function') {
// custom function defined in navigation_keys
key(base);
} else {
// key (e.which value) is defined in navigation_keys
base.checkKeys(key);
}
} else if ( typeof row === 'string' && row in $.keyboard.keyaction ) {
// navigate called directly with a keyaction name
$.keyboard.keyaction[row]( base, this, e );
} else {
base.navigateKeys(null, row, indx);
}
});
});
};
}));
/*! jQuery UI Virtual Keyboard previewKeyset v1.1.1 *//*
* for Keyboard v1.18+ only (updated 7/7/2015)
*
* By Rob Garrison (aka Mottie & Fudgey)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to add a preview
* of other keysets to the main keyboard.
*
* Requires:
* jQuery
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .previewKeyset();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .previewKeyset(); // this keyboard extension
*
*/
/* jshint browser:true, jquery:true, unused:false */
/* global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.keyboard = $.keyboard || {};
$.fn.previewKeyset = function( options ) {
return this.each( function() {
// make sure a keyboard is attached
var base = $( this ).data( 'keyboard' ),
namespace = base.namespace + 'Preview',
defaults = {
sets : [ 'normal', 'shift', 'alt', 'alt-shift' ]
};
if ( !base ) { return; }
base.previewKeyset_options = $.extend( {}, defaults, options );
base.extensionNamespace.push( namespace );
base.previewKeyset = function() {
var kbcss = $.keyboard.css,
sets = base.previewKeyset_options.sets,
// only target option defined sets
$sets = base.$keyboard.find( '.' + kbcss.keySet ).filter( '[name="' + sets.join('"],[name="') + '"]' );
if ( $sets.length > 1 ) {
// start with normal keyset & find all non-action buttons
$sets.eq( 0 ).find( '.' + kbcss.keyButton ).not( '.' + kbcss.keyAction ).each(function(){
var indx, nam,
data = {},
len = sets.length,
// find all keys with the same position
$sibs = $sets.find( 'button[data-pos="' + $(this).attr('data-pos') + '"]' );
for ( indx = 0; indx < len; indx++ ) {
nam = $sibs.eq( indx ).parent().attr( 'name' );
if ( $.inArray( nam, sets ) >= 0 ) {
data[ 'data-' + nam ] = $sibs.eq( indx ).find( '.' + kbcss.keyText ).text();
}
}
$sibs.attr( data );
});
}
};
// visible event is fired before this extension is initialized, so check!
if (base.options.alwaysOpen && base.isVisible()) {
base.previewKeyset();
} else {
base.$el
.unbind($.keyboard.events.kbBeforeVisible + namespace)
.bind($.keyboard.events.kbBeforeVisible + namespace, function() {
base.previewKeyset();
});
}
});
};
}));
/*! jQuery UI Virtual Keyboard Scramble Extension v1.8.0 *//*
* for Keyboard v1.18+ (updated 2019-05-02)
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to scramble the
* specified keyboard keys
*
* Requires:
* jQuery v1.4.4+
* Keyboard v1.17.14+ - https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .addScramble();
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options) // keyboard plugin
* .addScramble(); // this keyboard extension
*
*/
/* jshint browser:true, jquery:true, unused:false */
/* global require:false, define:false, module:false */
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
}(function($) {
'use strict';
$.keyboard = $.keyboard || {};
$.fn.addScramble = function(options) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
// keys to randomize
targetKeys : /[a-z\d]/i,
// randomize by row, otherwise randomize all keys
byRow : true,
// if true, randomize one keyset & duplicate
byKeySet : false,
// if true, randomize only once on keyboard visible
randomizeOnce : true,
// if true, randomize after user input;
// only `targetKeys` cause a new randomization
randomizeInput : false,
// initialization callback function
init : null, // function(keyboard){}
// use the same scrambled keyboard for all targetted keyboards
// not fully implemented!
sameForAll : false
};
return this.each(function() {
// make sure a keyboard is attached
var o,
base = $(this).data('keyboard'),
namespace = base.namespace + 'Scramble',
opts = base.options;
if (!base || base.scramble_options) { return; }
o = base.scramble_options = $.extend({}, defaults, options);
base.extensionNamespace.push( namespace );
// save create callback
o.orig_create = opts.create;
base.scramble_setup = function($keyboard) {
var $sets, set, $keys, key, index, tmp,
rowIndex, keyboardmap, map, keyboard, row;
$sets = $keyboard.find('.' + $.keyboard.css.keySet);
if ($keyboard.length) {
if (o.byKeySet) {
$sets = $sets.eq(0);
}
for (set = 0; set < $sets.length; set++) {
/*jshint loopfunc:true */
$keys = $sets.eq(set);
rowIndex = 0;
row = [];
map = [];
keyboardmap = [];
keyboard = [];
$keys.children('button, span, br').each(function() {
if (this.tagName === 'BR') {
if (o.byRow) {
row.push(this);
map.push(false);
keyboard[rowIndex] = row;
keyboardmap[rowIndex] = map;
row = [];
map = [];
rowIndex++;
} else {
keyboard[rowIndex] = this;
keyboardmap[rowIndex] = false;
rowIndex++;
}
} else {
tmp = $(this).attr('data-value') || '';
tmp = tmp.length === 1 && o.targetKeys.test(tmp) ? tmp : false;
if (o.byRow) {
row.push(this);
map.push (tmp);
} else {
keyboard[rowIndex] = this;
keyboardmap[rowIndex] = tmp;
rowIndex++;
}
}
});
// remove original <br> elements
$keys.find('.' + $.keyboard.css.endRow).remove();
// re-map keys
if (!o.byRow) {
row = base.shuffle( keyboard, keyboardmap );
for (key = 0; key < row.length; key++) {
$keys.append(row[key]);
}
} else {
for (index = 0; index < keyboard.length; index++) {
row = base.shuffle( keyboard[index], keyboardmap[index] );
for (key = 0; key < row.length; key++) {
$keys.append(row[key]);
}
}
}
}
if (o.byKeySet) {
$keyboard = base.realign($keyboard);
}
return $keyboard;
}
};
// get a random uint from 0 ... max-1
base.getRandomUInt = function(max) {
var cryptoObj = window.crypto || window.msCrypto;
if (cryptoObj !== undefined) {
var random_array = new Uint32Array(1);
cryptoObj.getRandomValues(random_array);
return random_array[0] % max;
}
// fallback
return Math.floor(Math.random() * max);
};
// modified from Fisher-Yates shuffle ( http://bost.ocks.org/mike/shuffle/ )
// to allow not shuffling specifically mapped array elements
base.shuffle = function(array, map) {
var swap, random,
index = array.length;
// While there remain elements to shuffle...
while (index > 0) {
// Pick a remaining element...
random = base.getRandomUInt(index);
if (map[index - 1] === false) {
index--;
}
// skip elements that are mapped to false
if (map[index - 1] !== false && map[random] !== false) {
// And swap it with the current element
index--;
swap = array[index];
array[index] = array[random];
array[random] = swap;
}
}
return array;
};
// make other keysets "line-up" with scrambled keyset
base.realign = function($keyboard) {
var selector, typ, pos,
$sets = $keyboard.find('.' + $.keyboard.css.keySet),
$orig = $sets.eq(0);
$sets = $sets.filter(':gt(0)');
$orig.children().each(function(i, cell) {
typ = cell.tagName === 'BR';
pos = $(cell).attr('data-pos');
/*jshint loopfunc:true */
$sets.each(function(j, k) {
selector = typ ? 'br:first' : 'button[data-pos="' + pos + '"]';
$(k).find(selector).appendTo( k );
});
});
return $keyboard;
};
base.setScrambleLayout = function() {
// scrambled layout already initialized
if (!/^scrambled/.test(opts.layout)) {
base.orig_layout = opts.layout;
var savedLayout = savedLayout || 'scrambled' + Math.round(Math.random() * 10000);
opts.layout = o.sameForAll ? savedLayout : 'scrambled' + Math.round(Math.random() * 10000);
}
};
// create scrambled keyboard layout
opts.create = function() {
var layout = opts.layout;
$.keyboard.builtLayouts[layout] = {
mappedKeys : {},
acceptedKeys : [],
$keyboard : null
};
base.layout = opts.layout = base.orig_layout;
// build original layout, if not already built, e.g. "qwerty"
base.buildKeyboard( base.layout, true );
base.layout = opts.layout = layout;
// clone, scramble then save layout
$.keyboard.builtLayouts[layout] = $.extend(true, {}, $.keyboard.builtLayouts[base.orig_layout]);
if ( o.randomizeOnce ) {
$.keyboard.builtLayouts[layout].$keyboard =
base.scramble_setup( $.keyboard.builtLayouts[base.orig_layout].$keyboard.clone() );
}
base.$keyboard = $.keyboard.builtLayouts[layout].$keyboard;
// randomize after every input - see #522
if ( o.randomizeInput ) {
base.$el
.unbind($.keyboard.events.kbChange + namespace)
.bind($.keyboard.events.kbChange + namespace, function(e, kb) {
if ( o.targetKeys.test( kb.last.key ) ) {
// prevent hover class flash on previous key after scramble
kb.$keyboard
.find('.' + opts.css.buttonHover)
.removeClass(opts.css.buttonHover);
kb.$keyboard = kb.scramble_setup(kb.$keyboard);
// now make sure the key under the mouse is highlighted
$(document.elementFromPoint(e.clientX, e.clientY)).trigger('mouseenter');
}
});
} else if ( !o.randomizeOnce ) {
base.$el
.unbind($.keyboard.events.kbBeforeVisible + namespace)
.bind($.keyboard.events.kbBeforeVisible + namespace, function(e, kb) {
kb.$keyboard = kb.scramble_setup(kb.$keyboard);
});
}
if ( typeof o.orig_create === 'function' ) {
o.orig_create( base );
}
};
base.setScrambleLayout();
// special case when keyboard is set to always be open
if (opts.alwaysOpen && base.$keyboard.length) {
setTimeout(function() {
var built = $.keyboard.builtLayouts;
base.$keyboard = base.scramble_setup(base.$keyboard);
base.setScrambleLayout();
if (typeof built[opts.layout] === 'undefined') {
built[opts.layout] = {
mappedKeys : $.extend({}, built[base.layout].mappedKeys),
acceptedKeys : $.extend([], built[base.layout].acceptedKeys),
$keyboard : base.$keyboard.clone()
};
}
if (typeof o.init === 'function') {
o.init(base);
}
}, 0);
} else {
if (typeof o.init === 'function') {
o.init(base);
}
}
});
};
}));
/*! jQuery UI Virtual Keyboard Typing Simulator v1.12.0 *//*
* for Keyboard v1.18+ only (2019-05-02)
*
* By Rob Garrison (aka Mottie)
* Licensed under the MIT License
*
* Use this extension with the Virtual Keyboard to simulate
* typing for tutorials or whatever else use you can find
*
* Requires:
* jQuery
* Keyboard plugin : https://github.com/Mottie/Keyboard
*
* Setup:
* $('.ui-keyboard-input')
* .keyboard(options)
* .addTyping(typing-options);
*
* // or if targeting a specific keyboard
* $('#keyboard1')
* .keyboard(options)
* .addTyping(typing-options);
*
* Basic Usage:
* // To disable manual typing on the virtual keyboard, just set "showTyping"
* // option to false
* $('#keyboard-input').keyboard(options).addTyping({ showTyping: false });
*
* // Change the default typing delay (time the virtual keyboard highlights the
* // manually typed key) - default = 250 milliseconds
* $('#keyboard-input').keyboard(options).addTyping({ delay: 500 });
*
* // get keyboard object, open it, then start typing simulation
* $('#keyboard-input').getkeyboard().reveal().typeIn('Hello World', 700);
*
* // get keyboard object, open it, type in "This is a test" with 700ms delay
* // between types, then accept & close the keyboard
* $('#keyboard-input')
* .getkeyboard()
* .reveal()
* .typeIn('This is a test', 700, function(keyboard) {
* keyboard.accept();
* });
*/
/* More Examples:
* $('#inter').getkeyboard().reveal().typeIn('\tHello \b\n\tWorld', 500);
* $('#meta')
* .getkeyboard().reveal()
* .typeIn('abCDd11123\u2648\u2649\u264A\u264B', 700, function() {
* alert('all done!');
* });
*/
/* jshint browser:true, jquery:true, unused:false */
/* global require:false, define:false, module:false */
;( function( factory ) {
if ( typeof define === 'function' && define.amd ) {
define( ['jquery'], factory );
} else if (
typeof module === 'object' &&
typeof module.exports === 'object'
) {
module.exports = factory( require( 'jquery' ) );
} else {
factory( jQuery );
}
}( function( $ ) {
$.fn.addTyping = function( options ) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
showTyping : true,
lockTypeIn : false,
delay : 250,
hoverDelay : 250
},
$keyboard = $.keyboard;
return this.each( function() {
// make sure a keyboard is attached
var o, base = $( this ).data( 'keyboard' );
if ( !base ) {
return;
}
// variables
o = base.typing_options = $.extend( {}, defaults, options );
base.typing_keymap = {
' ' : 'space',
'"' : '34',
"'" : '39',
'&nbsp;' : 'space',
'\b' : 'bksp', // delete character to the left
'{b}' : 'bksp',
'{d}' : 'del', // delete character to the right
'{l}' : 'left', // move caret left
'{r}' : 'right', // move caret right
'\n' : 'enter',
'\r' : 'enter',
'{e}' : 'enter',
'\t' : 'tab',
'{t}' : 'tab'
};
base.typing_xref = {
8 : 'bksp',
9 : 'tab',
13 : 'enter',
32 : 'space',
37 : 'left',
39 : 'right',
46 : 'del'
};
base.typing_event = false;
base.typing_namespace = base.namespace + 'typing';
base.extensionNamespace.push( base.typing_namespace );
// save lockInput setting
o.savedLockInput = base.options.lockInput;
base.typing_setup_reset = function() {
var kbevents = $keyboard.events,
namespace = base.typing_namespace,
events = [ kbevents.kbHidden, kbevents.kbInactive, '' ]
.join( namespace + ' ' );
// reset "typeIn" when keyboard is closed
base.$el
.unbind( namespace )
.bind( events, function() {
base.typing_reset();
});
base
.unbindButton( namespace )
.bindButton( 'mousedown' + namespace, function() {
base.typing_reset();
});
};
base.typing_setup = function() {
var namespace = base.typing_namespace;
base.typing_setup_reset();
base.$el
.bind( $keyboard.events.kbBeforeVisible + namespace, function() {
base.typing_setup();
});
base.$preview
.unbind( namespace )
.bind( 'keyup' + namespace, function( e ) {
if ( o.init && o.lockTypeIn || !o.showTyping ) {
return false;
}
if ( e.which >= 37 && e.which <=40 ) {
return; // ignore arrow keys
}
if ( e.which === 16 ) {
base.shiftActive = false;
}
if ( e.which === 18 ) {
base.altActive = false;
}
if ( e.which === 16 || e.which === 18 ) {
base.showSet();
// Alt key will shift focus to the menu - doesn't work in Windows
setTimeout( function() {
if (base.$preview) {
base.$preview.focus();
}
}, 200 );
return;
}
})
// change keyset when either shift or alt is held down
.bind( 'keydown' + namespace, function( e ) {
if ( o.init && o.lockTypeIn || !o.showTyping ) {
return false;
}
e.temp = false; // prevent repetitive calls while keydown repeats.
if ( e.which === 16 ) {
e.temp = !base.shiftActive; base.shiftActive = true;
}
// it should be ok to reset e.temp, since both alt and shift will
// call this function separately
if ( e.which === 18 ) {
e.temp = !base.altActive; base.altActive = true;
}
if ( e.temp ) {
base.showSet();
base.$preview.focus(); // Alt shift focus to the menu
}
base.typing_event = true;
// Simulate key press for tab and backspace since they don't fire
// the keypress event
if ( base.typing_xref[ e.which ] ) {
base.typing_findKey( '', e ); // pass event object
}
})
.bind( 'keypress' + namespace, function( e ) {
if ( o.init && o.lockTypeIn ) {
return false;
}
// Simulate key press on virtual keyboard
if ( base.typing_event && !base.options.lockInput ) {
base.typing_reset();
base.typing_event = true;
base.typing_findKey( '', e ); // pass event object
}
});
};
base.typing_reset = function() {
base.typing_event = o.init = false;
o.text = '';
o.len = o.current = 0;
base.options.lockInput = o.savedLockInput;
// clearTimeout( base.typing_timer );
};
// Store typing text
base.typeIn = function( txt, delay, callback, e ) {
if ( !base.isVisible() ) {
// keyboard was closed
clearTimeout( base.typing_timer );
base.typing_reset();
return;
}
if ( !base.typing_event ) {
if ( o.init !== true ) {
o.init = true;
base.options.lockInput = o.lockTypeIn;
o.text = txt || o.text || '';
o.len = o.text.length;
o.delay = delay || o.delay;
o.current = 0; // position in text string
if ( callback ) {
o.callback = callback;
}
}
// function that loops through and types each character
txt = o.text.substring( o.current, ++o.current );
// add support for curly-wrapped single character: {l}, {r}, {d}, etc.
if (
txt === '{' &&
o.text.substring( o.current + 1, o.current + 2 ) === '}'
) {
txt += o.text.substring( o.current, o.current += 2 );
}
base.typing_findKey( txt, e );
} else if ( typeof txt === 'undefined' ) {
// typeIn called by user input
base.typing_event = false;
base.options.lockInput = o.savedLockInput;
return;
}
};
base.typing_findKey = function( txt, e ) {
var tar, m, n, k, key, ks, meta, set,
kbcss = $keyboard.css,
mappedKeys = $keyboard.builtLayouts[base.layout].mappedKeys;
// stop if keyboard is closed
if ( !base.isOpen || !base.$keyboard.length ) {
return;
}
ks = base.$keyboard.find( '.' + kbcss.keySet );
k = txt in base.typing_keymap ? base.typing_keymap[ txt ] : txt;
// typing_event is true when typing on the actual keyboard - look for
// actual key; All of this breaks when the CapLock is on... unable to
// find a cross-browser method that works.
tar = '.' + kbcss.keyButton + '[data-action="' + k + '"]';
if ( base.typing_event && e ) {
// xref used for keydown
// ( 46 = delete in keypress & period on keydown )
if (
e.type !== 'keypress' &&
base.typing_xref.hasOwnProperty( e.keyCode || e.which )
) {
// special named keys: bksp, tab and enter
tar = '.' +
kbcss.keyPrefix +
base.processName( base.typing_xref[ e.keyCode || e.which ] );
} else {
m = String.fromCharCode( e.charCode || e.which );
tar = ( mappedKeys.hasOwnProperty( m ) ) ?
'.' + kbcss.keyButton + '[data-value="' +
mappedKeys[ m ].replace(/"/g, '\\"') + '"]' :
'.' + kbcss.keyPrefix + base.processName( m );
}
}
// find key
key = ks.filter( ':visible' ).find( tar );
if ( key.length ) {
// key is visible, simulate typing
base.typing_simulateKey( key, txt, e );
} else {
// key not found, check if it is in the keymap
// (tab, space, enter, etc)
if ( base.typing_event ) {
key = ks.find( tar );
} else {
// key not found, check if it is in the keymap
// (tab, space, enter, etc)
n = txt in base.typing_keymap ?
base.typing_keymap[ txt ] :
base.processName( txt );
// find actual key on keyboard
key = ks.find( '.' + kbcss.keyPrefix + n );
}
// find the keyset
set = key.closest( '.' + kbcss.keySet );
// figure out which keyset the key is in then simulate clicking on
// that meta key, then on the key
if ( set.attr('name' ) ) {
if ( o.showTyping ) {
// get meta key name
meta = set.attr( 'name' );
// show correct key set
base.shiftActive = /shift/.test( meta );
base.altActive = /alt/.test( meta );
base.metaActive = base.last.keyset[ 2 ] = /\bmeta/.test(meta) ?
( meta ).match(/meta[\w-]+/)[0] : false;
base.showSet( base.metaActive );
}
// Add the key
base.typing_simulateKey( key, txt, e );
} else {
if ( !base.typing_event ) {
// Key doesn't exist on the keyboard, so just enter it
if (
txt in base.typing_keymap &&
base.typing_keymap[txt] in $keyboard.keyaction
) {
$keyboard.keyaction[ base.typing_keymap[ txt ] ]( base, key, e );
} else {
base.insertText( txt );
}
base.checkCombos();
base.$el.trigger( $keyboard.events.kbChange, [ base, base.el ] );
}
}
}
if ( o.current <= o.len && o.len !== 0 ) {
if ( !base.isVisible() ) {
return; // keyboard was closed, abort!!
}
base.typing_timer = setTimeout( function() {
base.typeIn();
}, o.delay );
} else if ( o.len !== 0 ) {
// o.len is zero when the user typed on the actual keyboard during
// simulation
base.typing_reset();
if ( typeof o.callback === 'function' ) {
// ensure all typing animation is done before the callback
base.typing_timer = setTimeout( function() {
// if the user typed during the key simulation, the "o" variable
// may sometimes be undefined
if ( typeof o.callback === 'function' ) {
o.callback( base );
}
}, o.delay );
}
return;
} else {
base.typing_reset();
}
};
// mouseover the key, add the text directly, then mouseout on the key
base.typing_simulateKey = function( el, txt, e ) {
var len = el.length;
if ( !base.isVisible() ) {
return;
}
if ( o.showTyping && len ) {
el.filter( ':visible' ).trigger( 'mouseenter' + base.namespace );
if ( o.showTyping && len ) {
setTimeout( function() {
el.trigger( 'mouseleave' + base.namespace );
}, Math.min( o.hoverDelay, o.delay ) );
}
}
if ( !base.typing_event ) {
// delay required or initial tab does not get added
// in the main demo (international keyboard)
setTimeout( function() {
if (
txt in base.typing_keymap &&
base.typing_keymap[ txt ] in $keyboard.keyaction
) {
e = e || $.Event( 'keypress' );
e.target = el; // "Enter" checks for the e.target
$keyboard.keyaction[ base.typing_keymap[ txt ] ]( base, el, e );
} else {
base.insertText( txt );
}
base.checkCombos();
base.$el.trigger( $keyboard.events.kbChange, [ base, base.el ] );
}, o.delay/3 );
}
};
// visible event is fired before this extension is initialized, so check!
if ( o.showTyping && base.options.alwaysOpen && base.isVisible() ) {
base.typing_setup();
} else {
// capture and simulate typing
base.$el
.unbind( $keyboard.events.kbBeforeVisible + base.typing_namespace )
.bind( $keyboard.events.kbBeforeVisible + base.typing_namespace, function() {
if ( o.showTyping ) {
base.typing_setup();
} else {
base.typing_setup_reset();
}
});
}
});
};
}));
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
* Licensed under the MIT License (LICENSE.txt).
*
* Version: 3.1.12
*
* Requires: jQuery 1.2.2+
*/
/*! Mousewheel version: 3.1.12 * (c) 2014 Brandon Aaron * MIT License */
(function (factory) {
if ( typeof define === 'function' && define.amd ) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS style for Browserify
module.exports = factory;
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
slice = Array.prototype.slice,
nullLowestDeltaTimeout, lowestDelta;
if ( $.event.fixHooks ) {
for ( var i = toFix.length; i; ) {
$.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
}
}
var special = $.event.special.mousewheel = {
version: '3.1.12',
setup: function() {
if ( this.addEventListener ) {
for ( var i = toBind.length; i; ) {
this.addEventListener( toBind[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
// Store the line height and page height for this particular element
$.data(this, 'mousewheel-line-height', special.getLineHeight(this));
$.data(this, 'mousewheel-page-height', special.getPageHeight(this));
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i = toBind.length; i; ) {
this.removeEventListener( toBind[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
// Clean up the data we added to the element
$.removeData(this, 'mousewheel-line-height');
$.removeData(this, 'mousewheel-page-height');
},
getLineHeight: function(elem) {
var $elem = $(elem),
$parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
if (!$parent.length) {
$parent = $('body');
}
return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
},
getPageHeight: function(elem) {
return $(elem).height();
},
settings: {
adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
normalizeOffset: true // calls getBoundingClientRect for each event
}
};
$.fn.extend({
mousewheel: function(fn) {
return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
},
unmousewheel: function(fn) {
return this.unbind('mousewheel', fn);
}
});
function handler(event) {
var orgEvent = event || window.event,
args = slice.call(arguments, 1),
delta = 0,
deltaX = 0,
deltaY = 0,
absDelta = 0,
offsetX = 0,
offsetY = 0;
event = $.event.fix(orgEvent);
event.type = 'mousewheel';
// Old school scrollwheel delta
if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; }
if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; }
if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; }
if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }
// Firefox < 17 horizontal scrolling related to DOMMouseScroll event
if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaX = deltaY * -1;
deltaY = 0;
}
// Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
delta = deltaY === 0 ? deltaX : deltaY;
// New school wheel delta (wheel event)
if ( 'deltaY' in orgEvent ) {
deltaY = orgEvent.deltaY * -1;
delta = deltaY;
}
if ( 'deltaX' in orgEvent ) {
deltaX = orgEvent.deltaX;
if ( deltaY === 0 ) { delta = deltaX * -1; }
}
// No change actually happened, no reason to go any further
if ( deltaY === 0 && deltaX === 0 ) { return; }
// Need to convert lines and pages to pixels if we aren't already in pixels
// There are three delta modes:
// * deltaMode 0 is by pixels, nothing to do
// * deltaMode 1 is by lines
// * deltaMode 2 is by pages
if ( orgEvent.deltaMode === 1 ) {
var lineHeight = $.data(this, 'mousewheel-line-height');
delta *= lineHeight;
deltaY *= lineHeight;
deltaX *= lineHeight;
} else if ( orgEvent.deltaMode === 2 ) {
var pageHeight = $.data(this, 'mousewheel-page-height');
delta *= pageHeight;
deltaY *= pageHeight;
deltaX *= pageHeight;
}
// Store lowest absolute delta to normalize the delta values
absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
if ( !lowestDelta || absDelta < lowestDelta ) {
lowestDelta = absDelta;
// Adjust older deltas if necessary
if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
lowestDelta /= 40;
}
}
// Adjust older deltas if necessary
if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
// Divide all the things by 40!
delta /= 40;
deltaX /= 40;
deltaY /= 40;
}
// Get a whole, normalized value for the deltas
delta = Math[ delta >= 1 ? 'floor' : 'ceil' ](delta / lowestDelta);
deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
// Normalise offsetX and offsetY properties
if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
var boundingRect = this.getBoundingClientRect();
offsetX = event.clientX - boundingRect.left;
offsetY = event.clientY - boundingRect.top;
}
// Add information to the event object
event.deltaX = deltaX;
event.deltaY = deltaY;
event.deltaFactor = lowestDelta;
event.offsetX = offsetX;
event.offsetY = offsetY;
// Go ahead and set deltaMode to 0 since we converted to pixels
// Although this is a little odd since we overwrite the deltaX/Y
// properties with normalized deltas.
event.deltaMode = 0;
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
// Clearout lowestDelta after sometime to better
// handle multiple device types that give different
// a different lowestDelta
// Ex: trackpad = 3 and mouse wheel = 120
if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
function nullLowestDelta() {
lowestDelta = null;
}
function shouldAdjustOldDeltas(orgEvent, absDelta) {
// If this is an older event and the delta is divisable by 120,
// then we are assuming that the browser is treating this as an
// older mouse wheel event and that we should divide the deltas
// by 40 to try and get a more usable deltaFactor.
// Side note, this actually impacts the reported scroll distance
// in older browsers and can cause scrolling to be slower than native.
// Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
}
}));
/**
* Skipped minification because the original files appears to be already minified.
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
*/
/*!
*
* simple-keyboard v2.28.42
* https://github.com/hodgef/simple-keyboard
*
* Copyright (c) Francisco Hodge (https://github.com/hodgef)
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
!function(t,e){"object"===typeof exports&&"object"===typeof module?module.exports=e():"function"===typeof define&&define.amd?define("SimpleKeyboard",[],e):"object"===typeof exports?exports.SimpleKeyboard=e():t.SimpleKeyboard=e()}(window,(function(){return function(t){var e={};function __webpack_require__(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,__webpack_require__),o.l=!0,o.exports}return __webpack_require__.m=t,__webpack_require__.c=e,__webpack_require__.d=function(t,e,n){__webpack_require__.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},__webpack_require__.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},__webpack_require__.t=function(t,e){if(1&e&&(t=__webpack_require__(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(__webpack_require__.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)__webpack_require__.d(n,o,function(e){return t[e]}.bind(null,o));return n},__webpack_require__.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return __webpack_require__.d(e,"a",e),e},__webpack_require__.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},__webpack_require__.p="",__webpack_require__(__webpack_require__.s=0)}([function(t,e,n){t.exports=n(2)},function(t,e,n){},function(t,e,n){"use strict";n.r(e);n(1);function _createForOfIteratorHelper(t){if("undefined"===typeof Symbol||null==t[Symbol.iterator]){if(Array.isArray(t)||(t=function(t,e){if(!t)return;if("string"===typeof t)return _arrayLikeToArray(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);"Object"===n&&t.constructor&&(n=t.constructor.name);if("Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(t,e)}(t))){var e=0,F=function(){};return{s:F,n:function(){return e>=t.length?{done:!0}:{done:!1,value:t[e++]}},e:function(t){throw t},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var n,o,i=!0,s=!1;return{s:function(){n=t[Symbol.iterator]()},n:function(){var t=n.next();return i=t.done,t},e:function(t){s=!0,o=t},f:function(){try{i||null==n.return||n.return()}finally{if(s)throw o}}}}function _arrayLikeToArray(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n<e;n++)o[n]=t[n];return o}function _typeof(t){return(_typeof="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"===typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function _defineProperties(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}var o=function(){function Utilities(t){var e=t.getOptions,n=t.getCaretPosition,o=t.dispatch;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,Utilities),this.getOptions=e,this.getCaretPosition=n,this.dispatch=o,Utilities.bindMethods(Utilities,this)}var t,e,n;return t=Utilities,n=[{key:"bindMethods",value:function(t,e){var n,o=_createForOfIteratorHelper(Object.getOwnPropertyNames(t.prototype));try{for(o.s();!(n=o.n()).done;){var i=n.value;"constructor"===i||"bindMethods"===i||(e[i]=e[i].bind(e))}}catch(s){o.e(s)}finally{o.f()}}}],(e=[{key:"getButtonClass",value:function(t){var e=t.includes("{")&&t.includes("}")&&"{//}"!==t?"functionBtn":"standardBtn",n=t.replace("{","").replace("}",""),o="";return"standardBtn"!==e&&(o=" hg-button-".concat(n)),"hg-".concat(e).concat(o)}},{key:"getDefaultDiplay",value:function(){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}":"\u2191","{arrowleft}":"\u2190","{arrowdown}":"\u2193","{arrowright}":"\u2192","{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"}}},{key:"getButtonDisplayName",value:function(t,e,n){return(e=n?Object.assign({},this.getDefaultDiplay(),e):e||this.getDefaultDiplay())[t]||t}},{key:"getUpdatedInput",value:function(t,e,n,o){var i=this.getOptions(),s=e;return("{bksp}"===t||"{backspace}"===t)&&s.length>0?s=this.removeAt(s,n,o):"{space}"===t?s=this.addStringAt(s," ",n,o):"{tab}"!==t||"boolean"===typeof i.tabCharOnTab&&!1===i.tabCharOnTab?"{enter}"!==t&&"{numpadenter}"!==t||!i.newLineOnEnter?t.includes("numpad")&&Number.isInteger(Number(t[t.length-2]))?s=this.addStringAt(s,t[t.length-2],n,o):"{numpaddivide}"===t?s=this.addStringAt(s,"/",n,o):"{numpadmultiply}"===t?s=this.addStringAt(s,"*",n,o):"{numpadsubtract}"===t?s=this.addStringAt(s,"-",n,o):"{numpadadd}"===t?s=this.addStringAt(s,"+",n,o):"{numpaddecimal}"===t?s=this.addStringAt(s,".",n,o):"{"===t||"}"===t?s=this.addStringAt(s,t,n,o):t.includes("{")||t.includes("}")||(s=this.addStringAt(s,t,n,o)):s=this.addStringAt(s,"\n",n,o):s=this.addStringAt(s,"\t",n,o),s}},{key:"updateCaretPos",value:function(t,e){var n=this.updateCaretPosAction(t,e);this.dispatch((function(t){t.caretPosition=n}))}},{key:"updateCaretPosAction",value:function(t,e){var n=this.getOptions(),o=this.getCaretPosition();return e?o>0&&(o-=t):o+=t,n.debug&&console.log("Caret at:",o,"(".concat(this.keyboardDOMClass,")")),o}},{key:"addStringAt",value:function(t,e,n,o){var i;return n||0===n?(i=[t.slice(0,n),e,t.slice(n)].join(""),this.isMaxLengthReached()||o&&this.updateCaretPos(e.length)):i=t+e,i}},{key:"removeAt",value:function(t,e,n){var o;if(0===this.getCaretPosition())return t;var i=/([\uD800-\uDBFF][\uDC00-\uDFFF])/g;return e&&e>=0?t.substring(e-2,e).match(i)?(o=t.substr(0,e-2)+t.substr(e),n&&this.updateCaretPos(2,!0)):(o=t.substr(0,e-1)+t.substr(e),n&&this.updateCaretPos(1,!0)):t.slice(-2).match(i)?(o=t.slice(0,-2),n&&this.updateCaretPos(2,!0)):(o=t.slice(0,-1),n&&this.updateCaretPos(1,!0)),o}},{key:"handleMaxLength",value:function(t,e){var n=this.getOptions(),o=n.maxLength,i=t[n.inputName],s=e.length-1>=o;if(e.length<=i.length)return!1;if(Number.isInteger(o))return n.debug&&console.log("maxLength (num) reached:",s),s?(this.maxLengthReached=!0,!0):(this.maxLengthReached=!1,!1);if("object"===_typeof(o)){var a=i.length===o[n.inputName];return n.debug&&console.log("maxLength (obj) reached:",a),a?(this.maxLengthReached=!0,!0):(this.maxLengthReached=!1,!1)}}},{key:"isMaxLengthReached",value:function(){return Boolean(this.maxLengthReached)}},{key:"isTouchDevice",value:function(){return"ontouchstart"in window||navigator.maxTouchPoints}},{key:"pointerEventsSupported",value:function(){return window.PointerEvent}},{key:"camelCase",value:function(t){return!!t&&t.toLowerCase().trim().split(/[.\-_\s]/g).reduce((function(t,e){return e.length?t+e[0].toUpperCase()+e.slice(1):t}))}}])&&_defineProperties(t.prototype,e),n&&_defineProperties(t,n),Utilities}();function PhysicalKeyboard_defineProperties(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}var i=function(){function PhysicalKeyboard(t){var e=t.dispatch,n=t.getOptions;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,PhysicalKeyboard),this.dispatch=e,this.getOptions=n,o.bindMethods(PhysicalKeyboard,this)}var t,e,n;return t=PhysicalKeyboard,(e=[{key:"handleHighlightKeyDown",value:function(t){var e=this.getOptions(),n=this.getSimpleKeyboardLayoutKey(t);this.dispatch((function(t){var o=t.getButtonElement(n)||t.getButtonElement("{".concat(n,"}"));o&&(o.style.backgroundColor=e.physicalKeyboardHighlightBgColor||"#9ab4d0",o.style.color=e.physicalKeyboardHighlightTextColor||"white")}))}},{key:"handleHighlightKeyUp",value:function(t){var e=this.getSimpleKeyboardLayoutKey(t);this.dispatch((function(t){var n=t.getButtonElement(e)||t.getButtonElement("{".concat(e,"}"));n&&n.removeAttribute&&n.removeAttribute("style")}))}},{key:"getSimpleKeyboardLayoutKey",value:function(t){var e;return((e=t.code.includes("Numpad")||t.code.includes("Shift")||t.code.includes("Space")||t.code.includes("Backspace")||t.code.includes("Control")||t.code.includes("Alt")||t.code.includes("Meta")?t.code:t.key)!==e.toUpperCase()||"F"===t.code[0]&&Number.isInteger(Number(t.code[1]))&&t.code.length<=3)&&(e=e.toLowerCase()),e}}])&&PhysicalKeyboard_defineProperties(t.prototype,e),n&&PhysicalKeyboard_defineProperties(t,n),PhysicalKeyboard}();function _toConsumableArray(t){return function(t){if(Array.isArray(t))return Keyboard_arrayLikeToArray(t)}(t)||function(t){if("undefined"!==typeof Symbol&&Symbol.iterator in Object(t))return Array.from(t)}(t)||function(t,e){if(!t)return;if("string"===typeof t)return Keyboard_arrayLikeToArray(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);"Object"===n&&t.constructor&&(n=t.constructor.name);if("Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Keyboard_arrayLikeToArray(t,e)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Keyboard_arrayLikeToArray(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n<e;n++)o[n]=t[n];return o}function Keyboard_classCallCheck(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Keyboard_defineProperties(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function _defineProperty(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var s=function(){function SimpleKeyboard(){var t=this;Keyboard_classCallCheck(this,SimpleKeyboard),_defineProperty(this,"handleParams",(function(t){var e,n,o;if("string"===typeof t[0])e=t[0].split(".").join(""),n=document.querySelector(".".concat(e)),o=t[1];else if(t[0]instanceof HTMLDivElement){if(!t[0].className)throw console.warn("Any DOM element passed as parameter must have a class."),new Error("KEYBOARD_DOM_CLASS_ERROR");e=t[0].className.split(" ")[0],n=t[0],o=t[1]}else e="simple-keyboard",n=document.querySelector(".".concat(e)),o=t[0];return{keyboardDOMClass:e,keyboardDOM:n,options:o}})),_defineProperty(this,"getOptions",(function(){return t.options})),_defineProperty(this,"getCaretPosition",(function(){return t.caretPosition})),_defineProperty(this,"registerModule",(function(e,n){t.modules[e]||(t.modules[e]={}),n(t.modules[e])})),_defineProperty(this,"getKeyboardClassString",(function(){for(var e=arguments.length,n=new Array(e),o=0;o<e;o++)n[o]=arguments[o];var i=[t.keyboardDOMClass].concat(n).filter((function(t){return!!t}));return i.join(" ")}));for(var e=arguments.length,n=new Array(e),s=0;s<e;s++)n[s]=arguments[s];var a=this.handleParams(n),r=a.keyboardDOMClass,u=a.keyboardDOM,c=a.options,l=void 0===c?{}:c;if(this.utilities=new o({getOptions:this.getOptions,getCaretPosition:this.getCaretPosition,dispatch:this.dispatch}),this.caretPosition=null,this.keyboardDOM=u,this.options=l,this.options.layoutName=this.options.layoutName||"default",this.options.theme=this.options.theme||"hg-theme-default",this.options.inputName=this.options.inputName||"default",this.options.preventMouseDownDefault=this.options.preventMouseDownDefault||!1,this.keyboardPluginClasses="",o.bindMethods(SimpleKeyboard,this),this.input={},this.input[this.options.inputName]="",this.keyboardDOMClass=r,this.buttonElements={},window.SimpleKeyboardInstances||(window.SimpleKeyboardInstances={}),this.currentInstanceName=this.utilities.camelCase(this.keyboardDOMClass),window.SimpleKeyboardInstances[this.currentInstanceName]=this,this.allKeyboardInstances=window.SimpleKeyboardInstances,this.keyboardInstanceNames=Object.keys(window.SimpleKeyboardInstances),this.isFirstKeyboardInstance=this.keyboardInstanceNames[0]===this.currentInstanceName,this.physicalKeyboard=new i({dispatch:this.dispatch,getOptions:this.getOptions}),!this.keyboardDOM)throw console.warn('".'.concat(r,'" was not found in the DOM.')),new Error("KEYBOARD_DOM_ERROR");this.render(),this.modules={},this.loadModules()}var t,e,n;return t=SimpleKeyboard,(e=[{key:"handleButtonClicked",value:function(t){var e=this.options.debug;if("{//}"===t)return!1;"function"===typeof this.options.onKeyPress&&this.options.onKeyPress(t),this.input[this.options.inputName]||(this.input[this.options.inputName]="");var n=this.utilities.getUpdatedInput(t,this.input[this.options.inputName],this.caretPosition);if(this.input[this.options.inputName]!==n&&(!this.options.inputPattern||this.options.inputPattern&&this.inputPatternIsValid(n))){if(this.options.maxLength&&this.utilities.handleMaxLength(this.input,n))return!1;this.input[this.options.inputName]=this.utilities.getUpdatedInput(t,this.input[this.options.inputName],this.caretPosition,!0),e&&console.log("Input changed:",this.input),this.options.syncInstanceInputs&&this.syncInstanceInputs(),"function"===typeof this.options.onChange&&this.options.onChange(this.input[this.options.inputName]),"function"===typeof this.options.onChangeAll&&this.options.onChangeAll(this.input)}e&&console.log("Key pressed:",t)}},{key:"handleButtonMouseDown",value:function(t,e){var n=this;this.options.preventMouseDownDefault&&e.preventDefault(),this.options.stopMouseDownPropagation&&e.stopPropagation(),e&&e.target.classList.add(this.activeButtonClass),this.isMouseHold=!0,this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),this.holdTimeout&&clearTimeout(this.holdTimeout),this.options.disableButtonHold||(this.holdTimeout=setTimeout((function(){!n.isMouseHold||(t.includes("{")||t.includes("}"))&&"{delete}"!==t&&"{backspace}"!==t&&"{bksp}"!==t&&"{space}"!==t&&"{tab}"!==t||(n.options.debug&&console.log("Button held:",t),n.handleButtonHold(t,e)),clearTimeout(n.holdTimeout)}),500))}},{key:"handleButtonMouseUp",value:function(t){var e=this;this.recurseButtons((function(t){t.classList.remove(e.activeButtonClass)})),this.isMouseHold=!1,this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),t&&"function"===typeof this.options.onKeyReleased&&this.options.onKeyReleased(t)}},{key:"handleKeyboardContainerMouseDown",value:function(t){this.options.preventMouseDownDefault&&t.preventDefault()}},{key:"handleButtonHold",value:function(t){var e=this;this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),this.holdInteractionTimeout=setTimeout((function(){e.isMouseHold?(e.handleButtonClicked(t),e.handleButtonHold(t)):clearTimeout(e.holdInteractionTimeout)}),100)}},{key:"syncInstanceInputs",value:function(){var t=this;this.dispatch((function(e){e.replaceInput(t.input),e.caretPosition=t.caretPosition}))}},{key:"clearInput",value:function(t){t=t||this.options.inputName,this.input[t]="",this.caretPosition=0,this.options.syncInstanceInputs&&this.syncInstanceInputs()}},{key:"getInput",value:function(t){return t=t||this.options.inputName,this.options.syncInstanceInputs&&this.syncInstanceInputs(),this.input[t]}},{key:"setInput",value:function(t,e){e=e||this.options.inputName,this.input[e]=t,this.options.syncInstanceInputs&&this.syncInstanceInputs()}},{key:"replaceInput",value:function(t){this.input=t}},{key:"setOptions",value:function(t){t=t||{},this.options=Object.assign(this.options,t),this.onSetOptions(t),this.render()}},{key:"onSetOptions",value:function(t){t.inputName&&(this.options.debug&&console.log("inputName changed. caretPosition reset."),this.caretPosition=null)}},{key:"clear",value:function(){this.keyboardDOM.innerHTML="",this.keyboardDOM.className=this.keyboardDOMClass,this.buttonElements={}}},{key:"dispatch",value:function(t){if(!window.SimpleKeyboardInstances)throw console.warn("SimpleKeyboardInstances is not defined. Dispatch cannot be called."),new Error("INSTANCES_VAR_ERROR");return Object.keys(window.SimpleKeyboardInstances).forEach((function(e){t(window.SimpleKeyboardInstances[e],e)}))}},{key:"addButtonTheme",value:function(t,e){var n=this;if(!e||!t)return!1;t.split(" ").forEach((function(o){e.split(" ").forEach((function(e){n.options.buttonTheme||(n.options.buttonTheme=[]);var i=!1;n.options.buttonTheme.map((function(t){if(t.class.split(" ").includes(e)){i=!0;var n=t.buttons.split(" ");n.includes(o)||(i=!0,n.push(o),t.buttons=n.join(" "))}return t})),i||n.options.buttonTheme.push({class:e,buttons:t})}))})),this.render()}},{key:"removeButtonTheme",value:function(t,e){var n=this;if(!t&&!e)return this.options.buttonTheme=[],this.render(),!1;t&&Array.isArray(this.options.buttonTheme)&&this.options.buttonTheme.length&&(t.split(" ").forEach((function(t){n.options.buttonTheme.map((function(o,i){if(e&&e.includes(o.class)||!e){var s=o.buttons.split(" ").filter((function(e){return e!==t}));s.length?o.buttons=s.join(" "):(n.options.buttonTheme.splice(i,1),o=null)}return o}))})),this.render())}},{key:"getButtonElement",value:function(t){var e,n=this.buttonElements[t];return n&&(e=n.length>1?n:n[0]),e}},{key:"inputPatternIsValid",value:function(t){var e,n=this.options.inputPattern;if((e=n instanceof RegExp?n:n[this.options.inputName])&&t){var o=e.test(t);return this.options.debug&&console.log('inputPattern ("'.concat(e,'"): ').concat(o?"passed":"did not pass!")),o}return!0}},{key:"setEventListeners",value:function(){!this.isFirstKeyboardInstance&&this.allKeyboardInstances||(this.options.debug&&console.log("Caret handling started (".concat(this.keyboardDOMClass,")")),document.addEventListener("keyup",this.handleKeyUp),document.addEventListener("keydown",this.handleKeyDown),document.addEventListener("mouseup",this.handleMouseUp),document.addEventListener("touchend",this.handleTouchEnd))}},{key:"handleKeyUp",value:function(t){this.caretEventHandler(t),this.options.physicalKeyboardHighlight&&this.physicalKeyboard.handleHighlightKeyUp(t)}},{key:"handleKeyDown",value:function(t){this.options.physicalKeyboardHighlight&&this.physicalKeyboard.handleHighlightKeyDown(t)}},{key:"handleMouseUp",value:function(t){this.caretEventHandler(t)}},{key:"handleTouchEnd",value:function(t){this.caretEventHandler(t)}},{key:"caretEventHandler",value:function(t){var e;t.target.tagName&&(e=t.target.tagName.toLowerCase()),this.dispatch((function(n){n.isMouseHold&&(n.isMouseHold=!1),"textarea"!==e&&"input"!==e||n.options.disableCaretPositioning?n.options.disableCaretPositioning&&(n.caretPosition=null):(n.caretPosition=t.target.selectionStart,n.options.debug&&console.log("Caret at: ",t.target.selectionStart,t.target.tagName.toLowerCase(),"(".concat(n.keyboardDOMClass,")")))}))}},{key:"recurseButtons",value:function(t){var e=this;if(!t)return!1;Object.keys(this.buttonElements).forEach((function(n){return e.buttonElements[n].forEach(t)}))}},{key:"destroy",value:function(){this.options.debug&&console.log("Destroying simple-keyboard instance: ".concat(this.currentInstanceName)),document.removeEventListener("keyup",this.handleKeyUp),document.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("mouseup",this.handleMouseUp),document.removeEventListener("touchend",this.handleTouchEnd),document.onpointerup=null,document.ontouchend=null,document.ontouchcancel=null,document.onmouseup=null;var deleteButton=function(t){t.onpointerdown=null,t.onpointerup=null,t.onpointercancel=null,t.ontouchstart=null,t.ontouchend=null,t.ontouchcancel=null,t.onclick=null,t.onmousedown=null,t.onmouseup=null,t.remove(),t=null};this.recurseButtons(deleteButton),this.recurseButtons=null,deleteButton=null,this.keyboardDOM.onpointerdown=null,this.keyboardDOM.ontouchstart=null,this.keyboardDOM.onmousedown=null,this.clear(),window.SimpleKeyboardInstances[this.currentInstanceName]=null,delete window.SimpleKeyboardInstances[this.currentInstanceName],this.initialized=!1}},{key:"getButtonThemeClasses",value:function(t){var e=this.options.buttonTheme,n=[];return Array.isArray(e)&&e.forEach((function(e){if(e.class&&"string"===typeof e.class&&e.buttons&&"string"===typeof e.buttons){var o=e.class.split(" ");e.buttons.split(" ").includes(t)&&(n=[].concat(_toConsumableArray(n),_toConsumableArray(o)))}else console.warn('Incorrect "buttonTheme". Please check the documentation.',e)})),n}},{key:"setDOMButtonAttributes",value:function(t,e){var n=this.options.buttonAttributes;Array.isArray(n)&&n.forEach((function(n){n.attribute&&"string"===typeof n.attribute&&n.value&&"string"===typeof n.value&&n.buttons&&"string"===typeof n.buttons?n.buttons.split(" ").includes(t)&&e(n.attribute,n.value):console.warn('Incorrect "buttonAttributes". Please check the documentation.',n)}))}},{key:"onTouchDeviceDetected",value:function(){this.processAutoTouchEvents(),this.disableContextualWindow()}},{key:"disableContextualWindow",value:function(){window.oncontextmenu=function(t){if(t.target.classList.contains("hg-button"))return t.preventDefault(),t.stopPropagation(),!1}}},{key:"processAutoTouchEvents",value:function(){this.options.autoUseTouchEvents&&(this.options.useTouchEvents=!0,this.options.debug&&console.log("autoUseTouchEvents: Touch device detected, useTouchEvents enabled."))}},{key:"onInit",value:function(){this.options.debug&&console.log("".concat(this.keyboardDOMClass," Initialized")),this.setEventListeners(),"function"===typeof this.options.onInit&&this.options.onInit()}},{key:"beforeFirstRender",value:function(){this.utilities.isTouchDevice()&&this.onTouchDeviceDetected(),"function"===typeof this.options.beforeFirstRender&&this.options.beforeFirstRender(),this.isFirstKeyboardInstance&&this.utilities.pointerEventsSupported()&&!this.options.useTouchEvents&&!this.options.useMouseEvents&&this.options.debug&&console.log("Using PointerEvents as it is supported by this browser"),this.options.useTouchEvents&&this.options.debug&&console.log("useTouchEvents has been enabled. Only touch events will be used.")}},{key:"beforeRender",value:function(){"function"===typeof this.options.beforeRender&&this.options.beforeRender()}},{key:"onRender",value:function(){"function"===typeof this.options.onRender&&this.options.onRender()}},{key:"onModulesLoaded",value:function(){"function"===typeof this.options.onModulesLoaded&&this.options.onModulesLoaded()}},{key:"loadModules",value:function(){var t=this;Array.isArray(this.options.modules)&&(this.options.modules.forEach((function(e){var n=new e;if(n.constructor.name&&"Function"!==n.constructor.name){var o="module-".concat(t.utilities.camelCase(n.constructor.name));t.keyboardPluginClasses=t.keyboardPluginClasses+" ".concat(o)}n.init(t)})),this.keyboardPluginClasses=this.keyboardPluginClasses+" modules-loaded",this.render(),this.onModulesLoaded())}},{key:"getModuleProp",value:function(t,e){return!!this.modules[t]&&this.modules[t][e]}},{key:"getModulesList",value:function(){return Object.keys(this.modules)}},{key:"parseRowDOMContainers",value:function(t,e,n,o){var i=this,s=Array.from(t.children),a=0;return s.length&&n.forEach((function(n,r){var u=o[r];if(!u||!(u>n))return!1;var c=n-a,l=u-a,h=document.createElement("div");h.className+="hg-button-container";var d="".concat(i.options.layoutName,"-r").concat(e,"c").concat(r);h.setAttribute("data-skUID",d);var p=s.splice(c,l-c+1);a=l-c,p.forEach((function(t){return h.appendChild(t)})),s.splice(c,0,h),t.innerHTML="",s.forEach((function(e){return t.appendChild(e)})),i.options.debug&&console.log("rowDOMContainer",p,c,l,a+1)})),t}},{key:"render",value:function(){var t=this;this.clear(),this.initialized||this.beforeFirstRender(),this.beforeRender();var e="hg-layout-".concat(this.options.layoutName),n=this.options.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}"],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}"]},o=this.options.useTouchEvents||!1,i=o?"hg-touch-events":"",s=this.options.useMouseEvents||!1,a=this.options.disableRowButtonContainers;this.keyboardDOM.className=this.getKeyboardClassString(this.options.theme,e,this.keyboardPluginClasses,i),n[this.options.layoutName].forEach((function(e,n){var i=e.split(" "),r=document.createElement("div");r.className+="hg-row";var u=[],c=[];i.forEach((function(e,i){var l,h=!a&&e.includes("[")&&e.length>1,d=!a&&e.includes("]")&&e.length>1;h&&(u.push(i),e=e.replace(/\[/g,"")),d&&(c.push(i),e=e.replace(/\]/g,""));var p=t.utilities.getButtonClass(e),f=t.utilities.getButtonDisplayName(e,t.options.display,t.options.mergeDisplay),y=t.options.useButtonTag?"button":"div",b=document.createElement(y);b.className+="hg-button ".concat(p),(l=b.classList).add.apply(l,_toConsumableArray(t.getButtonThemeClasses(e))),t.setDOMButtonAttributes(e,(function(t,e){b.setAttribute(t,e)})),t.activeButtonClass="hg-activeButton",!t.utilities.pointerEventsSupported()||o||s?o?(b.ontouchstart=function(n){t.handleButtonClicked(e),t.handleButtonMouseDown(e,n)},b.ontouchend=function(){t.handleButtonMouseUp(e)},b.ontouchcancel=function(){t.handleButtonMouseUp(e)}):(b.onclick=function(){t.isMouseHold=!1,t.handleButtonClicked(e)},b.onmousedown=function(n){t.handleButtonMouseDown(e,n)},b.onmouseup=function(){t.handleButtonMouseUp(e)}):(b.onpointerdown=function(n){t.handleButtonClicked(e),t.handleButtonMouseDown(e,n)},b.onpointerup=function(){t.handleButtonMouseUp(e)},b.onpointercancel=function(){t.handleButtonMouseUp(e)}),b.setAttribute("data-skBtn",e);var m="".concat(t.options.layoutName,"-r").concat(n,"b").concat(i);b.setAttribute("data-skBtnUID",m);var g=document.createElement("span");g.innerHTML=f,b.appendChild(g),t.buttonElements[e]||(t.buttonElements[e]=[]),t.buttonElements[e].push(b),r.appendChild(b)})),r=t.parseRowDOMContainers(r,n,u,c),t.keyboardDOM.appendChild(r)})),this.onRender(),this.initialized||(this.initialized=!0,!this.utilities.pointerEventsSupported()||o||s?o?(document.ontouchend=function(){return t.handleButtonMouseUp()},document.ontouchcancel=function(){return t.handleButtonMouseUp()},this.keyboardDOM.ontouchstart=function(e){return t.handleKeyboardContainerMouseDown(e)}):o||(document.onmouseup=function(){return t.handleButtonMouseUp()},this.keyboardDOM.onmousedown=function(e){return t.handleKeyboardContainerMouseDown(e)}):(document.onpointerup=function(){return t.handleButtonMouseUp()},this.keyboardDOM.onpointerdown=function(e){return t.handleKeyboardContainerMouseDown(e)}),this.onInit())}}])&&Keyboard_defineProperties(t.prototype,e),n&&Keyboard_defineProperties(t,n),SimpleKeyboard}();e.default=s}])}));
//# sourceMappingURL=index.js.map
\ No newline at end of file
{% extends "bootstrap/base.html" %}
{% block head %}
{{super()}}
<!-- bootstrap -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
<!-- keyboard css-->
<link rel="stylesheet" href="{{url_for('static',filename='css/keyboard.css')}}">
<link rel="stylesheet" href="{{url_for('static',filename='css/main.css')}}">
<script>
$(document).click(function (event) {
$target = $(event.target);
if ($target.closest('.input').length || $target.closest('#keyboard').length ||$target.closest('#login').length) {
document.getElementById("keyboard").style.visibility = 'visible';
} else {
document.getElementById("keyboard").style.visibility = 'hidden';
}
});
</script>
{% endblock head %}
{% block content%}
<body class="bg-light m-5">
<h2 class="text-muted text-center m-5">Wifi Password</h2>
<center>
<div class="row align-items-center m-5 col-8">
<div class="col-10 inline ">
<input type="password" class="form-control input" id="wifi-password"
placeholder="Tap on the virtual keyboard to start">
</div>
<div class="col-2 inline">
<button type="submit" class="btn btn-primary" id="login" style="height:50px">Login</button>
</div>
</div>
<div class="row align-items-center">
<div class="col m-5 inline">
<div class="simple-keyboard" id="keyboard" style="visibility: hidden"></div>
</div>
</div>
</center>
<script src="{{url_for('static', filename='js/keyboard.min.js')}}"></script>
<script src="{{url_for('static', filename='js/index.js')}}"></script>
<!-- keyboard js-->
</body>
{% block footer %}
<footer class="footer" >
<div class="footer navbar-fixed-bottom text-center">
<p class="text-muted">&copy; NTUST PRLAB</p>
</div>
</footer>
{% endblock footer %}
{% endblock %}
{% extends "bootstrap/base.html" %}
{% block head %}
{{super()}}
<link href="{{url_for('static',filename='css/keyboard.css')}}" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="container pad-t-50">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">WIFI SSID</th>
</tr>
</thead>
<tbody>
{% for ssid in data %}
<tr>
<td>{{ssid}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="button" id="confirm" class="btn btn-danger">confirm</button>
</div>
{% block footer %}
<footer class="footer" >
<div class="footer navbar-fixed-bottom text-center">
<p class="text-muted">&copy; NCKU Partner</p>
</div>
</footer>
{% endblock footer %}
{% endblock content %}
{% block scripts %}
{{super()}}
{% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment