Hi @mfassier ! Here's a quick modification of the vKeyboard script that should only send numbers after a "return" click. Let me know if it works well for you!
<script>
// the semi-colon before function invocation is a safety net against concatenated
// scripts and/or other plugins which may not be closed properly.
; (function ($, window, document, undefined) {
// undefined is used here as the undefined global variable in ECMAScript 3 is
// mutable (ie. it can be changed by someone else). undefined isn't really being
// passed in so we can ensure the value of it is truly undefined. In ES5, undefined
// can no longer be modified.
// window and document are passed through as local variable rather than global
// as this (slightly) quickens the resolution process and can be more efficiently
// minified (especially when both are regularly referenced in your plugin).
// Create the defaults once
var pluginName = "jkeyboard",
defaults = {
layout: "english",
input: $('#input'),
customLayouts: {
selectable: []
},
};
var function_keys = {
backspace: {
text: 'DEL',
},
return: {
text: 'Enter'
},
shift: {
text: 'Shift'
},
space: {
text: 'Space'
},
numeric_switch: {
text: '123',
command: function () {
this.createKeyboard('numeric');
this.events();
}
},
layout_switch: {
text: '<i class="fa fa-keyboard-o" aria-hidden="true"></i>',
command: function () {
var l = this.toggleLayout();
this.createKeyboard(l);
this.events();
}
},
character_switch: {
text: 'ABC',
command: function () {
this.createKeyboard(layout);
this.events();
}
},
symbol_switch: {
text: '#+=',
command: function () {
this.createKeyboard('symbolic');
this.events();
}
}
};
var layouts = {
selectable: ['azeri', 'english', 'russian','french', 'emoji'],
azeri: [
['q', 'ü', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'ö', 'ğ'],
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ı', 'ə'],
['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'ç', 'ş', 'backspace'],
['numeric_switch', 'layout_switch', 'space', 'return']
],
english: [
['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',],
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',],
['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'backspace'],
['numeric_switch', 'layout_switch', 'space', 'return']
],
russian: [
['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х'],
['ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э'],
['shift', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', 'backspace'],
['numeric_switch', 'layout_switch', 'space', 'return']
],
french: [
['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',],
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l','à','ç'],
['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm','é','è', 'backspace'],
['numeric_switch', 'layout_switch', 'space', 'return']
],
emoji: [
['😀', '😁', '😂', '🤣', '😃', '😄', '😅', '😆', '😉', '😊',],
['😋', '😎', '😍', '😘', 'g', 'h', 'j', 'k', 'l','à','ç'],
['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm','é','è', 'backspace'],
['numeric_switch', 'layout_switch', 'space', 'return']
],
numeric: [
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
['-', '/', ':', ';', '(', ')', '$', '&', '@', '"'],
['symbol_switch', '.', ',', '?', '!', "'", 'backspace'],
['character_switch', 'layout_switch', 'space', 'return'],
],
numbers_only: [
['1', '2', '3',],
['4', '5', '6',],
['7', '8', '9',],
['0', 'backspace', 'return'],
],
symbolic: [
['[', ']', '{', '}', '#', '%', '^', '*', '+', '='],
['_', '\\', '|', '~', '<', '>'],
['numeric_switch', '.', ',', '?', '!', "'", 'backspace'],
['character_switch', 'layout_switch', 'space', 'return'],
]
}
var shift = false, capslock = false, layout = 'english', layout_id = 0;
// The actual plugin constructor
function Plugin(element, options) {
this.element = element;
// jQuery has an extend method which merges the contents of two or
// more objects, storing the result in the first object. The first object
// is generally empty as we don't want to alter the default options for
// future instances of the plugin
this.settings = $.extend({}, defaults, options);
// Extend & Merge the cusom layouts
layouts = $.extend(true, {}, this.settings.customLayouts, layouts);
if (Array.isArray(this.settings.customLayouts.selectable)) {
$.merge(layouts.selectable, this.settings.customLayouts.selectable);
}
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function () {
layout = this.settings.layout;
this.createKeyboard(layout);
this.events();
},
setInput: function (newInputField) {
this.settings.input = newInputField;
},
createKeyboard: function (layout) {
shift = false;
capslock = false;
var keyboard_container = $('<ul/>').addClass('jkeyboard'),
me = this;
layouts[layout].forEach(function (line, index) {
var line_container = $('<li/>').addClass('jline');
line_container.append(me.createLine(line));
keyboard_container.append(line_container);
});
$(this.element).html('').append(keyboard_container);
},
createLine: function (line) {
var line_container = $('<ul/>');
line.forEach(function (key, index) {
var key_container = $('<li/>').addClass('jkey').data('command', key);
if (function_keys[key]) {
key_container.addClass(key).html(function_keys[key].text);
}
else {
key_container.addClass('letter').html(key);
}
line_container.append(key_container);
})
return line_container;
},
events: function () {
var letters = $(this.element).find('.letter'),
shift_key = $(this.element).find('.shift'),
space_key = $(this.element).find('.space'),
backspace_key = $(this.element).find('.backspace'),
return_key = $(this.element).find('.return'),
me = this,
fkeys = Object.keys(function_keys).map(function (k) {
return '.' + k;
}).join(',');
letters.on('click', function () {
me.type((shift || capslock) ? $(this).text().toUpperCase() : $(this).text());
});
space_key.on('click', function () {
me.type(' ');
});
return_key.on('click', function () {
me.enter();
});
backspace_key.on('click', function () {
me.backspace();
});
shift_key.on('click', function () {
if (capslock) {
me.toggleShiftOff();
capslock = false;
} else {
me.toggleShiftOn();
}
}).on('dblclick', function () {
capslock = true;
});
$(fkeys).on('click', function () {
var command = function_keys[$(this).data('command')].command;
if (!command) return;
command.call(me);
});
},
type: function (key) {
var input = this.settings.input,
val = input.val(),
input_node = input.get(0),
start = input_node.selectionStart,
end = input_node.selectionEnd;
var max_length = $(input).attr("maxlength");
if (start == end && end == val.length) {
if (!max_length || val.length < max_length) {
input.val(val + key);
input.change()
$('#vkeyname').text(val + key)
}
} else {
if (input_node.type == "text"){
var new_string = this.insertToString(start, end, val, key);
input.val(new_string);
start++;
end = start;
input_node.setSelectionRange(start, end);
input.change()
}else if (input_node.type == "number"){
input.val(val + key);
}else{
input.val(val + key);
input.change()
}
$('#vkeyname').text(val + key)
}
input.trigger('focus');
if (shift && !capslock) {
this.toggleShiftOff();
}
},
enter: function () {
var input = this.settings.input,
val = input.val();
input_node = input.get(0),
start = input_node.selectionStart,
end = input_node.selectionEnd;
if (input.type == "text"){
val = val + "\n";
$('#vkeyname').text(val)
}
input.change()
input.focus()
},
backspace: function () {
var input = this.settings.input,
val = input.val();
input_node = input.get(0),
start = input_node.selectionStart,
end = input_node.selectionEnd;
if (input.type == "text"){
input.val(val.slice(0, start-1) + val.slice(start))
input_node.setSelectionRange(start-1, start-1);
//console.log(val)
$('#vkeyname').text(val)
}else{
input.val(val.slice(0,-1))
$('#vkeyname').text(val.slice(0,-1))
}
input.change()
//input.focus()
},
toggleShiftOn: function () {
var letters = $(this.element).find('.letter'),
shift_key = $(this.element).find('.shift');
letters.addClass('uppercase');
shift_key.addClass('active')
shift = true;
},
toggleShiftOff: function () {
var letters = $(this.element).find('.letter'),
shift_key = $(this.element).find('.shift');
letters.removeClass('uppercase');
shift_key.removeClass('active');
shift = false;
},
toggleLayout: function () {
layout_id = layout_id || 0;
var plain_layouts = layouts.selectable;
layout_id++;
var current_id = layout_id % plain_layouts.length;
var SelectedLayoutName = plain_layouts[current_id];
$('#vkeyname').text('V-Keyboard ' + SelectedLayoutName )
return plain_layouts[current_id];
},
insertToString: function (start, end, string, insert_string) {
return string.substring(0, start) + insert_string + string.substring(end, string.length);
}
};
/*
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[ pluginName ] = function ( options ) {
return this.each(function() {
if ( !$.data( this, "plugin_" + pluginName ) ) {
$.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
}
});
};
*/
var methods = {
init: function(options) {
if (!this.data("plugin_" + pluginName)) {
this.data("plugin_" + pluginName, new Plugin(this, options));
}
},
setInput: function(content) {
this.data("plugin_" + pluginName).setInput($(content));
},
setLayout: function(layoutname) {
// change layout if it is not match current
object = this.data("plugin_" + pluginName);
if (typeof(layouts[layoutname]) !== 'undefined' && object.settings.layout != layoutname) {
object.settings.layout = layoutname;
object.createKeyboard(layoutname);
object.events();
};
},
};
$.fn[pluginName] = function (methodOrOptions) {
if (methods[methodOrOptions]) {
return methods[methodOrOptions].apply(this.first(), Array.prototype.slice.call( arguments, 1));
} else if (typeof methodOrOptions === 'object' || ! methodOrOptions) {
// Default to "init"
return methods.init.apply(this.first(), arguments);
} else {
$.error('Method ' + methodOrOptions + ' does not exist on jQuery.tooltip');
}
};
})(jQuery, window, document);
</script>
<style>
.jkeyboard {
display: inline-block;
}
.jkeyboard, .jkeyboard .jline, .jkeyboard .jline ul {
display: block;
margin: 0;
padding: 0;
}
.jkeyboard .jline {
text-align: center;
margin-left: -14px;
}
.jkeyboard .jline ul li {
font-family: arial, sans-serif;
font-size: 20px;
display: inline-block;
border: 1px solid #468db3;
-webkit-box-shadow: 0 0 3px #468db3;
-webkit-box-shadow: inset 0 0 3px #468db3;
margin: 5px 0 1px 6px;
color: #000000;
border-radius: 5px;
width: 52px;
height: 52px;
box-sizing: border-box;
text-align: center;
line-height: 52px;
overflow: hidden;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
}
.jkeyboard .jline ul li.uppercase {
text-transform: uppercase;
}
.jkeyboard .jline ul li:hover, .jkeyboard .jline ul li:active {
background-color: #185a82;
}
.jkeyboard .jline .return {
width: 80px;
}
.jkeyboard .jline .space {
width: 366px;
}
.jkeyboard .jline .numeric_switch {
width: 65px;
}
.jkeyboard .jline .layout_switch {
}
.jkeyboard .jline .shift {
width: 60px;
}
.jkeyboard .jline .backspace {
width: 69px;
}
</style>
<style>
body {font-family: Arial, Helvetica, sans-serif;}
.nr-dashboard-theme .nr-dashboard-template .md-button:not(:first-of-type) {
margin-top: 0px;
}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
opacity:0.99;
z-index: 100; /* Sit on top */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content */
.modal-content {
position: fixed;
background-color: #fefefe;
margin: auto;
padding: 0;
bottom: 0%;
left: 50%;
transform: translate(-50%, 0%);
border: 1px solid #888;
width: fit-content;
max-width: 100%;
max-height: 100%;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
-webkit-animation-name: animate;
-webkit-animation-duration: 0.4s;
animation-name: animate;
animation-duration: 0.4s
}
/* Add Animation */
@-webkit-keyframes animate {
from {bottom:100%; opacity:0}
to {bottom:0%; opacity:1}
}
@keyframes animate {
from {bottom:100%; opacity:0}
to {bottom:0%; opacity:1}
}
/* The Close Button */
.close {
color: black;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
.modal-header {
padding: 2px 16px;
background-color: aliceblue;
color: white;
}
.modal-body {padding: 2px 16px;}
.modal-footer {
padding: 2px 16px;
background-color: #5cb85c;
color: white;
}
</style>
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<div class="modal-header">
<span class="close" onclick="closeModal()">×</span>
<h2 id="vkeyname" style="background-color: aliceblue !important; color: black !important; text-align: center; min-height: 30px;">V-Keyboard</h2>
</div>
<div class="modal-body">
<div id="keyboard"></div>
<div>
</div>
</div>
</div>
</div>
<script>
// Get the modal
var modal = document.getElementById('myModal');
/*
$('input[type=text]').click(function () {
$('#keyboard').unbind().removeData();
$('#keyboard').jkeyboard({
layout: "english",
input: $('#'+$(this).attr('id'))
});
});
$('input[type=number]').click(function () {
$('#keyboard').unbind().removeData();
$('#keyboard').jkeyboard({
layout: "numbers_only",
input: $('#'+$(this).attr('id'))
});
});
*/
var inputTags;
var inputType;
var getinputs = function() {
inputTags = document.getElementsByTagName("input");
console.log(inputTags)
for (var i = 0; i < inputTags.length; i++) {
inputTags[i].addEventListener('click', openModal, false)
}
}
setTimeout(function(){ getinputs(); }, 1000);
var inputTarget;
var openModal = function() {
inputType = event.target.type
inputTarget = event.target
var layoutName;
if (inputType == "number"){
//inputTarget.type = "number" //hack because chrome doesn't allow setselection in number inputs
//inputTarget.value = ""
layoutName = "numbers_only"
}else{
layoutName = "english"
}
$('#vkeyname').text(event.target.value)
$('#keyboard').unbind().removeData();
modal.style.display = "block";
$('#keyboard').jkeyboard({
layout: layoutName,
input: $('#'+$(this).attr('id'))
});
}
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on <span> (x), close the modal
//span.onclick = function(event) {
//closeModal()
//}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
var source = event.target;
if (source == modal || source == span) {
closeModal(source)
}
};
var closeModal = function(source){
//console.log("closing")
modal.style.display = "none";
if (inputType == "number"){
inputTarget.type = "number" //hack because chrome doesn't allow selectionstart on number inputs
}
}
</script>
<script>
var clickState = 1;
var btn = document.querySelector('.VK');
btn.addEventListener('click', function(){
if (clickState == 0) {
this.textContent = 'V-KeyBoard On';
modal = document.getElementById('myModal');
clickState = 1;
} else {
this.textContent = 'V-KeyBoard Off';
modal = document.getElementById('empty');
clickState = 0;
}
});
</script>
<style>
.VK{
position: fixed;
top: 60px;
right: 20px;
height: 30px;
}
</style>
<div id="empty"></div>
<button class="VK">V-KeyBoard On</button>