I'm writing a program in javascript that is supposed to be a fast paced typing challenge. The issue is that my script that's checking for input is crashing my browser before I can enter anything. I thought that it'd pause to wait for input but it seems like I might be wrong?
Here is the function that crashes my browser:
var level1 = function () {
var letter;
var ascii;
var ncorrect = 0;
var input = "0";
var timedout = false;
document.getElementById('prompt').text = "Level 1 : Type Here!" // this is supposed to change text on the page... It doesn't work but not that's not my question.
while (ncorrect < 26){
timedout = false;
setTimeout(timedout = true, 5000);
ascii = Math.floor(Math.random() * 122) + 97; // ASCII's of lower case letters
letter = String.fromCharCode(ascii);
document.getElementById('letter').text = letter;
input = document.getElementById('keyinput');
console.log(input);
if(!timedout && input === letter) {
clearTimeout();
ncorrect++;
}
else {
ncorrect = 0;
}
}
return 0;
}
If it's not a simple fix...
What would be a better way of monitoring input and responding to a right answer?
Thanks, I know it's a little broad of a question but I'm struggling to figure out what I'm looking for.
Javascript is already running an event loop in the background, so you don't need your own. This loop runs continuously and checks to see if any events have fired on any of the HTML DOM Elements. For example, if a button has been clicked, the event loop will pick up a click event for that element. You can add event handlers to the element, which are functions that fire when certain events occur to that element. What you want to do is set an event handler for the event that fires whenever the text in your input area (I'm assuming that the user is typing in an input or textarea tag) is fired.
For example, the following simple program will create a typing challenge 100 random characters long
var ncorrect = 0;
var timedout = false;
//select an empty paragraph to fill with text
var challengeText = document.getElementbyId("challengeText");
challengeText.innerHtml = "";
//Append 100 random characters to the paragraph
for (var i=0;i<100;i++) {
challengetText.innerHtml += String.fromCharCode(Math.floor(Math.random() * 122) + 97);
}
//Check the number of characters typed since the last the loop hit the element
var lastCharsTyped = 0;
var charsTyped = 0;
//Grab the user input
var input = document.getElementById("userInput")
//Set the event handler to fire when the user presses a key (technically, when they lift their finger
input.onkeyup = function(keyEvent){
//Ugly ternary to deal with the fact that not all browsers use the same api. If you haven't seen this before it means if which is a key of keyEvent then keyCoe is event.which, otherwise it's event.keyCode
var keyCode = ('which' in keyEvent) ? keyEvent.which : keyEvent.keyCode;
//Check if the key pressed is equal to the character in the text to match at the same position
if (keyCode === challengeText.innerHtml.charCodeAt(input.value.length)) { ncorrect ++} else {ncorrect = 0;}
}
It won't handle deletes or shift very gracefully, but it should give you an idea of the direction to take.
As a stylistic note, its customary to declare and initialize your variables right before you use them, rather than at the start of your program.
You can use setTimeout() and pass in a function that checks the input after whichever time you specify. Here's one way to implement this:
setTimeout( function () {
var textbox = document.getElementById('textbox');
if (textbox.value !== 'The quick brown fox jumps over the lazy dog.') {
alert('You didn\'t pass.');
} else {
alert('Congratulations!');
}
}, 5000);
Type in the phrase "The quick brown fox jumps over the lazy dog."
<input type="textbox" id="textbox"></input>
setTimeout is passed a function expression that checks user input and spits out an alert based on their typing prowess. The second argument 5000 means the function passed into setTimeout will be called at the nearest opportunity after 5000 ms has passed.
Related
I started learning javascript, and I am trying to make a little project to play around.
I want to validate that the input field for username contains only letters (uppercase or lowercase) and when the value is correct, to outline the field with a color. (I don't care about the design, i care about functionality since it's purpose is for learning).
I have this code: https://jsfiddle.net/7zcv4g1m/1/
const userField = document.querySelector('#user .user');
const passwordField = document.querySelector('#password .password');
const regEx = /^[a-zA-Z]+$/g;
function checkUser() {
// userField.setAttribute('class', 'user');
let userText = userField.value.substring(0, userField.value.length);
let expr = regEx.test(userText);
if (expr == true && userText.length > 0) {
userField.setAttribute('class', 'user test');
} else {
userField.setAttribute('class', 'user');
}
}
userField.addEventListener("focusout", checkUser, false);
My problem is this: at first run, if I click on the element and type a correct text, it outlines the input as expected when I focusOut of the element. The issue is when I click back in the element and just click somewhere outsite of the element to trigger focusout event, without modifying anything in the text. Somehow, my regex condition (the expr variable in the code) is considered to be false, instead of being true, and it turn the element's output back to grey instead of green. If I click back in and after out, it turns back the input border to green.
I don't understand why is this happening and where I made a mistake. Or maybe I wrote the code wrong. If anyone can please give me a hint, will be much appreciated.
It's caused by regEx.test(userText). This should work:
function checkUser() {
// userField.setAttribute('class', 'user');
let userText = userField.value.substring(0, userField.value.length);
let expr = userText.match(regEx);
if (expr && userText.length > 0) {
userField.setAttribute('class', 'user test');
} else {
userField.setAttribute('class', 'user');
}
}
delete modificier g in RegEx, like as
const regEx = /^[a-zA-Z]+$/
the event.preventDefault does not working in android as I know.
so what is the best alternative way to prevent user typing special character in android on keydown event.
note: the replace value solution when input event fired is good but in my situation doesn't solve the problem.
In my case, the problem with replacing value on input event on Android, was with caret, that jumped to wrong position while typing.
I’ve solved it like this:
let input = document.getElementById("input")
function withoutForbiddenChars(str) {
// change to your set of chars
return str.replace(/[^\d]+/g, '')
}
function handleInput(event) {
let charsBeforeCaret = input.value.slice(0, input.selectionStart)
let charsAfterCaret = input.value.slice(input.selectionStart)
charsBeforeCaret = withoutForbiddenChars(charsBeforeCaret)
charsAfterCaret = withoutForbiddenChars(charsAfterCaret)
input.value = charsBeforeCaret + charsAfterCaret
let newCaretPos = charsBeforeCaret.length
input.selectionStart = newCaretPos
input.selectionEnd = newCaretPos
}
input.addEventListener('input', handleInput, false)
Demo: https://codepen.io/udovichenko/pen/vYWWjmR
I have input box
<input type="text" class="text-primary" ng-pattern="ip_regex or ipv6_regex" name="newIP" ng-model="macbinding.newIP" ng-change="checkDuplicates('newIP')">
I already 2 patterns for IPv4 and IPv6 ready.
$scope.ip_regex = '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$';
$scope.ipv6_regex = '((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?';
But how can I apply those ng-pattern dynamically to that input base on-change if a string contain a : ?
Ex. 2001::1
If inputs contain : then, I know it an IPv6 then, I will use the ng-pattern="ipv6_regex"
Is this something that I can achieve on front-end HTML, or do I need to parse the input and do a logic in my angular controller ?
Can I use ng-if for that ?
You can use a combination of ng-model to store and examine your user's input, and a timeOut function to tell you when to check the input. For example.
Your input tag would look like this
<input id="textBox" ng-model="$ctrl.userInput" value="$ctrl.userInput"/>
And the Js (I wrote it in typescript, but it should be readable enough that you get the gist.)
userInput: string = '';
//setup before functions
typingTimer: number; //timer identifier
//on keyup, start the countdown
$('#textBox').on('keyup', function () {
if (typingTimer){
clearTimeout(typingTimer);
}
//if no keyup event is found in 3000ms (3 seconds) execute doneTyping()
typingTimer = setTimeout(doneTyping, 3000);
});
//user is "finished typing," do something
function doneTyping() {
//check for ':'
var foundSemiColon: boolean = false;
//for every character in, userInput see if that character's code value equals 58.
//58 is the ASCII representation of a semi-colon
for (var i: number = 0; i < userInput.length; i++) {
if (userInput.charCodeAt(i) === 58) {
//Semi-colon found use IPv6
break;
}
}
//if foundSemiColon === false you didn't find a semi-colon
if (!foundSemiColon) {
//use IPv4
}
//Now that you're done and know what to use, clear your timeOut event
clearTimeout(typingTimer);
}
Currently i am doing a project with remapping characters to words by detecting the keyup function. Unfortunately, i have only been able to retrieve the first character and remap to the word i want. In my project, i need to directly retrieve all of my keyboard input and directly convert it to the word that i want within the same textarea. For example when i type in the textarea, it will convert to "are" directly. I don't know why it stopped retrieving the second character and remapping not function. Below is my code, hope someone can tell me my error. Thank you.
<textarea class="width-100" id="translated-text" onkeyup="myFunctionkey(event);" rows="10"></textarea>
<script>
function myFunctionkey(e) {
conversion();
}
function conversion(){
var x = document.getElementById('translated-text');
if(x.value == 'a'){
x.value='yes';
}
if(x.value == 'q'){
x.value = 'are';
}
}
</script>
From what I understand, you only want to grab the input and replace a key stroke with a complete word.
Maybe this will do. I've changed onkeyup to onkeypress because this is more reliable from what I remember.
<textarea id="translated-text" cols="50" rows="10" onkeypress="replaceInputChar(event);"></textarea>
<script type="text/javascript">
//create replacement map
var map = {
"a": "and",
"b": "bold",
"c": "change"
};
function replaceInputChar(e)
{
var ctl = document.getElementById("translated-text"); //control
var char = String.fromCharCode(e.keyCode); //typed char
if (char in map) //check if letter is defined in map
{
//insert replacement instead of letter
if("selectionStart" in ctl)
{
//in modern browsers we can easily mimic default behavior at cursor position
var pos = ctl.selectionStart;
ctl.value = ctl.value.substr(0, pos) + map[char] + ctl.value.substr(ctl.selectionEnd);
ctl.selectionStart = pos + map[char].length;
ctl.selectionEnd = ctl.selectionStart;
}
else
ctl.value += map[char];
if ("preventDefault" in e) //modern browser event cancelling
e.preventDefault();
else
{
//old browser event cancelling
e.returnValue = false; //IE8
return false;
}
}
}
</script>
You should use comparison operator '==' instead of assignment operator '=' while remapping the value, like this:
x.value=='a'
Edit:
You should check the updated code for your problem here:
https://jsfiddle.net/o4coLr5t/1/
Now, the characters you choose to remap in javascript will display the string, that you map the character to. Otherwise it will display nothing on pressing keys. So, try and add all the character keycodes to the javascript code. Hope that helps.
I have a scenario where I need to run regex tests on a numeric input that represents phone company operator services.
In one instance, there is a prefix 118 which can act on its own or with a suffix of up to two digits.
At the moment, my function looks something like the below. My problem is that the least specific '118' exact match fires before the more specific one.
There is no sleep/wait in Javascript and unless I'm mistaken, I don't think I can get setTimeout to return a simple "return true" ?
I don't mind if the answer to this question is in pure Javascript or Jquery, but not having a dependency on Jquery would be preferable.
function isOperatorService(vNumber) {
var vNumber = vNumber.replace(/\D/g,'');
if (/^((44){0,1}118[0-9]{3})$/.test(vNumber)) {
console.log("118 specific");
return true;
}
if(/^((44){0,1}[19]{1}[0-9]{1}[0-79]{1})$/.test(vNumber)) {
console.log("Other shortcodes");
return true;
}
return false;
}
UPDATE: Re: "Provide your input and expected output."
Pretty much as I described above, in Pseudo-code :
if == 118
wait incase the user has not finished typing (e.g. wait incase 118118...)
else
do other regex cheks
Add a simple debouncer:
var timeout;
var typeDelay = 300; // wait after last type
var changeEvents = "propertychange keyup input paste change";
$('#yourinput').on(changeEvents, function () {
//clear your timeout
clearTimeout(timeout);
// Add another listener
timeout = setTimeout(function () {
// Do your regex here
function_ended_typing();
}, typeDelay);
});