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)
)
}
Related
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.
I'm trying to setup a filter on a database application, for lost property for a scout camp. The idea is the following:
The lost property items are logged into the database by reception as either 'Lost', 'Handed In', 'Owner Notified' or 'Returned' (meaning 4 lists generated from a table, with a status flag which is used to filter which list an item appears in).
At the top of each list, I have a form field (text) which I would like to use to filter the list, simply by the reception team member typing in some words that describe the item (eg, Jacket blue)
I've set a common class name to each row in the list table (a different one for each list, so listLost, listFound, listNotified, listReturned)
I've then used some of the database fields to add additional classes to the list (eg, item, colour, first name, surname - these are converted to UCASE to get around the case sensitive nature of JavaScript), so the final class might look like:
class="listLost JACKET BLUE FRED BLOGGS"
The reception team member can then type into the text field, something like 'Jacket Blue' and my JavaScript function is supposed to filter the list as follows:
the input from the text field is split into an array, using SPACE as the separator
it looks for all items in the page with a particular common class name (in this example, it would be listLost)
it then pages through the array comparing the class list for each (in this case, table row) with the array value and it if finds a match, the table row will be displayed, if not, it won't
Here's my JavaScript function:
function filterLostProperty(filterField,filterList)
{
var filterStr = document.getElementById(filterField).value;
var filterVals = filterStr.split(" ");
var filterItems = document.getElementsByClassName(filterList);
var displayCheck = 0
for (x = 0; x < filterItems.length; x++)
{
for (y = 0; y < filterVals.length ; y++)
{
if (filterItems[x].classList.contains(filterVals[y].toUpperCase()))
{
displayCheck++
}
}
if (displayCheck > 0)
{
filterItems[x].style.display = "table-row";
}
else
{
filterItems[x].style.display = "none";
}
}
}
The form field has:
onChange="filterLostProperty('filterLost','listLost')
where filterLost is the ID of the text field from which the search string comes.
PROBLEM: it doesn't really filter in the way it should... some strings just generate everything, some bring up the item you wanted plus 2 you didn't, some don't generate anything at all. And when there is more than one word it goes even more weird.
Does anyone have any suggestions about where I might have gone wrong here? Or is my method here just too overly complicated and I'm missing a simple trick with something?
21.11.2017
So - I edited my function further after having a bit of an idea that I would instead of generating an Array of the filter text (as the array approach was only using the last entered word as the filter text), I would just create a string with AND between each one (using a replace function to replace SPACE with AND Operator), in the hope that it would do a 'If class list contains X and Y and Z then blah blah'...
I tested this with fixed values at first on my test page:
function manualFilter(filterList)
{
var filterItems = document.getElementsByClassName(filterList);
for (x = 0; x < filterItems.length; x++)
{
{
if (filterItems[x].classList.contains("WALLET" && "BLUE"))
{
filterItems[x].style.display = "table-row";
}
else
{
filterItems[x].style.display = "none";
}
}
}
}
My test page is at https://bookings.springbank.org.uk/testFilter.asp and the test filter can be triggered by clicking the 'Manual Filter' button.
Problem is that when I do this, I get the row with WALLET BLUE in as expected (and not the row with WALLET BLACK which is good)... but I also get the row with JACKET BLUE (presumably because it's matched BLUE)... ideally, I don't want this to display.
If this can be made to work (effectively replacing the spaces from the text field entry with an AND operator to be interpreted by the IF statement)... the only other bit I'm not totally clear on (not being particularly proficient in JavaScript) is how I can do this dynamically from the function... presumably it's going to be a case of a certain number of consecutive quotes so that the && is interpreted as and AND operator and not simply as part of a string?
I need to select a complete sentence in a HTML text in which I cannot write any placeholder.
When the user selects a piece of text, I want the selection to extend from point to point. The problem I'm facing is that if I extend my sentence over the "tag limit" I'm not able to get it with the standard methods.
This is what I'm trying to do:
Attach a selection changed method:
document.addEventListener('selectionchange', TextSelected);
Extend get my "range"
function ExpandSelection()
{
//get the next "." (end of the sentence)
var last = window.getSelection().focusOffset;
while(window.getSelection().focusNode.textContent.charAt(last) != '.')
{
last++;
}
//get the previous "." (beginning of the sentence" !!! NOT WORKING
var first = window.getSelection().anchorOffset;
while(window.getSelection().focusNode.textContent.charAt(first) != '.')
{
first--;
}
first++;
return { start: first, end : last }
}
My problem is, right now, that my selection is working in "moving forward" but when I try to move backward I'm not able to get the previous characters.
Does anybody has another way to do it?
Summarizing: if somebody is selecting something (also a single letter) I want the selection to expand to the complete sentence.
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>
I need to take a textbox that is full of formatted info about accounts and then sort it somehow. I would like to know if it would be ideal (I'm trying to make this as efficient as possible) to parse the info into a two dimensional array, or if I should make account objects that will hold info in fields.
The program is simply meant to format the data so that it can be printed out without having to copy/paste.
So far I have...
function generateOutputfvoc()
{
var accountLines = document.getElementById('accountLines').value;
var accountLinesTemp = accountLines.split(/[\s]/);
for(var i = 0; i < accountLinesTemp.length; i++)
{
if(accountLinesTemp[i].match(/
Edit (1-18-13): Here is an example input. It is basically text copied from a web CRM tool. Note, this example input is something I typed up randomly.
P8B000001234567 stackoverflow Thing 12522225555 444 Active 2005-02-26 CO1000123456
P8B000001234568 stackoverflow Another Thing 444 Active 2005-02-26 CO1000123456
P8B000001234569 stackoverflow Another Thing 556 Active 2005-02-26 CO1000123456
I would like my program to take the text and simply output the text like this:
P8B000001234567 stackoverflow Thing 12522225555 444 Active 2005-02-26 CO1000123456
P8B000001234568 stackoverflow Another Thing 444 Active 2005-02-26 CO1000123456
P8B000001234569 stackoverflow Another Thing 556 Active 2005-02-26 CO1000123456
Also, I would like to know if I should use jQuery variables. I asked this because I have been looking online a lot and I found examples that use code that looks like this:
$check=fcompcheck();
if($check)
{
$output=document.frm1.type.value+" / ";
$output=$output+"Something - "+document.frm1.disco.value+" / ";
Note the: $output variable. The dollar sign indicates a jQuery variable, right?
Thank you for any help you might be able to offer me.
Update (1-19-13): I've taken a shot at it, but I'm making slow progress. I'm used to programming Java and my JavaScript looks too similar, I can tell I'm makings errors.
I'm taking it one step at a time. Here is the logic I'm using now.
Person pastes text into text box and pushes the generate button
Program takes the contents of the text box and parses it into a large array, removing only whitespace
Program then searches for patterns in the text and begins passing values into variables
I am trying to get the program to simply identify the pattern "Summary section collapse Name" because these four words should always be in this sequence. Once it identifies this it will pass the next two array values into first and last name variables. Here's some of the code:
var contactNameFirst, contactNameLast;
// Parse the input box into an array
var inputArr = document.getElementById('inputBox').value.split(/[\s]/);
for(var i = 0; i < inputArr.length; i++)
{
if(inputArr[i] == "Summary" && inputArr[i - 1] == "section" && inputArr[i - 2] == "Collapse" && inputArr[i + 1] == "Name")
{
if(inputArr[i + 2] != "Details")
{
contactNameFirst = inputArr[i + 2];
}
else
{
contactNameFirst = "";
}
if(inputArr[i + 3] != "Details")
{
contactNameLast = inputArr[i + 3];
}
else
{
contactNameLast = "";
}
}
}
document.getElementById('contactNameOutput').innerHTML = contactNameFirst + " " + contactNameLast;
Also, should I create a new post for this now, or keep editing this one?
Your accountLinesTemp is an Array of String, you could use the Array.sort function to sort your array as expected, and then use Array.join to get the full String if necessary.
See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort on MDN for more information.