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