diff --git a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js
index fbaa599c7a..d840f78729 100644
--- a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js
+++ b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js
@@ -120,6 +120,7 @@ var DateTimeShortcuts = {
},
handleClockQuicklink: function(num, val) {
DateTimeShortcuts.clockInputs[num].value = val;
+ DateTimeShortcuts.clockInputs[num].focus();
DateTimeShortcuts.dismissClock(num);
},
// Add calendar widget to a given field.
@@ -247,12 +248,21 @@ var DateTimeShortcuts = {
format = format.replace('\n', '\\n');
format = format.replace('\t', '\\t');
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) {
var d = new Date();
d.setDate(d.getDate() + offset)
DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
+ DateTimeShortcuts.calendarInputs[num].focus();
DateTimeShortcuts.dismissCalendar(num);
},
cancelEventPropagation: function(e) {
diff --git a/django/contrib/admin/media/js/inlines.js b/django/contrib/admin/media/js/inlines.js
index 55118dfc4b..9decaae444 100644
--- a/django/contrib/admin/media/js/inlines.js
+++ b/django/contrib/admin/media/js/inlines.js
@@ -55,24 +55,41 @@
var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
var nextIndex = parseInt(totalForms.val());
var template = $("#" + options.prefix + "-empty");
- var row = template.clone(true).get(0);
- $(row).removeClass(options.emptyCssClass).removeAttr("id").insertBefore($(template));
- $(row).html($(row).html().replace(/__prefix__/g, nextIndex));
- $(row).addClass(options.formCssClass).attr("id", options.prefix + (nextIndex + 1));
- if ($(row).is("TR")) {
+ var row = template.clone(true);
+ row.removeClass(options.emptyCssClass)
+ .addClass(options.formCssClass)
+ .attr("id", options.prefix + nextIndex)
+ .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
// the remove button into the last table cell:
- $(row).children(":last").append('
");
- } else if ($(row).is("UL") || $(row).is("OL")) {
+ row.children(":last").append('");
+ } else if (row.is("ul") || row.is("ol")) {
// If they're laid out as an ordered/unordered list,
// insert an after the last list item:
- $(row).append('' + options.deleteText + "");
+ row.append('' + options.deleteText + "");
} else {
// Otherwise, just insert the remove button as the
// last child element of the form's container:
- $(row).children(":first").append('' + options.deleteText + "");
+ row.children(":first").append('' + options.deleteText + "");
}
- $(row).find("input,select,textarea,label,a").each(function() {
+ row.find("input,select,textarea,label,a").each(function() {
updateElementIndex(this, options.prefix, totalForms.val());
});
// Update number of total forms
@@ -82,7 +99,7 @@
addButton.parent().hide();
}
// 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:
var row = $(this).parents("." + options.formCssClass);
row.remove();
@@ -109,7 +126,7 @@
});
// If a post-add callback was supplied, call it with the added form:
if (options.added) {
- options.added($(row));
+ options.added(row);
}
return false;
});
diff --git a/django/contrib/admin/media/js/inlines.min.js b/django/contrib/admin/media/js/inlines.min.js
index 29e048df54..891cc3fca5 100644
--- a/django/contrib/admin/media/js/inlines.min.js
+++ b/django/contrib/admin/media/js/inlines.min.js
@@ -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)});
-if(a(this).length&&f){var i;if(a(this).attr("tagName")=="TR"){f=this.eq(0).children().length;a(this).parent().append(''+b.addText+" |
");i=a(this).parent().find("tr:last a")}else{a(this).filter(":last").after('");i=a(this).filter(":last").next().find("a")}i.click(function(){var d=a("#id_"+b.prefix+"-TOTAL_FORMS"),e=parseInt(d.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('");else a(c).is("UL")||a(c).is("OL")?a(c).append(''+b.deleteText+""):
-a(c).children(":first").append(''+b.deleteText+"");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();
-for(var k=0,m=g.length;k0;a(this).each(function(){a(this).not("."+b.emptyCssClass).addClass(b.formCssClass)});
+if(a(this).length&&g){var i;if(a(this).attr("tagName")=="TR"){g=this.eq(0).children().length;a(this).parent().append(''+b.addText+" |
");i=a(this).parent().find("tr:last a")}else{a(this).filter(":last").after('");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"),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,
+f))});if(d.is("tr"))d.children(":last").append('");else d.is("ul")||d.is("ol")?d.append(''+b.deleteText+""):d.children(":first").append(''+b.deleteText+"");d.find("input,select,textarea,label,a").each(function(){l(this,b.prefix,e.val())});a(e).val(f+1);h.val()!=""&&
+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 0) {
+ values.push($(this).val());
+ }
+ });
+ field.val(URLify(values.join(' '), maxLength));
+ };
+
+ dependencies.keyup(populate).change(populate).focus(populate);
+ });
+ };
+})(jQuery.noConflict());
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 6f66893c26..ae90bce067 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -274,6 +274,7 @@ class ModelAdmin(BaseModelAdmin):
js.extend(['js/jquery.min.js', 'js/actions.min.js'])
if self.prepopulated_fields:
js.append('js/urlify.js')
+ js.append('js/prepopulate.js')
if self.opts.get_ordered_objects():
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']
if self.prepopulated_fields:
js.append('js/urlify.js')
+ js.append('js/prepopulate.js')
if self.filter_vertical or self.filter_horizontal:
js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
diff --git a/django/contrib/admin/templates/admin/edit_inline/stacked.html b/django/contrib/admin/templates/admin/edit_inline/stacked.html
index fb112a0166..6eb4492e49 100644
--- a/django/contrib/admin/templates/admin/edit_inline/stacked.html
+++ b/django/contrib/admin/templates/admin/edit_inline/stacked.html
@@ -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({
prefix: "{{ inline_admin_formset.formset.prefix }}",
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",
removed: updateInlineLabel,
added: (function(row) {
+ initPrepopulatedFields(row);
reinitDateTimeShortCuts();
updateSelectFilter();
updateInlineLabel(row);
diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html
index dc9552f454..48be38db5d 100644
--- a/django/contrib/admin/templates/admin/edit_inline/tabular.html
+++ b/django/contrib/admin/templates/admin/edit_inline/tabular.html
@@ -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({
prefix: "{{ inline_admin_formset.formset.prefix }}",
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",
removed: alternatingRows,
added: (function(row) {
+ initPrepopulatedFields(row);
reinitDateTimeShortCuts();
updateSelectFilter();
alternatingRows(row);
diff --git a/django/contrib/admin/templates/admin/prepopulated_fields_js.html b/django/contrib/admin/templates/admin/prepopulated_fields_js.html
index e1cdb9614e..f0eb471dfb 100644
--- a/django/contrib/admin/templates/admin/prepopulated_fields_js.html
+++ b/django/contrib/admin/templates/admin/prepopulated_fields_js.html
@@ -1,11 +1,23 @@