blob: 8ae5267967c5f98b13b15f999c16ebbd0285e13d [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
Akrond5620d42017-12-06 15:30:28 +010010 KorAP._validDateMatchRE = new RegExp("^[lg]?eq$");
11 KorAP._validDateRE = new RegExp("^(?:\\d{4})(?:-\\d\\d(?:-\\d\\d)?)?$");
12
Nils Diewald7148c6f2015-05-04 15:07:53 +000013 /*
14 * Localizations
15 */
Nils Diewalda1228622015-04-25 01:59:10 +000016 var loc = KorAP.Locale;
Nils Diewalda1228622015-04-25 01:59:10 +000017 loc.WDAY = loc.WDAY || [
18 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'
19 ];
Nils Diewalda1228622015-04-25 01:59:10 +000020 loc.MONTH = loc.MONTH || [
21 'January', 'February', 'March', 'April',
22 'May', 'June', 'July', 'August',
23 'September', 'October', 'November',
24 'December'
25 ];
26
27 var d = document;
28
Nils Diewald7148c6f2015-05-04 15:07:53 +000029 // The datepicker class
Nils Diewalda1228622015-04-25 01:59:10 +000030 return {
Nils Diewald7148c6f2015-05-04 15:07:53 +000031
32 /**
33 * Create a new datepicker view.
34 */
Nils Diewalda1228622015-04-25 01:59:10 +000035 create : function () {
36 return Object.create(this)._init();
37 },
38
Nils Diewald7148c6f2015-05-04 15:07:53 +000039 // Init datepicker
Nils Diewalda1228622015-04-25 01:59:10 +000040 _init : function () {
Nils Diewald652e5f42015-05-10 18:11:45 +000041 this._selected = [];
Nils Diewalda1228622015-04-25 01:59:10 +000042 return this;
43 },
44
Nils Diewalda79b2682015-05-18 18:34:06 +000045
Nils Diewald7148c6f2015-05-04 15:07:53 +000046 /**
47 * Get or select a specific date.
48 */
Nils Diewalda1228622015-04-25 01:59:10 +000049 select : function (year, month, day) {
50 if (arguments.length >= 1) {
Akrond5620d42017-12-06 15:30:28 +010051 this._selected = {'year' : year};
52 this._showYear = year;
53 if (arguments.length >= 2) {
54 this._selected['month'] = month;
55 this._showMonth = month;
56 if (arguments.length >= 3) {
57 this._selected['day'] = day;
58 this._showDay = day;
59 };
60 };
Akron56ea7e32016-04-20 12:25:52 +020061
Akrond5620d42017-12-06 15:30:28 +010062 return this;
Nils Diewalda1228622015-04-25 01:59:10 +000063 };
Akron56ea7e32016-04-20 12:25:52 +020064
Nils Diewalda1228622015-04-25 01:59:10 +000065 return this._selected;
66 },
67
Nils Diewald7148c6f2015-05-04 15:07:53 +000068
69 /**
70 * Select a specific date and
71 * init the accompanied action.
72 */
73 set : function (year, month, day) {
74 this.select(year, month, day);
Akron56ea7e32016-04-20 12:25:52 +020075 this.store();
76 },
77
78 store : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +000079 if (this._click !== undefined)
Akrond5620d42017-12-06 15:30:28 +010080 this._click(this._selected);
Nils Diewald7148c6f2015-05-04 15:07:53 +000081 else
Akrond5620d42017-12-06 15:30:28 +010082 console.dir(this._selected);
Nils Diewald7148c6f2015-05-04 15:07:53 +000083 },
Akrond5620d42017-12-06 15:30:28 +010084
Nils Diewald7148c6f2015-05-04 15:07:53 +000085 /**
86 * Set the action for clicking as a callback.
87 * The callback will retrieve a an object with
88 * an optional year attribute,
89 * an optional month attribute,
90 * and an optional day attribute
91 */
92 onclick : function (cb) {
93 this._click = cb;
94 },
95
Akron56ea7e32016-04-20 12:25:52 +020096
Nils Diewald7148c6f2015-05-04 15:07:53 +000097 /**
98 * Show the datepicker.
99 * Will either show the selected year/month
100 * or the current date.
101 * Will return the element for appending to the dom.
102 */
Nils Diewalda1228622015-04-25 01:59:10 +0000103 show : function (year, month) {
Akron56ea7e32016-04-20 12:25:52 +0200104
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');
Akrond5620d42017-12-06 15:30:28 +0100109
Nils Diewald7148c6f2015-05-04 15:07:53 +0000110 var today = new Date();
111
112 // Show year
Akron56ea7e32016-04-20 12:25:52 +0200113 this._showYear = (year !== undefined) ? year :
Akrond5620d42017-12-06 15:30:28 +0100114 (this._selected['year'] ? this._selected['year'] :
115 today.getYear() + 1900);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000116
117 // Show month
118 this._showMonth = month ? month :
Akrond5620d42017-12-06 15:30:28 +0100119 (this._selected['month'] ? this._selected['month'] :
120 (today.getMonth() + 1));
Nils Diewald7148c6f2015-05-04 15:07:53 +0000121
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());
Akronc59f7322016-04-20 13:46:05 +0200126 this._element.appendChild(this._stringHelper());
Akron56ea7e32016-04-20 12:25:52 +0200127
Nils Diewald87507832015-05-01 23:36:41 +0000128 return this._element;
129 },
130
Akronc59f7322016-04-20 13:46:05 +0200131 _stringHelper : function () {
Akron56ea7e32016-04-20 12:25:52 +0200132
133 // Create element
Akron56ea7e32016-04-20 12:25:52 +0200134 // Add input field
Akronc59f7322016-04-20 13:46:05 +0200135 var input = document.createElement('input');
136 input.value = this.toString();
137 input.setAttribute('tabindex', 0);
Akron56ea7e32016-04-20 12:25:52 +0200138
Akronc59f7322016-04-20 13:46:05 +0200139 input.addEventListener(
Akrond5620d42017-12-06 15:30:28 +0100140 'keyup',
141 function (e) {
142 if (this.fromString(input.value)) {
143 this._updateYear();
144 this._updateMonth();
145 this._updateDay();
146 };
147 }.bind(this)
Akron56ea7e32016-04-20 12:25:52 +0200148 );
149
Akrond5620d42017-12-06 15:30:28 +0100150 input.addEventListener(
151 'keypress',
152 function (e) {
153 if (e.keyCode == 13) {
154 if (this.fromString(input.value))
155 this.store();
156
157 e.halt();
158 return false;
159 }
160 }.bind(this)
161 )
162
Akronc59f7322016-04-20 13:46:05 +0200163 return input;
Akron56ea7e32016-04-20 12:25:52 +0200164 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000165
Nils Diewald7148c6f2015-05-04 15:07:53 +0000166 /**
167 * Get the HTML element associated with the datepicker.
168 */
Nils Diewald87507832015-05-01 23:36:41 +0000169 element : function () {
170 return this._element;
Nils Diewalda1228622015-04-25 01:59:10 +0000171 },
172
Nils Diewald845282c2015-05-14 07:53:03 +0000173 /**
174 * Get the current date in string format.
175 */
176 today : function () {
177 var today = new Date();
178 var str = today.getYear() + 1900;
179 var m = today.getMonth() + 1;
180 var d = today.getDate();
181 str += '-' + (m < 10 ? '0' + m : m);
182 str += '-' + (d < 10 ? '0' + d : d);
183 return str;
184 },
Nils Diewald7148c6f2015-05-04 15:07:53 +0000185
Akron56ea7e32016-04-20 12:25:52 +0200186 toString : function () {
187 // There are values selected
188 var v = '';
189 var s = this._selected;
190 if (s['year']) {
Akrond5620d42017-12-06 15:30:28 +0100191 v += s['year'];
192 if (s['month']) {
193 v += '-';
194 v += s['month'] < 10 ? '0' + s['month'] : s['month'];
195 if (s['day']) {
196 v += '-';
197 v += s['day'] < 10 ? '0' + s['day'] : s['day'];
198 };
199 };
Akron56ea7e32016-04-20 12:25:52 +0200200 };
201 return v;
202 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000203
Nils Diewald7148c6f2015-05-04 15:07:53 +0000204 /**
205 * Increment the year.
206 */
Nils Diewalda1228622015-04-25 01:59:10 +0000207 incrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000208 if (this._showYear < 9999) {
Akrond5620d42017-12-06 15:30:28 +0100209 this._showYear++;
210 this._updateYear();
211 this._updateMonth();
212 this._updateDay();
213 return this;
Nils Diewalda79b2682015-05-18 18:34:06 +0000214 };
Nils Diewalda1228622015-04-25 01:59:10 +0000215 return;
216 },
217
Nils Diewalda79b2682015-05-18 18:34:06 +0000218
Nils Diewald7148c6f2015-05-04 15:07:53 +0000219 /**
220 * Decrement the year.
221 */
Nils Diewalda1228622015-04-25 01:59:10 +0000222 decrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000223 if (this._showYear > 0) {
Akrond5620d42017-12-06 15:30:28 +0100224 this._showYear--;
225 this._updateYear();
226 this._updateMonth();
227 this._updateDay();
228 return this;
Nils Diewalda79b2682015-05-18 18:34:06 +0000229 };
Nils Diewalda1228622015-04-25 01:59:10 +0000230 return;
231 },
232
Nils Diewalda79b2682015-05-18 18:34:06 +0000233
Nils Diewald7148c6f2015-05-04 15:07:53 +0000234 /**
235 * Increment the month.
236 */
Nils Diewalda1228622015-04-25 01:59:10 +0000237 incrMonth : function () {
238 this._showMonth++;
239 if (this._showMonth > 12) {
Akrond5620d42017-12-06 15:30:28 +0100240 this._showMonth = 1;
241 this.incrYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000242 }
243 else {
Akrond5620d42017-12-06 15:30:28 +0100244 this._updateMonth();
245 this._updateDay();
Nils Diewalda1228622015-04-25 01:59:10 +0000246 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000247 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000248 },
249
Nils Diewalda79b2682015-05-18 18:34:06 +0000250
Nils Diewald7148c6f2015-05-04 15:07:53 +0000251 /**
252 * Decrement the month.
253 */
Nils Diewalda1228622015-04-25 01:59:10 +0000254 decrMonth : function () {
255 this._showMonth--;
256 if (this._showMonth < 1) {
Akrond5620d42017-12-06 15:30:28 +0100257 this._showMonth = 12;
258 this.decrYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000259 }
260 else {
Akrond5620d42017-12-06 15:30:28 +0100261 this._updateMonth();
262 this._updateDay();
Nils Diewalda1228622015-04-25 01:59:10 +0000263 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000264
265 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000266 },
267
Nils Diewald7148c6f2015-05-04 15:07:53 +0000268
269 // Create the year helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000270 _yearHelper : function () {
271 var year = d.createElement('div');
272 year.classList.add('year');
273
274 // Decrement year
275 year.appendChild(d.createElement('span'))
Akrond5620d42017-12-06 15:30:28 +0100276 .onclick = this.decrYear.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000277
278 this._yElement = year.appendChild(d.createElement('span'));
279 this._yElement.appendChild(document.createTextNode(this._showYear));
280
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000281 this._yElement.onclick = function () {
Akrond5620d42017-12-06 15:30:28 +0100282 this.set(this._showYear);
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000283 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000284 this._selectYear();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000285
Nils Diewalda1228622015-04-25 01:59:10 +0000286 // Increment year
287 year.appendChild(d.createElement('span'))
Akrond5620d42017-12-06 15:30:28 +0100288 .onclick = this.incrYear.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000289
290 return year;
291 },
292
Nils Diewald7148c6f2015-05-04 15:07:53 +0000293 // Update the year helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000294 _updateYear : function () {
295 this._yElement.firstChild.data = this._showYear;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000296 this._selectYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000297 },
298
Nils Diewald7148c6f2015-05-04 15:07:53 +0000299
300 // Check if the viewed year is current
301 _selectYear : function () {
302 if (this._showYear === this.select()['year'])
Akrond5620d42017-12-06 15:30:28 +0100303 this._yElement.classList.add('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000304 else
Akrond5620d42017-12-06 15:30:28 +0100305 this._yElement.classList.remove('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000306 },
307
308
309 // Create the month helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000310 _monthHelper : function () {
311 var month = d.createElement('div');
312 month.classList.add('month');
313
314 // Decrement month
315 month.appendChild(d.createElement('span'))
Akrond5620d42017-12-06 15:30:28 +0100316 .onclick = this.decrMonth.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000317
318 this._mElement = month.appendChild(d.createElement('span'));
319 this._mElement.appendChild(
Akrond5620d42017-12-06 15:30:28 +0100320 document.createTextNode(loc.MONTH[this._showMonth-1])
Nils Diewalda1228622015-04-25 01:59:10 +0000321 );
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000322 this._mElement.onclick = function () {
Akrond5620d42017-12-06 15:30:28 +0100323 this.set(this._showYear, this._showMonth);
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000324 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000325
326 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000327
328 // Increment month
329 month.appendChild(d.createElement('span'))
Akrond5620d42017-12-06 15:30:28 +0100330 .onclick = this.incrMonth.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000331
332 return month;
333 },
334
Nils Diewald7148c6f2015-05-04 15:07:53 +0000335 // Update the month helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000336 _updateMonth : function () {
Akronc59f7322016-04-20 13:46:05 +0200337 if (this._showMonth === undefined || this._showMonth > 12)
Akrond5620d42017-12-06 15:30:28 +0100338 this._showMonth = 1;
Akronc59f7322016-04-20 13:46:05 +0200339
Nils Diewalda1228622015-04-25 01:59:10 +0000340 this._mElement.firstChild.data = loc.MONTH[this._showMonth-1];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000341 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000342 },
343
Nils Diewald7148c6f2015-05-04 15:07:53 +0000344
345 // Check if the viewed month is current
346 _selectMonth : function () {
347 if (this._showYear === this.select()['year'] &&
Akrond5620d42017-12-06 15:30:28 +0100348 this._showMonth === this.select()['month'])
349 this._mElement.classList.add('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000350 else
Akrond5620d42017-12-06 15:30:28 +0100351 this._mElement.classList.remove('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000352 },
353
354
355 // Create the day (calendar) helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000356 _dayHelper : function () {
357 var table = d.createElement('table');
358
Nils Diewald7148c6f2015-05-04 15:07:53 +0000359 // Localized day view
Nils Diewalda1228622015-04-25 01:59:10 +0000360 var tr = table.appendChild(d.createElement('thead'))
Akrond5620d42017-12-06 15:30:28 +0100361 .appendChild(d.createElement('tr'));
Nils Diewalda1228622015-04-25 01:59:10 +0000362 for (var i = 0; i < 7; i++) {
Akrond5620d42017-12-06 15:30:28 +0100363 tr.appendChild(d.createElement('th'))
364 .appendChild(d.createTextNode(loc.WDAY[i]));
Nils Diewalda1228622015-04-25 01:59:10 +0000365 };
366
367 this._dBElement = this._dayBody();
368
369 table.appendChild(this._dBElement);
370 return table;
371 },
372
373 _dayBody : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000374 var showDate = new Date(
Akrond5620d42017-12-06 15:30:28 +0100375 this._showYear,
376 this._showMonth - 1,
377 1,
378 0,
379 0,
380 0,
381 0
Nils Diewald7148c6f2015-05-04 15:07:53 +0000382 );
383 var date = new Date(
Akrond5620d42017-12-06 15:30:28 +0100384 this._showYear,
385 this._showMonth - 1,
386 1,
387 0,
388 0,
389 0,
390 0
Nils Diewald7148c6f2015-05-04 15:07:53 +0000391 );
392 var today = new Date();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000393 var that = this;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000394
395 // What happens, in case someone clicks
396 // on a date
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000397 var click = function () {
Akrond5620d42017-12-06 15:30:28 +0100398 that.set(
399 that._showYear,
400 that._showMonth,
401 parseInt(this.firstChild.data)
402 );
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000403 };
Nils Diewalda1228622015-04-25 01:59:10 +0000404
405 // Skip back to the previous monday (may be in the last month)
406 date.setDate(date.getDate() - ((date.getDay() + 6) % 7));
407
408 var tb = d.createElement('tbody');
409
410 var s = this.select();
411
412 // Iterate over all days of the table
413 while (1) {
414
Akrond5620d42017-12-06 15:30:28 +0100415 // Loop through the week
416 var tr = tb.appendChild(d.createElement('tr'));
417 for (var i = 0; i < 7; i++) {
418 var td = tr.appendChild(d.createElement('td'));
419
420 // Not part of the current month
421 if (date.getMonth() !== showDate.getMonth()) {
422 td.classList.add('out');
423 }
424 else {
425 td.onclick = click;
426 };
427
428 // This is the current day
429 if (date.getDate() === today.getDate() &&
430 date.getMonth() === today.getMonth() &&
431 date.getFullYear() === today.getFullYear()) {
432 td.classList.add('today');
433 };
Nils Diewalda1228622015-04-25 01:59:10 +0000434
Akrond5620d42017-12-06 15:30:28 +0100435 // This is the day selected
436 if (s && s['day']) {
437 if (date.getDate() === s['day'] &&
438 date.getMonth() === s['month']-1 &&
439 date.getFullYear() === s['year']) {
440 td.classList.add('selected');
441 };
442 };
Nils Diewalda1228622015-04-25 01:59:10 +0000443
Akrond5620d42017-12-06 15:30:28 +0100444 // Add the current day to the table
445 td.appendChild(
446 d.createTextNode(date.getDate())
447 );
448
449 // Next day
450 date.setDate(date.getDate() + 1);
451 };
Nils Diewalda1228622015-04-25 01:59:10 +0000452
Akrond5620d42017-12-06 15:30:28 +0100453 if (date.getMonth() !== showDate.getMonth())
454 break;
Nils Diewalda1228622015-04-25 01:59:10 +0000455 };
456 return tb;
457 },
458
Nils Diewald7148c6f2015-05-04 15:07:53 +0000459 // Update the calendar view
Nils Diewalda1228622015-04-25 01:59:10 +0000460 _updateDay : function () {
461 var newBody = this._dayBody();
462 this._dBElement.parentNode.replaceChild(
Akrond5620d42017-12-06 15:30:28 +0100463 newBody,
464 this._dBElement
Nils Diewalda1228622015-04-25 01:59:10 +0000465 );
466 this._dBElement = newBody;
Akron56ea7e32016-04-20 12:25:52 +0200467 },
468
469 fromString : function (v) {
Akronc59f7322016-04-20 13:46:05 +0200470 if (v === undefined)
Akrond5620d42017-12-06 15:30:28 +0100471 return false;
Akron56ea7e32016-04-20 12:25:52 +0200472
Akronc59f7322016-04-20 13:46:05 +0200473 if (!KorAP._validDateRE.test(v))
Akrond5620d42017-12-06 15:30:28 +0100474 return false;
Akron56ea7e32016-04-20 12:25:52 +0200475
Akronc59f7322016-04-20 13:46:05 +0200476 var d = v.split('-', 3);
477 d[0] = parseInt(d[0]);
478 if (d[1]) d[1] = parseInt(d[1]);
479 if (d[2]) d[2] = parseInt(d[2]);
480
481 // Select values
482 this.select(d[0], d[1], d[2]);
483 return true;
Nils Diewalda1228622015-04-25 01:59:10 +0000484 }
485 };
486});