DateTimeShortcuts.js 14 KB

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