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) |