Specifying number of characters contained per line in a textarea element - javascript

I need to specify number of characters contained per line in a textarea element (Link to fiddle).
This is the horror I'm witnessing:
So cols="50" actually gives me following row lengths:
| Without scroll | With scroll
Chrome 50 47
FF 52 50
What I actually meant with cols="50" is that I want the textarea to hold exactly 50 characters per line. How I can achieve this so that it works in all major browsers?
EDIT: I would also like to point out that in the real page the total number of characters in a textarea is not limited so y-scrolling must be possible. Whether or not line breaks are automatically included by a textarea (or equivalent element) doesn't matter since the text is later split into rows containing maximum of 50 characters before sending them to the server with ajax post.

It seems this issue is only in Chrome, so you could do something like this:
<script>
window.onload = function(){
textareas = document.getElementsByTagName("textarea");
var isChrome = navigator.userAgent.indexOf("Chrome") != -1;
for(var i = 0; i < textareas.length; ++i){
if(isChrome){
textareas[i].style.width = textareas[i].offsetWidth + textareas[i].cols/3 + "px";
}
}
}
</script>
Check it out here: JSFiddle

Heres how you can do it in javascript:
<script>
var textareas = document.getElementsByTagName("textarea");
for(var i = 0; i < textareas.length; ++i){
textareas[i].addEventListener("input", handleInput);
textareas[i].cols += 3;
handleInput(null, textareas[i]);
}
function handleInput(event, area){
if(area === undefined) area = this;
area.value = fixText( area.value, area.value.length, area.cols-3);
}
function fixText(text, length, limit){
var counter = 0;
for(var i = 0; i < length; ++i){
var currChar = text[i];
counter++;
if(currChar === "\n"){
counter = 0;
} else if(counter > limit){
text = text.substring(0,i) + "\n" + text.substring(i, text.length);
counter = 0;
}
}
return text;
}
Here i use the col attribute of the textarea and add a linebreak every VALUE_OF_COL characters that doesn't contain a linebreak.
Check it out here: JSFiddle

Related

Use two inputs to look like textarea

I've tried to solve this by my own but I've been struggling a lot.
I've got 5 inputs that are stick together (they actually look like a textarea), and what I'm trying to do, is to fix a limit of the number of characters in each input, and when we reach the char limit, the cursor automatically focus on the next input and paste the last word that we couldn't entirely write in the last input before and if we erase few characters of this word, its goes back to the previous input (only if the characters limits isn't reached).
Here's what I tried to do:
function passage(enCours, suivant, limite){
if (enCours.value.length == limite)
{
$('#cmzTextLines'+suivant).focus();
}
}
function test(now, suivant){
var text = $('#cmzTextLines'+now).val();
var textSuivant = $('#cmzTextLines'+suivant).val();
//var lines = text.split("\n");
for (var i = 0; i < text.length; i++) {
if (text[i].length <= maxLength) continue;
var j = 0; space = maxLength;
while (j++ <= maxLength) {
if (text[i].charAt(j) === " ") space = j;
}
textSuivant = text[i].substring(space + 1) + (textSuivant || "");
text[i] = text[i].substring(0, space);
}
}
The HTML:
<input type="text" class="form-control" id="cmzTextLines1" name="cmzTextLines1" onkeyup="passage(this, 2, 30); test(1, 2);">
<input type="text" class="form-control" id="cmzTextLines2" name="cmzTextLines2"
onkeyup="passage(this, 3, 30); test(2, 3);">
JSFiddle: https://jsfiddle.net/fumm44f3/2/
var replacedval = rawval.substring(0, rawval.length - lastwordlength);
$(this).val(replacedval);
$(this).next(".form-control").val(lastword);
It'd be simple enough from here to check to see if an input has 0 characters on backspace as it already checks for backspace, and then go to prev input if so.

JS: innerHTML inconsistency

I am using Google Chrome version 43.0.2357.130. I am trying to append output to an HTML element using innerHTML, which is being done inside of a loop. I get the expected result most of the time, but if I click on the "Generate" button over and over, eventually it will give me an unexpected result. For instance, one of the passwords will be chopped off at a random spot. I used the JS debugger in Chrome, but that didn't help much. Then I tried to debug it myself by using the alert() function alongside the innerHTML property so that I could compare the output. The output in the alert() popup was never truncated, unlike innerHTML.
I highlighted what I think is the problem code with '/* PROBLEM CODE */' in the JS file. The files should be placed in the same directory. Here is the HTML and JS:
<!DOCTYPE html>
<html>
<head>
<title>PassGen - Random Password Generator</title>
<!--link rel="stylesheet" src="//normalize-css.googlecode.com/svn/trunk/normalize.css"-->
<!--link href="css/main.css" rel="stylesheet" type="text/css"-->
<!--script src="../app/js/jquery-2.1.4.js"></script-->
</head>
<body>
<form>
<h2>Password amount</h2>
<input type="text" id="amount" name="amount" />
<h2>Letter amount</h2>
<input type="text" id="letters" name="letters" />
<h2>Number amount </h2>
<input type="text" id="numbers" />
<h2>Symbol amount</h2>
<input type="text" id="symbols" />
<input onclick="generatePassword(); return false;" type="submit" value="Generate" />
</form>
<p id="output"></p>
<script src="plain-app.js"></script>
</body>
</html>
// get the DOM element we will be using for the final output
var output = document.getElementById("output");
function generatePassword(amount) {
clearPasswords();
// get DOM form elements (user input)
var amount = document.getElementById("amount").value;
var letters = document.getElementById("letters").value;
var numbers = document.getElementById("numbers").value;
var symbols = document.getElementById("symbols").value;
// populate character sets
var letterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var numberSet = "0123456789";
var symbolSet = "~!##$%^&*()-_+=><";
var array = [];
// if there is no password amount specified, create one password
if(amount === undefined) {
amount = 1;
}
for(var j = 0; j < amount; j++) {
// random character sets to be concatenated later
var rl = "";
var rn = "";
var rs = "";
var tp = ""; // concatenated password before shuffling
// 3 random letters
for(var i = 0; i < letters; i++) {
var rnd = Math.floor((Math.random() * 52));
rl += letterSet[rnd];
}
// 3 random numbers
for(var i = 0; i < numbers; i++) {
var rnd = Math.floor((Math.random() * 10));
rn += numberSet[rnd];
}
// 3 random symbols
for(var i = 0; i < symbols; i++) {
var rnd = Math.floor((Math.random() * 17));
rs += symbolSet[rnd];
}
tp = rl + rn + rs; // string concatentation
tp = tp.split(''); // transform string into an array
// shuffling
for(var i = 0; i < tp.length; i++) {
var rnd = Math.floor(Math.random() * tp.length);
var temp = tp[i];
tp[i] = tp[rnd];
tp[rnd] = temp;
}
// transform the array into a string
tp = tp.join("");
array[j] = tp; // for logging and debugging purposes
// tp can be replaced with array[j], but still get the inconsistency
/* PROBLEM CODE */
output.innerHTML += (tp + "<br />");
/* PROBLEM CODE */
//alert(array[j]);
}
console.log(array);
return array; // not useful?
}
// clear all password output
function clearPasswords() {
while(output.hasChildNodes()) {
output.removeChild(output.firstChild);
}
}
Does innerHTML have side effects I don't know about or am I using it incorrectly? Should it not be used for appends? Should appendChild() be used instead?
The problem is that some characters have special meaning in HTML: <, >, &.
Therefore, you can
Remove those characters from the list
Escape them: <, >, &
output.innerHTML += tp.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&') + "<br />";
Parse the text as text instead of as HTML, e.g.
Use textContent and white-space
output.textContent += tp + "\n";
#output { white-space: pre-line; }
Use createTextNode and appendChild
output.appendChild(document.createTextNode(tp));
output.appendChild(document.crateElement('br'));
The problem occurred in the symbolSet. It contained the characters < and >. When they were selected at random and added to the password, the browser tried to render them as elements when I was outputting the password to the screen. To fix this, I just removed the two characters from symbolSet, and changed the random symbol generation loop to reflect the shortened length of symbolSet.
I changed the two problematic sections of code to
var symbolSet = "~!##$%^&*()-_+=";
and
for(var i = 0; i < symbols; i++) {
var rnd = Math.floor((Math.random() * 15)); // this end of this line
rs += symbolSet[rnd];
}
In addition, I changed the useless if statement to (this can be applied to all of the fields)
if(!isNumber(amount) || amount === 0) {
amount = 1;
}
and added an isNumber function to check for valid input on all of the fields.
function isNumber(obj) {
return !isNaN(parseFloat(obj));
}

Remove excess words from a textbox

I have a script which is almost complete but I can't figure out the last bit here. The script is meant to limit the amount of words that can be entered into a text area and if they go over the word limit these extra words are removed. I have the amount of words beyond the max labeled as overage. For instance, if you were to enter in 102 words, then the overage would be 2. How would I remove those two words from the text area?
jQuery(document).ready(function($) {
var max = 100;
$('#text').keyup(function(e) {
if (e.which < 0x20) {
return;
}
var value = $('#text').val();
var regex = /\s+/gi;
var wordCount = value.trim().replace(regex, ' ').split(' ').length;
if (wordCount == max) {
// Reached max, prevent additional.
e.preventDefault();
} else if (wordCount > max) {
<!--Edited to show code from user3003216-->
<!--Isn't working like this, textarea doesn't update.-->
var overage = wordCount - max;
var words = value.split(' ');
for(var i = 0; i<overage; i++){
words.pop();
}
}
});
});
The easiest way to approach this is just to count the number of words on keypress and go from there. Check whether there are more words than the amount allowed. If so, remove all the excess words: while (text.length > maxWords). Then just replace the value of the text box with the updated text.
fiddle
JavaScript
var maxWords = 10;
$("#myText").keypress(function (event) {
var text = $(this).val().split(" "); // grabs the text and splits it
while (text.length > maxWords) { // while more words than maxWords
event.preventDefault();
text.pop(); // remove the last word
// event.preventDefault() isn't absolutely necessary,
// it just slightly alters the typing;
// remove it to see the difference
}
$(this).val(text.join(" ")); // replace the text with the updated text
})
HTML
<p>Enter no more than 10 words:</p>
<textarea id="myText"></textarea>
CSS
textarea {
width: 300px;
height: 100px;
}
You can easily test whether it works by pasting more than maxWords—in this case, 10—words into the textarea and pressing space. All the extra words will be removed.
You can put below code into your else if statement..
else if (wordCount > max) {
var overage = wordCount - max;
var words = value.split(' ');
for(var i = 0; i<overage; i++){
words.pop();
}
}
And if you want to get your string back from that words, you can use join like below:
str = words.join(' ');
well it would be better to use java script so here you go:
var maxWords = 20;
event.rc = true;
var words = event.value.split(" ");
if (words.length>maxWords) {
app.alert("You may not enter more than " + maxWords + " words in this field.");
event.rc = false;
}
jsFiddle Demo
You can use val to re-value the text-box. The array slice method will allow you to pull the first 100 words out of the array. Then just join them with a space and stick them back in the text-box.
$(document).ready(function($) {
var max = 100;
$('#text').keyup(function(e) {
if (e.which < 0x20) {
return;
}
var value = $('#text').val();
var words = value.trim().split(/\s+/gi);
var wordCount = words.length;
if (wordCount == max) {
// Reached max, prevent additional.
e.preventDefault();
} else if (wordCount > max) {
var substring = words.slice(0, max).join(' ');
$("#text").val(substring + ' ');
}
});
});
While you've already accepted an answer I thought I might be able to offer a slightly more refined version:
function limitWords(max){
// setting the value of the textarea:
$(this).val(function(i,v){
// i: the index of the current element in the collection,
// v: the current (pre-manipulation) value of the element.
// splitting the value by sequences of white-space characters,
// turning it into an Array. Slicing that array taking the first 10 elements,
// joining these words back together with a single space between them:
return v.split(/\s+/).slice(0,10).join(' ');
});
}
$('#demo').on('keyup paste input', limitWords);
JS Fiddle demo.
References:
JavaScript:
Array.prototype.join().
Array.prototype.slice().
String.prototype.split().
jQuery:
on().
val().

textarea with limited lines and char limits

i need functionaliy which will have TextArea with
1) maximum total lines- 6 and
2) in each line there must be maximum of 16 chars
3) if user enters 17th character the cursor should go to the next line
and user will type in there (the line will be counted)
4) if user reaches to the 7th line it will not allow user to write
5) if user type e.g "Hello, I Love StackOverflow and its features" (counting
from 1st Char 'H', the 16th char is 't' but it is whole word 'StackOverflow',
it shouldn't break and continue to next line e.g.
Hello, I Love St
ackOverflow
now the whole word should come to next line like:
Hello, I Love
StackOverflow
and its features
here is the link what i have done so far
http://jsfiddle.net/nqjQ2/2/
sometimes some of the functionality work, some times not, and facing browser issues for onKeyUp and onKeyDown
can anyone help me with it ?
I think this is mostly what you want:
<textarea id="splitLines"></textarea>
JavaScript:
var textarea = document.getElementById("splitLines");
textarea.onkeyup = function() {
var lines = textarea.value.split("\n");
for (var i = 0; i < lines.length; i++) {
if (lines[i].length <= 16) continue;
var j = 0; space = 16;
while (j++ <= 16) {
if (lines[i].charAt(j) === " ") space = j;
}
lines[i + 1] = lines[i].substring(space + 1) + (lines[i + 1] || "");
lines[i] = lines[i].substring(0, space);
}
textarea.value = lines.slice(0, 6).join("\n");
};
See the fiddle in action.
In Jquery
$(function () {
var limit = function (event) {
var linha = $(this).attr("limit").split(",")[0];
var coluna = $(this).attr("limit").split(",")[1];
var array = $(this)
.val()
.split("\n");
$.each(array, function (i, value) {
array[i] = value.slice(0, linha);
});
if (array.length >= coluna) {
array = array.slice(0, coluna);
}
$(this).val(array.join("\n"))
}
$("textarea[limit]")
.keydown(limit)
.keyup(limit);
})
<textarea limit='10,5' cols=10 rows=5 ></textarea>
http://jsfiddle.net/PVv6c/

Limiting number of lines and letters in single line in textarea

Problem:
I am trying to limit number of lines AND letters in each line in a textbox.
What i got so far:
So far i managed to limit lines count using this:
var text = $(this).val();
var lines = text.split("\n");
if(e.keyCode == 13 && lines.length >= $(this).attr('rows')) {
return false;
}
This won't allow user to push return key (keyCode 13) if the limit of lines is reached.
The problem:
Now i am trying to limit number of letters in a single line too, because if i reach end of my textarea (with return key) i still can hold a letter/write tons of text, and it will jump to another line when it reaches end of line. That way this limitation can be "cheated" and i am looking for a solution for that.
My ideas, not solving the problem:
else{
for(var i = 0; i < lines.length && e.keyCode != 13; i++) {
if(lines[i].length >= $(this).attr('cols')) {
return false; // prevent characters from appearing
}
}
}
I tried this to limit number of letters. That works, but it got flaws. If i reach max letters in one line (ANY), i CANT TYPE IN ANY LINE anymore.
I have no idea how to check only line i am typing in RIGHT NOW.
Tested in chrome :
http://jsfiddle.net/3e3EH/1/
$(document).ready(function(){
var textArea = $('#foo');
var maxRows = textArea.attr('rows');
var maxChars = textArea.attr('cols');
textArea.keypress(function(e){
var text = textArea.val();
var lines = text.split('\n');
if (e.keyCode == 13){
return lines.length < maxRows;
}
else{
var caret = textArea.get(0).selectionStart;
console.log(caret);
var line = 0;
var charCount = 0;
$.each(lines, function(i,e){
charCount += e.length;
if (caret <= charCount){
line = i;
return false;
}
//\n count for 1 char;
charCount += 1;
});
var theLine = lines[line];
return theLine.length < maxChars;
}
});
});​
Edit
As jbabey pointed out, ctrl+v or right-click -> paste can be an issue. right click can easily be prevented. for ctrl+v, you probable can detect it too...
Just disabling javascript will obviously break the thing, too.
Anyways, as any client-side validation, you have to double check on server-side.
Here's what I came up with. Fairly clean and seems to work for all the tests I can give it.
JavaScript:
$(function () {
$('textarea').on('keypress', function (event) {
var text = $('textarea').val();
var lines = text.split("\n");
var currentLine = this.value.substr(0, this.selectionStart).split("\n").length;
console.log(lines);
console.log(currentLine);
console.log(lines[currentLine - 1]);
if (event.keyCode == 13) {
if (lines.length >= $(this).attr('rows')) return false;
} else {
if (lines[currentLine - 1].length >= $(this).attr('cols')) {
return false; // prevent characters from appearing
}
}
});
});
HTML:
<textarea rows="10" cols="15"></textarea>
DEMO
Instead of looping over each line get the current line number of your cursor and check only the character length of that line. See this SO answer for implementation details.
Then change your else statement to look like this:
else{
var currLine = getLineNumber();
if (lines[currLine].length >= $(this.attr('cols')) {
return false; // prevent characters from appearing
}
}
A little late, but i made this plugin https://github.com/luisdalmolin/jquery-limitLines.
Can be usefull sometimes.

Categories