blob: 0fd47dd68febb2fef28ed2576b31acbe9136e96d [file] [log] [blame]
Nils Diewalda1228622015-04-25 01:59:10 +00001/**
Nils Diewald7148c6f2015-05-04 15:07:53 +00002 * Simple Date picker for the
Nils Diewalda1228622015-04-25 01:59:10 +00003 * Virtual Collection builder.
Nils Diewald7148c6f2015-05-04 15:07:53 +00004 *
5 * @author Nils Diewald
Nils Diewalda1228622015-04-25 01:59:10 +00006 */
7define(['util'], function () {
8 "use strict";
9
Nils Diewald7148c6f2015-05-04 15:07:53 +000010 /*
11 * Localizations
12 */
Nils Diewalda1228622015-04-25 01:59:10 +000013 var loc = KorAP.Locale;
Nils Diewalda1228622015-04-25 01:59:10 +000014 loc.WDAY = loc.WDAY || [
15 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'
16 ];
Nils Diewalda1228622015-04-25 01:59:10 +000017 loc.MONTH = loc.MONTH || [
18 'January', 'February', 'March', 'April',
19 'May', 'June', 'July', 'August',
20 'September', 'October', 'November',
21 'December'
22 ];
23
24 var d = document;
25
Nils Diewald7148c6f2015-05-04 15:07:53 +000026 // The datepicker class
Nils Diewalda1228622015-04-25 01:59:10 +000027 return {
Nils Diewald7148c6f2015-05-04 15:07:53 +000028
29 /**
30 * Create a new datepicker view.
31 */
Nils Diewalda1228622015-04-25 01:59:10 +000032 create : function () {
33 return Object.create(this)._init();
34 },
35
Nils Diewald7148c6f2015-05-04 15:07:53 +000036 // Init datepicker
Nils Diewalda1228622015-04-25 01:59:10 +000037 _init : function () {
Nils Diewald652e5f42015-05-10 18:11:45 +000038 this._selected = [];
Nils Diewalda1228622015-04-25 01:59:10 +000039 return this;
40 },
41
Nils Diewalda79b2682015-05-18 18:34:06 +000042
Nils Diewald7148c6f2015-05-04 15:07:53 +000043 /**
44 * Get or select a specific date.
45 */
Nils Diewalda1228622015-04-25 01:59:10 +000046 select : function (year, month, day) {
47 if (arguments.length >= 1) {
48 this._selected = {'year' : year};
Akron56ea7e32016-04-20 12:25:52 +020049 this._showYear = year;
Nils Diewalda1228622015-04-25 01:59:10 +000050 if (arguments.length >= 2) {
51 this._selected['month'] = month;
Akron56ea7e32016-04-20 12:25:52 +020052 this._showMonth = month;
53 if (arguments.length >= 3) {
Nils Diewalda1228622015-04-25 01:59:10 +000054 this._selected['day'] = day;
Akron56ea7e32016-04-20 12:25:52 +020055 this._showDay = day;
56 };
Nils Diewalda1228622015-04-25 01:59:10 +000057 };
Akron56ea7e32016-04-20 12:25:52 +020058
Nils Diewalda1228622015-04-25 01:59:10 +000059 return this;
60 };
Akron56ea7e32016-04-20 12:25:52 +020061
Nils Diewalda1228622015-04-25 01:59:10 +000062 return this._selected;
63 },
64
Nils Diewald7148c6f2015-05-04 15:07:53 +000065
66 /**
67 * Select a specific date and
68 * init the accompanied action.
69 */
70 set : function (year, month, day) {
71 this.select(year, month, day);
Akron56ea7e32016-04-20 12:25:52 +020072 this.store();
73 },
74
75 store : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +000076 if (this._click !== undefined)
77 this._click(this._selected);
78 else
79 console.dir(this._selected);
80 },
81
Nils Diewald7148c6f2015-05-04 15:07:53 +000082 /**
83 * Set the action for clicking as a callback.
84 * The callback will retrieve a an object with
85 * an optional year attribute,
86 * an optional month attribute,
87 * and an optional day attribute
88 */
89 onclick : function (cb) {
90 this._click = cb;
91 },
92
Akron56ea7e32016-04-20 12:25:52 +020093
Nils Diewald7148c6f2015-05-04 15:07:53 +000094 /**
95 * Show the datepicker.
96 * Will either show the selected year/month
97 * or the current date.
98 * Will return the element for appending to the dom.
99 */
Nils Diewalda1228622015-04-25 01:59:10 +0000100 show : function (year, month) {
Akron56ea7e32016-04-20 12:25:52 +0200101
Nils Diewald7148c6f2015-05-04 15:07:53 +0000102 var e = this._element = d.createElement('div');
103 e.setAttribute('tabindex', 0);
104 e.style.outline = 0;
105 e.classList.add('datepicker');
106
107 var today = new Date();
108
109 // Show year
Akron56ea7e32016-04-20 12:25:52 +0200110 this._showYear = (year !== undefined) ? year :
Nils Diewald7148c6f2015-05-04 15:07:53 +0000111 (this._selected['year'] ? this._selected['year'] :
Nils Diewald652e5f42015-05-10 18:11:45 +0000112 today.getYear() + 1900);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000113
114 // Show month
115 this._showMonth = month ? month :
116 (this._selected['month'] ? this._selected['month'] :
117 (today.getMonth() + 1));
118
119 // Append all helpers
Nils Diewald87507832015-05-01 23:36:41 +0000120 this._element.appendChild(this._monthHelper());
121 this._element.appendChild(this._yearHelper());
122 this._element.appendChild(this._dayHelper());
Akronc59f7322016-04-20 13:46:05 +0200123 this._element.appendChild(this._stringHelper());
Akron56ea7e32016-04-20 12:25:52 +0200124
Nils Diewald87507832015-05-01 23:36:41 +0000125 return this._element;
126 },
127
Akronc59f7322016-04-20 13:46:05 +0200128 _stringHelper : function () {
Akron56ea7e32016-04-20 12:25:52 +0200129
130 // Create element
Akron56ea7e32016-04-20 12:25:52 +0200131 // Add input field
Akronc59f7322016-04-20 13:46:05 +0200132 var input = document.createElement('input');
133 input.value = this.toString();
134 input.setAttribute('tabindex', 0);
Akron56ea7e32016-04-20 12:25:52 +0200135
Akronc59f7322016-04-20 13:46:05 +0200136 input.addEventListener(
137 'keyup',
Akron56ea7e32016-04-20 12:25:52 +0200138 function (e) {
139 if (e.keyCode == 13) {
Akronc59f7322016-04-20 13:46:05 +0200140 if (this.fromString(input.value))
141 this.store();
142
Akron56ea7e32016-04-20 12:25:52 +0200143 e.halt();
144 return false;
Akronc59f7322016-04-20 13:46:05 +0200145 }
146 else {
147 if (this.fromString(input.value)) {
148 this._updateYear();
149 this._updateMonth();
150 this._updateDay();
151 };
Akron56ea7e32016-04-20 12:25:52 +0200152 };
153 }.bind(this)
154 );
155
Akronc59f7322016-04-20 13:46:05 +0200156 return input;
Akron56ea7e32016-04-20 12:25:52 +0200157 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000158
Nils Diewald7148c6f2015-05-04 15:07:53 +0000159 /**
160 * Get the HTML element associated with the datepicker.
161 */
Nils Diewald87507832015-05-01 23:36:41 +0000162 element : function () {
163 return this._element;
Nils Diewalda1228622015-04-25 01:59:10 +0000164 },
165
Nils Diewald845282c2015-05-14 07:53:03 +0000166 /**
167 * Get the current date in string format.
168 */
169 today : function () {
170 var today = new Date();
171 var str = today.getYear() + 1900;
172 var m = today.getMonth() + 1;
173 var d = today.getDate();
174 str += '-' + (m < 10 ? '0' + m : m);
175 str += '-' + (d < 10 ? '0' + d : d);
176 return str;
177 },
Nils Diewald7148c6f2015-05-04 15:07:53 +0000178
Akron56ea7e32016-04-20 12:25:52 +0200179 toString : function () {
180 // There are values selected
181 var v = '';
182 var s = this._selected;
183 if (s['year']) {
184 v += s['year'];
185 if (s['month']) {
186 v += '-';
187 v += s['month'] < 10 ? '0' + s['month'] : s['month'];
188 if (s['day']) {
189 v += '-';
190 v += s['day'] < 10 ? '0' + s['day'] : s['day'];
191 };
192 };
193 };
194 return v;
195 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000196
Nils Diewald7148c6f2015-05-04 15:07:53 +0000197 /**
198 * Increment the year.
199 */
Nils Diewalda1228622015-04-25 01:59:10 +0000200 incrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000201 if (this._showYear < 9999) {
202 this._showYear++;
203 this._updateYear();
204 this._updateMonth();
205 this._updateDay();
206 return this;
207 };
Nils Diewalda1228622015-04-25 01:59:10 +0000208 return;
209 },
210
Nils Diewalda79b2682015-05-18 18:34:06 +0000211
Nils Diewald7148c6f2015-05-04 15:07:53 +0000212 /**
213 * Decrement the year.
214 */
Nils Diewalda1228622015-04-25 01:59:10 +0000215 decrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000216 if (this._showYear > 0) {
217 this._showYear--;
218 this._updateYear();
219 this._updateMonth();
220 this._updateDay();
221 return this;
222 };
Nils Diewalda1228622015-04-25 01:59:10 +0000223 return;
224 },
225
Nils Diewalda79b2682015-05-18 18:34:06 +0000226
Nils Diewald7148c6f2015-05-04 15:07:53 +0000227 /**
228 * Increment the month.
229 */
Nils Diewalda1228622015-04-25 01:59:10 +0000230 incrMonth : function () {
231 this._showMonth++;
232 if (this._showMonth > 12) {
233 this._showMonth = 1;
234 this.incrYear();
235 }
236 else {
237 this._updateMonth();
238 this._updateDay();
239 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000240 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000241 },
242
Nils Diewalda79b2682015-05-18 18:34:06 +0000243
Nils Diewald7148c6f2015-05-04 15:07:53 +0000244 /**
245 * Decrement the month.
246 */
Nils Diewalda1228622015-04-25 01:59:10 +0000247 decrMonth : function () {
248 this._showMonth--;
249 if (this._showMonth < 1) {
250 this._showMonth = 12;
251 this.decrYear();
252 }
253 else {
254 this._updateMonth();
255 this._updateDay();
256 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000257
258 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000259 },
260
Nils Diewald7148c6f2015-05-04 15:07:53 +0000261
262 // Create the year helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000263 _yearHelper : function () {
264 var year = d.createElement('div');
265 year.classList.add('year');
266
267 // Decrement year
268 year.appendChild(d.createElement('span'))
269 .onclick = this.decrYear.bind(this);
270
271 this._yElement = year.appendChild(d.createElement('span'));
272 this._yElement.appendChild(document.createTextNode(this._showYear));
273
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000274 this._yElement.onclick = function () {
275 this.set(this._showYear);
276 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000277 this._selectYear();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000278
Nils Diewalda1228622015-04-25 01:59:10 +0000279 // Increment year
280 year.appendChild(d.createElement('span'))
281 .onclick = this.incrYear.bind(this);
282
283 return year;
284 },
285
Nils Diewald7148c6f2015-05-04 15:07:53 +0000286 // Update the year helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000287 _updateYear : function () {
288 this._yElement.firstChild.data = this._showYear;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000289 this._selectYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000290 },
291
Nils Diewald7148c6f2015-05-04 15:07:53 +0000292
293 // Check if the viewed year is current
294 _selectYear : function () {
295 if (this._showYear === this.select()['year'])
296 this._yElement.classList.add('selected');
297 else
298 this._yElement.classList.remove('selected');
299 },
300
301
302 // Create the month helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000303 _monthHelper : function () {
304 var month = d.createElement('div');
305 month.classList.add('month');
306
307 // Decrement month
308 month.appendChild(d.createElement('span'))
309 .onclick = this.decrMonth.bind(this);
310
311 this._mElement = month.appendChild(d.createElement('span'));
312 this._mElement.appendChild(
313 document.createTextNode(loc.MONTH[this._showMonth-1])
314 );
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000315 this._mElement.onclick = function () {
316 this.set(this._showYear, this._showMonth);
317 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000318
319 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000320
321 // Increment month
322 month.appendChild(d.createElement('span'))
323 .onclick = this.incrMonth.bind(this);
324
325 return month;
326 },
327
Nils Diewald7148c6f2015-05-04 15:07:53 +0000328 // Update the month helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000329 _updateMonth : function () {
Akronc59f7322016-04-20 13:46:05 +0200330 if (this._showMonth === undefined || this._showMonth > 12)
331 this._showMonth = 1;
332
Nils Diewalda1228622015-04-25 01:59:10 +0000333 this._mElement.firstChild.data = loc.MONTH[this._showMonth-1];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000334 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000335 },
336
Nils Diewald7148c6f2015-05-04 15:07:53 +0000337
338 // Check if the viewed month is current
339 _selectMonth : function () {
340 if (this._showYear === this.select()['year'] &&
341 this._showMonth === this.select()['month'])
342 this._mElement.classList.add('selected');
343 else
344 this._mElement.classList.remove('selected');
345 },
346
347
348 // Create the day (calendar) helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000349 _dayHelper : function () {
350 var table = d.createElement('table');
351
Nils Diewald7148c6f2015-05-04 15:07:53 +0000352 // Localized day view
Nils Diewalda1228622015-04-25 01:59:10 +0000353 var tr = table.appendChild(d.createElement('thead'))
354 .appendChild(d.createElement('tr'));
355 for (var i = 0; i < 7; i++) {
356 tr.appendChild(d.createElement('th'))
357 .appendChild(d.createTextNode(loc.WDAY[i]));
358 };
359
360 this._dBElement = this._dayBody();
361
362 table.appendChild(this._dBElement);
363 return table;
364 },
365
366 _dayBody : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000367 var showDate = new Date(
368 this._showYear,
369 this._showMonth - 1,
370 1,
371 0,
372 0,
373 0,
374 0
375 );
376 var date = new Date(
377 this._showYear,
378 this._showMonth - 1,
379 1,
380 0,
381 0,
382 0,
383 0
384 );
385 var today = new Date();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000386 var that = this;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000387
388 // What happens, in case someone clicks
389 // on a date
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000390 var click = function () {
391 that.set(
392 that._showYear,
393 that._showMonth,
394 parseInt(this.firstChild.data)
395 );
396 };
Nils Diewalda1228622015-04-25 01:59:10 +0000397
398 // Skip back to the previous monday (may be in the last month)
399 date.setDate(date.getDate() - ((date.getDay() + 6) % 7));
400
401 var tb = d.createElement('tbody');
402
403 var s = this.select();
404
405 // Iterate over all days of the table
406 while (1) {
407
408 // Loop through the week
409 var tr = tb.appendChild(d.createElement('tr'));
410 for (var i = 0; i < 7; i++) {
411 var td = tr.appendChild(d.createElement('td'));
412
413 // Not part of the current month
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000414 if (date.getMonth() !== showDate.getMonth()) {
Nils Diewalda1228622015-04-25 01:59:10 +0000415 td.classList.add('out');
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000416 }
417 else {
418 td.onclick = click;
419 };
Nils Diewalda1228622015-04-25 01:59:10 +0000420
421 // This is the current day
422 if (date.getDate() === today.getDate() &&
423 date.getMonth() === today.getMonth() &&
424 date.getFullYear() === today.getFullYear()) {
425 td.classList.add('today');
426 };
427
428 // This is the day selected
Nils Diewald87507832015-05-01 23:36:41 +0000429 if (s && s['day']) {
Nils Diewalda1228622015-04-25 01:59:10 +0000430 if (date.getDate() === s['day'] &&
431 date.getMonth() === s['month']-1 &&
432 date.getFullYear() === s['year']) {
433 td.classList.add('selected');
434 };
435 };
436
437 // Add the current day to the table
438 td.appendChild(
439 d.createTextNode(date.getDate())
440 );
441
442 // Next day
443 date.setDate(date.getDate() + 1);
444 };
445
446 if (date.getMonth() !== showDate.getMonth())
447 break;
448 };
449 return tb;
450 },
451
Nils Diewald7148c6f2015-05-04 15:07:53 +0000452 // Update the calendar view
Nils Diewalda1228622015-04-25 01:59:10 +0000453 _updateDay : function () {
454 var newBody = this._dayBody();
455 this._dBElement.parentNode.replaceChild(
456 newBody,
457 this._dBElement
458 );
459 this._dBElement = newBody;
Akron56ea7e32016-04-20 12:25:52 +0200460 },
461
462 fromString : function (v) {
Akronc59f7322016-04-20 13:46:05 +0200463 if (v === undefined)
464 return false;
Akron56ea7e32016-04-20 12:25:52 +0200465
Akronc59f7322016-04-20 13:46:05 +0200466 if (!KorAP._validDateRE.test(v))
467 return false;
Akron56ea7e32016-04-20 12:25:52 +0200468
Akronc59f7322016-04-20 13:46:05 +0200469 var d = v.split('-', 3);
470 d[0] = parseInt(d[0]);
471 if (d[1]) d[1] = parseInt(d[1]);
472 if (d[2]) d[2] = parseInt(d[2]);
473
474 // Select values
475 this.select(d[0], d[1], d[2]);
476 return true;
Nils Diewalda1228622015-04-25 01:59:10 +0000477 }
478 };
479});