How to convert the result of externalHeight() to REM? - javascript

I could adjust the font size of the root HTML to fit the HTML window, for example:
var inputFont = parseFloat($("html").css("font-size"));
if (inputFont)
$("html").css("font-size", inputFont * 0.9);
Prior to this adjustment, I could make some elements fit to each other, for example:
buttonElem.outerHeight( $(labelElem).outerHeight() );
So, I would need to repeat this again, or to set the height in REM for buttonElem from the beginning, right?
Do you know how to quickly convert the result of externalHeight() to REM?
Will this conversion help?
Thanks.

calcREM() function is added:
function calcREM(px)
{
if( !isNaN(px) )
{
var remInPx = parseFloat($("html").css("font-size"));
return (parseFloat(px) / remInPx).toString() + "rem";
}
}
The code above has been updated to:
buttonElem.outerHeight( calcREM($(labelElem).outerHeight()) );
Here is the test.
The buttonElem before.
The buttonElem after converting pixels to REM using the calcREM () function.
Note: my CSS includes the definition:
html {
font-size: 16px;
}

Related

JavaScript page resizing

I know that you don't normally like doing things like this but I'm at University and have to do a project with several different stylesheets for the same page. I have been given JavaScript code to enable me to resize the page when the window is resized.
This code works however I am getting a peculiar effect on one of the stylesheets where the content div takes up most of the page when it shouldn't, this page has measurements in ems whereas my other stylesheets use px but I am supposed to use ems for at least one page. Although I could give my lecturer a reason for it being bigger I would prefer to fix the problem. The JavaScript code I am using is shown below:
function smoothresize() {
blockwidth = 59.4; /*This is in ems as per the lecturers request a well and is the size of the container div I created*/
minmargin = 0;
minsize = 10;
emwidth = (minmargin * 2) + blockwidth;
computeResize(emwidth, minsize, false)
}
function computeResize(wide, minsize, jerk) {
windowpixels = document.documentElement.clientWidth;
pixelsize = windowpixels / wide;
emsize = calculateEmsize(pixelsize, minsize, jerk);
b = document.getElementsByTagName('html')[0];
b.style.fontSize = emsize + "em";
}
function calculateEmsize(psize, minsize, jerk) {
if (psize > minsize) {
raw = psize;
}
else {
raw = minsize;
}
if (jerk) {
result = ((Math.floor(raw)) / 16);
}
else {
result = raw / 16;
}
return result
}
This is where I have Implemented the code in my XHTML:
<body onload="smoothresize()" onresize="smoothresize()">
I wouldn't be able to use jQuery as a solution to the problem either, I would only be able to modify the code given.
Any help in this matter Would be greatly appreciated
Check out jQuery's user interface plugin. It contains a "resizable" option; you ought to be able to add <script type="text/javascript">window.onload=function(){};</script> that loads the desired JQUI function upon page load.

How to convert pixels to em in a easy way

I am looking for a easy way to add a line of code to a plugin of mine, to convert a couple of pixel values into em values, because the layout of my project needs to be in ems. Is there an easy way to do this, because I don't want to add a third-party plugin to the site.
Won't post the code here, as it has nothing to do with the plugin it self.
Example: 13px -> ??em
I think your question is very important. Since the classes of display resolutions are rapidly increasing, using em positioning to support wide range of screen resolutions is a really appealing approach. But no matter how hard you try to keep everything in em -- sometimes you get a pixel value maybe from JQuery drag and drop or from another library, and you would want to convert this value to em before sending it back to server for persistence. That way next time user looks at the page, item would be in correct position -- regardless of screen resolution of the device they are using.
JQuery plugins are not very scary when you can review the code, specially if they are short and sweet like this plugin to convert pixel values to em as you want. In fact it is so short I will paste the whole thing here. For copyright notice see the link.
$.fn.toEm = function(settings){
settings = jQuery.extend({
scope: 'body'
}, settings);
var that = parseInt(this[0],10),
scopeTest = jQuery('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;"> </div>').appendTo(settings.scope),
scopeVal = scopeTest.height();
scopeTest.remove();
return (that / scopeVal).toFixed(8) + 'em';
};
$.fn.toPx = function(settings){
settings = jQuery.extend({
scope: 'body'
}, settings);
var that = parseFloat(this[0]),
scopeTest = jQuery('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;"> </div>').appendTo(settings.scope),
scopeVal = scopeTest.height();
scopeTest.remove();
return Math.round(that * scopeVal) + 'px';
};
Usage Example: $(myPixelValue).toEm(); or $(myEmValue).toPx();.
I just tested this in my application, it works great. So I thought I share.
The following seems to do as you require, though it's based on the font-size of the parent, and of the element itself, being returned in px:
function px2em(elem) {
var W = window,
D = document;
if (!elem || elem.parentNode.tagName.toLowerCase() == 'body') {
return false;
}
else {
var parentFontSize = parseInt(W.getComputedStyle(elem.parentNode, null).fontSize, 10),
elemFontSize = parseInt(W.getComputedStyle(elem, null).fontSize, 10);
var pxInEms = Math.floor((elemFontSize / parentFontSize) * 100) / 100;
elem.style.fontSize = pxInEms + 'em';
}
}
JS Fiddle proof of concept.
Notes:
The function returns false, if the element you're trying to convert to em is the body, though that's because I couldn't work out whether it was sensible to set the value to 1em or simply leave it alone.
It uses window.getComputedStyle(), so it's not going to work with IE, without some adjustments.
References:
Math.floor().
parentNode.
parseInt().
tagName.
toLowerCase().
window.getComputedStyle().
Pixels and ems are fundamentally different types of unit. You can't simply convert between them.
For instance, a user with a default font size of 16px on a site where top-level headings are styled at 200% font size, 1em may be equal to 32px. Move the heading elsewhere in the document, it could be 64px or 16px. Give the same document to a different user, it might be 30/60/15px. Start talking about a different element, and it can change again.
The closest you can come to what you want is to convert from pixels to ems+document+context+settings. But if somebody has asked you to lay out your project with ems, they will probably not be pleased that you are trying to do it in pixels then "converting".
Usually when you want to convert px to em, the conversion happens on the element itself. getComputedStyle returns value in px which break their responsiveness. The code below can be used to help with this issue:
/**
* Get the equivalent EM value on a given element with a given pixel value.
*
* Normally the number of pixel specified should come from the element itself (e.g. element.style.height) since EM is
* relative.
*
* #param {Object} element - The HTML element.
* #param {Number} pixelValue - The number of pixel to convert in EM on this specific element.
*
* #returns {Boolean|Number} The EM value, or false if unable to convert.
*/
window.getEmValueFromElement = function (element, pixelValue) {
if (element.parentNode) {
var parentFontSize = parseFloat(window.getComputedStyle(element.parentNode).fontSize);
var elementFontSize = parseFloat(window.getComputedStyle(element).fontSize);
var pixelValueOfOneEm = (elementFontSize / parentFontSize) * elementFontSize;
return (pixelValue / pixelValueOfOneEm);
}
return false;
};
Using it would be as simple as:
var element = document.getElementById('someDiv');
var computedHeightInEm = window.getEmValueFromElement(element, element.offsetHeight);
Old question, but for reference, here is something I cobbled together, scope and suffix are optional. Pass it a rem or em value as string, eg. '4em' [ you can use spaces and upper/lowercase ] and it will return the px value. Unless you give it a scope, which would be the target element for finding the local EM value, it will default to body, effectively giving you the rem value. Lastly, the optional suffix parameter [ boolean ] will add 'px' to the returned value such that 48 becomes 48px for example.
ex: emRemToPx( '3em', '#content' )
return 48 on a font-size 16px / 100% document
/**
* emRemToPx.js | #whatsnewsisyphus
* To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
* see CC0 Public Domain Dedication <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
var emRemToPx = function( value, scope, suffix ) {
if (!scope || value.toLowerCase().indexOf("rem") >= 0) {
scope = 'body';
}
if (suffix === true) {
suffix = 'px';
} else {
suffix = null;
}
var multiplier = parseFloat(value);
var scopeTest = $('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;"> </div>').appendTo(scope);
var scopeVal = scopeTest.height();
scopeTest.remove();
return Math.round(multiplier * scopeVal) + suffix;
};
I've packaged this functionality into a library, complete with parameter type checking: px-to-em
Given this HTML:
<p id="message" style="font-size: 16px;">Hello World!</p>
You can expect these outputs:
pxToEm(16, message) === 1
pxToEm(24, message) === 1.5
pxToEm(32, message) === 2
Since the OP requested a way to do this without a library, I've copied the source code of px-to-em to a live demo:
function pxToEm (px, element) {
element = element === null || element === undefined ? document.documentElement : element;
var temporaryElement = document.createElement('div');
temporaryElement.style.setProperty('position', 'absolute', 'important');
temporaryElement.style.setProperty('visibility', 'hidden', 'important');
temporaryElement.style.setProperty('font-size', '1em', 'important');
element.appendChild(temporaryElement);
var baseFontSize = parseFloat(getComputedStyle(temporaryElement).fontSize);
temporaryElement.parentNode.removeChild(temporaryElement);
return px / baseFontSize;
}
console.log(pxToEm(16, message), 'Should be 1');
console.log(pxToEm(24, message), 'Should be 1.5');
console.log(pxToEm(32, message), 'Should be 2');
<p id="message" style="font-size: 16px;">Hello World!</p>
I learned from this answer that with getComputedStyle we can reliably obtain the divisor px value with the decimal point, which improves the accuracy of the calculation. I found that the answer by Aras could be off by over 0.5px, which caused rounding errors for us.
Try using this:
parseInt(myPixelValue) / parseFloat($("body").css("font-size"));
Ems don't equal pixels in anyway. They are a relative measurement.
<span style="font-size: 1em;">This is 1em font size, which means the text is the same size as the parent</span>
<span style="font-size: 1.5em;">This is 1.5em font size, which means the text is 150% the size as the parent</span>
The base size is determined by the user-agent (browser).

Decimal ignored when changing font size with JS

I'm trying to add some text resize functionality using this code:
$('#text-resize a').click(function(){
var currentValue = $('#page-body').css('fontSize');
var currentSize = parseFloat(currentValue, 10);
var fontUnit = currentValue.slice(-2);
var newSize = currentSize;
if ($(this).attr('rel') == 'decrease'){
if (currentSize > 13){
var newSize = currentSize / 1.2;
}
}
else if ($(this).attr('rel') == 'increase'){
if (currentSize < 19){
var newSize = currentSize * 1.2;
}
}
else {
newSize = 1;
fontUnit = 'em';
}
newSize += fontUnit;
$('#page-body').css('fontSize', newSize);
return false;
});
I know it's not the cleanest code, but my problem is that at some point (either getting or setting the font size for #page-body decimal points are being lost.
For example, I start with a value of 16px (from my CSS file) and when I increase it gets calculated to 19.2px. If I increase again, an alert of the currentValue (I have left out the alert) says it's 19px.
Can anyone tell me why decimal places are being ignored and how to prevent that?
If it helps, my starting CSS includes:
body { font-size: 16px; }
#page-body { font-size: 1em; }
Thanks
A font size can only be a whole number of pixels, so when you set the font-size the browser casts the invalid font size to something it can use. The next time you get it, it's an integer number.
Since you're setting the font size on an element identified by ID, you should store the size in a variable and only set (never get) the element css font size.
For example, see http://jsfiddle.net/Qfzpb/
Sub-pixel rendering is inconsistent between browsers.
Font size can be a <length>, and a <length> is a <number> (with or without a decimal point) immediately followed by a unit identifier (e.g., px, em, etc.).
http://www.w3.org/TR/CSS21/fonts.html#font-size-props
CSS 3 says " UAs should support reasonably useful ranges and precisions. " Open-to-interpretation wording as 'reasonable' and 'useful':
http://dev.w3.org/csswg/css3-values/#numeric-types
$('#page-body').css('fontSize')
This may return different values(depending on the used browser).
Usually (in modern browsers) jQuery gets the value by using getComputedStyle() .
The returned value here is the value used by the browser, not the value the style-property is set to.
You may use this instead:
var currentValue = document.getElementById('page-body').style.fontSize
||
$('#page-body').css('fontSize');
See the fiddle to determine the differences: http://jsfiddle.net/doktormolle/DMWhh/

Determine Pixel Length of String in Javascript/jQuery?

Is there any way to determine the pixel length of a string in jQuery/JavaScript?
The contexts used for HTML Canvases have a built-in method for checking the size of a font. This method returns a TextMetrics object, which has a width property that contains the width of the text.
function getWidthOfText(txt, fontname, fontsize){
if(getWidthOfText.c === undefined){
getWidthOfText.c=document.createElement('canvas');
getWidthOfText.ctx=getWidthOfText.c.getContext('2d');
}
var fontspec = fontsize + ' ' + fontname;
if(getWidthOfText.ctx.font !== fontspec)
getWidthOfText.ctx.font = fontspec;
return getWidthOfText.ctx.measureText(txt).width;
}
Or, as some of the other users have suggested, you can wrap it in a span element:
function getWidthOfText(txt, fontname, fontsize){
if(getWidthOfText.e === undefined){
getWidthOfText.e = document.createElement('span');
getWidthOfText.e.style.display = "none";
document.body.appendChild(getWidthOfText.e);
}
if(getWidthOfText.e.style.fontSize !== fontsize)
getWidthOfText.e.style.fontSize = fontsize;
if(getWidthOfText.e.style.fontFamily !== fontname)
getWidthOfText.e.style.fontFamily = fontname;
getWidthOfText.e.innerText = txt;
return getWidthOfText.e.offsetWidth;
}
EDIT 2020: added font name+size caching at Igor Okorokov's suggestion.
Wrap text in a span and use jquery width()
I don't believe you can do just a string, but if you put the string inside of a <span> with the correct attributes (size, font-weight, etc); you should then be able to use jQuery to get the width of the span.
<span id='string_span' style='font-weight: bold; font-size: 12'>Here is my string</span>
<script>
$('#string_span').width();
</script>
Put it in an absolutely-positioned div then use clientWidth to get the displayed width of the tag. You can even set the visibility to "hidden" to hide the div:
<div id="text" style="position:absolute;visibility:hidden" >This is some text</div>
<input type="button" onclick="getWidth()" value="Go" />
<script type="text/javascript" >
function getWidth() {
var width = document.getElementById("text").clientWidth;
alert(" Width :"+ width);
}
</script>
Based on vSync's answer, the pure javascript method is lightning fast for large amount of objects.
Here is the Fiddle: https://jsfiddle.net/xeyq2d5r/8/
[1]: https://jsfiddle.net/xeyq2d5r/8/ "JSFiddle"
I received favorable tests for the 3rd method proposed, that uses the native javascript vs HTML Canvas
Google was pretty competive for option 1 and 3, 2 bombed.
FireFox 48:
Method 1 took 938.895 milliseconds.
Method 2 took 1536.355 milliseconds.
Method 3 took 135.91499999999996 milliseconds.
Edge 11
Method 1 took 4895.262839793865 milliseconds.
Method 2 took 6746.622271896686 milliseconds.
Method 3 took 1020.0315412885484 milliseconds.
Google Chrome: 52
Method 1 took 336.4399999999998 milliseconds.
Method 2 took 2271.71 milliseconds.
Method 3 took 333.30499999999984 milliseconds.
First replicate the location and styling of the text and then use Jquery width() function. This will make the measurements accurate.
For example you have css styling with a selector of:
.style-head span
{
//Some style set
}
You would need to do this with Jquery already included above this script:
var measuringSpan = document.createElement("span");
measuringSpan.innerText = 'text to measure';
measuringSpan.style.display = 'none'; /*so you don't show that you are measuring*/
$('.style-head')[0].appendChild(measuringSpan);
var theWidthYouWant = $(measuringSpan).width();
Needless to say
theWidthYouWant
will hold the pixel length. Then remove the created elements after you are done or you will get several if this is done a several times. Or add an ID to reference instead.
Maybe it will useful for some
const getMaxPixelsOfStrings = ({ strings, styles = {} }) => {
const spans = strings.map(str => {
const span = document.createElement('span')
span.append(str)
Object.assign(span.style, {
position: 'absolute',
...styles,
})
return span
})
document.querySelector('html').prepend(...spans)
const maxPixels = Math.max(...spans.map(span => span.getBoundingClientRect().width))
spans.forEach(span => span.remove())
return maxPixels
}
usage
getMaxPixelsOfStrings({
strings: ['One', 'Two', 'Three', 'Four', 'Five'],
styles: {
fontSize: '18px',
letterSpacing: '1px',
},
})
If you use Snap.svg, the following works:
var tPaper = Snap(300, 300);
var tLabelText = tPaper.text(100, 100, "label text");
var tWidth = tLabelText.getBBox().width; // the width of the text in pixels.
tLabelText.attr({ x : 150 - (tWidth/2)}); // now it's centered in x

How to autosize a textarea using Prototype?

I'm currently working on an internal sales application for the company I work for, and I've got a form that allows the user to change the delivery address.
Now I think it would look much nicer, if the textarea I'm using for the main address details would just take up the area of the text in it, and automatically resize if the text was changed.
Here's a screenshot of it currently.
Any ideas?
#Chris
A good point, but there are reasons I want it to resize. I want the area it takes up to be the area of the information contained in it. As you can see in the screen shot, if I have a fixed textarea, it takes up a fair wack of vertical space.
I can reduce the font, but I need address to be large and readable. Now I can reduce the size of the text area, but then I have problems with people who have an address line that takes 3 or 4 (one takes 5) lines. Needing to have the user use a scrollbar is a major no-no.
I guess I should be a bit more specific. I'm after vertical resizing, and the width doesn't matter as much. The only problem that happens with that, is the ISO number (the large "1") gets pushed under the address when the window width is too small (as you can see on the screenshot).
It's not about having a gimick; it's about having a text field the user can edit that won't take up unnecessary space, but will show all the text in it.
Though if someone comes up with another way to approach the problem I'm open to that too.
I've modified the code a little because it was acting a little odd. I changed it to activate on keyup, because it wouldn't take into consideration the character that was just typed.
resizeIt = function() {
var str = $('iso_address').value;
var cols = $('iso_address').cols;
var linecount = 0;
$A(str.split("\n")).each(function(l) {
linecount += 1 + Math.floor(l.length / cols); // Take into account long lines
})
$('iso_address').rows = linecount;
};
Facebook does it, when you write on people's walls, but only resizes vertically.
Horizontal resize strikes me as being a mess, due to word-wrap, long lines, and so on, but vertical resize seems to be pretty safe and nice.
None of the Facebook-using-newbies I know have ever mentioned anything about it or been confused. I'd use this as anecdotal evidence to say 'go ahead, implement it'.
Some JavaScript code to do it, using Prototype (because that's what I'm familiar with):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="http://www.google.com/jsapi"></script>
<script language="javascript">
google.load('prototype', '1.6.0.2');
</script>
</head>
<body>
<textarea id="text-area" rows="1" cols="50"></textarea>
<script type="text/javascript" language="javascript">
resizeIt = function() {
var str = $('text-area').value;
var cols = $('text-area').cols;
var linecount = 0;
$A(str.split("\n")).each( function(l) {
linecount += Math.ceil( l.length / cols ); // Take into account long lines
})
$('text-area').rows = linecount + 1;
};
// You could attach to keyUp, etc. if keydown doesn't work
Event.observe('text-area', 'keydown', resizeIt );
resizeIt(); //Initial on load
</script>
</body>
</html>
PS: Obviously this JavaScript code is very naive and not well tested, and you probably don't want to use it on textboxes with novels in them, but you get the general idea.
One refinement to some of these answers is to let CSS do more of the work.
The basic route seems to be:
Create a container element to hold the textarea and a hidden div
Using Javascript, keep the textarea’s contents synced with the div’s
Let the browser do the work of calculating the height of that div
Because the browser handles rendering / sizing the hidden div, we avoid
explicitly setting the textarea’s height.
document.addEventListener('DOMContentLoaded', () => {
textArea.addEventListener('change', autosize, false)
textArea.addEventListener('keydown', autosize, false)
textArea.addEventListener('keyup', autosize, false)
autosize()
}, false)
function autosize() {
// Copy textarea contents to div browser will calculate correct height
// of copy, which will make overall container taller, which will make
// textarea taller.
textCopy.innerHTML = textArea.value.replace(/\n/g, '<br/>')
}
html, body, textarea {
font-family: sans-serif;
font-size: 14px;
}
.textarea-container {
position: relative;
}
.textarea-container > div, .textarea-container > textarea {
word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
box-sizing: border-box;
padding: 2px;
width: 100%;
}
.textarea-container > textarea {
overflow: hidden;
position: absolute;
height: 100%;
}
.textarea-container > div {
padding-bottom: 1.5em; /* A bit more than one additional line of text. */
visibility: hidden;
}
<div class="textarea-container">
<textarea id="textArea"></textarea>
<div id="textCopy"></div>
</div>
Here's another technique for autosizing a textarea.
Uses pixel height instead of line height: more accurate handling of line wrap if a proportional font is used.
Accepts either ID or element as input
Accepts an optional maximum height parameter - useful if you'd rather not let the text area grow beyond a certain size (keep it all on-screen, avoid breaking layout, etc.)
Tested on Firefox 3 and Internet Explorer 6
Code:
(plain vanilla JavaScript)
function FitToContent(id, maxHeight)
{
var text = id && id.style ? id : document.getElementById(id);
if (!text)
return;
/* Accounts for rows being deleted, pixel value may need adjusting */
if (text.clientHeight == text.scrollHeight) {
text.style.height = "30px";
}
var adjustedHeight = text.clientHeight;
if (!maxHeight || maxHeight > adjustedHeight)
{
adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
if (maxHeight)
adjustedHeight = Math.min(maxHeight, adjustedHeight);
if (adjustedHeight > text.clientHeight)
text.style.height = adjustedHeight + "px";
}
}
Demo:
(uses jQuery, targets on the textarea I'm typing into right now - if you have Firebug installed, paste both samples into the console and test on this page)
$("#post-text").keyup(function()
{
FitToContent(this, document.documentElement.clientHeight)
});
Probably the shortest solution:
jQuery(document).ready(function(){
jQuery("#textArea").on("keydown keyup", function(){
this.style.height = "1px";
this.style.height = (this.scrollHeight) + "px";
});
});
This way you don't need any hidden divs or anything like that.
Note: you might have to play with this.style.height = (this.scrollHeight) + "px"; depending on how you style the textarea (line-height, padding and that kind of stuff).
Here's a Prototype version of resizing a text area that is not dependent on the number of columns in the textarea. This is a superior technique because it allows you to control the text area via CSS as well as have variable width textarea. Additionally, this version displays the number of characters remaining. While not requested, it's a pretty useful feature and is easily removed if unwanted.
//inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
if (window.Widget == undefined) window.Widget = {};
Widget.Textarea = Class.create({
initialize: function(textarea, options)
{
this.textarea = $(textarea);
this.options = $H({
'min_height' : 30,
'max_length' : 400
}).update(options);
this.textarea.observe('keyup', this.refresh.bind(this));
this._shadow = new Element('div').setStyle({
lineHeight : this.textarea.getStyle('lineHeight'),
fontSize : this.textarea.getStyle('fontSize'),
fontFamily : this.textarea.getStyle('fontFamily'),
position : 'absolute',
top: '-10000px',
left: '-10000px',
width: this.textarea.getWidth() + 'px'
});
this.textarea.insert({ after: this._shadow });
this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
this.textarea.insert({after: this._remainingCharacters});
this.refresh();
},
refresh: function()
{
this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
this.textarea.setStyle({
height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
});
var remaining = this.options.get('max_length') - $F(this.textarea).length;
this._remainingCharacters.update(Math.abs(remaining) + ' characters ' + (remaining > 0 ? 'remaining' : 'over the limit'));
}
});
Create the widget by calling new Widget.Textarea('element_id'). The default options can be overridden by passing them as an object, e.g. new Widget.Textarea('element_id', { max_length: 600, min_height: 50}). If you want to create it for all textareas on the page, do something like:
Event.observe(window, 'load', function() {
$$('textarea').each(function(textarea) {
new Widget.Textarea(textarea);
});
});
Here is a solution with JQuery:
$(document).ready(function() {
var $abc = $("#abc");
$abc.css("height", $abc.attr("scrollHeight"));
})
abc is a teaxtarea.
Check the below link:
http://james.padolsey.com/javascript/jquery-plugin-autoresize/
$(document).ready(function () {
$('.ExpandableTextCSS').autoResize({
// On resize:
onResize: function () {
$(this).css({ opacity: 0.8 });
},
// After resize:
animateCallback: function () {
$(this).css({ opacity: 1 });
},
// Quite slow animation:
animateDuration: 300,
// More extra space:
extraSpace:20,
//Textarea height limit
limit:10
});
});
Just revisiting this, I've made it a little bit tidier (though someone who is full bottle on Prototype/JavaScript could suggest improvements?).
var TextAreaResize = Class.create();
TextAreaResize.prototype = {
initialize: function(element, options) {
element = $(element);
this.element = element;
this.options = Object.extend(
{},
options || {});
Event.observe(this.element, 'keyup',
this.onKeyUp.bindAsEventListener(this));
this.onKeyUp();
},
onKeyUp: function() {
// We need this variable because "this" changes in the scope of the
// function below.
var cols = this.element.cols;
var linecount = 0;
$A(this.element.value.split("\n")).each(function(l) {
// We take long lines into account via the cols divide.
linecount += 1 + Math.floor(l.length / cols);
})
this.element.rows = linecount;
}
}
Just it call with:
new TextAreaResize('textarea_id_name_here');
I've made something quite easy. First I put the TextArea into a DIV. Second, I've called on the ready function to this script.
<div id="divTable">
<textarea ID="txt" Rows="1" TextMode="MultiLine" />
</div>
$(document).ready(function () {
var heightTextArea = $('#txt').height();
var divTable = document.getElementById('divTable');
$('#txt').attr('rows', parseInt(parseInt(divTable .style.height) / parseInt(altoFila)));
});
Simple. It is the maximum height of the div once it is rendered, divided by the height of one TextArea of one row.
I needed this function for myself, but none of the ones from here worked as I needed them.
So I used Orion's code and changed it.
I added in a minimum height, so that on the destruct it does not get too small.
function resizeIt( id, maxHeight, minHeight ) {
var text = id && id.style ? id : document.getElementById(id);
var str = text.value;
var cols = text.cols;
var linecount = 0;
var arStr = str.split( "\n" );
$(arStr).each(function(s) {
linecount = linecount + 1 + Math.floor(arStr[s].length / cols); // take into account long lines
});
linecount++;
linecount = Math.max(minHeight, linecount);
linecount = Math.min(maxHeight, linecount);
text.rows = linecount;
};
Like the answer of #memical.
However I found some improvements. You can use the jQuery height() function. But be aware of padding-top and padding-bottom pixels. Otherwise your textarea will grow too fast.
$(document).ready(function() {
$textarea = $("#my-textarea");
// There is some diff between scrollheight and height:
// padding-top and padding-bottom
var diff = $textarea.prop("scrollHeight") - $textarea.height();
$textarea.live("keyup", function() {
var height = $textarea.prop("scrollHeight") - diff;
$textarea.height(height);
});
});
My solution not using jQuery (because sometimes they don't have to be the same thing) is below. Though it was only tested in Internet Explorer 7, so the community can point out all the reasons this is wrong:
textarea.onkeyup = function () { this.style.height = this.scrollHeight + 'px'; }
So far I really like how it's working, and I don't care about other browsers, so I'll probably apply it to all my textareas:
// Make all textareas auto-resize vertically
var textareas = document.getElementsByTagName('textarea');
for (i = 0; i<textareas.length; i++)
{
// Retain textarea's starting height as its minimum height
textareas[i].minHeight = textareas[i].offsetHeight;
textareas[i].onkeyup = function () {
this.style.height = Math.max(this.scrollHeight, this.minHeight) + 'px';
}
textareas[i].onkeyup(); // Trigger once to set initial height
}
Here is an extension to the Prototype widget that Jeremy posted on June 4th:
It stops the user from entering more characters if you're using limits in textareas. It checks if there are characters left. If the user copies text into the textarea, the text is cut off at the max. length:
/**
* Prototype Widget: Textarea
* Automatically resizes a textarea and displays the number of remaining chars
*
* From: http://stackoverflow.com/questions/7477/autosizing-textarea
* Inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
*/
if (window.Widget == undefined) window.Widget = {};
Widget.Textarea = Class.create({
initialize: function(textarea, options){
this.textarea = $(textarea);
this.options = $H({
'min_height' : 30,
'max_length' : 400
}).update(options);
this.textarea.observe('keyup', this.refresh.bind(this));
this._shadow = new Element('div').setStyle({
lineHeight : this.textarea.getStyle('lineHeight'),
fontSize : this.textarea.getStyle('fontSize'),
fontFamily : this.textarea.getStyle('fontFamily'),
position : 'absolute',
top: '-10000px',
left: '-10000px',
width: this.textarea.getWidth() + 'px'
});
this.textarea.insert({ after: this._shadow });
this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
this.textarea.insert({after: this._remainingCharacters});
this.refresh();
},
refresh: function(){
this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
this.textarea.setStyle({
height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
});
// Keep the text/character count inside the limits:
if($F(this.textarea).length > this.options.get('max_length')){
text = $F(this.textarea).substring(0, this.options.get('max_length'));
this.textarea.value = text;
return false;
}
var remaining = this.options.get('max_length') - $F(this.textarea).length;
this._remainingCharacters.update(Math.abs(remaining) + ' characters remaining'));
}
});
#memical had an awesome solution for setting the height of the textarea on pageload with jQuery, but for my application I wanted to be able to increase the height of the textarea as the user added more content. I built off memical's solution with the following:
$(document).ready(function() {
var $textarea = $("p.body textarea");
$textarea.css("height", ($textarea.attr("scrollHeight") + 20));
$textarea.keyup(function(){
var current_height = $textarea.css("height").replace("px", "")*1;
if (current_height + 5 <= $textarea.attr("scrollHeight")) {
$textarea.css("height", ($textarea.attr("scrollHeight") + 20));
}
});
});
It's not very smooth but it's also not a client-facing application, so smoothness doesn't really matter. (Had this been client-facing, I probably would have just used an auto-resize jQuery plugin.)
For those that are coding for IE and encounter this problem. IE has a little trick that makes it 100% CSS.
<TEXTAREA style="overflow: visible;" cols="100" ....></TEXTAREA>
You can even provide a value for rows="n" which IE will ignore, but other browsers will use. I really hate coding that implements IE hacks, but this one is very helpful. It is possible that it only works in Quirks mode.
Internet Explorer, Safari, Chrome and Opera users need to remember to explicidly set the line-height value in CSS. I do a stylesheet that sets the initial properites for all text boxes as follows.
<style>
TEXTAREA { line-height: 14px; font-size: 12px; font-family: arial }
</style>
Here is a function I just wrote in jQuery to do it - you can port it to Prototype, but they don't support the "liveness" of jQuery so elements added by Ajax requests will not respond.
This version not only expands, but it also contracts when delete or backspace is pressed.
This version relies on jQuery 1.4.2.
Enjoy ;)
http://pastebin.com/SUKeBtnx
Usage:
$("#sometextarea").textareacontrol();
or (any jQuery selector for example)
$("textarea").textareacontrol();
It was tested on Internet Explorer 7/Internet Explorer 8, Firefox 3.5, and Chrome. All works fine.
Using ASP.NET, just simply do this:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Automatic Resize TextBox</title>
<script type="text/javascript">
function setHeight(txtarea) {
txtarea.style.height = txtdesc.scrollHeight + "px";
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="txtarea" runat= "server" TextMode="MultiLine" onkeyup="setHeight(this);" onkeydown="setHeight(this);" />
</form>
</body>
</html>

Categories