Limit textarea symbols to visible part - javascript

Is there any way to limit textarea entered symbols to visible part only?
I don't want scrolling, I have specified number of rows column for it and I want that user could not enter so many characters that possible scrolling will appear.
Of course I could set overflow:hidden but symbols anyway will be entered. Limiting to the number of characters is not my case, because different character take different width: for example W and 1. I need this logic because data entered in textarea are used on some print report and there is no possibility for scrolling in paper.
I have found only 2 possible solutions:
Use some average number of
characters. And limit by this
number. This is very rough. Because
for strings with average number of
big characters greater than usual it
will still hide some data.
Use rendering of entered
characters to some separate div and
calculate its width/height. Seem to
me will be very slow and not
sure this is the correct implementation.

You can use JavaScript to check the scrollHeight and if bigger than the "original" height, truncate the text until it has no scroll anymore. Code for this would be:
function CheckScroll(oTextarea) {
if (oTextarea.scrollHeight > oTextarea.offsetHeight) {
while (oTextarea.scrollHeight > oTextarea.offsetHeight) {
oTextarea.value = oTextarea.value.substr(0, oTextarea.value.length - 1);
}
}
}
And to trigger it:
<textarea cols="15" rows="3" onkeyup="CheckScroll(this);" onchange="CheckScroll(this);" onpaste="CheckScroll(this);"></textarea>
Live test case: http://jsfiddle.net/yahavbr/bNqVf/1/

I came up with something similar to Shadow Wizard's effort which uses oninput to detect all forms of input (like pasting, drag/drop), not just keyboard input. It requires switching off the scrollbars of the textarea with the following CSS:
textarea { overflow: hidden; }
You might want to set resize: none; for browsers like Firefox 4 and Chrome. Also, Opera's wrapping doesn't break if there are no spaces, but it doesn't support word-wrap: word-break; properly so I'm not sure how you'd work around this. The JavaScript involves remembering the content of the textarea each time it changes and, if the text exceeds the size of the element, the change is reverted to the previous value:
var prev = "",
tArea = document.getElementById("limit");
// Need to use onpropertychange event for IE8 and lower
if ("onpropertychange" in tArea && !("oninput" in tArea)) {
tArea.onpropertychange = function () {
// Only run code if value property changes
if (window.event.propertyName == "value")
this.oninput();
}
}
// oninput will fire for all types of input, not just keyboard
tArea.oninput = function () {
// Temporarily remove the onpropertychange event to prevent a stack overflow
var opc = this.onpropertychange;
this.onpropertychange = null;
// Revert value if the text exceeds the size of the box
if (this.scrollHeight > this.offsetHeight) {
this.value = prev;
}
prev = this.value;
if (opc)
this.onpropertychange = opc;
}
Working demo: http://jsfiddle.net/37Jnn/ - tested in Firefox 4, IE8, Chrome 9, Opera 10.

You could style it to use Courier, or some other non-proportional font. That way, you'd know exactly how many characters could fit, since all characters are the same size, which would make it easy to limit it using any one of several well-known techniques for limiting the number of characters in the string.
The downside is that it wouldn't look pretty (unless you happen to like how Courier looks), but it is a workable solution, and I can't think of anything else.

Just to summarize. I will exclude Courier font solution from discussion. Because in most cases it is not acceptable. Both solutions that use key up/property changes has drawback:
visually text is entered and only then removed.
Making substr(0, oTextarea.value.length - 1) has problems when last symbol is \n in IE. In this case it will hang because \r symbol is left. So it should be used oTextarea.value.length - 2 in case of last \n.
For on property change should be used some multi browser solution. For example like this
The only possible way to make such checks user friendly (not allowing entering) is to create for each text area other hidden text area and make all checks on this text area in events before data are really shown in original text area (like key down). But in this case it will require handling of all selection ranges, pastes and reapplying them on hidden. And logic will be not trivial.

Related

JavaScript recognizes up arrow press when on first line of text area [duplicate]

Given a textarea with content that flows like this
––––––––––––––––––––––––––
| This is some text, which |
| wraps like this. |
––––––––––––––––––––––––––
How can one tell if the text-cursor is on the first line of the textarea?
Obviously, checking for a newline character (\n) works if one wants to see if the cursor appears before the first line break, but testing for a 'soft' line break seems more challenging.
Here is a sample jsFiddle to experiment with.
I have not yet come up with a strategy, but I suspect it may involve copying the text up until the cursor position into a cloned textarea (or div), and making the width as long as it needs to be so it doesn't wrap. If the cloned area has a width less than the original's width, then the cursor would seem to have to be on the first line. There may a simpler option, something more elegant, or (best of all) an existing and well-tested solution.
Target browsers are Webkit (Chrome/Safari) & Firefox. I.e. IE compatibility is not a concern at this time (if that makes any difference).
Thanks for reading.
EDIT: Seeking line number of text caret, not mouse cursor.
falsarella gave an excellent answer, that highlighted an ambiguity in the question. What I am seeking is whether the text cursor (“caret” may be a better word) is on the first line. I have updated the question and the jsFiddle to reflect.
I only know of one "working method". The method requires use of textarea's "cols" attribute. Long story short, set the cols to the width you want, then divide the cursor position and floor it to see if it is less than 1, thus it = line 1!
Might be easier to explain if I just show you a code example.
$("textarea").live("keyup", function(e) {
if ($("textarea").attr("cols")) {
var cols = parseInt($("textarea").attr("cols")),
curPos = $('textarea').prop("selectionStart"),
result = Math.floor(curPos/cols);
var msg = (result < 1) ? "Cursor is on the First line!" : "Cursor is on the line #"+(result+1);
console.log($("p").text(msg).text());
};
});​
however, this may still require some wired math as some col sizes may still say "line 2" when the cursor is simply at the END of line one (which technically would still be right since any character would drop to line 2)
jsFiddle
Having that 15 is the line height, this works (tested in firefox):
http://jsfiddle.net/h46jh/12/
$("textarea").click(function (evt) {
cursor_position = evt.pageY - $('textarea').offset().top;
if (cursor_position <= 15) {
alert("first line");
} else {
alert("other line");
}
});
Credits:
Find mouse position relative to element

Convert textarea row/column to screen x/y coordinates

I have a textarea element on my webpage that will contain some plain text (alphanumerics, newlines, tabs, spaces). I know how to get the row and column of my cursor. But, I need a way to convert those into screen coordinates so I could display a floating div at that exact location of the cursor. I see two ways
Method 1: Take the offset of the textarea from (0,0) on screen. For x-coord, iterate through each character on that line and multiply the number of characters with the width of each character (tabs vs actual characters would be counted differently) and add it to the original offset. For y-coord, take the number of rows times the height of each row and add it to the original offset. But, how do I compute the character width and row height?
Method 2: Find a javascript library. Does anybody know of an existing javascript library/framework such as jQuery that would do this? I have looked and can't seem to find anything.
After the onchange event is fired, check for mouseMove events and then get the coordinates:
var waiting;
function text_changed(event) { //attach this to onChange
waiting = true;
setTimeout('waiting = false',1000);
}
function mouse_moved(event) { //attach this to mouseMove
if (waiting) {
display_div(event.pageX,event.pageY);
waiting = false;
}
}
function display_div(x,y) {
$('#floating_div').css('left',x).css('top',y).css('display','block');
}
if you have to, replace the jQuery with regular DOM scripting:
function display_div(x,y) {
var elmt = document.getElementById('floating_div');
elmnt.setAttribute('style','left:'+x+';top:'+y+';display:block');
}

Test if cursor is on the first line in a textarea (with soft-newlines)

Given a textarea with content that flows like this
––––––––––––––––––––––––––
| This is some text, which |
| wraps like this. |
––––––––––––––––––––––––––
How can one tell if the text-cursor is on the first line of the textarea?
Obviously, checking for a newline character (\n) works if one wants to see if the cursor appears before the first line break, but testing for a 'soft' line break seems more challenging.
Here is a sample jsFiddle to experiment with.
I have not yet come up with a strategy, but I suspect it may involve copying the text up until the cursor position into a cloned textarea (or div), and making the width as long as it needs to be so it doesn't wrap. If the cloned area has a width less than the original's width, then the cursor would seem to have to be on the first line. There may a simpler option, something more elegant, or (best of all) an existing and well-tested solution.
Target browsers are Webkit (Chrome/Safari) & Firefox. I.e. IE compatibility is not a concern at this time (if that makes any difference).
Thanks for reading.
EDIT: Seeking line number of text caret, not mouse cursor.
falsarella gave an excellent answer, that highlighted an ambiguity in the question. What I am seeking is whether the text cursor (“caret” may be a better word) is on the first line. I have updated the question and the jsFiddle to reflect.
I only know of one "working method". The method requires use of textarea's "cols" attribute. Long story short, set the cols to the width you want, then divide the cursor position and floor it to see if it is less than 1, thus it = line 1!
Might be easier to explain if I just show you a code example.
$("textarea").live("keyup", function(e) {
if ($("textarea").attr("cols")) {
var cols = parseInt($("textarea").attr("cols")),
curPos = $('textarea').prop("selectionStart"),
result = Math.floor(curPos/cols);
var msg = (result < 1) ? "Cursor is on the First line!" : "Cursor is on the line #"+(result+1);
console.log($("p").text(msg).text());
};
});​
however, this may still require some wired math as some col sizes may still say "line 2" when the cursor is simply at the END of line one (which technically would still be right since any character would drop to line 2)
jsFiddle
Having that 15 is the line height, this works (tested in firefox):
http://jsfiddle.net/h46jh/12/
$("textarea").click(function (evt) {
cursor_position = evt.pageY - $('textarea').offset().top;
if (cursor_position <= 15) {
alert("first line");
} else {
alert("other line");
}
});
Credits:
Find mouse position relative to element

How to calculate the width of an input HTML element so that it matches the size of its content?

How to calculate the width of an input HTML element so that it matches the size of its content ?
I already update an input on the fly as the user types :
<input type='text' onkeydown='this.size=this.value.length' />
However, this does not seem completely correct because it does not take into account the fact that some characters are longer than others :
I will get more and more whitespace if I type only some "l" characters
the size will be insufficient if I type only some "w" characters
How to proceed?
PS: Why I want to do this (already answered this in a answer that was deleted)?
I have sentences in which I have to replace the bracket content by inputs (ex: [user] is [years] old). I have no idea what the sentence can be, so I do not know an adequate length for the inputs, and I would like to keep it readable on one line (avoiding too much whitespace).
You could use a (hidden) canvas and the measureText() method of the context to get your string's width.
EDIT:
Looks fast enough.
First, define some CSS...
input,
#input-helper {
display: inline;
font-size: 14px;
font-family: serif;
line-height: 16px;
}
#input-helper {
position: absolute;
top: -10000px;
}
...then use some JavaScript...
var div = document.createElement("div");
div.id = "input-helper";
document.body.appendChild(div);
var input = document.querySelector("input");
input.addEventListener("keyup", function() {
div.textContent = this.value;
input.style.width = div.offsetWidth + "px";
});​
jsFiddle.
You will want to choose a reasonable start width for your input element too.
If using jQuery is not a problem, here is a demo I put together on jsFiddle. It uses an Autoexpand.js file that does what you want. Check out the last example in the fiddle.
Some specifics:
It's based on .keyup and .keypress for the fastest response possible.
It takes into account the HTML markup that's pasted into the box. Things like linebreaks are dealt with.
The source file shows smart processing by taking everything about the font into consideration.
Also included in the jsFiddle are links to download a pastebin version of the fiddle since jsFiddle Sandbox breaks in IE8. That said, it also works in IE7 too!
First : Add this div where you want
<div id="calcsize" style="display:none;"></div>
Second : Use this function
function getWidthof(txt)
{
$('#calcsize').empty().append(txt);
return $('#calcsize').width();
}

Javascript: detect textarea to be full

I am trying detect when a textarea becomes full for creating pagination effect. Using the .length property will not work, however, because long words 'jump' to new lines.
| I like to dooo| displays as | I like to |
| oooodle | | dooooooodle |
So what ends up happening is that the textarea always runs out of space before the .length property reaches the textarea limit. Is there any other way to detect textarea fullness? Jquery solutions are fine as well. Thanks.
You can try to check if scrollbars have appeared in your textarea. Here is a simple way to do this. Initially make the scrollbar one line shorter than the ultimate height you want to show, then on keypress check if scrollbars have appeared, then wait for the next space char to be entered. As soon as space char is entered do the following:
1. delete the space char,
2. increase the textarea height one line linger (so scrollbar disappears),
3. create a new textarea and move focus to the new textarea.
Update
Here is a demo. I changed my method a bit and this is the code:
Markup
<textarea class="paginate"></textarea>
JS
$('textarea.paginate').live('keydown', function() {
// scrollbars apreared
if (this.clientHeight < this.scrollHeight) {
var words = $(this).val().split(' ');
var last_word = words.pop();
var reduced = words.join(' ');
$(this).val(reduced);
$(this).css('height', '65px');
$(this).after('<textarea class="paginate"></textarea>');
$(this).next().focus().val(last_word);
}
});
CSS
.paginate { height: 60px; width: 200px; display: block;}
In runtime, you may listen to the key-press event of the textarea, pass the textarea.val() value into a hidden <pre id="mypre" style="display:none; "></pre>, then get mypre's width or even height $("#mypre").width(). It's your decision how you'll work with the "simulated" width/height.

Categories