mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
[soc2009/admin-ui] A far better way to implement adding inlines using javascript. Instead of handling all the prefix incrementing in Javascript and losing any default values, added a way to generate a template form that can be cloned every time a new inline is added.
This is for stacked inlines. Support for tabular and selector inlines coming next. git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/admin-ui@11152 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f5bb5b5f98
commit
d2d6301455
@ -115,6 +115,8 @@ class InlineAdminFormSet(object):
|
|||||||
for form in self.formset.extra_forms:
|
for form in self.formset.extra_forms:
|
||||||
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
|
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
|
||||||
|
|
||||||
|
yield InlineAdminForm(self.formset, self.formset.empty_form, self.fieldsets, self.opts.prepopulated_fields, None)
|
||||||
|
|
||||||
def fields(self):
|
def fields(self):
|
||||||
fk = getattr(self.formset, "fk", None)
|
fk = getattr(self.formset, "fk", None)
|
||||||
for field_name in flatten_fieldsets(self.fieldsets):
|
for field_name in flatten_fieldsets(self.fieldsets):
|
||||||
|
@ -350,6 +350,10 @@ table.orderable-initalized .order-cell, body>tr>td.order-cell {
|
|||||||
background-color: #F6F6F6;
|
background-color: #F6F6F6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty_form {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* FORM DEFAULTS */
|
/* FORM DEFAULTS */
|
||||||
|
|
||||||
input, textarea, select {
|
input, textarea, select {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
{{ inline_admin_formset.formset.non_form_errors }}
|
{{ inline_admin_formset.formset.non_form_errors }}
|
||||||
|
|
||||||
{% for inline_admin_form in inline_admin_formset %}
|
{% for inline_admin_form in inline_admin_formset %}
|
||||||
<div class="inline-related{% if forloop.last %} last-related{% endif %}" id="{{ inline_admin_formset.opts.verbose_name}}{{ forloop.counter }}">
|
<div class="inline-related{% if forloop.last %} empty_form{% endif %}" id="{{ inline_admin_formset.opts.verbose_name}}{% if not forloop.last %}{{ forloop.counter }}{% else %}-empty{% endif %}">
|
||||||
<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b> <span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %} #{{ forloop.counter }}{% endif %}</span>
|
<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b> <span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %} #{{ forloop.counter }}{% endif %}</span>
|
||||||
{% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
|
{% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
|
||||||
</h3>
|
</h3>
|
||||||
@ -22,62 +22,48 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<ul class="tools add_inline">
|
<ul class="tools add_inline" id="{{ inline_admin_formset.opts.verbose_name}}-addinline">
|
||||||
<li><a id="{{ inline_admin_formset.opts.verbose_name }}-add" class="add" href="#">Add a {{ inline_admin_formset.opts.verbose_name }}</a></li>
|
<li><a id="{{ inline_admin_formset.opts.verbose_name }}-add" class="add" href="#">Add a {{ inline_admin_formset.opts.verbose_name }}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function increment_fields(el) {
|
|
||||||
el.attr('id', el.attr('id').replace(/-(\d+)-/, function (num) {
|
|
||||||
var newnum = parseInt(num.replace(/-/g,''))+1;
|
|
||||||
return '-' + newnum + '-';
|
|
||||||
}));
|
|
||||||
|
|
||||||
el.attr('name', el.attr('name').replace(/-(\d+)-/, function (num) {
|
|
||||||
var newnum = parseInt(num.replace(/-/g,''))+1;
|
|
||||||
return '-' + newnum + '-';
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
var id_prefix = "{{ inline_admin_formset.opts.verbose_name }}";
|
var prefix = "{{ inline_admin_formset.opts.verbose_name }}";
|
||||||
var total_forms = $('#' + id_prefix + '-group input[id$="TOTAL_FORMS"]');
|
var id_prefix = "#" + prefix;
|
||||||
var initial_forms = $('#' + id_prefix + '-group').find('input[id$="INITIAL_FORMS"]');
|
var total_forms = $(id_prefix + '-group input[id$="TOTAL_FORMS"]');
|
||||||
|
var initial_forms = $(id_prefix + '-group').find('input[id$="INITIAL_FORMS"]');
|
||||||
|
|
||||||
// since javascript is turned on, unhide the "add new <inline>" link and hide the extras
|
// since javascript is turned on, unhide the "add new <inline>" link
|
||||||
$('.add_inline').show();
|
$('.add_inline').show();
|
||||||
|
|
||||||
if (parseInt(initial_forms.val()) > 0) {
|
// hide the extras, but only if there were no form errors
|
||||||
$('#' + id_prefix + '-group .inline-related:gt(' + (initial_forms.val() - 1) + ')').remove();
|
if (!$('.errornote').html()) {
|
||||||
}
|
if (parseInt(initial_forms.val()) > 0) {
|
||||||
else {
|
$(id_prefix + '-group .inline-related:gt(' + (initial_forms.val() - 1) + ')')
|
||||||
$('#' + id_prefix + '-group .inline-related:gt(0)').remove();
|
.not('.empty_form').remove();
|
||||||
$('#' + id_prefix + '-group .inline-related:first').hide();
|
}
|
||||||
}
|
else {
|
||||||
|
$(id_prefix + '-group .inline-related').not('.empty_form').remove();
|
||||||
total_forms.val(parseInt(initial_forms.val()));
|
|
||||||
|
|
||||||
// clicking on the "add" link will add a blank form to add a new inline object
|
|
||||||
$('#' + id_prefix + "-add").click(function() {
|
|
||||||
if (parseInt(total_forms.val()) == 0) {
|
|
||||||
$('#' + id_prefix + '-group .inline-related:first').fadeIn('normal');
|
|
||||||
total_forms.val(parseInt(total_forms.val()) + 1);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var last_inline = $('#' + id_prefix + '-group .inline-related:last');
|
total_forms.val(parseInt(initial_forms.val()));
|
||||||
var new_inline = last_inline.clone(true).hide().insertAfter(last_inline).fadeIn('normal');
|
}
|
||||||
|
|
||||||
new_inline.find('input, select').each(function(i) {
|
$(id_prefix + "-add").click(function() {
|
||||||
increment_fields($(this));
|
var new_inline = $(id_prefix + '-empty').clone(true)
|
||||||
$(this).val("");
|
.insertBefore(id_prefix + '-addinline').fadeIn('normal');
|
||||||
});
|
|
||||||
|
var inline_template = $(new_inline).html();
|
||||||
|
var new_inline_html = inline_template.replace(/__prefix__/g, total_forms.val().toString());
|
||||||
|
|
||||||
total_forms.val(parseInt(total_forms.val()) + 1);
|
total_forms.val(parseInt(total_forms.val()) + 1);
|
||||||
|
|
||||||
new_inline.find(".inline_label").text('#' + total_forms.val());
|
$(new_inline).html(new_inline_html);
|
||||||
|
$(new_inline).attr('id', prefix + total_forms.val().toString());
|
||||||
|
$(new_inline).find('.inline_label').html('#' + total_forms.val().toString());
|
||||||
|
$(new_inline).removeClass('empty_form');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -118,6 +118,21 @@ class BaseFormSet(StrAndUnicode):
|
|||||||
return self.forms[self.initial_form_count():]
|
return self.forms[self.initial_form_count():]
|
||||||
extra_forms = property(_get_extra_forms)
|
extra_forms = property(_get_extra_forms)
|
||||||
|
|
||||||
|
def _get_empty_form(self, **kwargs):
|
||||||
|
defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix("__prefix__")}
|
||||||
|
if self.data or self.files:
|
||||||
|
defaults['data'] = self.data
|
||||||
|
defaults['files'] = self.files
|
||||||
|
|
||||||
|
defaults['empty_permitted'] = True
|
||||||
|
defaults.update(kwargs)
|
||||||
|
|
||||||
|
form = self.form(**defaults)
|
||||||
|
self.add_fields(form, None)
|
||||||
|
|
||||||
|
return form
|
||||||
|
empty_form = property(_get_empty_form)
|
||||||
|
|
||||||
# Maybe this should just go away?
|
# Maybe this should just go away?
|
||||||
def _get_cleaned_data(self):
|
def _get_cleaned_data(self):
|
||||||
"""
|
"""
|
||||||
@ -133,7 +148,7 @@ class BaseFormSet(StrAndUnicode):
|
|||||||
Returns a list of forms that have been marked for deletion. Raises an
|
Returns a list of forms that have been marked for deletion. Raises an
|
||||||
AttributeError if deletion is not allowed.
|
AttributeError if deletion is not allowed.
|
||||||
"""
|
"""
|
||||||
if not self.can_delete:
|
if not self.is_valid or not self.can_delete:
|
||||||
raise AttributeError("'%s' object has no attribute 'deleted_forms'" % self.__class__.__name__)
|
raise AttributeError("'%s' object has no attribute 'deleted_forms'" % self.__class__.__name__)
|
||||||
# construct _deleted_form_indexes which is just a list of form indexes
|
# construct _deleted_form_indexes which is just a list of form indexes
|
||||||
# that have had their deletion widget set to True
|
# that have had their deletion widget set to True
|
||||||
@ -154,7 +169,7 @@ class BaseFormSet(StrAndUnicode):
|
|||||||
Returns a list of form in the order specified by the incoming data.
|
Returns a list of form in the order specified by the incoming data.
|
||||||
Raises an AttributeError if ordering is not allowed.
|
Raises an AttributeError if ordering is not allowed.
|
||||||
"""
|
"""
|
||||||
if not self.can_order:
|
if not self.is_valid or not self.can_order:
|
||||||
raise AttributeError("'%s' object has no attribute 'ordered_forms'" % self.__class__.__name__)
|
raise AttributeError("'%s' object has no attribute 'ordered_forms'" % self.__class__.__name__)
|
||||||
# Construct _ordering, which is a list of (form_index, order_field_value)
|
# Construct _ordering, which is a list of (form_index, order_field_value)
|
||||||
# tuples. After constructing this list, we'll sort it by order_field_value
|
# tuples. After constructing this list, we'll sort it by order_field_value
|
||||||
@ -267,7 +282,7 @@ class BaseFormSet(StrAndUnicode):
|
|||||||
"""A hook for adding extra fields on to each form instance."""
|
"""A hook for adding extra fields on to each form instance."""
|
||||||
if self.can_order:
|
if self.can_order:
|
||||||
# Only pre-fill the ordering field for initial forms.
|
# Only pre-fill the ordering field for initial forms.
|
||||||
if index < self.initial_form_count():
|
if index != None and index < self.initial_form_count():
|
||||||
form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), initial=index+1, required=False)
|
form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), initial=index+1, required=False)
|
||||||
else:
|
else:
|
||||||
form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), required=False)
|
form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_(u'Order'), required=False)
|
||||||
|
@ -664,7 +664,10 @@ class BaseModelFormSet(BaseFormSet):
|
|||||||
or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk)))
|
or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk)))
|
||||||
if pk_is_not_editable(pk) or pk.name not in form.fields:
|
if pk_is_not_editable(pk) or pk.name not in form.fields:
|
||||||
try:
|
try:
|
||||||
pk_value = self.get_queryset()[index].pk
|
if index:
|
||||||
|
pk_value = self.get_queryset()[index].pk
|
||||||
|
else:
|
||||||
|
pk_value = None
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pk_value = None
|
pk_value = None
|
||||||
if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
|
if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user