Ticket #15231: ticket15231_stable1.4.x.diff

File ticket15231_stable1.4.x.diff, 59.2 KB (added by Fabian Büchler, 6 years ago)

Patch for stable/1.4.x

  • django/contrib/admin/static/admin/css/widgets.css

    diff --git a/django/contrib/admin/static/admin/css/widgets.css b/django/contrib/admin/static/admin/css/widgets.css
    index 2989f2f..5ea723b 100644
    a b span.clearable-file-input label { 
    377377    right: 0;
    378378}
    379379
    380 .calendar-cancel {
     380.calendar-cancel,
     381.clock-cancel {
    381382    margin: 0 !important;
    382383    padding: 0 !important;
    383384    font-size: 10px;
  • deleted file django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js

    diff --git a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
    deleted file mode 100644
    index 3ecc06f..0000000
    + -  
    1 // Inserts shortcut buttons after all of the following:
    2 //     <input type="text" class="vDateField">
    3 //     <input type="text" class="vTimeField">
    4 
    5 var DateTimeShortcuts = {
    6     calendars: [],
    7     calendarInputs: [],
    8     clockInputs: [],
    9     calendarDivName1: 'calendarbox', // name of calendar <div> that gets toggled
    10     calendarDivName2: 'calendarin',  // name of <div> that contains calendar
    11     calendarLinkName: 'calendarlink',// name of the link that is used to toggle
    12     clockDivName: 'clockbox',        // name of clock <div> that gets toggled
    13     clockLinkName: 'clocklink',      // name of the link that is used to toggle
    14     shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts
    15     admin_media_prefix: '',
    16     init: function() {
    17         // Get admin_media_prefix by grabbing it off the window object. It's
    18         // set in the admin/base.html template, so if it's not there, someone's
    19         // overridden the template. In that case, we'll set a clearly-invalid
    20         // value in the hopes that someone will examine HTTP requests and see it.
    21         if (window.__admin_media_prefix__ != undefined) {
    22             DateTimeShortcuts.admin_media_prefix = window.__admin_media_prefix__;
    23         } else {
    24             DateTimeShortcuts.admin_media_prefix = '/missing-admin-media-prefix/';
    25         }
    26 
    27         var inputs = document.getElementsByTagName('input');
    28         for (i=0; i<inputs.length; i++) {
    29             var inp = inputs[i];
    30             if (inp.getAttribute('type') == 'text' && inp.className.match(/vTimeField/)) {
    31                 DateTimeShortcuts.addClock(inp);
    32             }
    33             else if (inp.getAttribute('type') == 'text' && inp.className.match(/vDateField/)) {
    34                 DateTimeShortcuts.addCalendar(inp);
    35             }
    36         }
    37     },
    38     // Add clock widget to a given field
    39     addClock: function(inp) {
    40         var num = DateTimeShortcuts.clockInputs.length;
    41         DateTimeShortcuts.clockInputs[num] = inp;
    42 
    43         // Shortcut links (clock icon and "Now" link)
    44         var shortcuts_span = document.createElement('span');
    45         shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
    46         inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
    47         var now_link = document.createElement('a');
    48         now_link.setAttribute('href', "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + get_format('TIME_INPUT_FORMATS')[0] + "'));");
    49         now_link.appendChild(document.createTextNode(gettext('Now')));
    50         var clock_link = document.createElement('a');
    51         clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
    52         clock_link.id = DateTimeShortcuts.clockLinkName + num;
    53         quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/icon_clock.gif', 'alt', gettext('Clock'));
    54         shortcuts_span.appendChild(document.createTextNode('\240'));
    55         shortcuts_span.appendChild(now_link);
    56         shortcuts_span.appendChild(document.createTextNode('\240|\240'));
    57         shortcuts_span.appendChild(clock_link);
    58 
    59         // Create clock link div
    60         //
    61         // Markup looks like:
    62         // <div id="clockbox1" class="clockbox module">
    63         //     <h2>Choose a time</h2>
    64         //     <ul class="timelist">
    65         //         <li><a href="#">Now</a></li>
    66         //         <li><a href="#">Midnight</a></li>
    67         //         <li><a href="#">6 a.m.</a></li>
    68         //         <li><a href="#">Noon</a></li>
    69         //     </ul>
    70         //     <p class="calendar-cancel"><a href="#">Cancel</a></p>
    71         // </div>
    72 
    73         var clock_box = document.createElement('div');
    74         clock_box.style.display = 'none';
    75         clock_box.style.position = 'absolute';
    76         clock_box.className = 'clockbox module';
    77         clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num);
    78         document.body.appendChild(clock_box);
    79         addEvent(clock_box, 'click', DateTimeShortcuts.cancelEventPropagation);
    80 
    81         quickElement('h2', clock_box, gettext('Choose a time'));
    82         var time_list = quickElement('ul', clock_box, '');
    83         time_list.className = 'timelist';
    84         var time_format = get_format('TIME_INPUT_FORMATS')[0];
    85         quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
    86         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 + "'));");
    87         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 + "'));");
    88         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 + "'));");
    89 
    90         var cancel_p = quickElement('p', clock_box, '');
    91         cancel_p.className = 'calendar-cancel';
    92         quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');');
    93         django.jQuery(document).bind('keyup', function(event) {
    94             if (event.which == 27) {
    95                 // ESC key closes popup
    96                 DateTimeShortcuts.dismissClock(num);
    97                 event.preventDefault();
    98             }
    99         });
    100     },
    101     openClock: function(num) {
    102         var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num)
    103         var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName+num)
    104 
    105         // Recalculate the clockbox position
    106         // is it left-to-right or right-to-left layout ?
    107         if (getStyle(document.body,'direction')!='rtl') {
    108             clock_box.style.left = findPosX(clock_link) + 17 + 'px';
    109         }
    110         else {
    111             // since style's width is in em, it'd be tough to calculate
    112             // px value of it. let's use an estimated px for now
    113             // TODO: IE returns wrong value for findPosX when in rtl mode
    114             //       (it returns as it was left aligned), needs to be fixed.
    115             clock_box.style.left = findPosX(clock_link) - 110 + 'px';
    116         }
    117         clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + 'px';
    118 
    119         // Show the clock box
    120         clock_box.style.display = 'block';
    121         addEvent(window.document, 'click', function() { DateTimeShortcuts.dismissClock(num); return true; });
    122     },
    123     dismissClock: function(num) {
    124        document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none';
    125        window.document.onclick = null;
    126     },
    127     handleClockQuicklink: function(num, val) {
    128        DateTimeShortcuts.clockInputs[num].value = val;
    129        DateTimeShortcuts.clockInputs[num].focus();
    130        DateTimeShortcuts.dismissClock(num);
    131     },
    132     // Add calendar widget to a given field.
    133     addCalendar: function(inp) {
    134         var num = DateTimeShortcuts.calendars.length;
    135 
    136         DateTimeShortcuts.calendarInputs[num] = inp;
    137 
    138         // Shortcut links (calendar icon and "Today" link)
    139         var shortcuts_span = document.createElement('span');
    140         shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
    141         inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
    142         var today_link = document.createElement('a');
    143         today_link.setAttribute('href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', 0);');
    144         today_link.appendChild(document.createTextNode(gettext('Today')));
    145         var cal_link = document.createElement('a');
    146         cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');');
    147         cal_link.id = DateTimeShortcuts.calendarLinkName + num;
    148         quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/icon_calendar.gif', 'alt', gettext('Calendar'));
    149         shortcuts_span.appendChild(document.createTextNode('\240'));
    150         shortcuts_span.appendChild(today_link);
    151         shortcuts_span.appendChild(document.createTextNode('\240|\240'));
    152         shortcuts_span.appendChild(cal_link);
    153 
    154         // Create calendarbox div.
    155         //
    156         // Markup looks like:
    157         //
    158         // <div id="calendarbox3" class="calendarbox module">
    159         //     <h2>
    160         //           <a href="#" class="link-previous">&lsaquo;</a>
    161         //           <a href="#" class="link-next">&rsaquo;</a> February 2003
    162         //     </h2>
    163         //     <div class="calendar" id="calendarin3">
    164         //         <!-- (cal) -->
    165         //     </div>
    166         //     <div class="calendar-shortcuts">
    167         //          <a href="#">Yesterday</a> | <a href="#">Today</a> | <a href="#">Tomorrow</a>
    168         //     </div>
    169         //     <p class="calendar-cancel"><a href="#">Cancel</a></p>
    170         // </div>
    171         var cal_box = document.createElement('div');
    172         cal_box.style.display = 'none';
    173         cal_box.style.position = 'absolute';
    174         cal_box.className = 'calendarbox module';
    175         cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num);
    176         document.body.appendChild(cal_box);
    177         addEvent(cal_box, 'click', DateTimeShortcuts.cancelEventPropagation);
    178 
    179         // next-prev links
    180         var cal_nav = quickElement('div', cal_box, '');
    181         var cal_nav_prev = quickElement('a', cal_nav, '<', 'href', 'javascript:DateTimeShortcuts.drawPrev('+num+');');
    182         cal_nav_prev.className = 'calendarnav-previous';
    183         var cal_nav_next = quickElement('a', cal_nav, '>', 'href', 'javascript:DateTimeShortcuts.drawNext('+num+');');
    184         cal_nav_next.className = 'calendarnav-next';
    185 
    186         // main box
    187         var cal_main = quickElement('div', cal_box, '', 'id', DateTimeShortcuts.calendarDivName2 + num);
    188         cal_main.className = 'calendar';
    189         DateTimeShortcuts.calendars[num] = new Calendar(DateTimeShortcuts.calendarDivName2 + num, DateTimeShortcuts.handleCalendarCallback(num));
    190         DateTimeShortcuts.calendars[num].drawCurrent();
    191 
    192         // calendar shortcuts
    193         var shortcuts = quickElement('div', cal_box, '');
    194         shortcuts.className = 'calendar-shortcuts';
    195         quickElement('a', shortcuts, gettext('Yesterday'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', -1);');
    196         shortcuts.appendChild(document.createTextNode('\240|\240'));
    197         quickElement('a', shortcuts, gettext('Today'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', 0);');
    198         shortcuts.appendChild(document.createTextNode('\240|\240'));
    199         quickElement('a', shortcuts, gettext('Tomorrow'), 'href', 'javascript:DateTimeShortcuts.handleCalendarQuickLink(' + num + ', +1);');
    200 
    201         // cancel bar
    202         var cancel_p = quickElement('p', cal_box, '');
    203         cancel_p.className = 'calendar-cancel';
    204         quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');');
    205         django.jQuery(document).bind('keyup', function(event) {
    206             if (event.which == 27) {
    207                 // ESC key closes popup
    208                 DateTimeShortcuts.dismissCalendar(num);
    209                 event.preventDefault();
    210             }
    211         });
    212     },
    213     openCalendar: function(num) {
    214         var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num)
    215         var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num)
    216         var inp = DateTimeShortcuts.calendarInputs[num];
    217 
    218         // Determine if the current value in the input has a valid date.
    219         // If so, draw the calendar with that date's year and month.
    220         if (inp.value) {
    221             var date_parts = inp.value.split('-');
    222             var year = date_parts[0];
    223             var month = parseFloat(date_parts[1]);
    224             if (year.match(/\d\d\d\d/) && month >= 1 && month <= 12) {
    225                 DateTimeShortcuts.calendars[num].drawDate(month, year);
    226             }
    227         }
    228 
    229         // Recalculate the clockbox position
    230         // is it left-to-right or right-to-left layout ?
    231         if (getStyle(document.body,'direction')!='rtl') {
    232             cal_box.style.left = findPosX(cal_link) + 17 + 'px';
    233         }
    234         else {
    235             // since style's width is in em, it'd be tough to calculate
    236             // px value of it. let's use an estimated px for now
    237             // TODO: IE returns wrong value for findPosX when in rtl mode
    238             //       (it returns as it was left aligned), needs to be fixed.
    239             cal_box.style.left = findPosX(cal_link) - 180 + 'px';
    240         }
    241         cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + 'px';
    242 
    243         cal_box.style.display = 'block';
    244         addEvent(window.document, 'click', function() { DateTimeShortcuts.dismissCalendar(num); return true; });
    245     },
    246     dismissCalendar: function(num) {
    247         document.getElementById(DateTimeShortcuts.calendarDivName1+num).style.display = 'none';
    248         window.document.onclick = null;
    249     },
    250     drawPrev: function(num) {
    251         DateTimeShortcuts.calendars[num].drawPreviousMonth();
    252     },
    253     drawNext: function(num) {
    254         DateTimeShortcuts.calendars[num].drawNextMonth();
    255     },
    256     handleCalendarCallback: function(num) {
    257         format = get_format('DATE_INPUT_FORMATS')[0];
    258         // the format needs to be escaped a little
    259         format = format.replace('\\', '\\\\');
    260         format = format.replace('\r', '\\r');
    261         format = format.replace('\n', '\\n');
    262         format = format.replace('\t', '\\t');
    263         format = format.replace("'", "\\'");
    264         return ["function(y, m, d) { DateTimeShortcuts.calendarInputs[",
    265                num,
    266                "].value = new Date(y, m-1, d).strftime('",
    267                format,
    268                "');DateTimeShortcuts.calendarInputs[",
    269                num,
    270                "].focus();document.getElementById(DateTimeShortcuts.calendarDivName1+",
    271                num,
    272                ").style.display='none';}"].join('');
    273     },
    274     handleCalendarQuickLink: function(num, offset) {
    275        var d = new Date();
    276        d.setDate(d.getDate() + offset)
    277        DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
    278        DateTimeShortcuts.calendarInputs[num].focus();
    279        DateTimeShortcuts.dismissCalendar(num);
    280     },
    281     cancelEventPropagation: function(e) {
    282         if (!e) e = window.event;
    283         e.cancelBubble = true;
    284         if (e.stopPropagation) e.stopPropagation();
    285     }
    286 }
    287 
    288 addEvent(window, 'load', DateTimeShortcuts.init);
  • deleted file django/contrib/admin/static/admin/js/calendar.js

    diff --git a/django/contrib/admin/static/admin/js/calendar.js b/django/contrib/admin/static/admin/js/calendar.js
    deleted file mode 100644
    index c95a95d..0000000
    + -  
    1 /*
    2 calendar.js - Calendar functions by Adrian Holovaty
    3 */
    4 
    5 function removeChildren(a) { // "a" is reference to an object
    6     while (a.hasChildNodes()) a.removeChild(a.lastChild);
    7 }
    8 
    9 // quickElement(tagType, parentReference, textInChildNode, [, attribute, attributeValue ...]);
    10 function quickElement() {
    11     var obj = document.createElement(arguments[0]);
    12     if (arguments[2] != '' && arguments[2] != null) {
    13         var textNode = document.createTextNode(arguments[2]);
    14         obj.appendChild(textNode);
    15     }
    16     var len = arguments.length;
    17     for (var i = 3; i < len; i += 2) {
    18         obj.setAttribute(arguments[i], arguments[i+1]);
    19     }
    20     arguments[1].appendChild(obj);
    21     return obj;
    22 }
    23 
    24 // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions
    25 var CalendarNamespace = {
    26     monthsOfYear: gettext('January February March April May June July August September October November December').split(' '),
    27     daysOfWeek: gettext('S M T W T F S').split(' '),
    28     firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')),
    29     isLeapYear: function(year) {
    30         return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0));
    31     },
    32     getDaysInMonth: function(month,year) {
    33         var days;
    34         if (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) {
    35             days = 31;
    36         }
    37         else if (month==4 || month==6 || month==9 || month==11) {
    38             days = 30;
    39         }
    40         else if (month==2 && CalendarNamespace.isLeapYear(year)) {
    41             days = 29;
    42         }
    43         else {
    44             days = 28;
    45         }
    46         return days;
    47     },
    48     draw: function(month, year, div_id, callback) { // month = 1-12, year = 1-9999
    49         var today = new Date();
    50         var todayDay = today.getDate();
    51         var todayMonth = today.getMonth()+1;
    52         var todayYear = today.getFullYear();
    53         var todayClass = '';
    54 
    55         month = parseInt(month);
    56         year = parseInt(year);
    57         var calDiv = document.getElementById(div_id);
    58         removeChildren(calDiv);
    59         var calTable = document.createElement('table');
    60         quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month-1] + ' ' + year);
    61         var tableBody = quickElement('tbody', calTable);
    62 
    63         // Draw days-of-week header
    64         var tableRow = quickElement('tr', tableBody);
    65         for (var i = 0; i < 7; i++) {
    66             quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]);
    67         }
    68 
    69         var startingPos = new Date(year, month-1, 1 - CalendarNamespace.firstDayOfWeek).getDay();
    70         var days = CalendarNamespace.getDaysInMonth(month, year);
    71 
    72         // Draw blanks before first of month
    73         tableRow = quickElement('tr', tableBody);
    74         for (var i = 0; i < startingPos; i++) {
    75             var _cell = quickElement('td', tableRow, ' ');
    76             _cell.style.backgroundColor = '#f3f3f3';
    77         }
    78 
    79         // Draw days of month
    80         var currentDay = 1;
    81         for (var i = startingPos; currentDay <= days; i++) {
    82             if (i%7 == 0 && currentDay != 1) {
    83                 tableRow = quickElement('tr', tableBody);
    84             }
    85             if ((currentDay==todayDay) && (month==todayMonth) && (year==todayYear)) {
    86                 todayClass='today';
    87             } else {
    88                 todayClass='';
    89             }
    90             var cell = quickElement('td', tableRow, '', 'class', todayClass);
    91 
    92             quickElement('a', cell, currentDay, 'href', 'javascript:void(' + callback + '('+year+','+month+','+currentDay+'));');
    93             currentDay++;
    94         }
    95 
    96         // Draw blanks after end of month (optional, but makes for valid code)
    97         while (tableRow.childNodes.length < 7) {
    98             var _cell = quickElement('td', tableRow, ' ');
    99             _cell.style.backgroundColor = '#f3f3f3';
    100         }
    101 
    102         calDiv.appendChild(calTable);
    103     }
    104 }
    105 
    106 // Calendar -- A calendar instance
    107 function Calendar(div_id, callback) {
    108     // div_id (string) is the ID of the element in which the calendar will
    109     //     be displayed
    110     // callback (string) is the name of a JavaScript function that will be
    111     //     called with the parameters (year, month, day) when a day in the
    112     //     calendar is clicked
    113     this.div_id = div_id;
    114     this.callback = callback;
    115     this.today = new Date();
    116     this.currentMonth = this.today.getMonth() + 1;
    117     this.currentYear = this.today.getFullYear();
    118 }
    119 Calendar.prototype = {
    120     drawCurrent: function() {
    121         CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback);
    122     },
    123     drawDate: function(month, year) {
    124         this.currentMonth = month;
    125         this.currentYear = year;
    126         this.drawCurrent();
    127     },
    128     drawPreviousMonth: function() {
    129         if (this.currentMonth == 1) {
    130             this.currentMonth = 12;
    131             this.currentYear--;
    132         }
    133         else {
    134             this.currentMonth--;
    135         }
    136         this.drawCurrent();
    137     },
    138     drawNextMonth: function() {
    139         if (this.currentMonth == 12) {
    140             this.currentMonth = 1;
    141             this.currentYear++;
    142         }
    143         else {
    144             this.currentMonth++;
    145         }
    146         this.drawCurrent();
    147     },
    148     drawPreviousYear: function() {
    149         this.currentYear--;
    150         this.drawCurrent();
    151     },
    152     drawNextYear: function() {
    153         this.currentYear++;
    154         this.drawCurrent();
    155     }
    156 }
  • new file django/contrib/admin/static/admin/js/datetimeshortcuts.js

    diff --git a/django/contrib/admin/static/admin/js/datetimeshortcuts.js b/django/contrib/admin/static/admin/js/datetimeshortcuts.js
    new file mode 100644
    index 0000000..d023c99
    - +  
     1/**
     2 * Django admin DateTime shortcuts
     3 *
     4 * @requires jQuery 1.4.2 or later
     5 *
     6 * DateTimeShortcuts
     7 * -----------------
     8 *
     9 * Inserts shortcut buttons (clock and calendar) after all input:text fields
     10 * having the classes .vDateField and .vTimeField.
     11 *
     12 * The $("selector").datetimeshortcuts() plugin is intended to be applied on
     13 * fieldsets or whole forms which contain, or may later contain (inline
     14 * fieldsets) date or time fields.
     15 *
     16 * All options as defined in datetimeshortcuts.defaults can be overwritten by
     17 * passing them as array to the datetimeshortcuts() method.
     18 *
     19 */
     20
     21(function($) {
     22
     23    $.fn.datetimeshortcuts = function(options) {
     24        // variables set in base.html
     25        var datetimeshortcuts_defaults = $('body').data('datetimeshortcuts_defaults');
     26
     27        // extend default settings with user options
     28        var o = $.extend({
     29                admin_media_prefix: $('body').data('admin_media_prefix')
     30            },
     31            $.fn.datetimeshortcuts.defaults,
     32            datetimeshortcuts_defaults,
     33            options);
     34
     35        // Check admin_media_prefix setting:
     36        // usually set in admin/base.html template, but if that was overridden,
     37        // it might be missing. Set it to something clearly invalid so that
     38        // somebody might notice it.
     39        if (o.admin_media_prefix === undefined) {
     40            o.admin_media_prefix = '/missing-admin-media-prefix/';
     41        }
     42
     43
     44        /* --- utitity functions ------------------------------------------- */
     45
     46        // month names
     47        var month_names = gettext('January February March April May June July August September October November December').split(' ');
     48
     49        // weekday names
     50        var weekdays = gettext('S M T W T F S').split(' ');
     51
     52        // first day of week
     53        var first_day_of_week = parseInt(get_format('FIRST_DAY_OF_WEEK'), 10);
     54
     55        // find leap years
     56        var is_leap_year = function(year) {
     57            return new Date(year, 1, 29).getDate() == 29;
     58        };
     59
     60        // number of days in month
     61        var get_days_in_month = function(year, month) {
     62            return 32 - new Date(year, month, 32).getDate();
     63        };
     64
     65
     66        /* --- initialization functions ------------------------------------ */
     67
     68        // add shortcuts for date fields
     69        var add_calendar = function(element) {
     70            // insert span.datetimeshortcuts
     71            var shortcuts = $('<span class="'+o.class_shortcuts+'">').insertAfter(element);
     72
     73            // insert today link
     74            if (o.enable_today) {
     75                shortcuts.append(' <a href="#" class="'+o.class_today+'">'+gettext('Today')+'</a>');
     76                if (o.enable_calendar) {
     77                    shortcuts.append(" | ");
     78                }
     79            }
     80
     81            // insert calendar link
     82            if (o.enable_calendar) {
     83                $('<a href="#" class="'+o.class_calendar+'"></a>')
     84                    .appendTo(shortcuts)
     85                    .append('<img src="'+o.admin_media_prefix + 'img/icon_calendar.gif" alt="'+gettext('Calendar')+'" />');
     86            }
     87        };
     88
     89        // add shortcuts for time fields
     90        var add_clock = function(element) {
     91            // insert span.datetimeshortcuts
     92            var shortcuts = $('<span class="'+o.class_shortcuts+'">').insertAfter(element);
     93
     94            // insert now link
     95            if (o.enable_now) {
     96                shortcuts.append(' <a href="#" class="'+o.class_now+'">'+gettext('Now')+'</a>');
     97                if (o.enable_clock) {
     98                    shortcuts.append(" | ");
     99                }
     100            }
     101
     102            // insert clock link
     103            if (o.enable_clock) {
     104                $('<a href="#" class="'+o.class_clock+'"></a>')
     105                    .appendTo(shortcuts)
     106                    .append('<img src="'+o.admin_media_prefix + 'img/icon_clock.gif" alt="'+gettext('Clock')+'" />');
     107            }
     108        };
     109
     110        // draw a month calendar table
     111        var draw_calendar_table = function(selected, show) {
     112            var y_sel, m_sel, d_sel;
     113            // selected date (optional)
     114            if (selected !== null) {
     115                y_sel = selected.getFullYear();
     116                m_sel = selected.getMonth();
     117                d_sel = selected.getDate();
     118            }
     119            // month to show
     120            var y_show = show.getFullYear();
     121            var m_show = show.getMonth();
     122            // today
     123            var today = new Date();
     124            var y_tod = today.getFullYear();
     125            var m_tod = today.getMonth();
     126            var d_tod = today.getDate();
     127
     128            // create table
     129            var cal = $('<table><caption>'+month_names[m_show]+' '+y_show+'</caption></table>');
     130
     131            // add day-of-week headers
     132            var row = $('<tr>').appendTo(cal);
     133            for (var i = 0; i < 7; i++) {
     134                row.append('<th>'+weekdays[(i + first_day_of_week) % 7]+'</th>');
     135            }
     136
     137            var start = new Date(y_show, m_show, 1 - first_day_of_week).getDay();
     138            var days = get_days_in_month(y_show, m_show);
     139
     140            // draw blanks before 1st of month
     141            row = $('<tr>').appendTo(cal);
     142            for (i = 0; i < start; i++) {
     143                $('<td> </td>').appendTo(row).addClass('nonday');
     144            }
     145
     146            // draw month days
     147            var current = 1;
     148            for (i = start; current <= days; i++) {
     149                if (i % 7 === 0 && current != 1) {
     150                    row = $('<tr>').appendTo(cal);
     151                }
     152                var today_class = '';
     153                // mark today
     154                if ((current == d_tod) && (m_show == m_tod) && (y_show == y_tod)) {
     155                    today_class = 'today';
     156                }
     157                // mark selected day
     158                if ((current == d_sel) && (m_show == m_sel) && (y_show == y_sel)) {
     159                    today_class = 'selected';
     160                }
     161                $('<td>').appendTo(row)
     162                    .addClass(today_class)
     163                    .append('<a href="#">'+current+'</a>')
     164                    .find('a')
     165                    .data('date', new Date(y_show, m_show, current++));
     166            }
     167
     168            // draw blanks after last of month
     169            while(row.children('td').length < 7) {
     170                $('<td> </td>').appendTo(row).addClass('nonday');
     171            }
     172
     173            return cal;
     174        };
     175
     176        // init one calendar per fieldset
     177        var init_calendar_box = function(fieldset) {
     178            // insert calendar box if not there
     179            if (fieldset.find('.'+o.class_calendarbox).length === 0) {
     180
     181                $('<div class="'+o.class_calendarbox+' module">'  +
     182                    '  <div>'+
     183                    '    <a href="#" class="calendarnav-previous"><</a>' +
     184                    '    <a href="#" class="calendarnav-next">></a>' +
     185                    '  </div>' +
     186                    '  <div class="calendar_table calendar"></div>' +
     187                    '  <div class="calendar-shortcuts">'+
     188                    '    <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>' +
     189                    '  </div>' +
     190                    '  <p class="calendar-cancel"><a href="#">'+gettext('Cancel')+'</p>' +
     191                    '</div>')
     192                    .appendTo(fieldset).css('position', 'absolute').hide();
     193
     194                // prev/next event handlers
     195                fieldset.find('.'+o.class_calendarbox)
     196                    .delegate('.calendarnav-previous, .calendarnav-next',
     197                              'click', function(event) {
     198                        var func = $(this).is('.calendarnav-next') ? 'calendar_next' : 'calendar_previous';
     199                        $(this).parents('.'+o.class_calendarbox).trigger(func);
     200                        event.preventDefault();
     201                        event.stopPropagation();
     202                    })
     203                    // days event handlers
     204                    .delegate('td a', 'click', function(event) {
     205                        fieldset.trigger('callback_calendar',
     206                                         $(event.target).data('date'));
     207                        event.preventDefault();
     208                        event.stopPropagation();
     209                    })
     210                    // cancel link
     211                    .find('.calendar-cancel').click(function(event) {
     212                        fieldset.trigger('hide_calendar');
     213                        event.preventDefault();
     214                        event.stopPropagation();
     215                    });
     216            }
     217        };
     218
     219        // init one clock box per fieldset
     220        var init_clock_box = function(fieldset) {
     221            // insert clock box if not there
     222            if (fieldset.find('.'+o.class_clockbox).length === 0) {
     223
     224                var timelist = $('<div class="'+o.class_clockbox+' module">'  +
     225                    '  <h2>'+gettext('Choose a time')+'</h2>' +
     226                    '  <ul class="timelist"></ul>' +
     227                    '  <p class="clock-cancel"><a href="#">'+gettext('Cancel')+'</p>' +
     228                    '</div>')
     229                    .appendTo(fieldset).css('position', 'absolute').hide()
     230                    .find('.timelist');
     231
     232                timelist.append('<li><a href="#">'+gettext('Now')+'</a></li>').find('a:last').data('time', new Date());
     233                timelist.append('<li><a href="#">'+gettext('Midnight')+'</a></li>').find('a:last').data('time', new Date(1970,1,1,0,0));
     234                timelist.append('<li><a href="#">'+gettext('6 a.m.')+'</a></li>').find('a:last').data('time', new Date(1970,1,1,6,0));
     235                timelist.append('<li><a href="#">'+gettext('Noon')+'</a></li>').find('a:last').data('time', new Date(1970,1,1,12,0));
     236
     237                // time links event handlers
     238                fieldset.find('.'+o.class_clockbox)
     239                    .delegate('li a', 'click', function(event) {
     240                        fieldset.trigger('callback_clock',
     241                                         $(event.target).data('time'));
     242                        event.preventDefault();
     243                        event.stopPropagation();
     244                    })
     245                    // cancel link
     246                    .find('.clock-cancel').click(function(event) {
     247                        fieldset.trigger('hide_clock');
     248                        event.preventDefault();
     249                        event.stopPropagation();
     250                    });
     251            }
     252        };
     253
     254        return this.each(function() {
     255            var fieldset = $(this);
     256
     257            /* --- setup datetimeshortcuts specific event handlers --------- */
     258            fieldset
     259
     260            // show calendar
     261            .bind('show_calendar', function(event) {
     262                fieldset.trigger('hide_clock');
     263                fieldset.trigger('hide_calendar');
     264
     265                var target = $(event.target);
     266                var calendar = fieldset.children('.'+o.class_calendarbox);
     267                var field = target
     268                    .parents('.'+o.class_shortcuts)
     269                    .prev(o.date_fields);
     270
     271                // Check current field value for valid date
     272                // and open calendar with that date selected
     273                var date_sel = null;
     274                var date_show = new Date();
     275                if (field.val().length > 0) {
     276                    // only support specific date formats here for simplicity
     277                    // (jQueryUI.datepicker.dateParse could help here)
     278                    var regex = null, y, m, d;
     279                    if (o.date_input_format == '%Y-%m-%d') {
     280                        regex = /^(\d{4})-(\d{2})-(\d{2})$/;
     281                        y=1; m=2; d=3;
     282                    }
     283                    else if (o.date_input_format == '%m/%d/%Y') {
     284                        regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
     285                        y=3; m=1; d=2;
     286                    }
     287                    else if (o.date_input_format == '%m/%d/%y') {
     288                        regex = /^(\d{2})\/(\d{2})\/(\d{2})$/;
     289                        y=3; m=1; d=2;
     290                    }
     291                    else if (o.date_input_format == '%d.%m.%Y') {
     292                        regex = /^(\d{2})\.(\d{2})\.(\d{4})$/;
     293                        y=3; m=2; d=1;
     294                    }
     295                    else if (o.date_input_format == '%d.%m.%y') {
     296                        regex = /^(\d{2})\.(\d{2})\.(\d{2})$/;
     297                        y=3; m=2; d=1;
     298                    }
     299
     300                    if (regex !== null) {
     301                        var match = regex.exec(field.val());
     302                        if (match !== null) {
     303                            year = match[y];
     304                            month = match[m];
     305                            day = match[d];
     306                            if (y.length == 2) {
     307                                year = '20'+year;
     308                            }
     309                            date_sel = new Date(year, month-1, day);
     310                            date_show = new Date(year, month-1, day);
     311                        }
     312                    }
     313                }
     314
     315                // open calendar
     316                calendar
     317                    // remember field and date
     318                    .data('calendar_date_field', field)
     319                    .data('calendar_date_show', date_show)
     320                    .data('calendar_date_sel', date_sel)
     321                    // draw correct month
     322                    .find('.calendar_table').empty()
     323                    .append(draw_calendar_table(date_sel, date_show))
     324                    .end().show();
     325
     326                // position based on LTR or RTL direction
     327                var target_pos = target.position();
     328                var dir = $('body').attr('direction');
     329                if (dir != 'rtl') {
     330                    calendar.css('left', target_pos.left + target.width() + 'px');
     331                }
     332                if (dir == 'rtl' ||
     333                    ((calendar.offset().left + calendar.width()) > $(window).width())) {
     334                    calendar.css('left',
     335                        target_pos.left - calendar.width() + 'px');
     336                }
     337                calendar.css('top',
     338                    Math.max(0, target_pos.top - calendar.height()/2) + 'px');
     339
     340                // bind close handler to document
     341                $('body').bind('click.datetimeshortcuts', function() {
     342                    fieldset.trigger('hide_calendar');
     343                });
     344            })
     345
     346            // show next month in calendar
     347            .bind('calendar_next', function(event) {
     348                var cal = $(event.target);
     349                var tbl = cal.find('.calendar_table').empty();
     350                var selected = cal.data('calendar_date_sel');
     351                var show = cal.data('calendar_date_show');
     352                var month = show.getMonth();
     353                var year = show.getFullYear();
     354                if (month == 11) {
     355                    month = 0;
     356                    year++;
     357                }
     358                else {
     359                    month++;
     360                }
     361                show.setFullYear(year, month, 1);
     362                cal.data('calendar_date_show', show);
     363                tbl.append(draw_calendar_table(selected, show));
     364            })
     365
     366            // show previous month in calendar
     367            .bind('calendar_previous', function(event) {
     368                var cal = $(event.target);
     369                var tbl = cal.find('.calendar_table').empty();
     370                var selected = cal.data('calendar_date_sel');
     371                var show = cal.data('calendar_date_show');
     372                var month = show.getMonth();
     373                var year = show.getFullYear();
     374                if (month === 0) {
     375                    month = 11;
     376                    year--;
     377                }
     378                else {
     379                    month--;
     380                }
     381                show.setFullYear(year, month, 1);
     382                cal.data('calendar_date_show', show);
     383                tbl.append(draw_calendar_table(selected, show));
     384            })
     385
     386            // hide calendar
     387            .bind('hide_calendar', function(event) {
     388                $(event.target)
     389                    .children('.'+o.class_calendarbox)
     390                    .removeData('calendar_date_field')
     391                    .removeData('calendar_date_sel')
     392                    .removeData('calendar_date_show')
     393                    .hide();
     394                $('document').unbind('.datetimeshortcuts');
     395            })
     396
     397            // show clock
     398            .bind('show_clock', function(event) {
     399                fieldset.trigger('hide_clock');
     400                fieldset.trigger('hide_calendar');
     401
     402                var target = $(event.target);
     403                var clock = fieldset.children('.'+o.class_clockbox);
     404                var field = target
     405                    .parents('.'+o.class_shortcuts)
     406                    .prev(o.time_fields);
     407
     408                // open clock
     409                clock
     410                    .data('clock_time_field', field)
     411                    .show();
     412
     413                // position based on LTR or RTL direction
     414                var target_pos = target.position();
     415                var dir = $('body').attr('direction');
     416                if (dir != 'rtl') {
     417                    clock.css('left', target_pos.left + target.width() + 'px');
     418                }
     419                if (dir == 'rtl' ||
     420                    ((clock.offset().left + clock.width()) > $(window).width())) {
     421                    clock.css('left', target_pos.left - clock.width() + 'px');
     422                }
     423                clock.css('top',
     424                    Math.max(0, target_pos.top - clock.height()/2) + 'px');
     425
     426                // bind close handler to document
     427                $('body').bind('click.datetimeshortcuts', function() {
     428                    fieldset.trigger('hide_clock');
     429                });
     430            })
     431
     432            // hide clock
     433            .bind('hide_clock', function(event) {
     434                $(event.target)
     435                    .children('.'+o.class_clockbox)
     436                    .removeData('clock_time_field')
     437                    .hide();
     438                $('document').unbind('.datetimeshortcuts');
     439            })
     440
     441            // calendar callback
     442            .bind('callback_calendar', function(event, date) {
     443                $(event.target)
     444                    .find('.'+o.class_calendarbox)
     445                    .data('calendar_date_field')
     446                    .val(date.strftime(o.date_input_format))
     447                    .focus();
     448                fieldset.trigger('hide_calendar');
     449            })
     450
     451            // today link callback
     452            .bind('callback_today', function(event, days_offset) {
     453                var d = new Date();
     454                d.setDate(d.getDate() + days_offset);
     455                $(event.target)
     456                   .val(d.strftime(o.date_input_format))
     457                   .focus();
     458            })
     459
     460            // clock callback
     461            .bind('callback_clock', function(event, time) {
     462                $(event.target)
     463                    .find('.'+o.class_clockbox)
     464                    .data('clock_time_field')
     465                    .val(time.strftime(o.time_input_format))
     466                    .focus();
     467                fieldset.trigger('hide_clock');
     468            })
     469
     470            // now link callback
     471            .bind('callback_now', function(event) {
     472                var d = new Date();
     473                $(event.target)
     474                    .val(d.strftime(o.time_input_format))
     475                    .focus();
     476            });
     477
     478
     479            /* --- add datetime shortcut widgets --------------------------- */
     480
     481            // add shortcuts to date fields
     482            fieldset.find(o.date_fields).each(function() {
     483                add_calendar($(this));
     484            });
     485            // add shortcuts to time fields
     486            fieldset.find(o.time_fields).each(function() {
     487                add_clock($(this));
     488            });
     489            // create calendar and clock widgets
     490            init_calendar_box(fieldset);
     491            init_clock_box(fieldset);
     492
     493
     494            /* --- setup $(this)-wide event delegation --------------------- */
     495            fieldset
     496
     497            // click on calendar
     498            .delegate("."+o.class_shortcuts+" ."+o.class_calendar,
     499                      "click", function(event) {
     500                $(event.target).trigger('show_calendar');
     501                // prevent following link
     502                event.preventDefault();
     503                event.stopPropagation();
     504            })
     505
     506            // click on today link
     507            .delegate("."+o.class_shortcuts+" ."+o.class_today,
     508                      "click", function(event) {
     509                $(event.target)
     510                    // find .datetimeshortcuts span
     511                    .parents('.'+o.class_shortcuts)
     512                    .prev(o.date_fields)
     513                    // update field
     514                    .trigger('callback_today', 0);
     515                fieldset.trigger('hide_calendar');
     516                // prevent following link
     517                event.preventDefault();
     518                event.stopPropagation();
     519            })
     520
     521            // click on yesterday/today/tomorrow links in calendar
     522            .delegate("."+o.class_calendarbox+" ."+o.class_today,
     523                      "click", function(event) {
     524                var target = $(event.target);
     525                var offset = 0;
     526                if (target.is('.yesterday')) {
     527                    offset = -1;
     528                }
     529                else if (target.is('.tomorrow')) {
     530                    offset = 1;
     531                }
     532                // find calendarbox
     533                target.parents('.'+o.class_calendarbox)
     534                    // target field is stored on calendar's data attribute
     535                    .data('calendar_date_field')
     536                    // update field
     537                    .trigger('callback_today', offset)
     538                    .focus();
     539                fieldset.trigger('hide_calendar');
     540                // prevent following link
     541                event.preventDefault();
     542                event.stopPropagation();
     543            })
     544
     545            // click on clock
     546            .delegate("."+o.class_shortcuts+" ."+o.class_clock,
     547                      "click", function(event) {
     548                $(event.target).trigger('show_clock');
     549                // prevent following link
     550                event.preventDefault();
     551                event.stopPropagation();
     552            })
     553
     554            // click on now link
     555            .delegate("."+o.class_shortcuts+" ."+o.class_now,
     556                      "click", function(event) {
     557                $(event.target)
     558                    // find .datetimeshortcuts span
     559                    .parents('.'+o.class_shortcuts)
     560                    .prev(o.time_fields)
     561                    // update field
     562                    .trigger('callback_now');
     563                fieldset.trigger('hide_clock');
     564                // prevent following link
     565                event.preventDefault();
     566                event.stopPropagation();
     567            });
     568        });
     569    };
     570
     571    $.fn.datetimeshortcuts.defaults = {
     572        // classes (do not change - css depends on these)
     573        class_shortcuts: "datetimeshortcuts",
     574        class_today: "today",
     575        class_calendar: "calendar",
     576        class_now: "now",
     577        class_clock: "clock",
     578        class_calendarbox: "calendarbox",
     579        class_clockbox: "clockbox",
     580        // date and time format
     581        date_input_format: get_format('DATE_INPUT_FORMATS')[0],
     582        time_input_format: get_format('TIME_INPUT_FORMATS')[0],
     583        // selectors for date and time fields
     584        date_fields: "input:text.vDateField",
     585        time_fields: "input:text.vTimeField",
     586        // enable clock or calendar widgets
     587        enable_calendar: true,
     588        enable_today: true,
     589        enable_clock: true,
     590        enable_now: true
     591    };
     592
     593    // by default, initialize on all fieldset.module elements
     594    // which hold any date or time fields
     595    $(document).ready(function() {
     596       $("fieldset.module").datetimeshortcuts();
     597    });
     598
     599})(django.jQuery);
  • new file django/contrib/admin/static/admin/js/datetimeshortcuts.min.js

    diff --git a/django/contrib/admin/static/admin/js/datetimeshortcuts.min.js b/django/contrib/admin/static/admin/js/datetimeshortcuts.min.js
    new file mode 100644
    index 0000000..d8927d8
    - +  
     1(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===void 0)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"),10),q=function(b,
     2a){var e,h,g;b!==null&&(e=b.getFullYear(),h=b.getMonth(),g=b.getDate());for(var i=a.getFullYear(),f=a.getMonth(),j=new Date,k=j.getFullYear(),m=j.getMonth(),j=j.getDate(),r=c("<table><caption>"+v[f]+" "+i+"</caption></table>"),n=c("<tr>").appendTo(r),l=0;l<7;l++)n.append("<th>"+w[(l+s)%7]+"</th>");for(var o=(new Date(i,f,1-s)).getDay(),q=32-(new Date(i,f,32)).getDate(),n=c("<tr>").appendTo(r),l=0;l<o;l++)c("<td> </td>").appendTo(n).addClass("nonday");for(var p=1,l=o;p<=q;l++)l%7===0&&p!=1&&(n=c("<tr>").appendTo(r)),
     3o="",p==j&&f==m&&i==k&&(o="today"),p==g&&f==h&&i==e&&(o="selected"),c("<td>").appendTo(n).addClass(o).append('<a href="#">'+p+"</a>").find("a").data("date",new Date(i,f,p++));for(;n.children("td").length<7;)c("<td> </td>").appendTo(n).addClass("nonday");return r},x=function(d){d.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="'+
     4b.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(d).css("position","absolute").hide(),d.find("."+b.class_calendarbox).delegate(".calendarnav-previous, .calendarnav-next","click",function(a){var e=c(this).is(".calendarnav-next")?"calendar_next":"calendar_previous";
     5c(this).parents("."+b.class_calendarbox).trigger(e);a.preventDefault();a.stopPropagation()}).delegate("td a","click",function(a){d.trigger("callback_calendar",c(a.target).data("date"));a.preventDefault();a.stopPropagation()}).find(".calendar-cancel").click(function(a){d.trigger("hide_calendar");a.preventDefault();a.stopPropagation()}))},y=function(d){if(d.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="#">'+
     6gettext("Cancel")+"</p></div>").appendTo(d).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,
     71,1,12,0));d.find("."+b.class_clockbox).delegate("li a","click",function(a){d.trigger("callback_clock",c(a.target).data("time"));a.preventDefault();a.stopPropagation()}).find(".clock-cancel").click(function(a){d.trigger("hide_clock");a.preventDefault();a.stopPropagation()})}};return this.each(function(){var d=c(this);d.bind("show_calendar",function(a){d.trigger("hide_clock");d.trigger("hide_calendar");var a=c(a.target),e=d.children("."+b.class_calendarbox),h=a.parents("."+b.class_shortcuts).prev(b.date_fields),
     8g=null,i=new Date;if(h.val().length>0){var f=null,j,k,m;b.date_input_format=="%Y-%m-%d"?(f=/^(\d{4})-(\d{2})-(\d{2})$/,j=1,k=2,m=3):b.date_input_format=="%m/%d/%Y"?(f=/^(\d{2})\/(\d{2})\/(\d{4})$/,j=3,k=1,m=2):b.date_input_format=="%m/%d/%y"?(f=/^(\d{2})\/(\d{2})\/(\d{2})$/,j=3,k=1,m=2):b.date_input_format=="%d.%m.%Y"?(f=/^(\d{2})\.(\d{2})\.(\d{4})$/,j=3,k=2,m=1):b.date_input_format=="%d.%m.%y"&&(f=/^(\d{2})\.(\d{2})\.(\d{2})$/,j=3,k=2,m=1);f!==null&&(f=f.exec(h.val()),f!==null&&(year=f[j],month=
     9f[k],day=f[m],j.length==2&&(year="20"+year),g=new Date(year,month-1,day),i=new Date(year,month-1,day)))}e.data("calendar_date_field",h).data("calendar_date_show",i).data("calendar_date_sel",g).find(".calendar_table").empty().append(q(g,i)).end().show();j=a.position();k=c("body").attr("direction");k!="rtl"&&e.css("left",j.left+a.width()+"px");(k=="rtl"||e.offset().left+e.width()>c(window).width())&&e.css("left",j.left-e.width()+"px");e.css("top",Math.max(0,j.top-e.height()/2)+"px");c("body").bind("click.datetimeshortcuts",
     10function(){d.trigger("hide_calendar")})}).bind("calendar_next",function(a){var a=c(a.target),b=a.find(".calendar_table").empty(),d=a.data("calendar_date_sel"),g=a.data("calendar_date_show"),i=g.getMonth(),f=g.getFullYear();i==11?(i=0,f++):i++;g.setFullYear(f,i,1);a.data("calendar_date_show",g);b.append(q(d,g))}).bind("calendar_previous",function(a){var a=c(a.target),b=a.find(".calendar_table").empty(),d=a.data("calendar_date_sel"),g=a.data("calendar_date_show"),i=g.getMonth(),f=g.getFullYear();i===
     110?(i=11,f--):i--;g.setFullYear(f,i,1);a.data("calendar_date_show",g);b.append(q(d,g))}).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){d.trigger("hide_clock");d.trigger("hide_calendar");var a=c(a.target),e=d.children("."+b.class_clockbox),h=a.parents("."+b.class_shortcuts).prev(b.time_fields);
     12e.data("clock_time_field",h).show();var h=a.position(),g=c("body").attr("direction");g!="rtl"&&e.css("left",h.left+a.width()+"px");(g=="rtl"||e.offset().left+e.width()>c(window).width())&&e.css("left",h.left-e.width()+"px");e.css("top",Math.max(0,h.top-e.height()/2)+"px");c("body").bind("click.datetimeshortcuts",function(){d.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",
     13function(a,e){c(a.target).find("."+b.class_calendarbox).data("calendar_date_field").val(e.strftime(b.date_input_format)).focus();d.trigger("hide_calendar")}).bind("callback_today",function(a,d){var h=new Date;h.setDate(h.getDate()+d);c(a.target).val(h.strftime(b.date_input_format)).focus()}).bind("callback_clock",function(a,e){c(a.target).find("."+b.class_clockbox).data("clock_time_field").val(e.strftime(b.time_input_format)).focus();d.trigger("hide_clock")}).bind("callback_now",function(a){var d=
     14new Date;c(a.target).val(d.strftime(b.time_input_format)).focus()});d.find(b.date_fields).each(function(){var a=c(this),a=c('<span class="'+b.class_shortcuts+'">').insertAfter(a);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/icon_calendar.gif" alt="'+gettext("Calendar")+'" />')});d.find(b.time_fields).each(function(){var a=
     15c(this),a=c('<span class="'+b.class_shortcuts+'">').insertAfter(a);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/icon_clock.gif" alt="'+gettext("Clock")+'" />')});x(d);y(d);d.delegate("."+b.class_shortcuts+" ."+b.class_calendar,"click",function(a){c(a.target).trigger("show_calendar");a.preventDefault();a.stopPropagation()}).delegate("."+
     16b.class_shortcuts+" ."+b.class_today,"click",function(a){c(a.target).parents("."+b.class_shortcuts).prev(b.date_fields).trigger("callback_today",0);d.trigger("hide_calendar");a.preventDefault();a.stopPropagation()}).delegate("."+b.class_calendarbox+" ."+b.class_today,"click",function(a){var e=c(a.target),h=0;e.is(".yesterday")?h=-1:e.is(".tomorrow")&&(h=1);e.parents("."+b.class_calendarbox).data("calendar_date_field").trigger("callback_today",h).focus();d.trigger("hide_calendar");a.preventDefault();
     17a.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");d.trigger("hide_clock");a.preventDefault();a.stopPropagation()})})};c.fn.datetimeshortcuts.defaults={class_shortcuts:"datetimeshortcuts",class_today:"today",class_calendar:"calendar",
     18class_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:!0,enable_today:!0,enable_clock:!0,enable_now:!0};c(document).ready(function(){c("fieldset.module").datetimeshortcuts()})})(django.jQuery);
  • django/contrib/admin/templates/admin/base.html

    diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html
    index 3b50adc..ef831f6 100644
    a b  
    1414
    1515<body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}">
    1616
     17<script type="text/javascript">
     18    if (typeof(django) != "undefined" && typeof(django.jQuery) != "undefined") {
     19        (function($) {
     20            $('body').data('admin_media_prefix', "{% filter escapejs %}{% static "admin/" %}{% endfilter %}");
     21            {# TODO: templatetag admin_datetimeshortcuts (?) to render the following from django.conf.settings #}
     22            $('body').data('datetimeshortcuts_defaults', {
     23                enable_calendar: true,
     24                enable_today: true,
     25                enable_clock: true,
     26                enable_now: true
     27            });
     28        })(django.jQuery);
     29    }
     30</script>
     31
    1732<!-- Container -->
    1833<div id="container">
    1934
  • django/contrib/admin/templates/admin/edit_inline/stacked.html

    diff --git a/django/contrib/admin/templates/admin/edit_inline/stacked.html b/django/contrib/admin/templates/admin/edit_inline/stacked.html
    index 08e8ca3..0456d6c 100644
    a b  
    2828                $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
    2929            });
    3030        };
    31         var reinitDateTimeShortCuts = function() {
    32             // Reinitialize the calendar and clock widgets by force, yuck.
    33             if (typeof DateTimeShortcuts != "undefined") {
    34                 $(".datetimeshortcuts").remove();
    35                 DateTimeShortcuts.init();
    36             }
    37         };
    3831        var updateSelectFilter = function() {
    3932            // If any SelectFilter widgets were added, instantiate a new instance.
    4033            if (typeof SelectFilter != "undefined"){
     
    7265            removed: updateInlineLabel,
    7366            added: (function(row) {
    7467                initPrepopulatedFields(row);
    75                 reinitDateTimeShortCuts();
    7668                updateSelectFilter();
    7769                updateInlineLabel(row);
    7870            })
  • django/contrib/admin/templates/admin/edit_inline/tabular.html

    diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html
    index 9e215af..157632e 100644
    a b  
    7575                .filter(":even").addClass("row1").end()
    7676                .filter(rows + ":odd").addClass("row2");
    7777        }
    78         var reinitDateTimeShortCuts = function() {
    79             // Reinitialize the calendar and clock widgets by force
    80             if (typeof DateTimeShortcuts != "undefined") {
    81                 $(".datetimeshortcuts").remove();
    82                 DateTimeShortcuts.init();
    83             }
    84         }
    8578        var updateSelectFilter = function() {
    8679            // If any SelectFilter widgets are a part of the new form,
    8780            // instantiate a new SelectFilter instance for it.
     
    120113            removed: alternatingRows,
    121114            added: (function(row) {
    122115                initPrepopulatedFields(row);
    123                 reinitDateTimeShortCuts();
    124116                updateSelectFilter();
    125117                alternatingRows(row);
    126118            })
  • django/contrib/admin/widgets.py

    diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
    index 29958b2..0d3f740 100644
    a b class AdminDateWidget(forms.DateInput): 
    5050
    5151    @property
    5252    def media(self):
    53         js = ["calendar.js", "admin/DateTimeShortcuts.js"]
     53        js = ["datetimeshortcuts.min.js"]
    5454        return forms.Media(js=[static("admin/js/%s" % path) for path in js])
    5555
    5656    def __init__(self, attrs=None, format=None):
    class AdminTimeWidget(forms.TimeInput): 
    6363
    6464    @property
    6565    def media(self):
    66         js = ["calendar.js", "admin/DateTimeShortcuts.js"]
     66        js = ["datetimeshortcuts.min.js"]
    6767        return forms.Media(js=[static("admin/js/%s" % path) for path in js])
    6868
    6969    def __init__(self, attrs=None, format=None):
Back to Top