blob: 84243a922421e3da86b333674fa67820c1559cf4 [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
102 // Create text view
103 this.showText();
104
Nils Diewald7148c6f2015-05-04 15:07:53 +0000105 var e = this._element = d.createElement('div');
106 e.setAttribute('tabindex', 0);
107 e.style.outline = 0;
108 e.classList.add('datepicker');
109
110 var today = new Date();
111
112 // Show year
Akron56ea7e32016-04-20 12:25:52 +0200113 this._showYear = (year !== undefined) ? year :
Nils Diewald7148c6f2015-05-04 15:07:53 +0000114 (this._selected['year'] ? this._selected['year'] :
Nils Diewald652e5f42015-05-10 18:11:45 +0000115 today.getYear() + 1900);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000116
117 // Show month
118 this._showMonth = month ? month :
119 (this._selected['month'] ? this._selected['month'] :
120 (today.getMonth() + 1));
121
122 // Append all helpers
Nils Diewald87507832015-05-01 23:36:41 +0000123 this._element.appendChild(this._monthHelper());
124 this._element.appendChild(this._yearHelper());
125 this._element.appendChild(this._dayHelper());
Akron56ea7e32016-04-20 12:25:52 +0200126 this._element.appendChild(this._closer());
127
Nils Diewald87507832015-05-01 23:36:41 +0000128 return this._element;
129 },
130
Akron56ea7e32016-04-20 12:25:52 +0200131 showText : function () {
132
133 // Create element
134 this._elementText = document.createElement('div');
135 var et = this._elementText;
136 et.setAttribute('tabindex', 0);
137 et.style.outline = 0;
138 et.classList.add('value');
139
140 // Add input field
141 this._input = et.appendChild(
142 document.createElement('input')
143 );
144 this._input.value = this.toString();
145
146 // Add toggle button
147 var datepicker = et.appendChild(
148 document.createElement('div')
149 );
150
151 datepicker.onclick =
152 this.viewCalendar.bind(this);
153
154 datepicker.appendChild(
155 document.createTextNode('x')
156 );
157
158 // Check for enter
159 this._input.addEventListener(
160 'keypress',
161 function (e) {
162 if (e.keyCode == 13) {
163 this.fromString(this._input.value);
164 this.store();
165 e.halt();
166 return false;
167 };
168 }.bind(this)
169 );
170
171 /*
172 var that = this;
173 et.addEventListener(
174 'blur',
175 function (e) {
176 that.fromString(input.value);
177
178 // Better: Hide!
179 this.parentNode.removeChild(this);
180 e.halt();
181 }
182 );
183 */
184 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000185
Nils Diewald7148c6f2015-05-04 15:07:53 +0000186 /**
187 * Get the HTML element associated with the datepicker.
188 */
Nils Diewald87507832015-05-01 23:36:41 +0000189 element : function () {
190 return this._element;
Nils Diewalda1228622015-04-25 01:59:10 +0000191 },
192
Akron56ea7e32016-04-20 12:25:52 +0200193 elementText : function () {
194 return this._elementText;
195 },
196
197 viewText : function () {
198
199 // Replace calendar view with text view
200 this._element.parentNode.replaceChild(
201 this._elementText,
202 this._element
203 );
204 },
205
206 viewCalendar : function () {
207 // Update calendar
208 this.fromString(this._input.value);
209
210 this._updateYear();
211 this._updateMonth();
212 this._updateDay();
213
214 // Replace calendar view with text view
215 this._elementText.parentNode.replaceChild(
216 this._element,
217 this._elementText
218 );
219 },
220
Nils Diewalda79b2682015-05-18 18:34:06 +0000221
Nils Diewald845282c2015-05-14 07:53:03 +0000222 /**
223 * Get the current date in string format.
224 */
225 today : function () {
226 var today = new Date();
227 var str = today.getYear() + 1900;
228 var m = today.getMonth() + 1;
229 var d = today.getDate();
230 str += '-' + (m < 10 ? '0' + m : m);
231 str += '-' + (d < 10 ? '0' + d : d);
232 return str;
233 },
Nils Diewald7148c6f2015-05-04 15:07:53 +0000234
Akron56ea7e32016-04-20 12:25:52 +0200235 toString : function () {
236 // There are values selected
237 var v = '';
238 var s = this._selected;
239 if (s['year']) {
240 v += s['year'];
241 if (s['month']) {
242 v += '-';
243 v += s['month'] < 10 ? '0' + s['month'] : s['month'];
244 if (s['day']) {
245 v += '-';
246 v += s['day'] < 10 ? '0' + s['day'] : s['day'];
247 };
248 };
249 };
250 return v;
251 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000252
Nils Diewald7148c6f2015-05-04 15:07:53 +0000253 /**
254 * Increment the year.
255 */
Nils Diewalda1228622015-04-25 01:59:10 +0000256 incrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000257 if (this._showYear < 9999) {
258 this._showYear++;
259 this._updateYear();
260 this._updateMonth();
261 this._updateDay();
262 return this;
263 };
Nils Diewalda1228622015-04-25 01:59:10 +0000264 return;
265 },
266
Nils Diewalda79b2682015-05-18 18:34:06 +0000267
Nils Diewald7148c6f2015-05-04 15:07:53 +0000268 /**
269 * Decrement the year.
270 */
Nils Diewalda1228622015-04-25 01:59:10 +0000271 decrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000272 if (this._showYear > 0) {
273 this._showYear--;
274 this._updateYear();
275 this._updateMonth();
276 this._updateDay();
277 return this;
278 };
Nils Diewalda1228622015-04-25 01:59:10 +0000279 return;
280 },
281
Nils Diewalda79b2682015-05-18 18:34:06 +0000282
Nils Diewald7148c6f2015-05-04 15:07:53 +0000283 /**
284 * Increment the month.
285 */
Nils Diewalda1228622015-04-25 01:59:10 +0000286 incrMonth : function () {
287 this._showMonth++;
288 if (this._showMonth > 12) {
289 this._showMonth = 1;
290 this.incrYear();
291 }
292 else {
293 this._updateMonth();
294 this._updateDay();
295 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000296 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000297 },
298
Nils Diewalda79b2682015-05-18 18:34:06 +0000299
Nils Diewald7148c6f2015-05-04 15:07:53 +0000300 /**
301 * Decrement the month.
302 */
Nils Diewalda1228622015-04-25 01:59:10 +0000303 decrMonth : function () {
304 this._showMonth--;
305 if (this._showMonth < 1) {
306 this._showMonth = 12;
307 this.decrYear();
308 }
309 else {
310 this._updateMonth();
311 this._updateDay();
312 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000313
314 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000315 },
316
Nils Diewald7148c6f2015-05-04 15:07:53 +0000317
318 // Create the year helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000319 _yearHelper : function () {
320 var year = d.createElement('div');
321 year.classList.add('year');
322
323 // Decrement year
324 year.appendChild(d.createElement('span'))
325 .onclick = this.decrYear.bind(this);
326
327 this._yElement = year.appendChild(d.createElement('span'));
328 this._yElement.appendChild(document.createTextNode(this._showYear));
329
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000330 this._yElement.onclick = function () {
331 this.set(this._showYear);
332 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000333 this._selectYear();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000334
Nils Diewalda1228622015-04-25 01:59:10 +0000335 // Increment year
336 year.appendChild(d.createElement('span'))
337 .onclick = this.incrYear.bind(this);
338
339 return year;
340 },
341
Nils Diewald7148c6f2015-05-04 15:07:53 +0000342 // Update the year helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000343 _updateYear : function () {
344 this._yElement.firstChild.data = this._showYear;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000345 this._selectYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000346 },
347
Nils Diewald7148c6f2015-05-04 15:07:53 +0000348
349 // Check if the viewed year is current
350 _selectYear : function () {
351 if (this._showYear === this.select()['year'])
352 this._yElement.classList.add('selected');
353 else
354 this._yElement.classList.remove('selected');
355 },
356
357
358 // Create the month helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000359 _monthHelper : function () {
360 var month = d.createElement('div');
361 month.classList.add('month');
362
363 // Decrement month
364 month.appendChild(d.createElement('span'))
365 .onclick = this.decrMonth.bind(this);
366
367 this._mElement = month.appendChild(d.createElement('span'));
368 this._mElement.appendChild(
369 document.createTextNode(loc.MONTH[this._showMonth-1])
370 );
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000371 this._mElement.onclick = function () {
372 this.set(this._showYear, this._showMonth);
373 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000374
375 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000376
377 // Increment month
378 month.appendChild(d.createElement('span'))
379 .onclick = this.incrMonth.bind(this);
380
381 return month;
382 },
383
Nils Diewald7148c6f2015-05-04 15:07:53 +0000384 // Update the month helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000385 _updateMonth : function () {
386 this._mElement.firstChild.data = loc.MONTH[this._showMonth-1];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000387 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000388 },
389
Nils Diewald7148c6f2015-05-04 15:07:53 +0000390
391 // Check if the viewed month is current
392 _selectMonth : function () {
393 if (this._showYear === this.select()['year'] &&
394 this._showMonth === this.select()['month'])
395 this._mElement.classList.add('selected');
396 else
397 this._mElement.classList.remove('selected');
398 },
399
400
401 // Create the day (calendar) helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000402 _dayHelper : function () {
403 var table = d.createElement('table');
404
Nils Diewald7148c6f2015-05-04 15:07:53 +0000405 // Localized day view
Nils Diewalda1228622015-04-25 01:59:10 +0000406 var tr = table.appendChild(d.createElement('thead'))
407 .appendChild(d.createElement('tr'));
408 for (var i = 0; i < 7; i++) {
409 tr.appendChild(d.createElement('th'))
410 .appendChild(d.createTextNode(loc.WDAY[i]));
411 };
412
413 this._dBElement = this._dayBody();
414
415 table.appendChild(this._dBElement);
416 return table;
417 },
418
Akron56ea7e32016-04-20 12:25:52 +0200419 // Create the day (calendar) helper element.
420 _closer : function () {
421 var closer = d.createElement('span');
422 closer.classList.add('closer');
423 closer.appendChild(d.createTextNode('x'));
424 closer.onclick = this.viewText.bind(this);
425 return closer;
426 },
427
Nils Diewalda1228622015-04-25 01:59:10 +0000428 _dayBody : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000429 var showDate = new Date(
430 this._showYear,
431 this._showMonth - 1,
432 1,
433 0,
434 0,
435 0,
436 0
437 );
438 var date = new Date(
439 this._showYear,
440 this._showMonth - 1,
441 1,
442 0,
443 0,
444 0,
445 0
446 );
447 var today = new Date();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000448 var that = this;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000449
450 // What happens, in case someone clicks
451 // on a date
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000452 var click = function () {
453 that.set(
454 that._showYear,
455 that._showMonth,
456 parseInt(this.firstChild.data)
457 );
458 };
Nils Diewalda1228622015-04-25 01:59:10 +0000459
460 // Skip back to the previous monday (may be in the last month)
461 date.setDate(date.getDate() - ((date.getDay() + 6) % 7));
462
463 var tb = d.createElement('tbody');
464
465 var s = this.select();
466
467 // Iterate over all days of the table
468 while (1) {
469
470 // Loop through the week
471 var tr = tb.appendChild(d.createElement('tr'));
472 for (var i = 0; i < 7; i++) {
473 var td = tr.appendChild(d.createElement('td'));
474
475 // Not part of the current month
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000476 if (date.getMonth() !== showDate.getMonth()) {
Nils Diewalda1228622015-04-25 01:59:10 +0000477 td.classList.add('out');
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000478 }
479 else {
480 td.onclick = click;
481 };
Nils Diewalda1228622015-04-25 01:59:10 +0000482
483 // This is the current day
484 if (date.getDate() === today.getDate() &&
485 date.getMonth() === today.getMonth() &&
486 date.getFullYear() === today.getFullYear()) {
487 td.classList.add('today');
488 };
489
490 // This is the day selected
Nils Diewald87507832015-05-01 23:36:41 +0000491 if (s && s['day']) {
Nils Diewalda1228622015-04-25 01:59:10 +0000492 if (date.getDate() === s['day'] &&
493 date.getMonth() === s['month']-1 &&
494 date.getFullYear() === s['year']) {
495 td.classList.add('selected');
496 };
497 };
498
499 // Add the current day to the table
500 td.appendChild(
501 d.createTextNode(date.getDate())
502 );
503
504 // Next day
505 date.setDate(date.getDate() + 1);
506 };
507
508 if (date.getMonth() !== showDate.getMonth())
509 break;
510 };
511 return tb;
512 },
513
Nils Diewald7148c6f2015-05-04 15:07:53 +0000514 // Update the calendar view
Nils Diewalda1228622015-04-25 01:59:10 +0000515 _updateDay : function () {
516 var newBody = this._dayBody();
517 this._dBElement.parentNode.replaceChild(
518 newBody,
519 this._dBElement
520 );
521 this._dBElement = newBody;
Akron56ea7e32016-04-20 12:25:52 +0200522 },
523
524 fromString : function (v) {
525 if (v !== undefined) {
526
527 var d = v.split('-', 3);
528 d[0] = parseInt(d[0]);
529 if (d[1]) d[1] = parseInt(d[1]);
530 if (d[2]) d[2] = parseInt(d[2]);
531
532 // Select values
533 this.select(d[0], d[1], d[2]);
534 };
Nils Diewalda1228622015-04-25 01:59:10 +0000535 }
536 };
537});