Too many if-else statements. Can they be made global? - javascript

I'm trying to streamline this script. I have 50 of these if e.keyCode statements, so double nesting if/else statements seems ridiculous, but all other attempts I've made haven't worked.
The first if/else statement if(e.keyCode == 66 && e.shiftKey) is necessary, but I'm not sure about the second if (typedAdjusted >= paperWidth % charWidth) which is throwing a warning if too many characters are typed on a line relative to a fixed width.
Can the functionality if (typedAdjusted >= paperWidth % charWidth) gives me be global? It will need to be checked against specific keyCodes. For instance, the letter "B" should be figured into typedAdjusted while BACKSPACE and TAB and COMMAND should not.
var typed = $("span.char").length;
var typedAdjusted = typed+1;
var paperWidth = 900;
var charWidth = 44;
if (e.keyCode == 66) {
if (e.keyCode == 66 && e.shiftKey) {
$('#charLine-1').append('<span class="char">B</span>');
if (typedAdjusted >= paperWidth % charWidth) {
$('body').append('<span id="warning">WARNING!</span>');
}
else {
return false;
}
}
else {
$('#charLine-1').append('<span class="char">b</span>');
if (typedAdjusted >= paperWidth % charWidth) {
$('body').append('<span id="warning">WARNING!</span>');
}
else {
return false;
}
}
}

What do you mean by having 50 of them? You... don't mean one for each letter?
And why do you check for the keycode value twice? Do you see that the code is precisely identical except for the character?
Keep a lookup table, or direct character translation, and shorten it to a single method:
var c = lookup(e.keyCode, e.shiftKey);
$('#charLine-1').append('<span class="char">' + c + '</span>');
if (typedAdjusted >= paperWidth % charWidth) {
$('body').append('<span id="warning">WARNING!</span>');
} else {
return false;
}
That's going to create a whole bunch of spans.
var normal = {
66: 'b', 67: 'c', // etc.
};
var shifted = {
66: 'B', 67: 'C', // etc.
};
/**
* Looks up keycode using appropriate map.
*
* Returns `undefined` if not found; shouldn't insert.
*/
function lookup(code, shift) {
return shift ? shifted[code] : normal[code];
}

IF you like checking each one use a switch: call the checkKey function as needed passing the event.
function checklen() {
var typed = $("span.char").length;
var typedAdjusted = typed + 1;
var paperWidth = 900;
var charWidth = 44;
return (typedAdjusted >= paperWidth % charWidth);
}
function checkKey(e) {
var mychar = '';
var checkit = false;
switch (e.keyCode) {
case 66:
mychar = e.shiftKey ? 'B' : 'b';
checkit = checklen();
break;
case 67:
mychar = e.shiftKey ? 'C' : 'c';
checkit = checklen();
break;
case 68:
mychar = e.shiftKey ? 'D' : 'd';
checkit = checklen();
break;
default:
checkit = false;
break;
}
if (!checkit) {
$('#charLine-1').append('<span class="char">' + mychar + '</span>');
}
else {
$('body').append('<span id="warning">WARNING!</span>');
}
}
to get it to work on the entire document:
$(document).ready(function(){
$(document).keydown(function(e) {
checkKey(e);
});
});
then just click on the page and type characters - note only 'b','c','d' on the code above.

If you observe the keypress event, you can use String.fromCharCode(event.keyCode) to get the character entered and not have to mess with a lookup table.
function (event) {
var key = event.keyCode;
if (key > 31 && key < 127) return String.fromCharCode(key);
}

Related

Number validation along with decimals in key press event

I am doing validation of number except on case. I am doing validation in key press event.
This is the process how am doing my validation..
Output length = Integral + decimals
Example: Integral = 5, decimals = 3
If user enter five digits then am not allowing to enter 6th digit. (i.e. 12345).
But if he type '.' then after am allowing to 3 decimals (i.e. 12345.678). This is working perfectly.
Am facing the issue with below case.
If user enter 1.234 then he navigating to before '.' place using arrows or by mouse click, then user unable to enter another digit. Because I am checking either the integral part or decimal part match the length then I am returning false.
Can any one help me out this. I can do with key up event, but I am trying to achieve this by key press event only. Is there any way to get the position where user entering the digit, if yes then I can get one solution.
var integral = 5, decimals = 3;
//below code in the key press event
if ([8, 9, 13, 37, 39,46].indexOf(e.keyCode) != -1) {
return true;
} else if (e.keyCode == 190 && !e.shiftKey && decimals) {
_value = $(this).val();
if (_value.indexOf('.') != -1) {
return false;
}
return true;
} else if (48 >= e.keyCode || e.keyCode <= 57) {
_value = $(this).val();
if (decimals) {
_value = _value.split('.');
if (_value[0].length == integral || (_value[1] || '').length == decimals) {
return false;
}
return true;
} else {
if (_value.length == integral) {
return false;
}
return true;
}
}
return false;
I used selectionEnd for getting position of where user is typing the digit. Using that I did it.
var evt = e.target || e.srcElement;
_value = $(evt).val();
if ([8, 9, 13, 37, 39, 46].indexOf(e.keyCode) != -1) {
return true;
}
else if (e.keyCode == 190 && !e.shiftKey && decimals) {
if (_value.indexOf('.') != -1) {
return false;
}
return true;
}
else if (48 >= e.keyCode || e.keyCode <= 57) {
if (decimals) {
var isHavingDot = false;
var dotPosition = '';
if (_value.indexOf('.') != -1) {
isHavingDot = true;
dotPosition = _value.indexOf('.')
}
var length = _value.length;
if (isHavingDot) {
_value = _value.split('.');
if (evt.selectionEnd <= dotPosition) {
if (_value[0].length >= integral) {
return false;
}
}
else if ((_value[1] || '').length >= decimals) {
return false;
}
}
else {
if (_value.length >= integral) {
return false;
}
}
return true;
}
else {
if (_value.length == integral) {
return false;
}
return true;
}
}
return false;
If you already know how to do it with the keyup event, then you should be able to take that code and insert it into the keypress handler and implement it on the value that would be in the input if you pass the value through.
For example (I assume your validation works like in the example):
$("#myinput").keypress(function (e) {
//first figure out what the value would be if the keypress were passed through
var key=(e.which) ? e.which : e.keyCode;
var inputvalue=String.fromCharCode((96 <= key && key <= 105)? key-48 : key)
var caretPos = document.getElementById("myinput").selectionStart;
var currentvalue=$("#myinput").val();
var outputstring=currentvalue.substring(0, caretPos) + inputvalue + currentvalue.substring(caretPos);
//allow decimals through
if (outputstring===".") {
e.preventDefault();
$("#myinput").val("0.");
return false;
}
//cancel keypress if they string already has a decimal
if(key===46) return (outputstring.split(".").length - 1)>2;
//now perform the truncation and validation
e.preventDefault();
var outputvalue=parseFloat(outputstring);
var decpart=Math.trunc((outputvalue- parseInt(outputvalue)) * 1000)/1000;
var intpart=Math.floor(outputvalue);
//perform your test on the output value here - only need to test the integer part, since the decimal part is truncated
var outputtest=String(intpart).length<=5;
if (outputtest){
//insert the value if it looks okay
$("#myinput").val(intpart+decpart);
}
return false;
});

Javascript Lookup table vs else if and multiple matching results

I'm creating a canvas game for fun, and I'm trying to re-factor some of my multiple else if statements to use object lookup tables instead.
This is my current code for assigning variable values on keydown:
function keyDown(e) {
keypressed = true;
if (e.keyCode == 39 || e.keyCode == 68) {rightKey = true; }
else if (e.keyCode == 37 || e.keyCode == 65) {leftKey = true;}
else if (e.keyCode == 38 || e.keyCode == 87) {upKey = true; }
else if (e.keyCode == 40 || e.keyCode == 83) {downKey = true; }
else if (e.keyCode == 80) { isPaused = !isPaused; document.body.classList.toggle('pause'); }
if (e.keyCode === 69) { startHit(); }
}
I want to assign both wsad keys and the arrow keys to do the same thing, thus the use of || in the if conditions.
I read that using an object literal lookup table is a faster way to achieve this and this is my attempt:
var codes = {
39 : function() {
return rightKey = true;
},
37 : function() {
return leftKey = true;
},
38 : function() {
return upKey = true;
},
40 : function() {
return downKey = true;
},
80 : function() {
isPaued = !isPaused;
document.body.classList.toggle('pause');
},
69 : startHit
}
codes[68] = codes[39];
codes[65] = codes[37];
codes[87] = codes[38];
codes[83] = codes[40];
function keyDown(e) {
keypressed = true;
codes[e.keyCode]();
}
This works just fine, but I'm not sure the assignment of the bottom keys is the best way to do this? I can't obviously use the || operator in the left hand assignment, so would there be a cleaner way to do this or should I just stick with the else ifs?
Also, I know I could use a switch statement, but I feel like it would look similar to the way I've done above.
Any advice would be great. Thanks.
Why not use a switch statement?
function keyDown(e) {
keypressed = true;
switch (e.keyCode) {
case 39:
case 68:
rightKey = true;
break;
case 37:
case 65:
leftKey = true;
break;
case 38:
case 87:
upKey = true;
break;
case 40:
case 83:
downKey = true;
break;
case 80:
isPaused = !isPaused;
document.body.classList.toggle('pause');
break;
case 69:
startHit();
}
}
what about this?
var codes = function (){
function rightKey(){
rightKey = true;
}
function leftKey() {
leftKey = true;
}
return {
39 : rightKey,
37 : leftKey,
'...': '...',
68 : rightKey,
65 : leftKey
}}()

How do I know, via key event code, if the character just entered in a <textarea> is lower or upper case?

I'm trying to capture the character just entered into a <textarea>, but I can only get which key is pressed via key event like keydown or keyup, not knowing if it's lower case or upper case.
For example, when I input A or a, the event key codes for keydown are all 65.
I thought of using val() to get the string in the <textare> and get the last character of it, but that is too slow and memory consuming, since I want to record every keyboard event while the user is typing.
So is there a way I can simply get the last entered character?
Try this:
var p = $('#log')[0];
$("#textarea").on("keypress", function(e) {
p.textContent = '';
var k = e.keyCode || e.which;
var character = String.fromCharCode(k);
if (!isNaN(character * 1)) {
p.textContent += 'character is numeric';
} else {
if (character == character.toUpperCase()) {
p.textContent += 'UPPER case true';
}
if (character == character.toLowerCase()) {
p.textContent += 'lower case true';
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="textarea"></textarea>
<p id="log"></p>
I see what you mean about the shiftKey
var myObj = $('#myTextarea');
function isLetter(char){
if ((char.toLowerCase() !== char) || (char.toUpperCase() !== char)) {
return true;
}
return;
}
myObj.keypress(function( event ){
var text = myObj.val();
var char = text.charAt(text.length-1);
if (!event.shiftKey && isLetter(char)) {
if (char == char.toUpperCase()) {
console.log('Upper');
}
if (char == char.toLowerCase()) {
console.log('Lower');
}
}
});
try:
<textarea id="area1"></textarea>
window.onload = function () {
document.getElementById("area1").onkeypress = function(event){
var code = event.which;
if ((code >= 65) && (code <= 90)) {
alert('Upper');
}
else if ((code >= 97) && (code <= 122)) {
alert('Lower');
}
}
}

How to record timing for keypress event?

I am trying to build a small script that shows, on call back, when I press key q then after one second I press w it should show q and w obviously, BUT When, I press q and then w not at the same time, just in less than one second, it should show other single character for ex: x and this is where I am stuck currently JsFIDDLE or my full code.
<script type="text/javascript">
function check(e){
var text = e.keyCode ? e.keyCode : e.charCode;
switch(text){
case 81:
text = 'q';
break;
case 87:
text = 'w';
break;
}
if(text == 8){
var str = document.getElementById("out").innerHTML;
var foo = str.substring(0, str.length -1);
document.getElementById("out").innerHTML = foo;
}else {
document.getElementById("out").innerHTML += text;
}
}
</script>
<input type='text' onkeyup='check(event);' id='in' />
<div id='out' ></div>
I am new to JavaScript, and I am lost as to what lets you record one key press then wait to listen if there is another one existing even inside a second. I have tried also, setInterval() function, but that only executes a function by amount of time it is given.
I think this is what you need:
var timer = new Date(),
previousChar;
function check (e) {
var foo,
text = e.keyCode ? e.keyCode : e.charCode,
out = document.getElementById('out'),
str = out.innerHTML;
switch (text) {
case 81: text = 'q'; break;
case 87: text = 'w'; break;
}
if (new Date() - timer < 1000 && text === 'w' && previousChar === 'q') {
text = 'x';
out.innerHTML = str.substring(0, str.length - 1);
}
if (text === 8) {
foo = str.substring(0, str.length - 1);
out.innerHTML = foo;
} else {
out.innerHTML += text;
}
previousChar = text;
timer = new Date();
return;
}
A live demo at jsFiddle.
EDIT
Since you've added some more requirements via the comments, here's an edited code for the task:
var timer = new Date(),
keyCombinations = {
ae: 'ä',
oe: 'ö',
qw: 'x'
};
function check(e){
var text, str, previousKeys,
key = e.keyCode || e.charCode,
out = document.getElementById('out');
text = String.fromCharCode(key);
str = out.innerHTML + text;
previousKeys = str.substring(str.length - 2, str.length);
if (new Date() - timer < 1000) {
if (previousKeys in keyCombinations) {
str = str.substring(0, str.length - 2) + keyCombinations[previousKeys];
}
}
out.innerHTML = str;
timer = new Date();
return;
}
Notice, that this code is for onkeypress event. It's more reliable when creating characters from keycodes. You can assign a separate eventhandling for the special keys, like backspace, within onkeyup handler function.
This is not a perfect code, but it gives you an idea, how to implement this task. It uses an object literal to store all key combinations and their replacements. This way you don't need to write any loop at all.
A live example at jsFiddle.
Here goes: If q has been pressed you got one second to get a 'w' otherwise you'll get an 'x'. Is this what you want? (Tried to make it as easy as possible to read, preferrably you'd refactor it a little :)
var openToW = false;
function check(e){
var text = e.keyCode ? e.keyCode : e.charCode;
if(text==81){
openToW=true;
document.getElementById("out").innerHTML='q';
setInterval(lock,1000);
}
if(text==87){
if(!openToW){
document.getElementById("out").innerHTML = 'x';
return;
}
else{
document.getElementById("out").innerHTML='w';
}
}
}
function lock(){
openToW=false;
}

How to catch event.keyCode and change it to another keyCode?

I have checked other questions here at SO, however they do not answer my question. I want to simply catch certain keyCode and replace it with another. I am working with characters, not white spaces, and I do not need to loose focus or the like.
Below is my code. But you can replace those keyCodes with your (eg. when capital "A" is pressed, it should replace with zero 0, etc.). The idea is to replace the keyCode.
phrase.keypress(function(event)
{
if (event.shiftKey)
{
switch (event.keyCode)
{
// Cyrillic capitalized "Н" was pressed
case 1053: event.keyCode = 1187; event.charCode = 1187; event.which = 1187; break;
// Cyrillic capitalized "О" was pressed
case 1054: event.keyCode = 1257; event.charCode = 1257; event.which = 1257; break;
// Cyrillic capitalized "У" was pressed
case 1059: event.keyCode = 1199; event.charCode = 1199; event.which = 1199; break;
}
}
});
I tried with keydown and keyup as well. They do not alter the keyCode. How can I do that?
P.S. If possible, I am looking for a solution which does not "event.preventDefault() and manually insert desired key to input field, then move cursor to the end". I want cleaner and "right" solution. Thank you.
Keyboard event properties are all READ-only. You cannot capture one keyCode and change it to another.
See reference from MDN - Keyboard Events - All are read only can't be set.
As you mentioned in your post. -- If you wan't to handle, then you have to stop browser default key press and set the desired value to the element yourself.
While the properties on the KeyboardEvent instance is READ ONLY, you can override KeyboardEvent's prototype and create a getter for whatever you want to change. Here is an example which changes the keycodes of hjkl to act like arrow keys.
Object.defineProperty(KeyboardEvent.prototype, 'keyCode', {
get: function() {
switch (this.key) {
case 'h': return 37; // left
case 'j': return 40; // down
case 'k': return 38; // up
case 'l': return 39; // right
default: return this.which
}
}
})
I am using the following code to achieve the same result as if I had changed the keyCode, without actually being able to change it.
function inputValidation() {
var srcField = event.srcElement;
var sKey = event.keyCode;
var inputLetter = String.fromCharCode(sKey);
if (typeof(srcField) !== "undefined" && srcField !== null) {
inputLetter = transformInput(inputLetter);
var caretPos = srcField.selectionStart;
var startString = srcField.value.slice(0, srcField.selectionStart);
var endString = srcField.value.slice(srcField.selectionEnd, srcField.value.length);
srcField.value = startString + inputLetter + endString;
setCaretPosition(srcField, caretPos+1); // '+1' puts the caret after the input
event.preventDefault ? event.preventDefault() : event.returnValue = false; //for IE8
}
}
srcField.selectionStart gives the starting position of the text you have selected and srcField.selectionEnd gives the end position of the selection, if you haven't selected any text srcField.selectionStart equals srcField.selectionEnd.
The function setCaretPosition came from this answer by kd7. I only changed it to make it receive the element instead of its Id
function setCaretPosition(elem, caretPos) {
if (elem != null) {
if (elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
} else {
if (elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
} else
elem.focus();
}
}
}
you can change value as manuel and handle keypress. if you want to check key declare a variable and check your keycode.
this.event.target.value = this.event.target.value + ".";
return false;
full code:
function isNumberKeyDec(evt) {
var charCode = (evt.which) ? evt.which : event.keyCode;
var apos = 0;
if (charCode == 44) {
apos = 1;
charCode = 46;
}
if (this.event.target.value.length == 0 && charCode == 46) {
return false;
}
if (this.event.target.value.length == 1 && this.event.target.value == "0" && charCode == 48) {
return false;
}
if (this.event.target.value.length == 1 && this.event.target.value == "0" && charCode != 46) {
this.event.target.value = "";
}
if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode != 46) {
return false;
}
if (charCode == 46 && this.event.target.value.indexOf(".") != -1) {
return false;
}
if (this.event.target.value.indexOf(".") != -1) {
if (this.event.target.value.substring(this.event.target.value.toString().indexOf(".")).length >= 2) {
return false;
}
}
if (this.event.target.value.indexOf(".") == -1 && charCode != 46) {
if (this.event.target.value.length >= 3 && charCode != 46) {
return false;
}
}
if (apos == 1) {
this.event.target.value = this.event.target.value + ".";
return false;
}
return true;
}

Categories