Index: django/contrib/admin/media/js/admin/DateTimeShortcuts.js
===================================================================
--- django/contrib/admin/media/js/admin/DateTimeShortcuts.js	(revision 12873)
+++ django/contrib/admin/media/js/admin/DateTimeShortcuts.js	(working copy)
@@ -120,6 +120,7 @@
     },
     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 @@
         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) {
Index: django/contrib/admin/media/js/prepopulate.js
===================================================================
--- django/contrib/admin/media/js/prepopulate.js	(revision 0)
+++ django/contrib/admin/media/js/prepopulate.js	(revision 0)
@@ -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());
Index: django/contrib/admin/media/js/inlines.js
===================================================================
--- django/contrib/admin/media/js/inlines.js	(revision 12873)
+++ django/contrib/admin/media/js/inlines.js	(working copy)
@@ -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('<div><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></div>");
-				} else if ($(row).is("UL") || $(row).is("OL")) {
+					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")) {
 					// If they're laid out as an ordered/unordered list,
 					// 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 {
 					// Otherwise, just insert the remove button as the
 					// 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());
 				});
 				// 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;
 			});
Index: django/contrib/admin/options.py
===================================================================
--- django/contrib/admin/options.py	(revision 12873)
+++ django/contrib/admin/options.py	(working copy)
@@ -273,6 +273,7 @@
             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'])
 
@@ -1197,9 +1198,10 @@
 
     def _media(self):
         from django.conf import settings
-        js = ['js/jquery.min.js', 'js/inlines.min.js']
+        js = ['js/jquery.min.js', 'js/inlines.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])
Index: django/contrib/admin/templates/admin/edit_inline/stacked.html
===================================================================
--- django/contrib/admin/templates/admin/edit_inline/stacked.html	(revision 12873)
+++ django/contrib/admin/templates/admin/edit_inline/stacked.html	(working copy)
@@ -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);
Index: django/contrib/admin/templates/admin/edit_inline/tabular.html
===================================================================
--- django/contrib/admin/templates/admin/edit_inline/tabular.html	(revision 12873)
+++ django/contrib/admin/templates/admin/edit_inline/tabular.html	(working copy)
@@ -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);
Index: django/contrib/admin/templates/admin/prepopulated_fields_js.html
===================================================================
--- django/contrib/admin/templates/admin/prepopulated_fields_js.html	(revision 12873)
+++ django/contrib/admin/templates/admin/prepopulated_fields_js.html	(working copy)
@@ -1,11 +1,23 @@
 <script type="text/javascript">
+(function($) {
+    var field = null;
+
 {% 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 %}
-    document.getElementById("{{ dependency.auto_id }}").onkeyup = function() {
-        var e = document.getElementById("{{ field.field.auto_id }}");
-        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" }}); }
-    }
+    field['dependency_ids'].push('#{{ dependency.auto_id }}');
+    field['dependency_list'].push('.{{ dependency.name }}');
     {% 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 %}
+})(jQuery.noConflict());
 </script>
