3 * @descripton Elastic is jQuery plugin that grow and shrink your textareas automatically
5 * @requires jQuery 1.2.6+
8 * @author-email jan.jarfalk@unwrongest.com
9 * @author-website http://www.unwrongest.com
11 * @licence MIT License - http://www.opensource.org/licenses/mit-license.php
18 // We will create a div clone of the textarea
19 // by copying these attributes from the textarea to the div.
32 'border-bottom-width',
44 return this.each( function() {
46 // Elastic only works on textareas
47 if ( this.type !== 'textarea' ) {
51 var $textarea = jQuery(this),
52 $twin = jQuery('<div />').css({
53 'position' : 'absolute',
55 'word-wrap' : 'break-word',
56 'white-space' :'pre-wrap'
58 lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
59 minheight = parseInt($textarea.css('height'),10) || lineHeight*3,
60 maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
63 // Opera returns max-height of -1 if not set
64 if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
66 // Append the twin to the DOM
67 // We are going to meassure the height of this, not the textarea.
68 $twin.appendTo($textarea.parent());
70 // Copy the essential styles (mimics) from the textarea to the twin
71 var i = mimics.length;
73 $twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
76 // Updates the width of the twin. (solution for textareas with widths in percent)
77 function setTwinWidth(){
78 var curatedWidth = Math.floor(parseInt($textarea.width(),10));
79 if($twin.width() !== curatedWidth){
80 $twin.css({'width': curatedWidth + 'px'});
82 // Update height of textarea
87 // Sets a given height and overflow state on the textarea
88 function setHeightAndOverflow(height, overflow){
90 var curratedHeight = Math.floor(parseInt(height,10));
91 if($textarea.height() !== curratedHeight){
92 $textarea.css({'height': curratedHeight + 'px','overflow':overflow});
96 // This function will update the height of the textarea if necessary
97 function update(forced) {
99 // Get curated content from the textarea.
100 var textareaContent = $textarea.val().replace(/&/g,'&').replace(/ {2}/g, ' ').replace(/<|>/g, '>').replace(/\n/g, '<br />');
102 // Compare curated content with curated twin.
103 var twinContent = $twin.html().replace(/<br>/ig,'<br />');
105 if(forced || textareaContent+' ' !== twinContent){
107 // Add an extra white space so new rows are added when you are at the end of a row.
108 $twin.html(textareaContent+' ');
110 // Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
111 if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){
113 var goalheight = $twin.height()+lineHeight;
114 if(goalheight >= maxheight) {
115 setHeightAndOverflow(maxheight,'auto');
116 } else if(goalheight <= minheight) {
117 setHeightAndOverflow(minheight,'hidden');
119 setHeightAndOverflow(goalheight,'hidden');
129 $textarea.css({'overflow':'hidden'});
131 // Update textarea size on keyup, change, cut and paste
132 $textarea.bind('keyup change cut paste', function(){
136 // Update width of twin if browser or textarea is resized (solution for textareas with widths in percent)
137 jQuery(window).bind('resize', setTwinWidth);
138 $textarea.bind('resize', setTwinWidth);
139 $textarea.bind('update', update);
141 // Compact textarea on blur
142 $textarea.bind('blur',function(){
143 if($twin.height() < maxheight){
144 if($twin.height() > minheight) {
145 $textarea.height($twin.height());
147 $textarea.height(minheight);
152 // And this line is to catch the browser paste event
153 $textarea.bind('input paste',function(e){ setTimeout( update, 250); });
155 // Run update once when elastic is initialized