(function(jQuery) {
    jQuery.fn.extend({ elastic: function() {
        var mimics = ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'fontSize', 'lineHeight', 'fontFamily', 'width', 'fontWeight']; return this.each(function() {
            if (this.type != 'textarea') { return false; }
            var $textarea = jQuery(this), $twin = jQuery('<div />').css({ 'display': 'none', 'word-wrap': 'break-word' }), lineHeight = parseInt($textarea.css('line-height'), 10) || parseInt($textarea.css('font-size'), '10'), minheight = parseInt($textarea.css('height'), 10) || lineHeight * 3, maxheight = parseInt($textarea.css('max-height'), 10) || Number.MAX_VALUE, goalheight = 0, i = 0; if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
            $twin.appendTo($textarea.parent()); var i = mimics.length; while (i--) { $twin.css(mimics[i].toString(), $textarea.css(mimics[i].toString())); }
            function setHeightAndOverflow(height, overflow) { if ($textarea.width() != 0) { $twin.width($textarea.width()); } curratedHeight = Math.floor(parseInt(height, 10)); if ($textarea.height() != curratedHeight) { $textarea.css({ 'height': curratedHeight + 'px', 'overflow': overflow }); } }
            function update() { var textareaContent = $textarea.val().replace(/&/g, '&amp;').replace(/  /g, '&nbsp;').replace(/<|>/g, '&gt;').replace(/\n/g, '<br />'); var twinContent = $twin.html(); if (textareaContent + '&nbsp;' != twinContent) { $twin.html(textareaContent + '&nbsp;'); if (Math.abs($twin.height() + lineHeight - $textarea.height()) > 3) { var goalheight = $twin.height() + lineHeight; if (goalheight >= maxheight) { setHeightAndOverflow(maxheight, 'auto'); } else if (goalheight <= minheight) { setHeightAndOverflow(minheight, 'hidden'); } else { setHeightAndOverflow(goalheight, 'hidden'); } } } if ($twin.height() > $textarea.height()) { $textarea.height($twin.height() + lineHeight); } }
            $textarea.css({ 'overflow': 'hidden' }); $textarea.keyup(function() { update(); }); $textarea.live('input paste', function(e) { setTimeout(update, 250); }); update();
        });
    }
    });
})(jQuery);
