calendar.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*global gettext, pgettext, get_format, quickElement, removeChildren*/
  2. /*
  3. calendar.js - Calendar functions by Adrian Holovaty
  4. depends on core.js for utility functions like removeChildren or quickElement
  5. */
  6. 'use strict';
  7. {
  8. // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions
  9. const CalendarNamespace = {
  10. monthsOfYear: [
  11. gettext('January'),
  12. gettext('February'),
  13. gettext('March'),
  14. gettext('April'),
  15. gettext('May'),
  16. gettext('June'),
  17. gettext('July'),
  18. gettext('August'),
  19. gettext('September'),
  20. gettext('October'),
  21. gettext('November'),
  22. gettext('December')
  23. ],
  24. monthsOfYearAbbrev: [
  25. pgettext('abbrev. month January', 'Jan'),
  26. pgettext('abbrev. month February', 'Feb'),
  27. pgettext('abbrev. month March', 'Mar'),
  28. pgettext('abbrev. month April', 'Apr'),
  29. pgettext('abbrev. month May', 'May'),
  30. pgettext('abbrev. month June', 'Jun'),
  31. pgettext('abbrev. month July', 'Jul'),
  32. pgettext('abbrev. month August', 'Aug'),
  33. pgettext('abbrev. month September', 'Sep'),
  34. pgettext('abbrev. month October', 'Oct'),
  35. pgettext('abbrev. month November', 'Nov'),
  36. pgettext('abbrev. month December', 'Dec')
  37. ],
  38. daysOfWeek: [
  39. pgettext('one letter Sunday', 'S'),
  40. pgettext('one letter Monday', 'M'),
  41. pgettext('one letter Tuesday', 'T'),
  42. pgettext('one letter Wednesday', 'W'),
  43. pgettext('one letter Thursday', 'T'),
  44. pgettext('one letter Friday', 'F'),
  45. pgettext('one letter Saturday', 'S')
  46. ],
  47. firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')),
  48. isLeapYear: function(year) {
  49. return (((year % 4) === 0) && ((year % 100) !== 0 ) || ((year % 400) === 0));
  50. },
  51. getDaysInMonth: function(month, year) {
  52. let days;
  53. if (month === 1 || month === 3 || month === 5 || month === 7 || month === 8 || month === 10 || month === 12) {
  54. days = 31;
  55. }
  56. else if (month === 4 || month === 6 || month === 9 || month === 11) {
  57. days = 30;
  58. }
  59. else if (month === 2 && CalendarNamespace.isLeapYear(year)) {
  60. days = 29;
  61. }
  62. else {
  63. days = 28;
  64. }
  65. return days;
  66. },
  67. draw: function(month, year, div_id, callback, selected) { // month = 1-12, year = 1-9999
  68. const today = new Date();
  69. const todayDay = today.getDate();
  70. const todayMonth = today.getMonth() + 1;
  71. const todayYear = today.getFullYear();
  72. let todayClass = '';
  73. // Use UTC functions here because the date field does not contain time
  74. // and using the UTC function variants prevent the local time offset
  75. // from altering the date, specifically the day field. For example:
  76. //
  77. // ```
  78. // var x = new Date('2013-10-02');
  79. // var day = x.getDate();
  80. // ```
  81. //
  82. // The day variable above will be 1 instead of 2 in, say, US Pacific time
  83. // zone.
  84. let isSelectedMonth = false;
  85. if (typeof selected !== 'undefined') {
  86. isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth() + 1) === month);
  87. }
  88. month = parseInt(month);
  89. year = parseInt(year);
  90. const calDiv = document.getElementById(div_id);
  91. removeChildren(calDiv);
  92. const calTable = document.createElement('table');
  93. quickElement('caption', calTable, CalendarNamespace.monthsOfYear[month - 1] + ' ' + year);
  94. const tableBody = quickElement('tbody', calTable);
  95. // Draw days-of-week header
  96. let tableRow = quickElement('tr', tableBody);
  97. for (let i = 0; i < 7; i++) {
  98. quickElement('th', tableRow, CalendarNamespace.daysOfWeek[(i + CalendarNamespace.firstDayOfWeek) % 7]);
  99. }
  100. const startingPos = new Date(year, month - 1, 1 - CalendarNamespace.firstDayOfWeek).getDay();
  101. const days = CalendarNamespace.getDaysInMonth(month, year);
  102. let nonDayCell;
  103. // Draw blanks before first of month
  104. tableRow = quickElement('tr', tableBody);
  105. for (let i = 0; i < startingPos; i++) {
  106. nonDayCell = quickElement('td', tableRow, ' ');
  107. nonDayCell.className = "nonday";
  108. }
  109. function calendarMonth(y, m) {
  110. function onClick(e) {
  111. e.preventDefault();
  112. callback(y, m, this.textContent);
  113. }
  114. return onClick;
  115. }
  116. // Draw days of month
  117. let currentDay = 1;
  118. for (let i = startingPos; currentDay <= days; i++) {
  119. if (i % 7 === 0 && currentDay !== 1) {
  120. tableRow = quickElement('tr', tableBody);
  121. }
  122. if ((currentDay === todayDay) && (month === todayMonth) && (year === todayYear)) {
  123. todayClass = 'today';
  124. } else {
  125. todayClass = '';
  126. }
  127. // use UTC function; see above for explanation.
  128. if (isSelectedMonth && currentDay === selected.getUTCDate()) {
  129. if (todayClass !== '') {
  130. todayClass += " ";
  131. }
  132. todayClass += "selected";
  133. }
  134. const cell = quickElement('td', tableRow, '', 'class', todayClass);
  135. const link = quickElement('a', cell, currentDay, 'href', '#');
  136. link.addEventListener('click', calendarMonth(year, month));
  137. currentDay++;
  138. }
  139. // Draw blanks after end of month (optional, but makes for valid code)
  140. while (tableRow.childNodes.length < 7) {
  141. nonDayCell = quickElement('td', tableRow, ' ');
  142. nonDayCell.className = "nonday";
  143. }
  144. calDiv.appendChild(calTable);
  145. }
  146. };
  147. // Calendar -- A calendar instance
  148. function Calendar(div_id, callback, selected) {
  149. // div_id (string) is the ID of the element in which the calendar will
  150. // be displayed
  151. // callback (string) is the name of a JavaScript function that will be
  152. // called with the parameters (year, month, day) when a day in the
  153. // calendar is clicked
  154. this.div_id = div_id;
  155. this.callback = callback;
  156. this.today = new Date();
  157. this.currentMonth = this.today.getMonth() + 1;
  158. this.currentYear = this.today.getFullYear();
  159. if (typeof selected !== 'undefined') {
  160. this.selected = selected;
  161. }
  162. }
  163. Calendar.prototype = {
  164. drawCurrent: function() {
  165. CalendarNamespace.draw(this.currentMonth, this.currentYear, this.div_id, this.callback, this.selected);
  166. },
  167. drawDate: function(month, year, selected) {
  168. this.currentMonth = month;
  169. this.currentYear = year;
  170. if(selected) {
  171. this.selected = selected;
  172. }
  173. this.drawCurrent();
  174. },
  175. drawPreviousMonth: function() {
  176. if (this.currentMonth === 1) {
  177. this.currentMonth = 12;
  178. this.currentYear--;
  179. }
  180. else {
  181. this.currentMonth--;
  182. }
  183. this.drawCurrent();
  184. },
  185. drawNextMonth: function() {
  186. if (this.currentMonth === 12) {
  187. this.currentMonth = 1;
  188. this.currentYear++;
  189. }
  190. else {
  191. this.currentMonth++;
  192. }
  193. this.drawCurrent();
  194. },
  195. drawPreviousYear: function() {
  196. this.currentYear--;
  197. this.drawCurrent();
  198. },
  199. drawNextYear: function() {
  200. this.currentYear++;
  201. this.drawCurrent();
  202. }
  203. };
  204. window.Calendar = Calendar;
  205. window.CalendarNamespace = CalendarNamespace;
  206. }