(function($) {
    $.fn.autoGrowInput = function(o) {

        o = $.extend({
            maxWidth: 1000,
            minWidth: 0,
            comfortZone: 70
        }, o);

        this.filter('input').each(function() {

            var minWidth = o.minWidth || $(this).width(),
                    val = '',
                    input = $(this),
                    testSubject = $('<tester/>').css({
                        position: 'absolute',
                        top: -9999,
                        left: -9999,
                        width: 'auto',
                        fontSize: input.css('fontSize'),
                        fontFamily: input.css('fontFamily'),
                        fontWeight: input.css('fontWeight'),
                        letterSpacing: input.css('letterSpacing'),
                        whiteSpace: 'nowrap'
                    }),
                    check = function() {

                        if (val === (val = input.val())) {
                            return;
                        }

                        // Enter new content into testSubject
                        var escaped = val.replace(/&/g, '&amp;').replace(/\s/g, '&nbsp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
                        testSubject.html(escaped);

                        // Calculate new width + whether to change
                        var testerWidth = testSubject.width(),
                                newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
                                currentWidth = input.width(),
                                isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
                                        || (newWidth > minWidth && newWidth < o.maxWidth);

                        // Animate width
                        if (isValidWidthChange) {
                            $(o.wrapper).stop(true, true).animate({width:newWidth}, 500);
                        }
                    };

            testSubject.insertAfter(input);

            $(this).bind('keyup keydown blur update', check);

        });

        return this;

    };
})(jQuery);