📜 ⬆️ ⬇️

Auto-change textarea when entering text

I usually do server-side programming in php, but from time to time I go outside and delve into layout, styles and javascript. Recently, I was assigned the task of changing the height of the textarea when entering comments to various objects. There is so much material on the Internet about this; there was not enough and not much to say. First glance rushed to the implemented solutions in such large networks as Vkontakte, Facebook, MyKrug. However, during the decision there were many obstacles and far from being cross-browser compatibility.



Solutions were different:
* draw on the scrollHeight and offsetHeight properties
* calculate the number of used lines by parsing the text
* or use the idea from the above described networks.
')
The final option was this decision. For textarea, an invisible layer (div) is created with the same width, font, font size, indents, then the newly modified text is copied into an invisible layer, the height is recognized by the layer, and this height is set in textarea. It sounds simple, but in the process of implementation there were a lot of pitfalls.
In the current implementation, prototype version 1.7 is used, but the earlier ones will also go (you can replace it with JQuery or completely cut the framework).

<!doctype><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Auto-size TextArea Demo</title>
<script type="text/javascript" src="/js/prototype/prototype.js"></script><script>
function resizeArea(text_id, minHeight, maxHeight)
{
var area = $(text_id);
var area_hidden = $(text_id + "_hidden");
var text = '';
area.value.replace(/[<>]/g, '_').split("\n").each( function(s) {
text = text + '<div>' + s.replace(/\s\s/g, ' &nbsp;') + '&nbsp;</div>'+"\n";
} );
area_hidden.innerHTML = text;
var height = area_hidden.offsetHeight + 15;
height = Math.max(minHeight, height);
height = Math.min(maxHeight, height);
area.style.height = height + 'px';
}
</script><style>
body, textarea {
font-family: Tahoma, Arial, 'Nimbus Sans L', sans-serif;
font-size: 13px;
}
.text {
width:700px !important;
border:1px solid #000;
}
.text .textarea_behavior{
border:0;
width:99%;
word-wrap: break-word;
}
.text textarea{
overflow:hidden;
}
.text .comment_text_hidden{
position: relative;
}
.text #comment_text_hidden{
visibility:hidden;
position: absolute;
}
</style></head><body>
<div class="text">
<div class="comment_text_hidden"><div class="textarea_behavior" id="comment_text_hidden"></div></div>
<textarea class="textarea_behavior" rows="3" id="comment_text" onkeyup="resizeArea('comment_text', 45, 450);"></textarea>
</div>
</body></html>


The decision may seem to someone very compact, to the other, on the contrary, insanely large. One thing for sure is the only final version that works equally well on all browsers available to me (FF, Ch, Op, IE7-9).

What is so special about the approach: you can’t just ask the textarea how much space the text takes, so put the text where you can find out how much it really takes place (in our case, only height is interesting). This is where a lot of pitfalls arise. How to place text from textarea into a div in order to precisely preserve the appearance and volume of text, hyphenation of words, tags, multiple spaces - in general everything that in plain text does not look like in html. Just to use the pre tag failed, because tame it turned out to be more difficult.

In order, all the pitfalls I have encountered (I do not cite some of the problems here, because the code has evolved and some previously solved problems simply cannot manifest themselves in this code). It turns out here only problems solved by the code:



The solution of the above problems is well reflected in the code. The layer is hidden very close to the textarea, this allows you not to think about setting the width to the layer. Several multiple spaces are replaced by chaser + & nbsp ;. Empty lines are <div> & nbsp; </ div> (all social networks mentioned above use <br>, but I did not succeed). Tags are escaped very simply: the characters <and> are replaced by _. Well, the most interesting discovery for me is the gap of continuous text in word-wrap styles: break-word ;.
Well, the most important thing in this idea is the complete coincidence of layer styles and textarea.

Disadvantages of other approaches


1. To rely on the scrollHeight and offsetHeight properties - the first option I have implemented. All anything, but here it is not possible to reduce the size of the textarea.

2. Calculate the number of used lines of parsing text. The second option. This is already better, but as it turned out, you can only apply by installing a font in the textarea type Monospace, where all the characters are the same width. This is the only way to achieve normal accuracy. However, this is contrary to the ideas of designers ...

I will give the code for the curious (part of the resizeArea function):

var linecount = 1;
area.value.split("\n").each( function(s) {
linecount += Math.floor( s.length / cols ) + 1;
} )
area.rows = linecount;


We count lines and add long lines. You just need to know the cols parameter - this is exactly what we know and cannot do without the Monospace font. If we compare the number of letters W and i, then the line includes a completely different number.

Result


The result of the work done is given above. Works in FF, Ch, Op, IE7-9. I hope you will find it useful. After the implementation of all sorts of options, I wanted to have unit tests on the guinya of all browsers ...

Interesting materials

Shifting long links and continuous text using CSS
Autosizing textarea
jQuery autoResize

Source: https://habr.com/ru/post/114182/


All Articles