Javascript: detect textarea to be full - javascript

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.

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

How to make contenteditable div accept only plaintext?

I have a div as a textarea, because div can change it's height based on the text inside it, the problem here is if someone copied some styled text (text and html) and pasted it, the style sticks with the text, contenteditable='plaintext-only' would solve the problem but it seems to be a webkit-only feature.
So is there a way to allow text only inside a div?
For reference: https://jsfiddle.net/w25dnuen/
Here's an example of a text area that will grow based on the contents you enter:
http://jsfiddle.net/janjarfalk/r3Ekw/
The reason that the elastic text area works is the external jquery.elastic.source.js which is located here: http://jquery-elastic.googlecode.com/svn/trunk/jquery.elastic.source.js
so now that you have looked at those two resources, let's talk about what it does. The script has an "udpate" function that basically just adds whitespace when it gets to the end of the row here:
// Add an extra white space so new rows are added when you are at the end of a row.
$twin.html(textareaContent+' ');
And then here you can see the respective functions:
// Updates the width of the twin. (solution for textareas with widths in percent)
function setTwinWidth(){
var curatedWidth = Math.floor(parseInt($textarea.width(),10));
if($twin.width() !== curatedWidth){
$twin.css({'width': curatedWidth + 'px'});
// Update height of textarea
update(true);
}
}
// Sets a given height and overflow state on the textarea
function setHeightAndOverflow(height, overflow){
var curratedHeight = Math.floor(parseInt(height,10));
if($textarea.height() !== curratedHeight){
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
}
}
This is all in the elastic function. Hopefully this gives a little insight and helps you out.

How do I get the height of a textarea

I need to get the height of a textarea. Seemingly so simple but it's driving me mad.
I have been researching for ages on stackoverflow with no luck: textarea-value-height and jquery-js-get-the-scrollbar-height-of-an-textarea and javascript-how-to-get-the-height-of-text-inside-of-a-textarea, among many others.
This is how it looks currently:
This is how I want it to look, open a full height:
.
Here is my html:
<textarea id="history" class="input-xxlarge" placeholder="Enter the content ..." rows="13"></textarea>
CSS:
.input-xxlarge {
display: inline-block;
height: auto;
font-size: 12px;
width: 530px;
resize: none;
overflow: auto;
}
jQuery:
var textarea = $('#history');
I've tried (inter alia):
1. textarea.height() --> always returns 0
2. textarea.ready(function() { // wait for DOM to load
textarea.height();
}
3. getting scrollheight from textarea as an HTMLTextareaElement (i.e. DOM Element) --> returns 0
4. var contentSpan = textarea.wrapInner('<span>');
var height = contentSpan.height(); --> always returns 0
Please help, I'm at my wit's end!
Ok, I've found a solution. Whether it's the best solution, I don't know, but it works and that, frankly, is all I care about, having spent almost a day on this issue.
Here it is for anyone who faces the same problem:
Select the textarea:
var textarea = $('#history');
Get the textarea's text:
var text = textarea.text();
Create a temporary div:
var div = $('<div id="temp"></div>');
Set the temp div's width to be the same as the textarea. Very important else the text will be all on one line in the new temp div!:
div.css({
"width":"530px"
});
Insert the text into the new temp div:
div.text(text);
Append it to the DOM:
$('body').append(div);
Get the height of the div:
var divHeight = $('#temp').height();
Remove the temp div from the DOM:
div.remove();
Had a similar issue, in my case I wanted to have an expand button, that would toggle between two states (expanded/collapsed). After searching also for hours I finally came up with this solution:
Use the .prop to get the content height - works with dynamically filled textareas and then on a load command set it to your textarea.
Get the inner height:
var innerHeight = $('#MyTextarea').prop('scrollHeight');
Set it to your element
$('#MyTextarea').height(innerHeight);
Complete code with my expand button(I had min-height set on my textarea):
$(document).on("click", '.expand-textarea', function () {
$(this).toggleClass('Expanded');
if($(this).hasClass('Expanded'))
$($(this).data('target')).height(1);
else
$($(this).data('target')).height($($(this).data('target')).prop('scrollHeight'));
});
Modern answer: textarea sizing is a few lines of ES6 implementable two primary ways. It does not require (or benefit from) jQuery, nor does it require duplication of the content being sized.
As this is most often required to implement the functionality of auto-sizing, the code given below implements this feature. If your modal dialog containing the text area is not artificially constrained, but can adapt to the inner content size, this can be a perfect solution. E.g. don't specify the modal body's height and remove overflow-y directives. (Then no JS will be required to adjust the modal height at all.)
See the final section for additional details if you really, truly only actually need to fetch the height, not adapt the height of the textarea itself.
Line–Based
Pro: almost trivial. Pro: exploits existing user-agent behavior which does the heavy lifting (font metric calculations) for you. Con: impossible to animate. Con: extended to support constraints as per my codepen used to explore this problem, constraints are encoded into the HTML, not part of the CSS, as data attributes.
/* Lines must not wrap using this technique. */
textarea { overflow-x: auto; white-space: nowrap; resize: none }
for ( let elem of document.getElementsByTagName('textarea') ) {
// Prevent "jagged flashes" as lines are added.
elem.addEventListener('keydown', e => if ( e.which === 13 ) e.target.rows = e.target.rows + 1)
// React to the finalization of keyboard entry.
elem.addEventListener('keyup', e => e.target.rows = (elem.value.match(/\n/g) || "").length + 1)
}
Scrollable Region–Based
Pro: still almost trivial. Pro: animatable in CSS (i.e. using transition), though with some mild difficulty relating to collapsing back down. Pro: constraints defined in CSS through min-height and max-height. Con: unless carefully calculated, constraints may crop lines.
for ( let elem of document.getElementsByTagName('textarea') )
elem.addEventListener('keyup', e => {
e.target.style.height = 0 // SEE NOTE
e.target.style.height = e.target.scrollHeight + 'px'
})
A shocking percentage of the search results utilizing scrollHeight never consider the case of reducing size; for details, see below. Or they utilize events "in the wrong order" resulting in an apparent delay between entry and update, e.g. pressing enter… then any other key in order to update. Example.
Solution to Initial Question
The initial question specifically related to fetching the height of a textarea. The second approach to auto-sizing, there, demonstrates the solution to that specific question in relation to the actual content. scrollHeight contains the height of the element regardless of constraint, e.g. its inner content size.
Note: scrollHeight is technically the Math.max() of the element's outer height or the inner height, whichever is larger. Thus the initial assignment of zero height. Without this, the textarea would expand, but never collapse. Initial assignment of zero ensures you retrieve the actual inner content height. For sampling without alteration, remove the height override (assign '') or preserve (prior to) then restore after retrieval of scrolllHeight.
To calculate just the height of the element as-is, utilize getComputedStyle and parse the result:
parseInt(getComputedStyle(elem).height, 10)
But really, please consider just adjusting the CSS to permit the modal to expand naturally rather than involving JavaScript at all.
Place this BEFORE any HTML elements.
<script src="/path/to/jquery.js"></script>
<script>
$(document).ready(function(){
var textarea = $('#history');
alert(textarea.height()); //returns correct height
});
</script>
You obviously do not have to alert it. I was just using an easily visible example.
Given a textarea with an id of "history", this jQuery will return it's height:
$('#history').height()
Please see a working example at http://jsfiddle.net/jhfrench/JcGGR/
You can also retrieve the height in pixels by using $('#history').css('height'); if you're not planning on doing any calculations.
for current height in px:
height = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('height')
for current width in px:
width = window.getComputedStyle(document.querySelector('textarea')).getPropertyValue('width')
change 'textarea' to '#history' or like a css selector. or textarea, since a variable is declared to select element.

How to find whether text in a text area is wrapped to multiple lines?

How can I find whether a long text in a textarea is wrapped into two or more lines?
I'm not talking about the new line chars as discussed here.
I'm aware of the plugin Textarea Line Count
Any simpler method?
I experimented on this and came up with a hack that involves the following:
Disabling text-wrapping in the textarea (plus disable padding)
Checking if the textarea's scrollWidth is greater than it's width.
The basic logic i used was that if the text is spanning multiple lines, that means when wrapping is turned off, we should get a horizontal scrollbar.
Demo: http://jsfiddle.net/fnG3d/
Disclaimer: The code below is the result of a 10 minute fiddle, definitely not production quality
function checkMulti(id) {
var ta = $('#'+id), multi = false;
// disable wrapping, padding and enable horiz scoll
ta.addClass('nowrap');
// check if there is anything to be scrolled horizontally (means multi-lines otherwise)
multi = ( ta[0].scrollWidth > ta.width() );
// checking done. remove the class.
ta.removeClass('nowrap');
alert('Spread over multiple-lines: ' + multi);
}
/* the nowrap class */
.nowrap {
overflow-x: scroll;
white-space: nowrap;
padding: 0;
}

Limit textarea symbols to visible part

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.

Categories