jazzband/django-mongonaut

View on GitHub
mongonaut/templates/mongonaut/includes/list_add.js

Summary

Maintainability
A
3 hrs
Test Coverage
function addInputFromPrevious(input, embeddedDoc){
    /* This is a fuction to insert an input after an existing
        input.  It will correclty update the id and name so the
        input can be posted as desired.

        embeddedDoc must be an array.
     */
    var newInput = input.clone();
    var currentNameArray = newInput.attr('name').split('_');
    var lastArrayString = currentNameArray.pop();
    var newIdNum = 1;
    var baseName = currentNameArray.join("_");
    var currentName = "";

    // Compute the name attribute for the input
    if (!isNaN(lastArrayString)) {
        newIdNum += +lastArrayString;
        currentName = baseName + '_' + newIdNum;
        newInput.attr('name', currentName);
    } else {
        if (currentNameArray.length > 0) {
            baseName = baseName + "_" + lastArrayString;
            currentName = baseName + "_" + newIdNum;
            newInput.attr('name', currentName);
        } else {
            baseName = lastArrayString;
            currentName = baseName + "_" + newIdNum;
            newInput.attr('name', currentName);
        }
    }

    // Default to no value for newly added fields
    var inputType = $(newInput).attr('type');
    if (inputType == "text") {
        $(newInput).attr('value', '');
    } else if (inputType == "checkbox" ) {
        $(newInput).attr('checked', false);
    } else {
        $(newInput).children("option[value='']").attr('selected', 'selected');
    }
    $(newInput).attr('id', "id_" + currentName);

    if (embeddedDoc){
        embeddedDoc.push($(newInput));
    } else {
        $(newInput).insertAfter(input);
        $(newInput).before('<br />');
    }
    // Cleanly add the new input field to the DOM

    return newInput;
}

function attachButtonList(input) {
    /* Used to place the add button on the page.  Upon each click it
       copies the previous input and increments the id and name by using
       the addInputFromPrevious function. */
    var currentInput = input;
    var inputName = currentInput.attr('name');
    var button = "<div class='btn btn-primary " + inputName + "'>add</div>";
    $(button).insertAfter(currentInput);

    $(document).on('click', "div[class~=" + inputName +"]", function(e){
        e.preventDefault();
        var newInput = addInputFromPrevious(currentInput);
        currentInput = newInput;
    });
}

function attachButtonEmbedded(inputs) {
    /* Used to place the add button on the page.  Upon each click it
       copies the previous input and increments the id and name by using
       the addInputFromPrevious function. */
    var finalInput = null;
    for (var j = 0; j < inputs.length; j++) {
        if (j + 1 == inputs.length) {
            finalInput = inputs[j];
        }
    }
    var finalInputName = $(finalInput).attr('name');
    var button = "<div class='btn btn-primary " + finalInputName + "'>add</div>";
    var embeddedParentDIV = inputs.parent().parent().parent();
    $(button).insertAfter(finalInput);


    $(document).on('click', "div[class~=" + finalInputName +"]", function(e){
        e.preventDefault();
        var addedInputs = [];
        var embeddedDocs = [];

        for (var j = 0; j < inputs.length; j++) {
            var newInput = addInputFromPrevious($(inputs[j]), embeddedDocs);
            addedInputs.push(newInput);
        }

        var newEmbeddedDoc = $("<div class='well'></div>");
        for (var k = 0; k < embeddedDocs.length; k++) {
            var newFieldSet = $("<div class='clearfix'></div>");
            var newInputField = embeddedDocs[k];
            var newLabel = "<label for='" + newInputField.attr("id") + "'>" + newInputField.attr("name") + "</label>";

            newFieldSet.append(newLabel);
            newFieldSet.append(newInputField);
            newEmbeddedDoc.append(newFieldSet);

            if (k + 1 == embeddedDocs.length) {
                finalInput = newInputField;
            }
        }

        // Move button to next document
        $("[class*='btn btn-primary " + finalInputName + "']").remove();
        $(button).insertAfter(finalInput);

        $(embeddedParentDIV).append(newEmbeddedDoc);
        inputs = addedInputs;
    });
}

var listFields = $('.listField');
var listClasses = [];
var initialInputs = [];
for (var i = 0; i < listFields.length; i++) {
    var field = listFields[i];
    var listClass = $(field).attr('class').split(' ').pop();

    // Make sure to only get the base class from the grop of list fields
    if ($.inArray(listClass, listClasses) == -1) {
        listClasses.push(listClass);
    }
}

// Get the last list item in the group
for (var i = 0; i < listClasses.length; i++) {
    var inputs = $('.' + listClasses[i]);
    var listDiv = inputs.parent().parent();
    $(listDiv).wrapAll("<div class='well' />");
    listDiv = $(listDiv[listDiv.length - 1]);
    initialInputs.push(listDiv.children('div').children('.listField'));
}

// Process embedded documents
var embeddedFields = $('.embeddedField');
var embeddedClasses = [];

// Group Embedded docs together
for (var i = 0; i < embeddedFields.length; i++) {
    var field = embeddedFields[i];
    var allClasses = $(field).attr('class').split(' ');

    for (j = 0; j < allClasses.length; j++) {
        var embeddedClass = allClasses[j];
        if ($.inArray(embeddedClass, ['listField', 'embeddedField', 'span6', 'xlarge', '']) != -1) {
            continue;
        }
        // Make sure to only get the base class from the group of embedded fields
        if ($.inArray(embeddedClass, embeddedClasses) == -1) {
            embeddedClasses.push(embeddedClass);
        }
    }
}

for (var i = 0; i < embeddedClasses.length; i++){
    var inputDivs = $("[class~='" + embeddedClasses[i] + "']").parent().parent();
    var idBase = embeddedClasses[i];

    $(inputDivs).wrapAll("<div class='well' />");
    $(inputDivs[0]).parent().before("<div>" + embeddedClasses[i] + "</div>");
}

// Attach the buttons to the correct fields.
var alreadyAttached = [];

// Go in reverse order to correctly attach buttons
for (var i = initialInputs.length - 1; i >= 0; i--) {
    var inputField = initialInputs[i];

    // Remove the trailing number from our name so we can track what has
    // already been added.
    var inputNameArray = inputField.attr("name").split("_");
    inputNameArray.pop();
    var newInputName = inputNameArray.join("_");

    // Make sure we do not add a button to the same field twice
    if ($.inArray(newInputName, alreadyAttached) != -1) {
        continue;
    }

    if (inputField.hasClass("embeddedField")) {
        var newFields = $("[class*='" + inputField.attr("class") + "']");
        attachButtonEmbedded(newFields);
    } else {
        attachButtonList(initialInputs[i]);
    }
    alreadyAttached.push(newInputName);
}

// Remove any empty divs leftover by the re-organization of the page.
$(document).ready(function() {
    $('div:empty').remove();
    var allDivs = $("div");
    allDivs.each( function(index, element) {
        if (element.innerHTML === "") {
            $(element).remove();
        }
    });
});