diff --git a/django/contrib/admin/media/js/inlines.js b/django/contrib/admin/media/js/inlines.js
index c45ce58..d969438 100644
|
a
|
b
|
|
| 26 | 26 | }; |
| 27 | 27 | var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS"); |
| 28 | 28 | var initialForms = $("#id_" + options.prefix + "-INITIAL_FORMS"); |
| 29 | | var maxForms = parseInt(totalForms.val()); |
| | 29 | var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS"); |
| | 30 | console.log(maxForms.val(), initialForms.val(), options.prefix); |
| 30 | 31 | // only show the add button if we are allowed to add more items |
| 31 | | var showAddButton = (maxForms - parseInt(initialForms.val())) > 0; |
| | 32 | var showAddButton = ((maxForms.val() == 0) || ((maxForms.val()-initialForms.val()) > 0)); |
| 32 | 33 | var selectedItems = this; |
| 33 | 34 | $(this).each(function(i) { |
| 34 | 35 | $(this).not("." + options.emptyCssClass).addClass(options.formCssClass); |
| 35 | | // hide the extras, but only if there were no form errors |
| 36 | | if (!$(".errornote").html()) { |
| 37 | | var relatedItems = $(selectedItems).not("." + options.emptyCssClass); |
| 38 | | extraRows = relatedItems.length; |
| 39 | | if (parseInt(initialForms.val()) >= 0) { |
| 40 | | $(relatedItems).slice(initialForms.val()).remove(); |
| 41 | | } else { |
| 42 | | $(relatedItems).remove(); |
| 43 | | } |
| 44 | | totalForms.val(parseInt(initialForms.val())); |
| 45 | | } |
| 46 | 36 | }); |
| 47 | 37 | if ($(this).length && showAddButton) { |
| 48 | 38 | var addButton; |
| … |
… |
|
| 58 | 48 | addButton = $(this).filter(":last").next().find("a"); |
| 59 | 49 | } |
| 60 | 50 | addButton.click(function() { |
| 61 | | var totalForms = parseInt($("#id_" + options.prefix + "-TOTAL_FORMS").val()); |
| 62 | | var initialForms = parseInt($("#id_" + options.prefix + "-INITIAL_FORMS").val()); |
| 63 | | var nextIndex = totalForms + 1; |
| | 51 | var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS"); |
| | 52 | var nextIndex = parseInt(totalForms.val()) + 1; |
| 64 | 53 | var template = $("#" + options.prefix + "-empty"); |
| 65 | 54 | var row = template.clone(true).get(0); |
| 66 | 55 | $(row).removeClass(options.emptyCssClass).removeAttr("id").insertBefore($(template)); |
| … |
… |
|
| 79 | 68 | // last child element of the form's container: |
| 80 | 69 | $(row).children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>"); |
| 81 | 70 | } |
| | 71 | $(row).find("input,select,textarea,label").each(function() { |
| | 72 | updateElementIndex(this, options.prefix, totalForms.val()); |
| | 73 | }); |
| 82 | 74 | // Update number of total forms |
| 83 | | $("#id_" + options.prefix + "-TOTAL_FORMS").val(nextIndex); |
| 84 | | // Hide add button in case we've hit the max |
| 85 | | if (maxForms <= nextIndex) { |
| | 75 | $(totalForms).val(nextIndex); |
| | 76 | // Hide add button in case we've hit the max, except we want to add infinitely |
| | 77 | console.log(maxForms.val(), totalForms.val()) |
| | 78 | if ((maxForms.val() != 0) && (maxForms.val() <= totalForms.val())) { |
| 86 | 79 | addButton.parent().hide(); |
| 87 | 80 | } |
| 88 | 81 | // The delete button of each row triggers a bunch of other things |
| … |
… |
|
| 96 | 89 | var forms = $("." + options.formCssClass); |
| 97 | 90 | $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length); |
| 98 | 91 | // Show add button again once we drop below max |
| 99 | | if (maxForms >= forms.length) { |
| | 92 | console.log(maxForms.val(), forms.length); |
| | 93 | if ((maxForms.val() == 0) || (maxForms.val() >= forms.length)) { |
| 100 | 94 | addButton.parent().show(); |
| 101 | 95 | } |
| 102 | 96 | // Also, update names and ids for all remaining form controls |
| … |
… |
|
| 108 | 102 | } |
| 109 | 103 | return false; |
| 110 | 104 | }); |
| 111 | | $(row).find("input,select,textarea,label").each(function() { |
| 112 | | updateElementIndex(this, options.prefix, totalForms); |
| 113 | | }); |
| 114 | 105 | // If a post-add callback was supplied, call it with the added form: |
| 115 | 106 | if (options.added) options.added($(row)); |
| 116 | 107 | return false; |
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 9dfdb8b..4e3cfdc 100644
|
a
|
b
|
class InlineModelAdmin(BaseModelAdmin):
|
| 1193 | 1193 | |
| 1194 | 1194 | def _media(self): |
| 1195 | 1195 | from django.conf import settings |
| 1196 | | js = ['js/jquery.min.js', 'js/inlines.min.js'] |
| | 1196 | js = ['js/jquery.min.js', 'js/inlines.js'] |
| 1197 | 1197 | if self.prepopulated_fields: |
| 1198 | 1198 | js.append('js/urlify.js') |
| 1199 | 1199 | if self.filter_vertical or self.filter_horizontal: |
diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index a86c18f..58af0ac 100644
|
a
|
b
|
__all__ = ('BaseFormSet', 'all_valid')
|
| 12 | 12 | # special field names |
| 13 | 13 | TOTAL_FORM_COUNT = 'TOTAL_FORMS' |
| 14 | 14 | INITIAL_FORM_COUNT = 'INITIAL_FORMS' |
| | 15 | MAX_NUM_FORM_COUNT = 'MAX_NUM_FORMS' |
| 15 | 16 | ORDERING_FIELD_NAME = 'ORDER' |
| 16 | 17 | DELETION_FIELD_NAME = 'DELETE' |
| 17 | 18 | |
| … |
… |
class ManagementForm(Form):
|
| 24 | 25 | def __init__(self, *args, **kwargs): |
| 25 | 26 | self.base_fields[TOTAL_FORM_COUNT] = IntegerField(widget=HiddenInput) |
| 26 | 27 | self.base_fields[INITIAL_FORM_COUNT] = IntegerField(widget=HiddenInput) |
| | 28 | self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField(widget=HiddenInput) |
| 27 | 29 | super(ManagementForm, self).__init__(*args, **kwargs) |
| 28 | 30 | |
| 29 | 31 | class BaseFormSet(StrAndUnicode): |
| … |
… |
class BaseFormSet(StrAndUnicode):
|
| 56 | 58 | else: |
| 57 | 59 | form = ManagementForm(auto_id=self.auto_id, prefix=self.prefix, initial={ |
| 58 | 60 | TOTAL_FORM_COUNT: self.total_form_count(), |
| 59 | | INITIAL_FORM_COUNT: self.initial_form_count() |
| | 61 | INITIAL_FORM_COUNT: self.initial_form_count(), |
| | 62 | MAX_NUM_FORM_COUNT: self.max_num |
| 60 | 63 | }) |
| 61 | 64 | return form |
| 62 | 65 | management_form = property(_management_form) |