FossilRepo

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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button