Index: django/contrib/admin/media/css/widgets.css
===================================================================
--- django/contrib/admin/media/css/widgets.css	(revision 15800)
+++ django/contrib/admin/media/css/widgets.css	(working copy)
@@ -333,7 +333,8 @@
     right: 0;
 }
 
-.calendar-cancel {
+.calendar-cancel,
+.clock-cancel {
     margin: 0 !important;
     padding: 0;
     font-size: 10px;
Index: django/contrib/admin/media/js/calendar.js
===================================================================
--- django/contrib/admin/media/js/calendar.js	(revision 15800)
+++ django/contrib/admin/media/js/calendar.js	(working copy)
@@ -1,156 +0,0 @@
-/*
-calendar.js - Calendar functions by Adrian Holovaty
-*/
-
-function removeChildren(a) { // "a" is reference to an object
-    while (a.hasChildNodes()) a.removeChild(a.lastChild);
-}
-
-// quickElement(tagType, parentReference, textInChildNode, [, attribute, attributeValue ...]);
-function quickElement() {
-    var obj = document.createElement(arguments[0]);
-    if (arguments[2] != '' && arguments[2] != null) {
-        var textNode = document.createTextNode(arguments[2]);
-        obj.appendChild(textNode);
-    }
-    var len = arguments.length;
-    for (var i = 3; i < len; i += 2) {
-        obj.setAttribute(arguments[i], arguments[i+1]);
-    }
-    arguments[1].appendChild(obj);
-    return obj;
-}
-
-// CalendarNamespace -- Provides a collection of HTML calendar-related helper functions
-var CalendarNamespace = {
-    monthsOfYear: gettext('January February March April May June July August September October November December').split(' '),
-    daysOfWeek: gettext('S M T W T F S').split(' '),
-    firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')),
-    isLeapYear: function(year) {
-        return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0));
-    },
-    getDaysInMonth: function(month,year) {
-        var days;
-        if (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) {
-            days = 31;
-        }
-        else if (month==4 || month==6 || month==9 || month==11) {
-            days = 30;
-        }
-        else if (month==2 && CalendarNamespace.isLeapYear(year)) {
-            days = 29;
-        }
-        else {
-            days = 28;
-        }
-        return days;
-    },
-    draw: function(month, year, div_id, callback) { // month = 1-12, year = 1-9999
-        var today = new Date();
-        var todayDay = today.getDate();
-        var todayMonth = today.getMonth()+1;
-        var todayYear = today.getFullYear();
-        var todayClass = '';
-
-        month = parseInt(month);
-        year = parseInt(year);
-        var calDiv = document.getElementById(div_id);
-        removeChildren(calDiv);
-        var calTable = document.createElement('table');
-        quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month-1] + ' ' + year);
-        var tableBody = quickElement('tbody', calTable);
-
-        // Draw days-of-week header
-        var tableRow = quickElement('tr', tableBody);
-        for (var i = 0; i < 7; i++) {
-            quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]);
-        }
-
-        var startingPos = new Date(year, month-1, 1 - CalendarNamespace.firstDayOfWeek).getDay();
-        var days = CalendarNamespace.getDaysInMonth(month, year);
-
-        // Draw blanks before first of month
-        tableRow = quickElement('tr', tableBody);
-        for (var i = 0; i < startingPos; i++) {
-            var _cell = quickElement('td', tableRow, ' ');
-            _cell.style.backgroundColor = '#f3f3f3';
-        }
-
-        // Draw days of month
-        var currentDay = 1;
-        for (var i = startingPos; currentDay <= days; i++) {
-            if (i%7 == 0 && currentDay != 1) {
-                tableRow = quickElement('tr', tableBody);
-            }
-            if ((currentDay==todayDay) && (month==todayMonth) && (year==todayYear)) {
-                todayClass='today';
-            } else {
-                todayClass='';
-            }
-            var cell = quickElement('td', tableRow, '', 'class', todayClass);
-
-            quickElement('a', cell, currentDay, 'href', 'javascript:void(' + callback + '('+year+','+month+','+currentDay+'));');
-            currentDay++;
-        }
-
-        // Draw blanks after end of month (optional, but makes for valid code)
-        while (tableRow.childNodes.length < 7) {
-            var _cell = quickElement('td', tableRow, ' ');
-            _cell.style.backgroundColor = '#f3f3f3';
-        }
-
-        calDiv.appendChild(calTable);
-    }
-}
-
-// Calendar -- A calendar instance
-function Calendar(div_id, callback) {
-    // div_id (string) is the ID of the element in which the calendar will
-    //     be displayed
-    // callback (string) is the name of a JavaScript function that will be
-    //     called with the parameters (year, month, day) when a day in the
-    //     calendar is clicked
-    this.div_id = div_id;
-    this.callback = callback;
-    this.today = new Date();
-    this.currentMonth = this.today.getMonth() + 1;
-    this.currentYear = this.today.getFullYear();
-}
-Calendar.prototype = {
-    drawCurrent: function() {
-        CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback);
-    },
-    drawDate: function(month, year) {
-        this.currentMonth = month;
-        this.currentYear = year;
-        this.drawCurrent();
-    },
-    drawPreviousMonth: function() {
-        if (this.currentMonth == 1) {
-            this.currentMonth = 12;
-            this.currentYear--;
-        }
-        else {
-            this.currentMonth--;
-        }
-        this.drawCurrent();
-    },
-    drawNextMonth: function() {
-        if (this.currentMonth == 12) {
-            this.currentMonth = 1;
-            this.currentYear++;
-        }
-        else {
-            this.currentMonth++;
-        }
-        this.drawCurrent();
-    },
-    drawPreviousYear: function() {
-        this.currentYear--;
-        this.drawCurrent();
-    },
-    drawNextYear: function() {
-        this.currentYear++;
-        this.drawCurrent();
-    }
-}
Index: django/contrib/admin/media/js/datetimeshortcuts.js
===================================================================
--- django/contrib/admin/media/js/datetimeshortcuts.js	(revision 0)
+++ django/contrib/admin/media/js/datetimeshortcuts.js	(revision 0)
@@ -0,0 +1,599 @@
+/**
+ * Django admin DateTime shortcuts
+ * 
+ * @requires jQuery 1.4.2 or later
+ *
+ * DateTimeShortcuts
+ * -----------------
+ * 
+ * Inserts shortcut buttons (clock and calendar) after all input:text fields
+ * having the classes .vDateField and .vTimeField.
+ *
+ * The $("selector").datetimeshortcuts() plugin is intended to be applied on
+ * fieldsets or whole forms which contain, or may later contain (inline
+ * fieldsets) date or time fields.
+ *
+ * All options as defined in datetimeshortcuts.defaults can be overwritten by
+ * passing them as array to the datetimeshortcuts() method.
+ *
+ */
+
+(function($) {
+    
+    $.fn.datetimeshortcuts = function(options) {
+        // variables set in base.html
+        var datetimeshortcuts_defaults = $('body').data('datetimeshortcuts_defaults');
+        
+        // extend default settings with user options
+        var o = $.extend({
+                admin_media_prefix: $('body').data('admin_media_prefix')
+            },
+            $.fn.datetimeshortcuts.defaults,
+            datetimeshortcuts_defaults,
+            options);
+        
+        // Check admin_media_prefix setting:
+        // usually set in admin/base.html template, but if that was overridden,
+        // it might be missing. Set it to something clearly invalid so that
+        // somebody might notice it.
+        if (o.admin_media_prefix == undefined) {
+            o.admin_media_prefix = '/missing-admin-media-prefix/';
+        }
+        
+        
+        /* --- utitity functions ------------------------------------------- */
+        
+        // month names
+        var month_names = gettext('January February March April May June July August September October November December').split(' ');
+        
+        // weekday names
+        var weekdays = gettext('S M T W T F S').split(' ');
+        
+        // first day of week
+        var first_day_of_week = parseInt(get_format('FIRST_DAY_OF_WEEK'));
+        
+        // find leap years
+        var is_leap_year = function(year) {
+            return new Date(year, 1, 29).getDate() == 29;
+        };
+        
+        // number of days in month
+        var get_days_in_month = function(month, year) {
+            return 32 - new Date(year, month-1, 32).getDate();
+        };
+        
+        
+        /* --- initialization functions ------------------------------------ */
+        
+        // add shortcuts for date fields
+        var add_calendar = function(element) {
+            // insert span.datetimeshortcuts
+            var shortcuts = $('<span class="'+o.class_shortcuts+'">').insertAfter(element);
+            
+            // insert today link
+            if (o.enable_today) {
+                shortcuts.append(' <a href="#" class="'+o.class_today+'">'+gettext('Today')+'</a>');
+                if (o.enable_calendar) {
+                    shortcuts.append(" | ");
+                }
+            }
+            
+            // insert calendar link
+            if (o.enable_calendar) {
+                $('<a href="#" class="'+o.class_calendar+'"></a>')
+                    .appendTo(shortcuts)
+                    .append('<img src="'+o.admin_media_prefix + 'img/admin/icon_calendar.gif" alt="'+gettext('Calendar')+'" />');
+            }
+        };
+        
+        // add shortcuts for time fields
+        var add_clock = function(element) {
+            // insert span.datetimeshortcuts
+            var shortcuts = $('<span class="'+o.class_shortcuts+'">').insertAfter(element);
+            
+            // insert now link
+            if (o.enable_now) {
+                shortcuts.append(' <a href="#" class="'+o.class_now+'">'+gettext('Now')+'</a>');
+                if (o.enable_clock) {
+                    shortcuts.append(" | ");
+                }
+            }
+            
+            // insert clock link
+            if (o.enable_clock) {
+                $('<a href="#" class="'+o.class_clock+'"></a>')
+                    .appendTo(shortcuts)
+                    .append('<img src="'+o.admin_media_prefix + 'img/admin/icon_clock.gif" alt="'+gettext('Clock')+'" />');
+            }
+        };
+        
+        // draw a month calendar table
+        var draw_calendar_table = function(selected, show) {
+            var y_sel, m_sel, d_sel;
+            // selected date (optional)
+            if (selected != null) {
+                y_sel = selected.getFullYear();
+                m_sel = selected.getMonth() + 1;
+                d_sel = selected.getDate();
+            }
+            // month to show
+            var y_show = show.getFullYear();
+            var m_show = show.getMonth() + 1;
+            // today
+            var today = new Date();
+            var y_tod = today.getFullYear();
+            var m_tod = today.getMonth() + 1;
+            var d_tod = today.getDate();
+            
+            // create table
+            var cal = $('<table><caption>'+month_names[m_show-1]+' '+y_show+'</caption></table>')
+            
+            // add day-of-week headers
+            var row = $('<tr>').appendTo(cal);
+            for (var i = 0; i < 7; i++) {
+                row.append('<th>'+weekdays[(i + first_day_of_week) % 7]+'</th>');
+            }
+            
+            var start = new Date(y_show, m_show-1, 1 - first_day_of_week).getDay();
+            var days = get_days_in_month(m_show, y_show);
+            
+            // draw blanks before 1st of month
+            var row = $('<tr>').appendTo(cal);
+            for (var i = 0; i < start; i++) {
+                $('<td> </td>').appendTo(row).addClass('nonday');
+            }
+            
+            // draw month days
+            var current = 1;
+            for (var i = start; current <= days; i++) {
+                if (i % 7 == 0 && current != 1) {
+                    row = $('<tr>').appendTo(cal);
+                }
+                var today_class = '';
+                // mark today
+                if ((current == d_tod) && (m_show == m_tod) && (y_show == y_tod)) {
+                    today_class = 'today';
+                }
+                // mark selected day
+                if ((current == d_sel) && (m_show == m_sel) && (y_show == y_sel)) {
+                    today_class = 'selected';
+                }
+                $('<td>').appendTo(row)
+                    .addClass(today_class)
+                    .append('<a href="#">'+current+'</a>')
+                    .find('a')
+                    .data('date', new Date(y_show, m_show-1, current++));
+            }
+            
+            // draw blanks after last of month
+            while(row.children('td').length < 7) {
+                $('<td> </td>').appendTo(row).addClass('nonday');
+            }
+            
+            return cal;
+        };
+        
+        // init one calendar per fieldset
+        var init_calendar_box = function(fieldset) {
+            // insert calendar box if not there
+            if (fieldset.find('.'+o.class_calendarbox).length == 0) {
+                
+                $('<div class="'+o.class_calendarbox+' module">'  +
+                    '  <div>'+
+                    '    <a href="#" class="calendarnav-previous"><</a>' +
+                    '    <a href="#" class="calendarnav-next">></a>' +
+                    '  </div>' +
+                    '  <div class="calendar_table calendar"></div>' +
+                    '  <div class="calendar-shortcuts">'+
+                    '    <a href="#" class="'+o.class_today+' yesterday">'+gettext('Yesterday')+'</a> | <a href="#" class="'+o.class_today+'">'+gettext('Today')+'</a> | <a href="#" class="'+o.class_today+' tomorrow">'+gettext('Tomorrow')+'</a>' +
+                    '  </div>' +
+                    '  <p class="calendar-cancel"><a href="#">'+gettext('Cancel')+'</p>' +
+                    '</div>')
+                    .appendTo(fieldset).css('position', 'absolute').hide();
+                
+                // prev/next event handlers
+                fieldset.find('.'+o.class_calendarbox)
+                    .delegate('.calendarnav-previous, .calendarnav-next',
+                              'click', function(event) {
+                        var func = $(this).is('.calendarnav-next') ? 'calendar_next' : 'calendar_previous';
+                        $(this).parents('.'+o.class_calendarbox).trigger(func);
+                        event.preventDefault();
+                        event.stopPropagation();
+                    })
+                    // days event handlers
+                    .delegate('td a', 'click', function(event) {
+                        fieldset.trigger('callback_calendar',
+                                         $(event.target).data('date'));
+                        event.preventDefault();
+                        event.stopPropagation();
+                    })
+                    // cancel link
+                    .find('.calendar-cancel').click(function(event) {
+                        fieldset.trigger('hide_calendar');
+                        event.preventDefault();
+                        event.stopPropagation();
+                    });
+            }
+        };
+        
+        // init one clock box per fieldset
+        var init_clock_box = function(fieldset) {
+            // insert clock box if not there
+            if (fieldset.find('.'+o.class_clockbox).length == 0) {
+                
+                var timelist = $('<div class="'+o.class_clockbox+' module">'  +
+                    '  <h2>'+gettext('Choose a time')+'</h2>' +
+                    '  <ul class="timelist"></ul>' +
+                    '  <p class="clock-cancel"><a href="#">'+gettext('Cancel')+'</p>' +
+                    '</div>')
+                    .appendTo(fieldset).css('position', 'absolute').hide()
+                    .find('.timelist');
+                
+                timelist.append('<li><a href="#">'+gettext('Now')+'</a></li>').find('a:last').data('time', new Date());
+                timelist.append('<li><a href="#">'+gettext('Midnight')+'</a></li>').find('a:last').data('time', new Date(1970,1,1,0,0));
+                timelist.append('<li><a href="#">'+gettext('6 a.m.')+'</a></li>').find('a:last').data('time', new Date(1970,1,1,6,0));
+                timelist.append('<li><a href="#">'+gettext('Noon')+'</a></li>').find('a:last').data('time', new Date(1970,1,1,12,0));
+                
+                // time links event handlers
+                fieldset.find('.'+o.class_clockbox)
+                    .delegate('li a', 'click', function(event) {
+                        fieldset.trigger('callback_clock',
+                                         $(event.target).data('time'));
+                        event.preventDefault();
+                        event.stopPropagation();
+                    })
+                    // cancel link
+                    .find('.clock-cancel').click(function(event) {
+                        fieldset.trigger('hide_clock');
+                        event.preventDefault();
+                        event.stopPropagation();
+                    });
+            }
+        };
+        
+        return this.each(function() {
+            var fieldset = $(this);
+            
+            /* --- setup datetimeshortcuts specific event handlers --------- */
+            fieldset
+            
+            // show calendar
+            .bind('show_calendar', function(event) {
+                fieldset.trigger('hide_clock');
+                fieldset.trigger('hide_calendar');
+                
+                var target = $(event.target);
+                var calendar = fieldset.children('.'+o.class_calendarbox);
+                var field = target
+                    .parents('.'+o.class_shortcuts)
+                    .prev(o.date_fields);
+                
+                // Check current field value for valid date
+                // and open calendar with that date selected
+                var date_sel = null;
+                var date_show = new Date();
+                if (field.val().length > 0) {
+                    // only support specific date formats here for simplicity
+                    // (jQueryUI.datepicker.dateParse could help here)
+                    var regex = null, y, m, d;
+                    if (o.date_input_format == '%Y-%m-%d') {
+                        regex = /^(\d{4})-(\d{2})-(\d{2})$/;
+                        y=1; m=2; d=3;
+                    }
+                    else if (o.date_input_format == '%m/%d/%Y') {
+                        regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
+                        y=3; m=1; d=2;
+                    }
+                    else if (o.date_input_format == '%m/%d/%y') {
+                        regex = /^(\d{2})\/(\d{2})\/(\d{2})$/;
+                        y=3; m=1; d=2;
+                    }
+                    else if (o.date_input_format == '%d.%m.%Y') {
+                        regex = /^(\d{2})\.(\d{2})\.(\d{4})$/;
+                        y=3; m=2; d=1;
+                    }
+                    else if (o.date_input_format == '%d.%m.%y') {
+                        regex = /^(\d{2})\.(\d{2})\.(\d{2})$/;
+                        y=3; m=2; d=1;
+                    }
+                    
+                    if (regex != null) {
+                        var match = regex.exec(field.val());
+                        if (match != null) {
+                            year = match[y];
+                            month = match[m];
+                            day = match[d];
+                            if (y.length == 2) {
+                                year = '20'+year;
+                            }
+                            date_sel = new Date(year, month-1, day);
+                            date_show = new Date(year, month-1, day);
+                        }
+                    }
+                }
+                
+                // open calendar
+                calendar
+                    // remember field and date
+                    .data('calendar_date_field', field)
+                    .data('calendar_date_show', date_show)
+                    .data('calendar_date_sel', date_sel)
+                    // draw correct month
+                    .find('.calendar_table').empty()
+                    .append(draw_calendar_table(date_sel, date_show))
+                    .end().show();
+                
+                // position based on LTR or RTL direction
+                var target_pos = target.position();
+                var dir = $('body').attr('direction');
+                if (dir != 'rtl') {
+                    calendar.css('left', target_pos.left + target.width() + 'px');
+                }
+                if (dir == 'rtl' ||
+                    ((calendar.offset().left + calendar.width()) > $(window).width())) {
+                    calendar.css('left',
+                        target_pos.left - calendar.width() + 'px');
+                }
+                calendar.css('top',
+                    Math.max(0, target_pos.top - calendar.height()/2) + 'px');
+                
+                // bind close handler to document
+                $('body').bind('click.datetimeshortcuts', function() {
+                    fieldset.trigger('hide_calendar');
+                });
+            })
+            
+            // show next month in calendar
+            .bind('calendar_next', function(event) {
+                var cal = $(event.target);
+                var tbl = cal.find('.calendar_table').empty();
+                var selected = cal.data('calendar_date_sel');
+                var show = cal.data('calendar_date_show');
+                var month = show.getMonth();
+                var year = show.getFullYear();
+                if (month == 11) {
+                    month = 1;
+                    year++;
+                }
+                else {
+                    month++;
+                }
+                show.setFullYear(year, month);
+                cal.data('calendar_date_show', show);
+                tbl.append(draw_calendar_table(selected, show))
+            })
+            
+            // show previous month in calendar
+            .bind('calendar_previous', function(event) {
+                var cal = $(event.target);
+                var tbl = cal.find('.calendar_table').empty();
+                var selected = cal.data('calendar_date_sel');
+                var show = cal.data('calendar_date_show');
+                var month = show.getMonth();
+                var year = show.getFullYear();
+                if (month == 0) {
+                    month = 11;
+                    year--;
+                }
+                else {
+                    month--;
+                }
+                show.setFullYear(year, month);
+                cal.data('calendar_date_show', show);
+                tbl.append(draw_calendar_table(selected, show))
+            })
+            
+            // hide calendar
+            .bind('hide_calendar', function(event) {
+                $(event.target)
+                    .children('.'+o.class_calendarbox)
+                    .removeData('calendar_date_field')
+                    .removeData('calendar_date_sel')
+                    .removeData('calendar_date_show')
+                    .hide();
+                $('document').unbind('.datetimeshortcuts');
+            })
+            
+            // show clock
+            .bind('show_clock', function(event) {
+                fieldset.trigger('hide_clock');
+                fieldset.trigger('hide_calendar');
+                
+                var target = $(event.target);
+                var clock = fieldset.children('.'+o.class_clockbox);
+                var field = target
+                    .parents('.'+o.class_shortcuts)
+                    .prev(o.time_fields);
+                
+                // open clock
+                clock
+                    .data('clock_time_field', field)
+                    .show();
+                
+                // position based on LTR or RTL direction
+                var target_pos = target.position();
+                var dir = $('body').attr('direction');
+                if (dir != 'rtl') {
+                    clock.css('left', target_pos.left + target.width() + 'px');
+                }
+                if (dir == 'rtl' ||
+                    ((clock.offset().left + clock.width()) > $(window).width())) {
+                    clock.css('left', target_pos.left - clock.width() + 'px');
+                }
+                clock.css('top',
+                    Math.max(0, target_pos.top - clock.height()/2) + 'px');
+                
+                // bind close handler to document
+                $('body').bind('click.datetimeshortcuts', function() {
+                    fieldset.trigger('hide_clock');
+                });
+            })
+            
+            // hide clock
+            .bind('hide_clock', function(event) {
+                $(event.target)
+                    .children('.'+o.class_clockbox)
+                    .removeData('clock_time_field')
+                    .hide();
+                $('document').unbind('.datetimeshortcuts');
+            })
+            
+            // calendar callback
+            .bind('callback_calendar', function(event, date) {
+                $(event.target)
+                    .find('.'+o.class_calendarbox)
+                    .data('calendar_date_field')
+                    .val(date.strftime(o.date_input_format))
+                    .focus();
+                fieldset.trigger('hide_calendar');
+            })
+            
+            // today link callback
+            .bind('callback_today', function(event, days_offset) {
+                var d = new Date();
+                d.setDate(d.getDate() + days_offset);
+                $(event.target)
+                   .val(d.strftime(o.date_input_format))
+                   .focus();
+            })
+            
+            // clock callback
+            .bind('callback_clock', function(event, time) {
+                $(event.target)
+                    .find('.'+o.class_clockbox)
+                    .data('clock_time_field')
+                    .val(time.strftime(o.time_input_format))
+                    .focus();
+                fieldset.trigger('hide_clock');
+            })
+            
+            // now link callback
+            .bind('callback_now', function(event) {
+                var d = new Date();
+                $(event.target)
+                    .val(d.strftime(o.time_input_format))
+                    .focus();
+            })
+            
+            
+            /* --- add datetime shortcut widgets --------------------------- */
+            
+            // add shortcuts to date fields
+            fieldset.find(o.date_fields).each(function() {
+                add_calendar($(this));
+            });
+            // add shortcuts to time fields
+            fieldset.find(o.time_fields).each(function() {
+                add_clock($(this));
+            });
+            // create calendar and clock widgets
+            init_calendar_box(fieldset);
+            init_clock_box(fieldset);
+            
+            
+            /* --- setup $(this)-wide event delegation --------------------- */
+            fieldset
+            
+            // click on calendar
+            .delegate("."+o.class_shortcuts+" ."+o.class_calendar,
+                      "click", function(event) {
+                $(event.target).trigger('show_calendar')
+                // prevent following link
+                event.preventDefault();
+                event.stopPropagation();
+            })
+            
+            // click on today link
+            .delegate("."+o.class_shortcuts+" ."+o.class_today,
+                      "click", function(event) {
+                $(event.target)
+                    // find .datetimeshortcuts span
+                    .parents('.'+o.class_shortcuts)
+                    .prev(o.date_fields)
+                    // update field
+                    .trigger('callback_today', 0);
+                fieldset.trigger('hide_calendar');
+                // prevent following link
+                event.preventDefault();
+                event.stopPropagation();
+            })
+            
+            // click on yesterday/today/tomorrow links in calendar
+            .delegate("."+o.class_calendarbox+" ."+o.class_today,
+                      "click", function(event) {
+                var target = $(event.target);
+                var offset = 0;
+                if (target.is('.yesterday')) {
+                    offset = -1;
+                }
+                else if (target.is('.tomorrow')) {
+                    offset = 1;
+                }
+                // find calendarbox
+                target.parents('.'+o.class_calendarbox)
+                    // target field is stored on calendar's data attribute
+                    .data('calendar_date_field')
+                    // update field
+                    .trigger('callback_today', offset)
+                    .focus();
+                fieldset.trigger('hide_calendar');
+                // prevent following link
+                event.preventDefault();
+                event.stopPropagation();
+            })
+            
+            // click on clock
+            .delegate("."+o.class_shortcuts+" ."+o.class_clock,
+                      "click", function(event) {
+                $(event.target).trigger('show_clock');
+                // prevent following link
+                event.preventDefault();
+                event.stopPropagation();
+            })
+            
+            // click on now link
+            .delegate("."+o.class_shortcuts+" ."+o.class_now,
+                      "click", function(event) {
+                $(event.target)
+                    // find .datetimeshortcuts span
+                    .parents('.'+o.class_shortcuts)
+                    .prev(o.time_fields)
+                    // update field
+                    .trigger('callback_now');
+                fieldset.trigger('hide_clock');
+                // prevent following link
+                event.preventDefault();
+                event.stopPropagation();
+            })
+        });
+    };
+    
+    $.fn.datetimeshortcuts.defaults = {
+        // classes (do not change - css depends on these)
+        class_shortcuts: "datetimeshortcuts",
+        class_today: "today",
+        class_calendar: "calendar",
+        class_now: "now",
+        class_clock: "clock",
+        class_calendarbox: "calendarbox",
+        class_clockbox: "clockbox",
+        // date and time format
+        date_input_format: get_format('DATE_INPUT_FORMATS')[0],
+        time_input_format: get_format('TIME_INPUT_FORMATS')[0],
+        // selectors for date and time fields
+        date_fields: "input:text.vDateField",
+        time_fields: "input:text.vTimeField",
+        // enable clock or calendar widgets
+        enable_calendar: true,
+        enable_today: true,
+        enable_clock: true,
+        enable_now: true
+    }
+    
+    // by default, initialize on all fieldset.module elements
+    // which hold any date or time fields
+    $(document).ready(function() {
+       $("fieldset.module").datetimeshortcuts();
+    });
+    
+})(django.jQuery);

Property changes on: django/contrib/admin/media/js/datetimeshortcuts.js
___________________________________________________________________
Added: svn:executable
   + *

Index: django/contrib/admin/media/js/admin/DateTimeShortcuts.js
===================================================================
--- django/contrib/admin/media/js/admin/DateTimeShortcuts.js	(revision 15800)
+++ django/contrib/admin/media/js/admin/DateTimeShortcuts.js	(working copy)
@@ -1,274 +0,0 @@
-// Inserts shortcut buttons after all of the following:
-//     <input type="text" class="vDateField">
-//     <input type="text" class="vTimeField">
-
-var DateTimeShortcuts = {
-    calendars: [],
-    calendarInputs: [],
-    clockInputs: [],
-    calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled
-    calendarDivName2: 'calendarin',  // name of <div> that contains calendar
-    calendarLinkName: 'calendarlink',// name of the link that is used to toggle
-    clockDivName: 'clockbox',        // name of clock <div> that gets toggled
-    clockLinkName: 'clocklink',      // name of the link that is used to toggle
-    shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts
-    admin_media_prefix: '',
-    init: function() {
-        // Get admin_media_prefix by grabbing it off the window object. It's
-        // set in the admin/base.html template, so if it's not there, someone's
-        // overridden the template. In that case, we'll set a clearly-invalid
-        // value in the hopes that someone will examine HTTP requests and see it.
-        if (window.__admin_media_prefix__ != undefined) {
-            DateTimeShortcuts.admin_media_prefix = window.__admin_media_prefix__;
-        } else {
-            DateTimeShortcuts.admin_media_prefix = '/missing-admin-media-prefix/';
-        }
-
-        var inputs = document.getElementsByTagName('input');
-        for (i=0; i<inputs.length; i++) {
-            var inp = inputs[i];
-            if (inp.getAttribute('type') == 'text' && inp.className.match(/vTimeField/)) {
-                DateTimeShortcuts.addClock(inp);
-            }
-            else if (inp.getAttribute('type') == 'text' && inp.className.match(/vDateField/)) {
-                DateTimeShortcuts.addCalendar(inp);
-            }
-        }
-    },
-    // Add clock widget to a given field
-    addClock: function(inp) {
-        var num = DateTimeShortcuts.clockInputs.length;
-        DateTimeShortcuts.clockInputs[num] = inp;
-
-        // Shortcut links (clock icon and "Now" link)
-        var shortcuts_span = document.createElement('span');
-        shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
-        inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
-        var now_link = document.createElement('a');
-        now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + get_format('TIME_INPUT_FORMATS')[0] + "'));");
-        now_link.appendChild(document.createTextNode(gettext('Now')));
-        var clock_link = document.createElement('a');
-        clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
-        clock_link.id = DateTimeShortcuts.clockLinkName + num;
-        quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_clock.gif', 'alt', gettext('Clock'));
-        shortcuts_span.appendChild(document.createTextNode('\240'));
-        shortcuts_span.appendChild(now_link);
-        shortcuts_span.appendChild(document.createTextNode('\240|\240'));
-        shortcuts_span.appendChild(clock_link);
-
-        // Create clock link div
-        //
-        // Markup looks like:
-        // <div id="clockbox1" class="clockbox module">
-        //     <h2>Choose a time</h2>
-        //     <ul class="timelist">
-        //         <li><a href="#">Now</a></li>
-        //         <li><a href="#">Midnight</a></li>
-        //         <li><a href="#">6 a.m.</a></li>
-        //         <li><a href="#">Noon</a></li>
-        //     </ul>
-        //     <p class="calendar-cancel"><a href="#">Cancel</a></p>
-        // </div>
-
-        var clock_box = document.createElement('div');
-        clock_box.style.display = 'none';
-        clock_box.style.position = 'absolute';
-        clock_box.className = 'clockbox module';
-        clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num);
-        document.body.appendChild(clock_box);
-        addEvent(clock_box, 'click', DateTimeShortcuts.cancelEventPropagation);
-
-        quickElement('h2', clock_box, gettext('Choose a time'));
-        time_list = quickElement('ul', clock_box, '');
-        time_list.className = 'timelist';
-        time_format = get_format('TIME_INPUT_FORMATS')[0];
-        quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
-        quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));");
-        quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));");
-        quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));");
-
-        cancel_p = quickElement('p', clock_box, '');
-        cancel_p.className = 'calendar-cancel';
-        quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');');
-    },
-    openClock: function(num) {
-        var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num)
-        var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName+num)
-
-        // Recalculate the clockbox position
-        // is it left-to-right or right-to-left layout ?
-        if (getStyle(document.body,'direction')!='rtl') {
-            clock_box.style.left = findPosX(clock_link) + 17 + 'px';
-        }
-        else {
-            // since style's width is in em, it'd be tough to calculate
-            // px value of it. let's use an estimated px for now
-            // TODO: IE returns wrong value for findPosX when in rtl mode
-            //       (it returns as it was left aligned), needs to be fixed.
-            clock_box.style.left = findPosX(clock_link) - 110 + 'px';
-        }
-        clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px';
-
-        // Show the clock box
-        clock_box.style.display = 'block';
-        addEvent(window.document, 'click', function() { DateTimeShortcuts.dismissClock(num); return true; });
-    },
-    dismissClock: function(num) {
-       document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none';
-       window.document.onclick = null;
-    },
-    handleClockQuicklink: function(num, val) {
-       DateTimeShortcuts.clockInputs[num].value = val;
-       DateTimeShortcuts.clockInputs[num].focus();
-       DateTimeShortcuts.dismissClock(num);
-    },
-    // Add calendar widget to a given field.
-    addCalendar: function(inp) {
-        var num = DateTimeShortcuts.calendars.length;
-
-        DateTimeShortcuts.calendarInputs[num] = inp;
-
-        // Shortcut links (calendar icon and "Today" link)
-        var shortcuts_span = document.createElement('span');
-        shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
-        inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
-        var today_link = document.createElement('a');
-        today_link.setAttribute('href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', 0);');
-        today_link.appendChild(document.createTextNode(gettext('Today')));
-        var cal_link = document.createElement('a');
-        cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');');
-        cal_link.id = DateTimeShortcuts.calendarLinkName + num;
-        quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_calendar.gif', 'alt', gettext('Calendar'));
-        shortcuts_span.appendChild(document.createTextNode('\240'));
-        shortcuts_span.appendChild(today_link);
-        shortcuts_span.appendChild(document.createTextNode('\240|\240'));
-        shortcuts_span.appendChild(cal_link);
-
-        // Create calendarbox div.
-        //
-        // Markup looks like:
-        //
-        // <div id="calendarbox3" class="calendarbox module">
-        //     <h2>
-        //           <a href="#" class="link-previous">&lsaquo;</a>
-        //           <a href="#" class="link-next">&rsaquo;</a> February 2003
-        //     </h2>
-        //     <div class="calendar" id="calendarin3">
-        //         <!-- (cal) -->
-        //     </div>
-        //     <div class="calendar-shortcuts">
-        //          <a href="#">Yesterday</a> | <a href="#">Today</a> | <a href="#">Tomorrow</a>
-        //     </div>
-        //     <p class="calendar-cancel"><a href="#">Cancel</a></p>
-        // </div>
-        var cal_box = document.createElement('div');
-        cal_box.style.display = 'none';
-        cal_box.style.position = 'absolute';
-        cal_box.className = 'calendarbox module';
-        cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num);
-        document.body.appendChild(cal_box);
-        addEvent(cal_box, 'click', DateTimeShortcuts.cancelEventPropagation);
-
-        // next-prev links
-        var cal_nav = quickElement('div', cal_box, '');
-        var cal_nav_prev = quickElement('a', cal_nav, '<', 'href', 'javascript:DateTimeShortcuts.drawPrev('+num+');');
-        cal_nav_prev.className = 'calendarnav-previous';
-        var cal_nav_next = quickElement('a', cal_nav, '>', 'href', 'javascript:DateTimeShortcuts.drawNext('+num+');');
-        cal_nav_next.className = 'calendarnav-next';
-
-        // main box
-        var cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num);
-        cal_main.className = 'calendar';
-        DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num));
-        DateTimeShortcuts.calendars[num].drawCurrent();
-
-        // calendar shortcuts
-        var shortcuts = quickElement('div', cal_box, '');
-        shortcuts.className = 'calendar-shortcuts';
-        quickElement('a', shortcuts, gettext('Yesterday'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', -1);');
-        shortcuts.appendChild(document.createTextNode('\240|\240'));
-        quickElement('a', shortcuts, gettext('Today'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', 0);');
-        shortcuts.appendChild(document.createTextNode('\240|\240'));
-        quickElement('a', shortcuts, gettext('Tomorrow'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', +1);');
-
-        // cancel bar
-        var cancel_p = quickElement('p', cal_box, '');
-        cancel_p.className = 'calendar-cancel';
-        quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');');
-    },
-    openCalendar: function(num) {
-        var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num)
-        var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num)
-        var inp = DateTimeShortcuts.calendarInputs[num];
-
-        // Determine if the current value in the input has a valid date.
-        // If so, draw the calendar with that date's year and month.
-        if (inp.value) {
-            var date_parts = inp.value.split('-');
-            var year = date_parts[0];
-            var month = parseFloat(date_parts[1]);
-            if (year.match(/\d\d\d\d/) && month >= 1 && month <= 12) {
-                DateTimeShortcuts.calendars[num].drawDate(month, year);
-            }
-        }
-
-        // Recalculate the clockbox position
-        // is it left-to-right or right-to-left layout ?
-        if (getStyle(document.body,'direction')!='rtl') {
-            cal_box.style.left = findPosX(cal_link) + 17 + 'px';
-        }
-        else {
-            // since style's width is in em, it'd be tough to calculate
-            // px value of it. let's use an estimated px for now
-            // TODO: IE returns wrong value for findPosX when in rtl mode
-            //       (it returns as it was left aligned), needs to be fixed.
-            cal_box.style.left = findPosX(cal_link) - 180 + 'px';
-        }
-        cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px';
-
-        cal_box.style.display = 'block';
-        addEvent(window.document, 'click', function() { DateTimeShortcuts.dismissCalendar(num); return true; });
-    },
-    dismissCalendar: function(num) {
-        document.getElementById(DateTimeShortcuts.calendarDivName1+num).style.display = 'none';
-        window.document.onclick = null;
-    },
-    drawPrev: function(num) {
-        DateTimeShortcuts.calendars[num].drawPreviousMonth();
-    },
-    drawNext: function(num) {
-        DateTimeShortcuts.calendars[num].drawNextMonth();
-    },
-    handleCalendarCallback: function(num) {
-        format = get_format('DATE_INPUT_FORMATS')[0];
-        // the format needs to be escaped a little
-        format = format.replace('\\', '\\\\');
-        format = format.replace('\r', '\\r');
-        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,
-               "');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) {
-        if (!e) e = window.event;
-        e.cancelBubble = true;
-        if (e.stopPropagation) e.stopPropagation();
-    }
-}
-
-addEvent(window, 'load', DateTimeShortcuts.init);
Index: django/contrib/admin/media/js/datetimeshortcuts.min.js
===================================================================
--- django/contrib/admin/media/js/datetimeshortcuts.min.js	(revision 0)
+++ django/contrib/admin/media/js/datetimeshortcuts.min.js	(revision 0)
@@ -0,0 +1,18 @@
+(function(c){c.fn.datetimeshortcuts=function(t){var u=c("body").data("datetimeshortcuts_defaults"),b=c.extend({admin_media_prefix:c("body").data("admin_media_prefix")},c.fn.datetimeshortcuts.defaults,u,t);if(b.admin_media_prefix==undefined)b.admin_media_prefix="/missing-admin-media-prefix/";var v=gettext("January February March April May June July August September October November December").split(" "),w=gettext("S M T W T F S").split(" "),s=parseInt(get_format("FIRST_DAY_OF_WEEK")),r=function(e,
+a){var d,g,h;if(e!=null){d=e.getFullYear();g=e.getMonth()+1;h=e.getDate()}var i=a.getFullYear(),f=a.getMonth()+1,j=new Date,k=j.getFullYear(),m=j.getMonth()+1;j=j.getDate();for(var q=c("<table><caption>"+v[f-1]+" "+i+"</caption></table>"),n=c("<tr>").appendTo(q),l=0;l<7;l++)n.append("<th>"+w[(l+s)%7]+"</th>");var o=(new Date(i,f-1,1-s)).getDay(),x=32-(new Date(i,f-1,32)).getDate();n=c("<tr>").appendTo(q);for(l=0;l<o;l++)c("<td> </td>").appendTo(n).addClass("nonday");var p=1;for(l=o;p<=x;l++){if(l%
+7==0&&p!=1)n=c("<tr>").appendTo(q);o="";if(p==j&&f==m&&i==k)o="today";if(p==h&&f==g&&i==d)o="selected";c("<td>").appendTo(n).addClass(o).append('<a href="#">'+p+"</a>").find("a").data("date",new Date(i,f-1,p++))}for(;n.children("td").length<7;)c("<td> </td>").appendTo(n).addClass("nonday");return q},y=function(e){if(e.find("."+b.class_calendarbox).length==0){c('<div class="'+b.class_calendarbox+' module">  <div>    <a href="#" class="calendarnav-previous"><</a>    <a href="#" class="calendarnav-next">></a>  </div>  <div class="calendar_table calendar"></div>  <div class="calendar-shortcuts">    <a href="#" class="'+
+b.class_today+' yesterday">'+gettext("Yesterday")+'</a> |\u00a0<a href="#" class="'+b.class_today+'">'+gettext("Today")+'</a> |\u00a0<a href="#" class="'+b.class_today+' tomorrow">'+gettext("Tomorrow")+'</a>  </div>  <p class="calendar-cancel"><a href="#">'+gettext("Cancel")+"</p></div>").appendTo(e).css("position","absolute").hide();e.find("."+b.class_calendarbox).delegate(".calendarnav-previous, .calendarnav-next","click",function(a){var d=c(this).is(".calendarnav-next")?"calendar_next":"calendar_previous";
+c(this).parents("."+b.class_calendarbox).trigger(d);a.preventDefault();a.stopPropagation()}).delegate("td a","click",function(a){e.trigger("callback_calendar",c(a.target).data("date"));a.preventDefault();a.stopPropagation()}).find(".calendar-cancel").click(function(a){e.trigger("hide_calendar");a.preventDefault();a.stopPropagation()})}},z=function(e){if(e.find("."+b.class_clockbox).length==0){var a=c('<div class="'+b.class_clockbox+' module">  <h2>'+gettext("Choose a time")+'</h2>  <ul class="timelist"></ul>  <p class="clock-cancel"><a href="#">'+
+gettext("Cancel")+"</p></div>").appendTo(e).css("position","absolute").hide().find(".timelist");a.append('<li><a href="#">'+gettext("Now")+"</a></li>").find("a:last").data("time",new Date);a.append('<li><a href="#">'+gettext("Midnight")+"</a></li>").find("a:last").data("time",new Date(1970,1,1,0,0));a.append('<li><a href="#">'+gettext("6 a.m.")+"</a></li>").find("a:last").data("time",new Date(1970,1,1,6,0));a.append('<li><a href="#">'+gettext("Noon")+"</a></li>").find("a:last").data("time",new Date(1970,
+1,1,12,0));e.find("."+b.class_clockbox).delegate("li a","click",function(d){e.trigger("callback_clock",c(d.target).data("time"));d.preventDefault();d.stopPropagation()}).find(".clock-cancel").click(function(d){e.trigger("hide_clock");d.preventDefault();d.stopPropagation()})}};return this.each(function(){var e=c(this);e.bind("show_calendar",function(a){e.trigger("hide_clock");e.trigger("hide_calendar");a=c(a.target);var d=e.children("."+b.class_calendarbox),g=a.parents("."+b.class_shortcuts).prev(b.date_fields),
+h=null,i=new Date;if(g.val().length>0){var f=null,j,k,m;if(b.date_input_format=="%Y-%m-%d"){f=/^(\d{4})-(\d{2})-(\d{2})$/;j=1;k=2;m=3}else if(b.date_input_format=="%m/%d/%Y"){f=/^(\d{2})\/(\d{2})\/(\d{4})$/;j=3;k=1;m=2}else if(b.date_input_format=="%m/%d/%y"){f=/^(\d{2})\/(\d{2})\/(\d{2})$/;j=3;k=1;m=2}else if(b.date_input_format=="%d.%m.%Y"){f=/^(\d{2})\.(\d{2})\.(\d{4})$/;j=3;k=2;m=1}else if(b.date_input_format=="%d.%m.%y"){f=/^(\d{2})\.(\d{2})\.(\d{2})$/;j=3;k=2;m=1}if(f!=null){f=f.exec(g.val());
+if(f!=null){year=f[j];month=f[k];day=f[m];if(j.length==2)year="20"+year;h=new Date(year,month-1,day);i=new Date(year,month-1,day)}}}d.data("calendar_date_field",g).data("calendar_date_show",i).data("calendar_date_sel",h).find(".calendar_table").empty().append(r(h,i)).end().show();j=a.position();k=c("body").attr("direction");k!="rtl"&&d.css("left",j.left+a.width()+"px");if(k=="rtl"||d.offset().left+d.width()>c(window).width())d.css("left",j.left-d.width()+"px");d.css("top",Math.max(0,j.top-d.height()/
+2)+"px");c("body").bind("click.datetimeshortcuts",function(){e.trigger("hide_calendar")})}).bind("calendar_next",function(a){a=c(a.target);var d=a.find(".calendar_table").empty(),g=a.data("calendar_date_sel"),h=a.data("calendar_date_show"),i=h.getMonth(),f=h.getFullYear();if(i==11){i=1;f++}else i++;h.setFullYear(f,i);a.data("calendar_date_show",h);d.append(r(g,h))}).bind("calendar_previous",function(a){a=c(a.target);var d=a.find(".calendar_table").empty(),g=a.data("calendar_date_sel"),h=a.data("calendar_date_show"),
+i=h.getMonth(),f=h.getFullYear();if(i==0){i=11;f--}else i--;h.setFullYear(f,i);a.data("calendar_date_show",h);d.append(r(g,h))}).bind("hide_calendar",function(a){c(a.target).children("."+b.class_calendarbox).removeData("calendar_date_field").removeData("calendar_date_sel").removeData("calendar_date_show").hide();c("document").unbind(".datetimeshortcuts")}).bind("show_clock",function(a){e.trigger("hide_clock");e.trigger("hide_calendar");a=c(a.target);var d=e.children("."+b.class_clockbox),g=a.parents("."+
+b.class_shortcuts).prev(b.time_fields);d.data("clock_time_field",g).show();g=a.position();var h=c("body").attr("direction");h!="rtl"&&d.css("left",g.left+a.width()+"px");if(h=="rtl"||d.offset().left+d.width()>c(window).width())d.css("left",g.left-d.width()+"px");d.css("top",Math.max(0,g.top-d.height()/2)+"px");c("body").bind("click.datetimeshortcuts",function(){e.trigger("hide_clock")})}).bind("hide_clock",function(a){c(a.target).children("."+b.class_clockbox).removeData("clock_time_field").hide();
+c("document").unbind(".datetimeshortcuts")}).bind("callback_calendar",function(a,d){c(a.target).find("."+b.class_calendarbox).data("calendar_date_field").val(d.strftime(b.date_input_format)).focus();e.trigger("hide_calendar")}).bind("callback_today",function(a,d){var g=new Date;g.setDate(g.getDate()+d);c(a.target).val(g.strftime(b.date_input_format)).focus()}).bind("callback_clock",function(a,d){c(a.target).find("."+b.class_clockbox).data("clock_time_field").val(d.strftime(b.time_input_format)).focus();
+e.trigger("hide_clock")}).bind("callback_now",function(a){var d=new Date;c(a.target).val(d.strftime(b.time_input_format)).focus()});e.find(b.date_fields).each(function(){var a=c(this);a=c('<span class="'+b.class_shortcuts+'">').insertAfter(a);if(b.enable_today){a.append(' <a href="#" class="'+b.class_today+'">'+gettext("Today")+"</a>");b.enable_calendar&&a.append(" | ")}b.enable_calendar&&c('<a href="#" class="'+b.class_calendar+'"></a>').appendTo(a).append('<img src="'+b.admin_media_prefix+'img/admin/icon_calendar.gif" alt="'+
+gettext("Calendar")+'" />')});e.find(b.time_fields).each(function(){var a=c(this);a=c('<span class="'+b.class_shortcuts+'">').insertAfter(a);if(b.enable_now){a.append(' <a href="#" class="'+b.class_now+'">'+gettext("Now")+"</a>");b.enable_clock&&a.append(" | ")}b.enable_clock&&c('<a href="#" class="'+b.class_clock+'"></a>').appendTo(a).append('<img src="'+b.admin_media_prefix+'img/admin/icon_clock.gif" alt="'+gettext("Clock")+'" />')});y(e);z(e);e.delegate("."+b.class_shortcuts+" ."+b.class_calendar,
+"click",function(a){c(a.target).trigger("show_calendar");a.preventDefault();a.stopPropagation()}).delegate("."+b.class_shortcuts+" ."+b.class_today,"click",function(a){c(a.target).parents("."+b.class_shortcuts).prev(b.date_fields).trigger("callback_today",0);e.trigger("hide_calendar");a.preventDefault();a.stopPropagation()}).delegate("."+b.class_calendarbox+" ."+b.class_today,"click",function(a){var d=c(a.target),g=0;if(d.is(".yesterday"))g=-1;else if(d.is(".tomorrow"))g=1;d.parents("."+b.class_calendarbox).data("calendar_date_field").trigger("callback_today",
+g).focus();e.trigger("hide_calendar");a.preventDefault();a.stopPropagation()}).delegate("."+b.class_shortcuts+" ."+b.class_clock,"click",function(a){c(a.target).trigger("show_clock");a.preventDefault();a.stopPropagation()}).delegate("."+b.class_shortcuts+" ."+b.class_now,"click",function(a){c(a.target).parents("."+b.class_shortcuts).prev(b.time_fields).trigger("callback_now");e.trigger("hide_clock");a.preventDefault();a.stopPropagation()})})};c.fn.datetimeshortcuts.defaults={class_shortcuts:"datetimeshortcuts",
+class_today:"today",class_calendar:"calendar",class_now:"now",class_clock:"clock",class_calendarbox:"calendarbox",class_clockbox:"clockbox",date_input_format:get_format("DATE_INPUT_FORMATS")[0],time_input_format:get_format("TIME_INPUT_FORMATS")[0],date_fields:"input:text.vDateField",time_fields:"input:text.vTimeField",enable_calendar:true,enable_today:true,enable_clock:true,enable_now:true};c(document).ready(function(){c("fieldset.module").datetimeshortcuts()})})(django.jQuery);
Index: django/contrib/admin/widgets.py
===================================================================
--- django/contrib/admin/widgets.py	(revision 15800)
+++ django/contrib/admin/widgets.py	(working copy)
@@ -46,16 +46,14 @@
 
 class AdminDateWidget(forms.DateInput):
     class Media:
-        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
-              settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
+        js = (settings.ADMIN_MEDIA_PREFIX + "js/datetimeshortcuts.min.js",)
 
     def __init__(self, attrs={}, format=None):
         super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'}, format=format)
 
 class AdminTimeWidget(forms.TimeInput):
     class Media:
-        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
-              settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
+        js = (settings.ADMIN_MEDIA_PREFIX + "js/datetimeshortcuts.min.js",)
 
     def __init__(self, attrs={}, format=None):
         super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'}, format=format)
Index: django/contrib/admin/templates/admin/edit_inline/stacked.html
===================================================================
--- django/contrib/admin/templates/admin/edit_inline/stacked.html	(revision 15800)
+++ django/contrib/admin/templates/admin/edit_inline/stacked.html	(working copy)
@@ -28,13 +28,6 @@
                 $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
             });
         }
-        var reinitDateTimeShortCuts = function() {
-            // Reinitialize the calendar and clock widgets by force, yuck.
-            if (typeof DateTimeShortcuts != "undefined") {
-                $(".datetimeshortcuts").remove();
-                DateTimeShortcuts.init();
-            }
-        }
         var updateSelectFilter = function() {
             // If any SelectFilter widgets were added, instantiate a new instance.
             if (typeof SelectFilter != "undefined"){
@@ -72,7 +65,6 @@
             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 15800)
+++ django/contrib/admin/templates/admin/edit_inline/tabular.html	(working copy)
@@ -73,13 +73,6 @@
                 .filter(":even").addClass("row1").end()
                 .filter(rows + ":odd").addClass("row2");
         }
-        var reinitDateTimeShortCuts = function() {
-            // Reinitialize the calendar and clock widgets by force
-            if (typeof DateTimeShortcuts != "undefined") {
-                $(".datetimeshortcuts").remove();
-                DateTimeShortcuts.init();
-            }
-        }
         var updateSelectFilter = function() {
             // If any SelectFilter widgets are a part of the new form,
             // instantiate a new SelectFilter instance for it.
@@ -118,7 +111,6 @@
             removed: alternatingRows,
             added: (function(row) {
                 initPrepopulatedFields(row);
-                reinitDateTimeShortCuts();
                 updateSelectFilter();
                 alternatingRows(row);
             })
Index: django/contrib/admin/templates/admin/base.html
===================================================================
--- django/contrib/admin/templates/admin/base.html	(revision 15800)
+++ django/contrib/admin/templates/admin/base.html	(working copy)
@@ -6,7 +6,6 @@
 {% block extrastyle %}{% endblock %}
 <!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{% load adminmedia %}{% admin_media_prefix %}css/ie.css{% endblock %}" /><![endif]-->
 {% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% admin_media_prefix %}css/rtl.css{% endblock %}" />{% endif %}
-<script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";</script>
 {% block extrahead %}{% endblock %}
 {% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
 </head>
@@ -14,6 +13,21 @@
 
 <body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}">
 
+<script type="text/javascript">
+    if (typeof(django) != "undefined" && typeof(django.jQuery) != "undefined") {
+	(function($) {
+	    $('body').data('admin_media_prefix', "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}");
+	    {# TODO: templatetag admin_datetimeshortcuts (?) to render the following from django.conf.settings #}
+	    $('body').data('datetimeshortcuts_defaults', {
+		enable_calendar: true,
+		enable_today: true,
+		enable_clock: true,
+		enable_now: true
+	    });
+	})(django.jQuery);
+    }
+</script>
+
 <!-- Container -->
 <div id="container">
 
