auto growing textarea with length indicator

by mirontoli

HTML

<div id="social-entry">
    <textarea type="text" id="social-entry-textarea" title="What are you creating right now?" maxlength="255" rows="1"></textarea>
    <div id="feedback" class="invisible">
        <div id="snake" class="round">
            <div id="snake-inner" class="round"></div>
        </div>
        <div id="log"></div>
    </div>
</div>

CSS

div#social-entry {
    width:400px;
    margin: 5em auto;
}
#social-entry-textarea {
    width: 94%;
    padding:5px 2.8%;
    margin-bottom:0.5em;
    color: #5D5D5D;
    height:1.5em;
    border: 1px solid #899BC1;
    font-family: tahoma,verdana,arial,sans-serif;
    resize:none;
    overflow-y:auto;
}
#snake {
    width: 100%;
    height:5px;
    background-color:transparent;
    border:1px solid darkGray;
    padding:0;
}
#snake-inner {
    height:5px;
    background-color:green;
    width:0px;
    margin:0;
}
div#log {
    width:100%;
    text-align:right;
    overflow-x:hidden;
}
.hidden {
    display:none;
}
.invisible {
    visibility:hidden;
}
.round {
    border-radius:3px;
}
div#social-entry.critical div#snake-inner {
    background-color:red;
}

JavaScript

$socialEntry = $("div#social-entry");
$socialEntryTextarea = $("#social-entry-textarea");
$socialEntryTextarea.val($socialEntryTextarea.attr("title"));
socialEntryTextAreaMax = $socialEntryTextarea.attr("maxlength");
socialEntryTextareaScrollHeight = $socialEntryTextarea.prop("scrollHeight");
socialEntryTextAreaPaddings = socialEntryTextareaScrollHeight - $socialEntryTextarea.height();
$socialEntryTextarea.live({
    keyup: function() {
        showSnake();
        updateHeight($(this));
        var letterQty = $(this).val().length;
        //run check for maxlength IE
        if (letterQty > socialEntryTextAreaMax) {
            // remove confusing over-maxlenght-notifications
            letterQty = socialEntryTextAreaMax;
            imposeLetters();
        }
        var width = $("#snake").width();
        var writtenPart = letterQty / socialEntryTextAreaMax;
        var writtenWidth = width * writtenPart;
        $("#snake-inner").width(writtenWidth);
        if (writtenPart > 0.9) {
            $socialEntry.addClass("critical");
        }
        else if ($socialEntry.hasClass("critical")) {
            $socialEntry.removeClass("critical");
        }
        $("#log").text(letterQty + " av max " + socialEntryTextAreaMax + " tecken");
    },
    blur: function() {
        hideSnake();
        if ($socialEntryTextarea.val().length == 0) {
            $socialEntryTextarea.val($socialEntryTextarea.attr("title"));
        }
    },
    focus: function() {
        if ($(this).val() == $(this).attr("title")) {
            $(this).val("");
        }
        var letterQty = $(this).val().length;
        if (letterQty > 0) {
            showSnake();
        }
    }
});

function showSnake() {
    if ($("#feedback").hasClass("invisible")) {
        $("#feedback").removeClass("invisible");
    }
}

function hideSnake() {
    $("#feedback").addClass("invisible");
}

function imposeLetters() {
    text = $socialEntryTextarea.val().substring(0, socialEntryTextAreaMax -...