get the new added characters to an input by js - javascript

I know this seems a quite easy target. I have an input[type=text], and I want to detect the new added character(s) in it. The normal way is:
$selector.keypress(function(e) {
//do sth here
var newchar = String.fromCharCode(e.which);
});
But the above method not working properly for some browsers on android devices. Typing the android virtual keyboard will not fire the keypress.
Then I found the following method is better:
$selector.on('input', function(e){
//do sth here
});
It works fine for android devices, and also, it can detect cut/paste.
Now the question is, is there a way to know the new added character(s) to the input? Do I need to do the complicated string comparison during inputing each time, i.e. compare the previous string and the new string in the input box? I said it's complicated because you may not always type in char(s) at the end, you may insert some char(s) in the middle of the previous string. Think about this, the previous string in the input box is "abc", the new string after pasting is "abcxabc", how can we know the new pasted string is "abcx", or "xabc"?
The method from keypress is quite simple:
String.fromCharCode(e.which);
So, is there similar way to do this by the on('input') method?
After reading Yeldar Kurmangaliyev's answer, I dived into this issue for a while, and find this is really more complicated than my previous expectation. The key point here is that there's a way to get the cursor position by calling: selectionEnd.
As Yeldar Kurmangaliyev mentioned, his answer can't cover the situation:
it is not working is when you select text and paste another text with
replacing the original one.
Based on his answer, I modified the getInputedString function as following:
function getInputedString(prev, curr, selEnd) {
if (selEnd === 0) {
return "";
}
//note: substr(start,length) and substring(start,end) are different
var preLen = prev.length;
var curLen = curr.length;
var index = (preLen > selEnd) ? selEnd : preLen;
var subStrPrev;
var subStrCurr;
for(i=index; i > 0; i--){
subStrPrev = prev.substr(0, i);
subStrCurr = curr.substr(0, i);
if (subStrCurr === subStrPrev) {
var subInterval = selEnd - i;
var interval = curLen - preLen;
if (interval>subInterval) {
return curr.substring(i, selEnd+(interval-subInterval));
}
else{
return curr.substring(i, selEnd);
}
}
}
return curr.substring(0, selEnd);
}
The code is quite self explanation. The core idea is, no matter what character(s) were added(type or paste), the new content MUST be ended at the cursor position.
There's also one issue for my code, e.g. when the prev is abcabc|, you select them all, and paste abc, the return value from my code will be "". Actually, I think it's reasonable, because for my scenario, I think this is just the same with delete the abc from previous abcabc|.
Also, I changed the on('input') event to on('keyup'), the reason is, for some android browsers, the this.selectionEnd will not work in a same way, e.g., the previous text is abc|, now I paste de and the current string will be abcde|, but depending on different browsers, the this.selectionEnd inside on('input') may be 3, or 5. i.e. some browsers will report the cursor position before adding the input, some will report the cursor position after adding the input.
Eventually, I found on('keyup') worked in the same way for all the browsers I tested.
The whole demo is as following:
DEMO ON JSFIDDLE
Working on the cross-browser compatibility is always difficult, especially when you need to consider the touch screen ones. Hope this can help someone, and have fun.

Important notes:
when a user types in a character, the cursor stands after it
when a user pastes the text, the cursor is also located after the pasted text
Assuming this, we can try to suggest the inputed \ pasted string.
For example, when we have a string abc and it becomes abcx|abc (| is a cursor) - we know that actually he pasted "abcx", but not "xabc".
How do this algorithmically? Lets assume that we have the previous input abc and the current input: abcx|abc (cursor is after x).
The new one is of length 7, while the previous one is of length 4. It means that a user inputed 4 characters. Just return these four characters :)
The only case when it is not working is when you select text and paste another text with replacing the original one. I am sure you will come up with a solution for it yoruself :)
Here is the working snippet:
function getInputedString(prev, curr, selEnd) {
if (prev.length > curr.length) {
console.log("User has removed \ cut character(s)");
return "";
}
var lengthOfPasted = curr.length - prev.length;
if (curr.substr(0, selEnd - lengthOfPasted) + curr.substr(selEnd) === prev)
{
return curr.substr(selEnd - lengthOfPasted, lengthOfPasted);
} else {
console.log("The user has replaced a selection :(");
return "n\\a";
}
}
var prevText = "";
$("input").on('input', function() {
var lastInput = getInputedString(prevText, this.value, this.selectionEnd);
prevText = this.value;
$("#result").text("Last input: " + lastInput);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
<div id="result">Start inputing...</div>

Related

How to hide text in input field as you type each character?

I have an input field, that basically takes a confirmation code(alphanumerical) while logging into an application. I want to implement the below functionality:
when you type each character, it appears in the text field for a fraction of time(say 1 second), and then it becomes an asterisk.
The reason I want this? This helps the user know what character he/she is typing in the input field and doesn't compromise on the security aspects.
What I have tried? I tried to make the input field type as "password" but that makes the character typed into an asterisk instantly. I don't want this, I want it to show for 1s then become an asterisk.
<input type=password placeholder="Please enter your alphanumerical code" />
Note: I don't want a display/hide toggle button implementation of the above, as I already am aware of that, and have seen answers about that, but it's not my intended implementation
I am working on a reactJS application, so an implementation based on react, JS, JSX, HTML, etc. would be preferred. Thanks :)
P.S This is my first question on stack overflow and I am very new to react, so please pardon me for any mistakes. Feel free to ask any doubts/queries you have regarding the question.
There is a ready-made solution for github: https://karaggeorge.github.io/react-better-password/
Consider the following algorithm:
On input:
get the caret position,
get the number of characters added or deleted
If added,
get the added characters
insert them in the shaddow string
// to do
after a defined time, or on next input, replace
added characters with asterisks (*)
If deleted
delete number deleted to the right of character pos
in the shadow string
Masking the characters runs on a timeout. If something is entered before the timeout runs, the timeout is cancelled and the characters masked immediately. If you type really quickly, multiple characters are visible for a very short time. If multiple characters are pasted, they are all displayed for the timeout lag.
Here's an implementation:
let maskInput = (function() {
// Keep reference to timeout
let timeoutRef = null;
// Set field to all asterisks, keep cursor at current position
function blankField(el) {
// Cancel timeout if there is one
if (timeoutRef) {
clearTimeout(timeoutRef);
timeoutRef = null;
}
// Get cursor position
let cursorPos = el.selectionStart;
// Mask values
el.value = el.value.replace(/./g, '*');
// Put cursor back in position
el.setSelectionRange(cursorPos, cursorPos);
}
return function (el) {
// Get the shaddow element
let inp = document.getElementById('i1');
// Get current cursor position
let cursorPos = el.selectionStart;
// Get number of characters added
let numAdded = el.value.length - inp.value.length;
// If characters were added
if (numAdded > 0) {
// Get characters added
let charsAdded = el.value.slice(cursorPos - numAdded, cursorPos);
// Insert characaters in inp
let insertIdx = cursorPos - numAdded;
inp.value = inp.value.substring(0, insertIdx) +
charsAdded +
inp.value.substring(insertIdx, inp.value.length);
timeoutRef = setTimeout(() => blankField(el), 250);
// If characters were deleted, delete numAdded characters
// to the right of the current cursor position in inp
} else if (numAdded < 0) {
inp.value = inp.value.substring(0, cursorPos) +
inp.value.substring(cursorPos - numAdded, inp.value.length);
}
}
}());
<input id="i0" oninput="maskInput(this)">Enter text<br>
<input id="i1" readonly>Shaddow text
This assumes that the listener is on an input element, plus the ID of the shadow input and masking character are hard coded. Both can easily be dynamic or set in a parameter object or similar.

Two different conditions for auto-tabbing text fields

Good morning,
First of all, thanks in advance for any help you might provide
I'll try and explain myself as clearly as possible:
I have a column of some 30ish equal text fields, with an unmodifiable width and height in a form. The users will have two options when inputting text into the text fields:
a) Type word by word
b) Copy from another souce a chunk of text and paste it into the text field.
Now, what I want is to have two different options for the form to auto-tab to the next text field if the first one has been filled.
These are the two options I have tried up to now, which both work when used on their own, but won't work together:
a) Custom Keystroke script for, lets say, Field.0:
if (event.fieldFull) {
this.getField("Field.1").setFocus();
}
b) Custom on-blur script for Field.0:
var temp = new Array();
temp = this.getField("Field.0").value.split(' ');
var rest = "";
ini = temp[0] + ' ';
var charsRead = temp[0].length + 1;
var index = 1;
while ((charsRead + temp[index].length) < 110){
ini = ini + temp[index] + ' ';
index++;
charsRead = charsRead + temp[index].length + 1;
}
for (var i=index ; i < temp.length-1 ; i++){
rest = rest + temp[i] + ' ';
}
this.getField("Field.0").value = ini;
this.getField("Field.1").value = rest;
this.getField("Field.1").setFocus();
As you might probably have noticed, I am no expert (not even close to one...) scripter, so the code might be inefficient or repetitive.
What the script does is: Store the words of the chunk pasted into an array (so as not to split the text in the middle of a word), and copy the first fitting words up to 110 chars (an arbitrary number which sometimes is too little and sometimes too much), and then takes the rest of the words in the array and pastes them into the next field.
When the user tabs out of the Field.0 the focus is set to Field.1. If the text is still too long, when he tabs out of Field.1, the focus is set to Field.2 with the second remainder of the text pasted into it. So, all he has to do is Ctrl+V and TAB, TAB, TAB until all the text has occupied the necessary fields.
Now, for the solution to point a), Scrolling Long Text has to be disabled, but, it is necessary for the script used to solve problem b).
What I am looking for is a way of, independently on how the user has inputted text, to auto-tab WHEN THE FIELD IS FULL. And by full I mean that the text has reached THE END OF THE VISIBLE AREA.
Be it while typing out the text (I suppose it'd has to be with a keystroke script) or when pasting a long phrase (with an on-blur, since keystroke doesn't work here).
Sorry for the long post and thank you once more for the help.
BTW: Using Adobe Acrobat X Pro.
If you have a monospaced font, you can determine how many characters fit in a text field.
Break the pasted text up into chunks of that size, then distribute these chunks over the fields.
So, using the chunk function found here:
//(On paste)
var brokenUpString = pastedString.chunk(maxInputLengthPerField);
for(var i = 0; brokenUpString[i]; i++){
fields[i]value = brokenUpString[i]
}
Now, if you want to move the cursor to the next text field when a user is typing, something like this may work:
//(On key up)
var currentField = 0;
if(fields[currentField].value.length == maxInputLengthPerField){
currentField++;
fields[currentField].setFocus();
}
The problem is that it's "hard" to detect how many characters are entered when a user keeps a button pressed, but you could just take the whole string, break it up, and distribute it over the fields, if that happens.
(chunk() function from the link:)
String.prototype.chunk = function(size) {
return [].concat.apply([],
this.split('').map(function(x,i){ return i%size ? [] : this.slice(i,i+size) }, this)
)
}

mark a specific word after each space

I'm trying to warning the user if he types a word that is not necessary in a textarea.
its just a little validation for some words.
i reach making something like this:
var words = "hello";
$("textarea").keyup(function(e){
var spliting = $("textarea").val().split(" ");
if(e.keyCode == 32){ // when the user hits space bar
if($.inArray(words, spliting) != -1){
$("span").css("background","red");
}else{
$("span").css("background","green");
}
}
});​
is this the best way of doing this ?
and how can i migrate the variable words as a array, if i need to check more then one word?
Demo
To use an array, you will need to loop over each word in it and loop over each word in the split array. However, you can return on the first match:
var words = ["hello","goodbye"];
$("textarea").keyup(function(e){
var spliting = $("textarea").val().split(" ");
for (var i=0; i<words.length; i++) {
if($.inArray(words[i], spliting) != -1){
$("span").css("background","red");
// break on first match since there is no need to continue looping
// if it is already red.
break;
}else{
$("span").css("background","green");
}
}
});​
I have removed the check for spaces. Even though it makes the function more efficient, you need to be wary of cases when someone goes back to correct spelling and ends up with an invalid word. The way you had it, those cases would never cause the flagged words to be found unless a space was typed later.
It would be advisable to call this function for onchange and blur events as well, since typing is not the only way users enter input into form inputs.
Here is the updated demo
You don't need to .split the input every time a key is pressed, this is a situation where a regular expression is to be preferred:
Check the updated fiddle
To generate the expression based on an array:
var blackList = ['hello','world'];
var expression = new RegExp('\\b(' + blackList.join('|') + ')\\b','i');
$("textarea").keyup(function(e)
{
//if (e.keyCode === 32)
//{in comment after reading the answer posted by Michael Berkowski
if ($(this).val().match(expression))
{
$("span").css("background","red");
return;
}
$("span").css("background","green");
//}
});​

How do I validate entry before input value is set?

I'm having a really strange problem. Here's my current Javascript:
jQuery('.highlightableTDCell input').keydown(function () {
var val = jQuery(this).val();
if (!GridView.prototype.validateStandardCellNumberFormat(val)) {
return false;
}
else return true;
});
When I use this, I can still get away with entering an illegal character, but no more than that. I'm really confused because I thought this would happen first.
Inside of the keydown event, the element.value has not yet been updated to account for the key that is currently being pressed. If you want to stop the key from hitting the input box, you need to interrogate the event.which and see if it is a key you want to allow or not.
The event is raised before the new content entered the input (letting you cancel the default behavior.)
You can use something like this, to get the new content:
$('.highlightableTDCell input').keypress(function(e){
var temp = this.value + String.fromCharCode(e.which)
return GridView.prototype.validateStandardCellNumberFormat(temp)
});
Note that it's not full proof. like when the user entered the new char in the middle of the input.
Validation should be done only on blur. With HTML5 it should be better, but not all browsers support it yet.
Tip: this.value == jQuery(this).val() There is no need to create jQuery object to get the value

On IE cursor is comming always at start in textarea

I am dealing with textarea, and on click of this I am calling one replace function which will remove some specified string in textarea, this is the basic operation.
Expected behavior after clicking on textarea
1) At first click :
It should remove specified string from textarea
Cursor should come at end of string
2) more than one click :
- Cursor should come at where ever user clicks in text area
Below is my replace function....
function replace(id,transFromDb) {
newStr = $("#"+id).val();
var len = null;
if(transFromDb == '') {
newStr = newStr.replace(Lang.Message27,'');
newStr = newStr.replace(Lang.Message28,'');
}
else {
newStr = newStr.replace(Lang.Message28,'');
newStr = newStr.replace(Lang.Message27,'');
}
/* change font weight as bold. */
$("#"+id).css({"fontWeight":"bold"});
$("#"+id).val(newStr);
}
Assume that Lang.Message is specified string.
It's working above behavior with FF.
Facing issue on IE, it always keep cursor position at first.
Please provide any solution....
Thanks in Adavance
Pravin
$("#idOfTextarea").focus(function() {
replace($(this).attr("id"), "");
});
I'm not sure what the second parameter of replace is receiving, so I've just put an empty string in, you'll have to fill that in yourself.
There's clean and easy code for moving the cursor to the end of the textarea here.

Categories

Resources