jQuery.fn.autoGrow = function(options){
  var colsDefault = 0;
  var rowsDefault = 0;
  var oldValue = '';
  var oldHeight = 0;
  var overflowAuto = false;
  var minHeight, maxHeight;

  function intval(value) {
    if (value === true) return 1;
    return isNaN(parseInt(value, 10)) ? 0 : parseInt(value, 10);
  }

  function replaceChars(text, nobr) {
  var res = "";
  for (var i = 0; i<text.length; i++) {
    var c = text.charCodeAt(i);
    switch(c) {
      case 0x26: res += "&amp;"; break;
      case 0x3C: res += "&lt;"; break;
      case 0x3E: res += "&gt;"; break;
      case 0x22: res += "&quot;"; break;
      case 0x0D: res += ""; break;
      case 0x0A: res += nobr?"\t":"<br>"; break;
      case 0x21: res += "&#33;"; break;
      case 0x27: res += "&#39;"; break;
      default: res += ((c > 0x80 && c < 0xC0) || c > 0x500) ? "&#"+c+";" : text.charAt(i); break;
    }
  }
  return res;
  }; 

  if ( $('#autosize_helper').length == 0 ) 
    $('body').append( $('<div id="autosize_helper"></div>').css({
     'position': 'absolute',
     'left': '-10000px',
     'top': '-10000px'
  }) );

  var _helper = $('#autosize_helper');

  function init(txtArea) {
   var txtArea = $(txtArea);

   minHeight = intval( options.minHeight ) || intval( txtArea.css('height') );
   maxHeight = intval( options.height ) || intval( txtArea.css('max-height') );
   fontSize  = intval( txtArea.css('fontSize') );
   txtArea.css('height', minHeight);
   var w = txtArea.css('width');
   if ( options.padding ) w -= options.padding * 2;

   _helper.css({
     'word-wrap': 'break-word',
     'width': w,
     'font-family': txtArea.css('font-family'),
     'fontSize': fontSize + 'px',
     'line-height': txtArea.css('line-height')
   });
   txtArea.css('overflow', 'hidden');
  }

  function bindEvents(txtArea) {
    txtArea.keyup( function(event) {
      grow(event, this);
    });
  }

 function grow(event, txtArea) {
   var value = $(txtArea).val(), newHeight;
   if (event.type != 'keyup') {
     if (event.keyCode == 13 && !event.ctrlKey && !event.altKey) {
       value += '\n';
    }
   }
   if (value == oldValue) {
     return;
   }
   oldValue = value;

   var w = $(txtArea).css('width');
   _helper.css('width', w).html( $.trim(replaceChars(value)).replace(/<br>$/, '<br>&nbsp;') );
   newHeight = _helper.height() + fontSize + intval( $(txtArea).css('border-width') ) * 2 + 4;
   newHeight = Math.max(newHeight, minHeight);

   if ( maxHeight > 0 && ( newHeight > maxHeight )) {
     newHeight = maxHeight;
     if ( !overflowAuto ) {
       if ( $.browser.mozilla ) var cr = txtArea.selectionStart;
       overflowAuto = true;
       $(txtArea).css({
         'overflow': 'auto',
         'overflowX': 'hidden',
         'height': newHeight + 'px',
       });
       if ( $.browser.mozilla ) self.input.setSelectionRange(cr, cr);
       oldHeight = newHeight;
     }
   } else {
     if ( overflowAuto ) {
       overflowAuto = false;
       if ( $.browser.mozilla ) var cr = txtArea.selectionStart;
       $(txtArea).css('overflow', 'hidden');
       if ( $.browser.mozilla ) txtArea.setSelectionRange(cr, cr);
     }
   }

   if ( oldHeight != newHeight ) {
     oldHeight = newHeight;
     $(txtArea).css('height', newHeight + 'px');
     if ( options.onResize ) options.onResize(newHeight);
   }
   }

  return this.each( function() {
    init( $(this) );
    bindEvents( $(this) );
    var obj = this;
    setTimeout(function () { $(obj).trigger('keyup') }, 100);
  });
};

$(document).ready( function () {
  $('textarea').autoGrow({minHeight: 65});
});

