Refs #29087 -- Refactored admin inlines.js.

Split logic into separate functions to clarify and allow reuse.
This commit is contained in:
Carlton Gibson 2019-10-24 16:32:38 +02:00 committed by Carlton Gibson
parent daa9415f78
commit 6ea3aadd17
2 changed files with 110 additions and 85 deletions

View File

@ -37,19 +37,17 @@
var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop("autocomplete", "off");
var nextIndex = parseInt(totalForms.val(), 10);
var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop("autocomplete", "off");
// only show the add button if we are allowed to add more items,
// note that max_num = None translates to a blank string.
var showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0;
$this.each(function(i) {
$(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
});
if ($this.length && showAddButton) {
var addButton = options.addButton;
var addButton;
/**
* The "Add another MyModel" button below the inline forms.
*/
var addInlineAddButton = function() {
if (addButton === null) {
if ($this.prop("tagName") === "TR") {
// If forms are laid out as table rows, insert the
// "add" button in a new table row:
var numCols = this.eq(-1).children().length;
var numCols = $this.eq(-1).children().length;
$parent.append('<tr class="' + options.addCssClass + '"><td colspan="' + numCols + '"><a href="#">' + options.addText + "</a></tr>");
addButton = $parent.find("tr:last a");
} else {
@ -58,73 +56,100 @@
addButton = $this.filter(":last").next().find("a");
}
}
addButton.on('click', function(e) {
e.preventDefault();
var template = $("#" + options.prefix + "-empty");
var row = template.clone(true);
row.removeClass(options.emptyCssClass)
.addClass(options.formCssClass)
.attr("id", options.prefix + "-" + nextIndex);
if (row.is("tr")) {
// If the forms are laid out in table rows, insert
// the remove button into the last table cell:
row.children(":last").append('<div><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></div>");
} else if (row.is("ul") || row.is("ol")) {
// If they're laid out as an ordered/unordered list,
// insert an <li> after the last list item:
row.append('<li><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></li>");
} else {
// Otherwise, just insert the remove button as the
// last child element of the form's container:
row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></span>");
}
row.find("*").each(function() {
updateElementIndex(this, options.prefix, totalForms.val());
});
// Insert the new form when it has been fully edited
row.insertBefore($(template));
// Update number of total forms
$(totalForms).val(parseInt(totalForms.val(), 10) + 1);
nextIndex += 1;
// Hide add button in case we've hit the max, except we want to add infinitely
if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) {
addButton.parent().hide();
}
// The delete button of each row triggers a bunch of other things
row.find("a." + options.deleteCssClass).on('click', function(e1) {
e1.preventDefault();
// Remove the parent form containing this button:
row.remove();
nextIndex -= 1;
// If a post-delete callback was provided, call it with the deleted form:
if (options.removed) {
options.removed(row);
}
$(document).trigger('formset:removed', [row, options.prefix]);
// Update the TOTAL_FORMS form count.
var forms = $("." + options.formCssClass);
$("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
// Show add button again once we drop below max
if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) {
addButton.parent().show();
}
// Also, update names and ids for all remaining form controls
// so they remain in sequence:
var i, formCount;
var updateElementCallback = function() {
updateElementIndex(this, options.prefix, i);
};
for (i = 0, formCount = forms.length; i < formCount; i++) {
updateElementIndex($(forms).get(i), options.prefix, i);
$(forms.get(i)).find("*").each(updateElementCallback);
}
});
// If a post-add callback was supplied, call it with the added form:
if (options.added) {
options.added(row);
}
$(document).trigger('formset:added', [row, options.prefix]);
addButton.on('click', addInlineClickHandler);
};
var addInlineClickHandler = function(e) {
e.preventDefault();
var template = $("#" + options.prefix + "-empty");
var row = template.clone(true);
row.removeClass(options.emptyCssClass)
.addClass(options.formCssClass)
.attr("id", options.prefix + "-" + nextIndex);
addInlineDeleteButton(row);
row.find("*").each(function() {
updateElementIndex(this, options.prefix, totalForms.val());
});
// Insert the new form when it has been fully edited.
row.insertBefore($(template));
// Update number of total forms.
$(totalForms).val(parseInt(totalForms.val(), 10) + 1);
nextIndex += 1;
// Hide the add button if there's a limit and it's been reached.
if ((maxForms.val() !== '') && (maxForms.val() - totalForms.val()) <= 0) {
addButton.parent().hide();
}
// Pass the new form to the post-add callback, if provided.
if (options.added) {
options.added(row);
}
$(document).trigger('formset:added', [row, options.prefix]);
};
/**
* The "X" button that is part of every unsaved inline.
* (When saved, it is replaced with a "Delete" checkbox.)
*/
var addInlineDeleteButton = function(row) {
if (row.is("tr")) {
// If the forms are laid out in table rows, insert
// the remove button into the last table cell:
row.children(":last").append('<div><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></div>");
} else if (row.is("ul") || row.is("ol")) {
// If they're laid out as an ordered/unordered list,
// insert an <li> after the last list item:
row.append('<li><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></li>");
} else {
// Otherwise, just insert the remove button as the
// last child element of the form's container:
row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="#">' + options.deleteText + "</a></span>");
}
// Add delete handler for each row.
row.find("a." + options.deleteCssClass).on('click', inlineDeleteHandler.bind(this));
};
var inlineDeleteHandler = function(e1) {
e1.preventDefault();
var deleteButton = $(e1.target);
var row = deleteButton.closest('.' + options.formCssClass);
// Remove the parent form containing this button:
row.remove();
nextIndex -= 1;
// Pass the deleted form to the post-delete callback, if provided.
if (options.removed) {
options.removed(row);
}
$(document).trigger('formset:removed', [row, options.prefix]);
// Update the TOTAL_FORMS form count.
var forms = $("." + options.formCssClass);
$("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
// Show add button again once below maximum number.
if ((maxForms.val() === '') || (maxForms.val() - forms.length) > 0) {
addButton.parent().show();
}
// Also, update names and ids for all remaining form controls so
// they remain in sequence:
var i, formCount;
var updateElementCallback = function() {
updateElementIndex(this, options.prefix, i);
};
for (i = 0, formCount = forms.length; i < formCount; i++) {
updateElementIndex($(forms).get(i), options.prefix, i);
$(forms.get(i)).find("*").each(updateElementCallback);
}
};
// Show the add button if we are allowed to add more items.
// Note that max_num = None translates to a blank string.
var showAddButton = maxForms.val() === '' || (maxForms.val() - totalForms.val()) > 0;
$this.each(function(i) {
$(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
});
// Create the add button.
addButton = options.addButton;
if ($this.length && showAddButton) {
addInlineAddButton();
}
return this;
};

View File

@ -1,10 +1,10 @@
(function(b){b.fn.formset=function(c){var a=b.extend({},b.fn.formset.defaults,c),d=b(this);c=d.parent();var h=function(a,e,f){var c=new RegExp("("+e+"-(\\d+|__prefix__))");e=e+"-"+f;b(a).prop("for")&&b(a).prop("for",b(a).prop("for").replace(c,e));a.id&&(a.id=a.id.replace(c,e));a.name&&(a.name=a.name.replace(c,e))},g=b("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),k=parseInt(g.val(),10),e=b("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off"),f=""===e.val()||0<e.val()-g.val();
d.each(function(e){b(this).not("."+a.emptyCssClass).addClass(a.formCssClass)});if(d.length&&f){var m=a.addButton;null===m&&("TR"===d.prop("tagName")?(d=this.eq(-1).children().length,c.append('<tr class="'+a.addCssClass+'"><td colspan="'+d+'"><a href="#">'+a.addText+"</a></tr>"),m=c.find("tr:last a")):(d.filter(":last").after('<div class="'+a.addCssClass+'"><a href="#">'+a.addText+"</a></div>"),m=d.filter(":last").next().find("a")));m.on("click",function(f){f.preventDefault();f=b("#"+a.prefix+"-empty");
var c=f.clone(!0);c.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+k);c.is("tr")?c.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="#">'+a.deleteText+"</a></div>"):c.is("ul")||c.is("ol")?c.append('<li><a class="'+a.deleteCssClass+'" href="#">'+a.deleteText+"</a></li>"):c.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="#">'+a.deleteText+"</a></span>");c.find("*").each(function(){h(this,a.prefix,g.val())});c.insertBefore(b(f));
b(g).val(parseInt(g.val(),10)+1);k+=1;""!==e.val()&&0>=e.val()-g.val()&&m.parent().hide();c.find("a."+a.deleteCssClass).on("click",function(f){f.preventDefault();c.remove();--k;a.removed&&a.removed(c);b(document).trigger("formset:removed",[c,a.prefix]);f=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(f.length);(""===e.val()||0<e.val()-f.length)&&m.parent().show();var d,g=function(){h(this,a.prefix,l)};var l=0;for(d=f.length;l<d;l++)h(b(f).get(l),a.prefix,l),b(f.get(l)).find("*").each(g)});
a.added&&a.added(c);b(document).trigger("formset:added",[c,a.prefix])})}return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null,addButton:null};b.fn.tabularFormset=function(c,a){var d=b(this),h=function(a){b(c).not(".add-row").removeClass("row1 row2").filter(":even").addClass("row1").end().filter(":odd").addClass("row2")},g=function(){"undefined"!==
typeof SelectFilter&&(b(".selectfilter").each(function(a,b){a=b.name.split("-");SelectFilter.init(b.id,a[a.length-1],!1)}),b(".selectfilterstacked").each(function(a,b){a=b.name.split("-");SelectFilter.init(b.id,a[a.length-1],!0)}))},k=function(a){a.find(".prepopulated_field").each(function(){var c=b(this).find("input, select, textarea"),e=c.data("dependency_list")||[],d=[];b.each(e,function(b,c){d.push("#"+a.find(".field-"+c).find("input, select, textarea").attr("id"))});d.length&&c.prepopulate(d,
c.attr("maxlength"))})};d.formset({prefix:a.prefix,addText:a.addText,formCssClass:"dynamic-"+a.prefix,deleteCssClass:"inline-deletelink",deleteText:a.deleteText,emptyCssClass:"empty-form",removed:h,added:function(a){k(a);"undefined"!==typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());g();h(a)},addButton:a.addButton});return d};b.fn.stackedFormset=function(c,a){var d=b(this),h=function(a){b(c).find(".inline_label").each(function(a){a+=1;b(this).html(b(this).html().replace(/(#\d+)/g,
"#"+a))})},g=function(){"undefined"!==typeof SelectFilter&&(b(".selectfilter").each(function(a,b){a=b.name.split("-");SelectFilter.init(b.id,a[a.length-1],!1)}),b(".selectfilterstacked").each(function(a,b){a=b.name.split("-");SelectFilter.init(b.id,a[a.length-1],!0)}))},k=function(a){a.find(".prepopulated_field").each(function(){var c=b(this).find("input, select, textarea"),d=c.data("dependency_list")||[],e=[];b.each(d,function(b,c){e.push("#"+a.find(".form-row .field-"+c).find("input, select, textarea").attr("id"))});
e.length&&c.prepopulate(e,c.attr("maxlength"))})};d.formset({prefix:a.prefix,addText:a.addText,formCssClass:"dynamic-"+a.prefix,deleteCssClass:"inline-deletelink",deleteText:a.deleteText,emptyCssClass:"empty-form",removed:h,added:function(a){k(a);"undefined"!==typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());g();h(a)},addButton:a.addButton});return d};b(document).ready(function(){b(".js-inline-admin-formset").each(function(){var c=b(this).data(),a=c.inlineFormset;
switch(c.inlineType){case "stacked":c=a.name+"-group .inline-related";b(c).stackedFormset(c,a.options);break;case "tabular":c=a.name+"-group .tabular.inline-related tbody:first > tr",b(c).tabularFormset(c,a.options)}})})})(django.jQuery);
(function(b){b.fn.formset=function(c){var a=b.extend({},b.fn.formset.defaults,c),d=b(this),h=d.parent(),l=function(a,e,k){var f=new RegExp("("+e+"-(\\d+|__prefix__))");e=e+"-"+k;b(a).prop("for")&&b(a).prop("for",b(a).prop("for").replace(f,e));a.id&&(a.id=a.id.replace(f,e));a.name&&(a.name=a.name.replace(f,e))},g=b("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),e=parseInt(g.val(),10),k=b("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off");c=function(){if(null===m)if("TR"===d.prop("tagName")){var b=
d.eq(-1).children().length;h.append('<tr class="'+a.addCssClass+'"><td colspan="'+b+'"><a href="#">'+a.addText+"</a></tr>");m=h.find("tr:last a")}else d.filter(":last").after('<div class="'+a.addCssClass+'"><a href="#">'+a.addText+"</a></div>"),m=d.filter(":last").next().find("a");m.on("click",n)};var n=function(f){f.preventDefault();f=b("#"+a.prefix+"-empty");var c=f.clone(!0);c.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+e);p(c);c.find("*").each(function(){l(this,
a.prefix,g.val())});c.insertBefore(b(f));b(g).val(parseInt(g.val(),10)+1);e+=1;""!==k.val()&&0>=k.val()-g.val()&&m.parent().hide();a.added&&a.added(c);b(document).trigger("formset:added",[c,a.prefix])},p=function(b){b.is("tr")?b.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="#">'+a.deleteText+"</a></div>"):b.is("ul")||b.is("ol")?b.append('<li><a class="'+a.deleteCssClass+'" href="#">'+a.deleteText+"</a></li>"):b.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="#">'+
a.deleteText+"</a></span>");b.find("a."+a.deleteCssClass).on("click",q.bind(this))},q=function(c){c.preventDefault();c=b(c.target).closest("."+a.formCssClass);c.remove();--e;a.removed&&a.removed(c);b(document).trigger("formset:removed",[c,a.prefix]);c=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(c.length);(""===k.val()||0<k.val()-c.length)&&m.parent().show();var d,g=function(){l(this,a.prefix,f)};var f=0;for(d=c.length;f<d;f++)l(b(c).get(f),a.prefix,f),b(c.get(f)).find("*").each(g)},
r=""===k.val()||0<k.val()-g.val();d.each(function(e){b(this).not("."+a.emptyCssClass).addClass(a.formCssClass)});var m=a.addButton;d.length&&r&&c();return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null,addButton:null};b.fn.tabularFormset=function(c,a){var d=b(this),h=function(a){b(c).not(".add-row").removeClass("row1 row2").filter(":even").addClass("row1").end().filter(":odd").addClass("row2")},
l=function(){"undefined"!==typeof SelectFilter&&(b(".selectfilter").each(function(a,b){a=b.name.split("-");SelectFilter.init(b.id,a[a.length-1],!1)}),b(".selectfilterstacked").each(function(a,b){a=b.name.split("-");SelectFilter.init(b.id,a[a.length-1],!0)}))},g=function(a){a.find(".prepopulated_field").each(function(){var c=b(this).find("input, select, textarea"),e=c.data("dependency_list")||[],d=[];b.each(e,function(b,c){d.push("#"+a.find(".field-"+c).find("input, select, textarea").attr("id"))});
d.length&&c.prepopulate(d,c.attr("maxlength"))})};d.formset({prefix:a.prefix,addText:a.addText,formCssClass:"dynamic-"+a.prefix,deleteCssClass:"inline-deletelink",deleteText:a.deleteText,emptyCssClass:"empty-form",removed:h,added:function(a){g(a);"undefined"!==typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());l();h(a)},addButton:a.addButton});return d};b.fn.stackedFormset=function(c,a){var d=b(this),h=function(a){b(c).find(".inline_label").each(function(a){a+=1;
b(this).html(b(this).html().replace(/(#\d+)/g,"#"+a))})},l=function(){"undefined"!==typeof SelectFilter&&(b(".selectfilter").each(function(a,b){a=b.name.split("-");SelectFilter.init(b.id,a[a.length-1],!1)}),b(".selectfilterstacked").each(function(a,b){a=b.name.split("-");SelectFilter.init(b.id,a[a.length-1],!0)}))},g=function(a){a.find(".prepopulated_field").each(function(){var c=b(this).find("input, select, textarea"),d=c.data("dependency_list")||[],e=[];b.each(d,function(b,c){e.push("#"+a.find(".form-row .field-"+
c).find("input, select, textarea").attr("id"))});e.length&&c.prepopulate(e,c.attr("maxlength"))})};d.formset({prefix:a.prefix,addText:a.addText,formCssClass:"dynamic-"+a.prefix,deleteCssClass:"inline-deletelink",deleteText:a.deleteText,emptyCssClass:"empty-form",removed:h,added:function(a){g(a);"undefined"!==typeof DateTimeShortcuts&&(b(".datetimeshortcuts").remove(),DateTimeShortcuts.init());l();h(a)},addButton:a.addButton});return d};b(document).ready(function(){b(".js-inline-admin-formset").each(function(){var c=
b(this).data(),a=c.inlineFormset;switch(c.inlineType){case "stacked":c=a.name+"-group .inline-related";b(c).stackedFormset(c,a.options);break;case "tabular":c=a.name+"-group .tabular.inline-related tbody:first > tr",b(c).tabularFormset(c,a.options)}})})})(django.jQuery);