Fixed #13068, #9264, #9983, #9784 - regression with pre-populated fields and javascript inlines, and related bugs.
Thanks to hejsan for the report, and to Sean Brant and Carl Meyer for the patch. #13068 is a regression caused by the new javascript inline forms in the admin. The others were existing javascript bugs with prepopulated fields. Since the solution depends on jQuery and would likely be very hard to backport without it, it will not be backported to 1.1.X. git-svn-id: http://code.djangoproject.com/svn/django/trunk@12937 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
97b9c7582b
commit
736b751ed9
|
@ -120,6 +120,7 @@ var DateTimeShortcuts = {
|
||||||
},
|
},
|
||||||
handleClockQuicklink: function(num, val) {
|
handleClockQuicklink: function(num, val) {
|
||||||
DateTimeShortcuts.clockInputs[num].value = val;
|
DateTimeShortcuts.clockInputs[num].value = val;
|
||||||
|
DateTimeShortcuts.clockInputs[num].focus();
|
||||||
DateTimeShortcuts.dismissClock(num);
|
DateTimeShortcuts.dismissClock(num);
|
||||||
},
|
},
|
||||||
// Add calendar widget to a given field.
|
// Add calendar widget to a given field.
|
||||||
|
@ -247,12 +248,21 @@ var DateTimeShortcuts = {
|
||||||
format = format.replace('\n', '\\n');
|
format = format.replace('\n', '\\n');
|
||||||
format = format.replace('\t', '\\t');
|
format = format.replace('\t', '\\t');
|
||||||
format = format.replace("'", "\\'");
|
format = format.replace("'", "\\'");
|
||||||
return "function(y, m, d) { DateTimeShortcuts.calendarInputs["+num+"].value = new Date(y, m-1, d).strftime('"+format+"');document.getElementById(DateTimeShortcuts.calendarDivName1+"+num+").style.display='none';}";
|
return ["function(y, m, d) { DateTimeShortcuts.calendarInputs[",
|
||||||
|
num,
|
||||||
|
"].value = new Date(y, m-1, d).strftime('",
|
||||||
|
format,
|
||||||
|
"');DateTimeShortcuts.calendarInputs[",
|
||||||
|
num,
|
||||||
|
"].focus();document.getElementById(DateTimeShortcuts.calendarDivName1+",
|
||||||
|
num,
|
||||||
|
").style.display='none';}"].join('');
|
||||||
},
|
},
|
||||||
handleCalendarQuickLink: function(num, offset) {
|
handleCalendarQuickLink: function(num, offset) {
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
d.setDate(d.getDate() + offset)
|
d.setDate(d.getDate() + offset)
|
||||||
DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
|
DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
|
||||||
|
DateTimeShortcuts.calendarInputs[num].focus();
|
||||||
DateTimeShortcuts.dismissCalendar(num);
|
DateTimeShortcuts.dismissCalendar(num);
|
||||||
},
|
},
|
||||||
cancelEventPropagation: function(e) {
|
cancelEventPropagation: function(e) {
|
||||||
|
|
|
@ -55,24 +55,41 @@
|
||||||
var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
|
var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
|
||||||
var nextIndex = parseInt(totalForms.val());
|
var nextIndex = parseInt(totalForms.val());
|
||||||
var template = $("#" + options.prefix + "-empty");
|
var template = $("#" + options.prefix + "-empty");
|
||||||
var row = template.clone(true).get(0);
|
var row = template.clone(true);
|
||||||
$(row).removeClass(options.emptyCssClass).removeAttr("id").insertBefore($(template));
|
row.removeClass(options.emptyCssClass)
|
||||||
$(row).html($(row).html().replace(/__prefix__/g, nextIndex));
|
.addClass(options.formCssClass)
|
||||||
$(row).addClass(options.formCssClass).attr("id", options.prefix + (nextIndex + 1));
|
.attr("id", options.prefix + nextIndex)
|
||||||
if ($(row).is("TR")) {
|
.insertBefore($(template));
|
||||||
|
row.find("*")
|
||||||
|
.filter(function() {
|
||||||
|
var el = $(this);
|
||||||
|
return el.attr("id") && el.attr("id").search(/__prefix__/) >= 0;
|
||||||
|
}).each(function() {
|
||||||
|
var el = $(this);
|
||||||
|
el.attr("id", el.attr("id").replace(/__prefix__/g, nextIndex));
|
||||||
|
})
|
||||||
|
.end()
|
||||||
|
.filter(function() {
|
||||||
|
var el = $(this);
|
||||||
|
return el.attr("name") && el.attr("name").search(/__prefix__/) >= 0;
|
||||||
|
}).each(function() {
|
||||||
|
var el = $(this);
|
||||||
|
el.attr("name", el.attr("name").replace(/__prefix__/g, nextIndex));
|
||||||
|
});
|
||||||
|
if (row.is("tr")) {
|
||||||
// If the forms are laid out in table rows, insert
|
// If the forms are laid out in table rows, insert
|
||||||
// the remove button into the last table cell:
|
// the remove button into the last table cell:
|
||||||
$(row).children(":last").append('<div><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></div>");
|
row.children(":last").append('<div><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></div>");
|
||||||
} else if ($(row).is("UL") || $(row).is("OL")) {
|
} else if (row.is("ul") || row.is("ol")) {
|
||||||
// If they're laid out as an ordered/unordered list,
|
// If they're laid out as an ordered/unordered list,
|
||||||
// insert an <li> after the last list item:
|
// insert an <li> after the last list item:
|
||||||
$(row).append('<li><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></li>");
|
row.append('<li><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></li>");
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, just insert the remove button as the
|
// Otherwise, just insert the remove button as the
|
||||||
// last child element of the form's container:
|
// last child element of the form's container:
|
||||||
$(row).children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>");
|
row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>");
|
||||||
}
|
}
|
||||||
$(row).find("input,select,textarea,label,a").each(function() {
|
row.find("input,select,textarea,label,a").each(function() {
|
||||||
updateElementIndex(this, options.prefix, totalForms.val());
|
updateElementIndex(this, options.prefix, totalForms.val());
|
||||||
});
|
});
|
||||||
// Update number of total forms
|
// Update number of total forms
|
||||||
|
@ -82,7 +99,7 @@
|
||||||
addButton.parent().hide();
|
addButton.parent().hide();
|
||||||
}
|
}
|
||||||
// The delete button of each row triggers a bunch of other things
|
// The delete button of each row triggers a bunch of other things
|
||||||
$(row).find("a." + options.deleteCssClass).click(function() {
|
row.find("a." + options.deleteCssClass).click(function() {
|
||||||
// Remove the parent form containing this button:
|
// Remove the parent form containing this button:
|
||||||
var row = $(this).parents("." + options.formCssClass);
|
var row = $(this).parents("." + options.formCssClass);
|
||||||
row.remove();
|
row.remove();
|
||||||
|
@ -109,7 +126,7 @@
|
||||||
});
|
});
|
||||||
// If a post-add callback was supplied, call it with the added form:
|
// If a post-add callback was supplied, call it with the added form:
|
||||||
if (options.added) {
|
if (options.added) {
|
||||||
options.added($(row));
|
options.added(row);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
(function(a){a.fn.formset=function(f){var b=a.extend({},a.fn.formset.defaults,f),l=function(d,e,j){var c=new RegExp("("+e+"-\\d+)");e=e+"-"+j;a(d).attr("for")&&a(d).attr("for",a(d).attr("for").replace(c,e));if(d.id)d.id=d.id.replace(c,e);if(d.name)d.name=d.name.replace(c,e)};f=a("#id_"+b.prefix+"-TOTAL_FORMS").attr("autocomplete","off");var h=a("#id_"+b.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off");f=h.val()==""||h.val()-f.val()>0;a(this).each(function(){a(this).not("."+b.emptyCssClass).addClass(b.formCssClass)});
|
(function(a){a.fn.formset=function(g){var b=a.extend({},a.fn.formset.defaults,g),l=function(e,f,j){var d=new RegExp("("+f+"-\\d+)");f=f+"-"+j;a(e).attr("for")&&a(e).attr("for",a(e).attr("for").replace(d,f));if(e.id)e.id=e.id.replace(d,f);if(e.name)e.name=e.name.replace(d,f)};g=a("#id_"+b.prefix+"-TOTAL_FORMS").attr("autocomplete","off");var h=a("#id_"+b.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off");g=h.val()==""||h.val()-g.val()>0;a(this).each(function(){a(this).not("."+b.emptyCssClass).addClass(b.formCssClass)});
|
||||||
if(a(this).length&&f){var i;if(a(this).attr("tagName")=="TR"){f=this.eq(0).children().length;a(this).parent().append('<tr class="'+b.addCssClass+'"><td colspan="'+f+'"><a href="javascript:void(0)">'+b.addText+"</a></tr>");i=a(this).parent().find("tr:last a")}else{a(this).filter(":last").after('<div class="'+b.addCssClass+'"><a href="javascript:void(0)">'+b.addText+"</a></div>");i=a(this).filter(":last").next().find("a")}i.click(function(){var d=a("#id_"+b.prefix+"-TOTAL_FORMS"),e=parseInt(d.val()),
|
if(a(this).length&&g){var i;if(a(this).attr("tagName")=="TR"){g=this.eq(0).children().length;a(this).parent().append('<tr class="'+b.addCssClass+'"><td colspan="'+g+'"><a href="javascript:void(0)">'+b.addText+"</a></tr>");i=a(this).parent().find("tr:last a")}else{a(this).filter(":last").after('<div class="'+b.addCssClass+'"><a href="javascript:void(0)">'+b.addText+"</a></div>");i=a(this).filter(":last").next().find("a")}i.click(function(){var e=a("#id_"+b.prefix+"-TOTAL_FORMS"),f=parseInt(e.val()),
|
||||||
j=a("#"+b.prefix+"-empty"),c=j.clone(true).get(0);a(c).removeClass(b.emptyCssClass).removeAttr("id").insertBefore(a(j));a(c).html(a(c).html().replace(/__prefix__/g,e));a(c).addClass(b.formCssClass).attr("id",b.prefix+(e+1));if(a(c).is("TR"))a(c).children(":last").append('<div><a class="'+b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></div>");else a(c).is("UL")||a(c).is("OL")?a(c).append('<li><a class="'+b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></li>"):
|
j=a("#"+b.prefix+"-empty"),d=j.clone(true);d.removeClass(b.emptyCssClass).addClass(b.formCssClass).attr("id",b.prefix+f).insertBefore(a(j));d.find("*").filter(function(){var c=a(this);return c.attr("id")&&c.attr("id").search(/__prefix__/)>=0}).each(function(){var c=a(this);c.attr("id",c.attr("id").replace(/__prefix__/g,f))}).end().filter(function(){var c=a(this);return c.attr("name")&&c.attr("name").search(/__prefix__/)>=0}).each(function(){var c=a(this);c.attr("name",c.attr("name").replace(/__prefix__/g,
|
||||||
a(c).children(":first").append('<span><a class="'+b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></span>");a(c).find("input,select,textarea,label,a").each(function(){l(this,b.prefix,d.val())});a(d).val(e+1);h.val()!=""&&h.val()<=d.val()&&i.parent().hide();a(c).find("a."+b.deleteCssClass).click(function(){var g=a(this).parents("."+b.formCssClass);g.remove();b.removed&&b.removed(g);g=a("."+b.formCssClass);a("#id_"+b.prefix+"-TOTAL_FORMS").val(g.length);if(h.val()==""||h.val()>=g.length)i.parent().show();
|
f))});if(d.is("tr"))d.children(":last").append('<div><a class="'+b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></div>");else d.is("ul")||d.is("ol")?d.append('<li><a class="'+b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></li>"):d.children(":first").append('<span><a class="'+b.deleteCssClass+'" href="javascript:void(0)">'+b.deleteText+"</a></span>");d.find("input,select,textarea,label,a").each(function(){l(this,b.prefix,e.val())});a(e).val(f+1);h.val()!=""&&
|
||||||
for(var k=0,m=g.length;k<m;k++)a(g.get(k)).find("input,select,textarea,label,a").each(function(){l(this,b.prefix,k)});return false});b.added&&b.added(a(c));return false})}return this};a.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}})(jQuery);
|
h.val()<=e.val()&&i.parent().hide();d.find("a."+b.deleteCssClass).click(function(){var c=a(this).parents("."+b.formCssClass);c.remove();b.removed&&b.removed(c);c=a("."+b.formCssClass);a("#id_"+b.prefix+"-TOTAL_FORMS").val(c.length);if(h.val()==""||h.val()>=c.length)i.parent().show();for(var k=0,m=c.length;k<m;k++)a(c.get(k)).find("input,select,textarea,label,a").each(function(){l(this,b.prefix,k)});return false});b.added&&b.added(d);return false})}return this};a.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}})(jQuery);
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
(function($) {
|
||||||
|
$.fn.prepopulate = function(dependencies, maxLength) {
|
||||||
|
/*
|
||||||
|
Depends on urlify.js
|
||||||
|
Populates a selected field with the values of the dependent fields,
|
||||||
|
URLifies and shortens the string.
|
||||||
|
dependencies - selected jQuery object of dependent fields
|
||||||
|
maxLength - maximum length of the URLify'd string
|
||||||
|
*/
|
||||||
|
return this.each(function() {
|
||||||
|
var field = $(this);
|
||||||
|
|
||||||
|
field.data('_changed', false);
|
||||||
|
field.change(function() {
|
||||||
|
field.data('_changed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
var populate = function () {
|
||||||
|
// Bail if the fields value has changed
|
||||||
|
if (field.data('_changed') == true) return;
|
||||||
|
|
||||||
|
var values = [];
|
||||||
|
dependencies.each(function() {
|
||||||
|
if ($(this).val().length > 0) {
|
||||||
|
values.push($(this).val());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
field.val(URLify(values.join(' '), maxLength));
|
||||||
|
};
|
||||||
|
|
||||||
|
dependencies.keyup(populate).change(populate).focus(populate);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})(jQuery.noConflict());
|
|
@ -274,6 +274,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
js.extend(['js/jquery.min.js', 'js/actions.min.js'])
|
js.extend(['js/jquery.min.js', 'js/actions.min.js'])
|
||||||
if self.prepopulated_fields:
|
if self.prepopulated_fields:
|
||||||
js.append('js/urlify.js')
|
js.append('js/urlify.js')
|
||||||
|
js.append('js/prepopulate.js')
|
||||||
if self.opts.get_ordered_objects():
|
if self.opts.get_ordered_objects():
|
||||||
js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
|
js.extend(['js/getElementsBySelector.js', 'js/dom-drag.js' , 'js/admin/ordering.js'])
|
||||||
|
|
||||||
|
@ -1201,6 +1202,7 @@ class InlineModelAdmin(BaseModelAdmin):
|
||||||
js = ['js/jquery.min.js', 'js/inlines.min.js']
|
js = ['js/jquery.min.js', 'js/inlines.min.js']
|
||||||
if self.prepopulated_fields:
|
if self.prepopulated_fields:
|
||||||
js.append('js/urlify.js')
|
js.append('js/urlify.js')
|
||||||
|
js.append('js/prepopulate.js')
|
||||||
if self.filter_vertical or self.filter_horizontal:
|
if self.filter_vertical or self.filter_horizontal:
|
||||||
js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
|
js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
|
||||||
return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
|
return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
|
||||||
|
|
|
@ -48,6 +48,17 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var initPrepopulatedFields = function(row) {
|
||||||
|
row.find('.prepopulated_field').each(function() {
|
||||||
|
var field = $(this);
|
||||||
|
var input = field.find('input, select, textarea');
|
||||||
|
var dependency_list = input.data('dependency_list') || [];
|
||||||
|
var dependencies = row.find(dependency_list.join(',')).find('input, select, textarea');
|
||||||
|
if (dependencies.length) {
|
||||||
|
input.prepopulate(dependencies, input.attr('maxlength'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
$(rows).formset({
|
$(rows).formset({
|
||||||
prefix: "{{ inline_admin_formset.formset.prefix }}",
|
prefix: "{{ inline_admin_formset.formset.prefix }}",
|
||||||
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
|
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
|
||||||
|
@ -57,6 +68,7 @@
|
||||||
emptyCssClass: "empty-form",
|
emptyCssClass: "empty-form",
|
||||||
removed: updateInlineLabel,
|
removed: updateInlineLabel,
|
||||||
added: (function(row) {
|
added: (function(row) {
|
||||||
|
initPrepopulatedFields(row);
|
||||||
reinitDateTimeShortCuts();
|
reinitDateTimeShortCuts();
|
||||||
updateSelectFilter();
|
updateSelectFilter();
|
||||||
updateInlineLabel(row);
|
updateInlineLabel(row);
|
||||||
|
|
|
@ -94,6 +94,17 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var initPrepopulatedFields = function(row) {
|
||||||
|
row.find('.prepopulated_field').each(function() {
|
||||||
|
var field = $(this);
|
||||||
|
var input = field.find('input, select, textarea');
|
||||||
|
var dependency_list = input.data('dependency_list') || [];
|
||||||
|
var dependencies = row.find(dependency_list.join(',')).find('input, select, textarea');
|
||||||
|
if (dependencies.length) {
|
||||||
|
input.prepopulate(dependencies, input.attr('maxlength'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
$(rows).formset({
|
$(rows).formset({
|
||||||
prefix: "{{ inline_admin_formset.formset.prefix }}",
|
prefix: "{{ inline_admin_formset.formset.prefix }}",
|
||||||
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
|
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
|
||||||
|
@ -103,6 +114,7 @@
|
||||||
emptyCssClass: "empty-form",
|
emptyCssClass: "empty-form",
|
||||||
removed: alternatingRows,
|
removed: alternatingRows,
|
||||||
added: (function(row) {
|
added: (function(row) {
|
||||||
|
initPrepopulatedFields(row);
|
||||||
reinitDateTimeShortCuts();
|
reinitDateTimeShortCuts();
|
||||||
updateSelectFilter();
|
updateSelectFilter();
|
||||||
alternatingRows(row);
|
alternatingRows(row);
|
||||||
|
|
|
@ -1,11 +1,23 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
(function($) {
|
||||||
|
var field = null;
|
||||||
|
|
||||||
{% for field in prepopulated_fields %}
|
{% for field in prepopulated_fields %}
|
||||||
document.getElementById("{{ field.field.auto_id }}").onchange = function() { this._changed = true; };
|
field = {
|
||||||
|
id: '#{{ field.field.auto_id }}',
|
||||||
|
dependency_ids: [],
|
||||||
|
dependency_list: [],
|
||||||
|
maxLength: {{ field.field.field.max_length|default_if_none:"50" }}
|
||||||
|
};
|
||||||
|
|
||||||
{% for dependency in field.dependencies %}
|
{% for dependency in field.dependencies %}
|
||||||
document.getElementById("{{ dependency.auto_id }}").onkeyup = function() {
|
field['dependency_ids'].push('#{{ dependency.auto_id }}');
|
||||||
var e = document.getElementById("{{ field.field.auto_id }}");
|
field['dependency_list'].push('.{{ dependency.name }}');
|
||||||
if (!e._changed) { e.value = URLify({% for innerdep in field.dependencies %}document.getElementById("{{ innerdep.auto_id }}").value{% if not forloop.last %} + ' ' + {% endif %}{% endfor %}, {{ field.field.field.max_length|default_if_none:"50" }}); }
|
|
||||||
}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
$('.empty-form .{{ field.field.name }}').addClass('prepopulated_field');
|
||||||
|
$(field.id).data('dependency_list', field['dependency_list'])
|
||||||
|
.prepopulate($(field['dependency_ids'].join(',')), field.maxLength);
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
})(jQuery.noConflict());
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue