Auto Submit Forms, No Double Sending With Feedback

Forked to handle change tracking, i.e. if 2 edits close together do NOT send first, also with UI feedback of progress. Update only after change, and lost focus, to facilities an "auto-save" like concept.

by NickJosevski

HTML

<form id="MyFormId">
<fieldset>
    <legend>Some Form</legend>
    <div id="last-action"><em>What's going on:</em><br /><br />
        <div id="la-text"></div>
        <div id="fast-bind"><em>Stats:</em><br /><span id="fast-span"></span></div>
    </div>
    <!-- NOTE: after 8 attempts the div will overflow, I chose not to handle this :p -->
    
    <div class="editor-label">
        <label for="GUID">GUID</label>
    </div>
    <div class="editor-field">
        <label id="GUID">29e3a04a-a7fe-41dc-974a-9285d3872cfe</label>
    </div>
    
    <div class="editor-label">
        <label for="Deadline">Deadline</label>
    </div>
    <div class="editor-field">
        <input id="Deadline" name="Deadline" type="text" value="" />
        <img src="http://nickjosevski.wordpress.com/wp-admin/images/wpspin_light.gif"
        class="ajax-loading" id="Deadline-loading" alt="">
    </div>
    <div class="editor-label">
        <label for="Name">Task Name</label>
    </div>
    <div class="editor-field">
        <input id="Name" name="Name" type="text" value="" />
        <img src="http://nickjosevski.wordpress.com/wp-admin/images/wpspin_light.gif"
        class="ajax-loading" id="Name-loading" alt="">
    </div>
    <div class="editor-label">
        <label for="Description">Description</label>
    </div>
    <div class="editor-field">
        <input id="Description" name="Description" type="text" value="" />
        <img src="http://nickjosevski.wordpress.com/wp-admin/images/wpspin_light.gif"
        class="ajax-loading" id="Description-loading" alt="">
    </div>
</fieldset>
</form>

CSS

div#last-action 
{
    float:right;
    margin-right:50px;
    height:200px;
    width:200px;
    background-color:navy; color:white;
}

div#fast-bind 
{ 
    margin-right:50px;
    margin-top:190px;
    height:450px;
    width:200px;
    background-color:#8064A2; color:black;
}

fieldset 
{
    margin: 1em 0;
    padding: 1em;
    border: 1px solid #CCC;
}

fieldset p 
{
    margin: 2px 12px 10px 10px;
}

.display-label,
.editor-label,
.display-field,
.editor-field
{
    margin: 0.5em 0;
}

.text-box
{
    width: 30em;
}

JavaScript

var activeInputs;


var check = 'http://upload.wikimedia.org/wikipedia/commons/d/d9/Green_check.png';
var busy = 'http://nickjosevski.wordpress.com/wp-admin/images/wpspin_light.gif';
var redX = 'http://upload.wikimedia.org/wikipedia/commons/7/7e/Red_x.png';

(function($) {
    
    activeInputs = {};

    $(':input').change(function() {
        var c = $(this);
        $.when(
        c.focusout()).then(function() {
            pushToControlList(c);
            startCountDownAndSendData(c, 5); //delay by 5 seconds
        });
    });
    
})(jQuery);


function getInputId(c){
    return c.attr('id');
}

function showSuccess(data) {
    
    //var feedbackItem = data[i] + '-loading';
    //$('.process').append('<img id="checkmark" src="/Content/check.png" />');

    var msgs = "";
    for (var i = 0; i < data.length; i++) {
        msgs += data[i] + "<br />";
    }
    $('#fast-bind').html(msgs);
}

function pushToControlList(c){
    var elemId = getInputId(c);   
    var countVal = pushModifiedControlOnProcessingStack(elemId);
    
    $('#fast-span').append('added ' + elemId + ' with # ' + countVal + '<br />');
}

function pushModifiedControlOnProcessingStack(elemId){
    var countVal = 1;
    if(activeInputs[elemId] == null)
        activeInputs[elemId] = 1;
    else
    {
        activeInputs[elemId] = countVal = activeInputs[elemId] + 1;
    }
    return countVal;
}

function popProcessedControlFromStack(elemId){
    var countVal = -1;
    
    if(activeInputs[elemId] == null)
        return -1; //erorr state
    
    if(activeInputs[elemId] > 1)
    {
        countVal = activeInputs[elemId];
        activeInputs[elemId] = activeInputs[elemId] - 1;
    }
    else 
    {
        countVal = activeInputs[elemId];
        //is this enough? we check for null in the push method, so for now ok...
        activeInputs[elemId] = null;
    }
    return countVal;
}

function startCountDownAndSendData(c, waitDuration) {

    function go() {
        if (waitDuration <= 0)...