blob: fe9e97d9c272a2690b1a97353fde4a03e6fdfd5a [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
Akron516b6f92018-01-03 17:46:59 +010039
Nils Diewald7148c6f2015-05-04 15:07:53 +000040 // Init datepicker
Nils Diewalda1228622015-04-25 01:59:10 +000041 _init : function () {
Nils Diewald652e5f42015-05-10 18:11:45 +000042 this._selected = [];
Nils Diewalda1228622015-04-25 01:59:10 +000043 return this;
44 },
45
Nils Diewalda79b2682015-05-18 18:34:06 +000046
Nils Diewald7148c6f2015-05-04 15:07:53 +000047 /**
48 * Get or select a specific date.
49 */
Nils Diewalda1228622015-04-25 01:59:10 +000050 select : function (year, month, day) {
51 if (arguments.length >= 1) {
Akrond5620d42017-12-06 15:30:28 +010052 this._selected = {'year' : year};
53 this._showYear = year;
54 if (arguments.length >= 2) {
55 this._selected['month'] = month;
56 this._showMonth = month;
57 if (arguments.length >= 3) {
58 this._selected['day'] = day;
59 this._showDay = day;
60 };
61 };
Akron56ea7e32016-04-20 12:25:52 +020062
Akrond5620d42017-12-06 15:30:28 +010063 return this;
Nils Diewalda1228622015-04-25 01:59:10 +000064 };
Akron56ea7e32016-04-20 12:25:52 +020065
Nils Diewalda1228622015-04-25 01:59:10 +000066 return this._selected;
67 },
68
Nils Diewald7148c6f2015-05-04 15:07:53 +000069
70 /**
71 * Select a specific date and
72 * init the accompanied action.
73 */
74 set : function (year, month, day) {
75 this.select(year, month, day);
Akron56ea7e32016-04-20 12:25:52 +020076 this.store();
77 },
78
79 store : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +000080 if (this._click !== undefined)
Akrond5620d42017-12-06 15:30:28 +010081 this._click(this._selected);
Nils Diewald7148c6f2015-05-04 15:07:53 +000082 else
Akrond5620d42017-12-06 15:30:28 +010083 console.dir(this._selected);
Nils Diewald7148c6f2015-05-04 15:07:53 +000084 },
Akrond5620d42017-12-06 15:30:28 +010085
Nils Diewald7148c6f2015-05-04 15:07:53 +000086 /**
87 * Set the action for clicking as a callback.
88 * The callback will retrieve a an object with
89 * an optional year attribute,
90 * an optional month attribute,
91 * and an optional day attribute
92 */
93 onclick : function (cb) {
94 this._click = cb;
95 },
96
Akron516b6f92018-01-03 17:46:59 +010097
98 input : function () {
99 return this._input;
100 },
Akron56ea7e32016-04-20 12:25:52 +0200101
Nils Diewald7148c6f2015-05-04 15:07:53 +0000102 /**
103 * Show the datepicker.
104 * Will either show the selected year/month
105 * or the current date.
106 * Will return the element for appending to the dom.
107 */
Nils Diewalda1228622015-04-25 01:59:10 +0000108 show : function (year, month) {
Akron56ea7e32016-04-20 12:25:52 +0200109
Nils Diewald7148c6f2015-05-04 15:07:53 +0000110 var e = this._element = d.createElement('div');
111 e.setAttribute('tabindex', 0);
112 e.style.outline = 0;
113 e.classList.add('datepicker');
Akrond5620d42017-12-06 15:30:28 +0100114
Nils Diewald7148c6f2015-05-04 15:07:53 +0000115 var today = new Date();
116
117 // Show year
Akron56ea7e32016-04-20 12:25:52 +0200118 this._showYear = (year !== undefined) ? year :
Akrond5620d42017-12-06 15:30:28 +0100119 (this._selected['year'] ? this._selected['year'] :
120 today.getYear() + 1900);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000121
122 // Show month
123 this._showMonth = month ? month :
Akrond5620d42017-12-06 15:30:28 +0100124 (this._selected['month'] ? this._selected['month'] :
125 (today.getMonth() + 1));
Nils Diewald7148c6f2015-05-04 15:07:53 +0000126
127 // Append all helpers
Akron516b6f92018-01-03 17:46:59 +0100128 e.appendChild(this._monthHelper());
129 e.appendChild(this._yearHelper());
130 e.appendChild(this._dayHelper());
131 this._input = e.appendChild(this._stringHelper());
132
133 // Always focus
134 e.addEventListener(
135 'mousedown',
136 function (ev) {
137 this._inField = true
138 }.bind(this)
139 );
140
141 e.addEventListener(
142 'mouseup',
143 function (ev) {
144 this._inField = false;
145 this._input.focus();
146 }.bind(this)
147 );
148
149 this._input.addEventListener(
150 'blur',
151 function (ev) {
152 if (!this._inField) {
153 if (this.fromString(this._input.value)) {
154 this.store();
155 };
156 };
157 ev.halt();
158 }.bind(this)
159 );
160
161 this._input.focus();
Akron56ea7e32016-04-20 12:25:52 +0200162
Nils Diewald87507832015-05-01 23:36:41 +0000163 return this._element;
164 },
165
Akronc59f7322016-04-20 13:46:05 +0200166 _stringHelper : function () {
Akron56ea7e32016-04-20 12:25:52 +0200167
168 // Create element
Akron56ea7e32016-04-20 12:25:52 +0200169 // Add input field
Akronc59f7322016-04-20 13:46:05 +0200170 var input = document.createElement('input');
171 input.value = this.toString();
172 input.setAttribute('tabindex', 0);
Akron56ea7e32016-04-20 12:25:52 +0200173
Akronc59f7322016-04-20 13:46:05 +0200174 input.addEventListener(
Akrond5620d42017-12-06 15:30:28 +0100175 'keyup',
176 function (e) {
177 if (this.fromString(input.value)) {
178 this._updateYear();
179 this._updateMonth();
180 this._updateDay();
181 };
182 }.bind(this)
Akron56ea7e32016-04-20 12:25:52 +0200183 );
184
Akrond5620d42017-12-06 15:30:28 +0100185 input.addEventListener(
186 'keypress',
187 function (e) {
188 if (e.keyCode == 13) {
189 if (this.fromString(input.value))
190 this.store();
191
192 e.halt();
193 return false;
194 }
195 }.bind(this)
196 )
197
Akronc59f7322016-04-20 13:46:05 +0200198 return input;
Akron56ea7e32016-04-20 12:25:52 +0200199 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000200
Nils Diewald7148c6f2015-05-04 15:07:53 +0000201 /**
202 * Get the HTML element associated with the datepicker.
203 */
Nils Diewald87507832015-05-01 23:36:41 +0000204 element : function () {
205 return this._element;
Nils Diewalda1228622015-04-25 01:59:10 +0000206 },
207
Nils Diewald845282c2015-05-14 07:53:03 +0000208 /**
209 * Get the current date in string format.
210 */
211 today : function () {
212 var today = new Date();
213 var str = today.getYear() + 1900;
214 var m = today.getMonth() + 1;
215 var d = today.getDate();
216 str += '-' + (m < 10 ? '0' + m : m);
217 str += '-' + (d < 10 ? '0' + d : d);
218 return str;
219 },
Nils Diewald7148c6f2015-05-04 15:07:53 +0000220
Akron56ea7e32016-04-20 12:25:52 +0200221 toString : function () {
222 // There are values selected
223 var v = '';
224 var s = this._selected;
225 if (s['year']) {
Akrond5620d42017-12-06 15:30:28 +0100226 v += s['year'];
227 if (s['month']) {
228 v += '-';
229 v += s['month'] < 10 ? '0' + s['month'] : s['month'];
230 if (s['day']) {
231 v += '-';
232 v += s['day'] < 10 ? '0' + s['day'] : s['day'];
233 };
234 };
Akron56ea7e32016-04-20 12:25:52 +0200235 };
236 return v;
237 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000238
Nils Diewald7148c6f2015-05-04 15:07:53 +0000239 /**
240 * Increment the year.
241 */
Nils Diewalda1228622015-04-25 01:59:10 +0000242 incrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000243 if (this._showYear < 9999) {
Akrond5620d42017-12-06 15:30:28 +0100244 this._showYear++;
245 this._updateYear();
246 this._updateMonth();
247 this._updateDay();
248 return this;
Nils Diewalda79b2682015-05-18 18:34:06 +0000249 };
Nils Diewalda1228622015-04-25 01:59:10 +0000250 return;
251 },
252
Nils Diewalda79b2682015-05-18 18:34:06 +0000253
Nils Diewald7148c6f2015-05-04 15:07:53 +0000254 /**
255 * Decrement the year.
256 */
Nils Diewalda1228622015-04-25 01:59:10 +0000257 decrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000258 if (this._showYear > 0) {
Akrond5620d42017-12-06 15:30:28 +0100259 this._showYear--;
260 this._updateYear();
261 this._updateMonth();
262 this._updateDay();
263 return this;
Nils Diewalda79b2682015-05-18 18:34:06 +0000264 };
Nils Diewalda1228622015-04-25 01:59:10 +0000265 return;
266 },
267
Nils Diewalda79b2682015-05-18 18:34:06 +0000268
Nils Diewald7148c6f2015-05-04 15:07:53 +0000269 /**
270 * Increment the month.
271 */
Nils Diewalda1228622015-04-25 01:59:10 +0000272 incrMonth : function () {
273 this._showMonth++;
274 if (this._showMonth > 12) {
Akrond5620d42017-12-06 15:30:28 +0100275 this._showMonth = 1;
276 this.incrYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000277 }
278 else {
Akrond5620d42017-12-06 15:30:28 +0100279 this._updateMonth();
280 this._updateDay();
Nils Diewalda1228622015-04-25 01:59:10 +0000281 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000282 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000283 },
284
Nils Diewalda79b2682015-05-18 18:34:06 +0000285
Nils Diewald7148c6f2015-05-04 15:07:53 +0000286 /**
287 * Decrement the month.
288 */
Nils Diewalda1228622015-04-25 01:59:10 +0000289 decrMonth : function () {
290 this._showMonth--;
291 if (this._showMonth < 1) {
Akrond5620d42017-12-06 15:30:28 +0100292 this._showMonth = 12;
293 this.decrYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000294 }
295 else {
Akrond5620d42017-12-06 15:30:28 +0100296 this._updateMonth();
297 this._updateDay();
Nils Diewalda1228622015-04-25 01:59:10 +0000298 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000299
300 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000301 },
302
Nils Diewald7148c6f2015-05-04 15:07:53 +0000303
304 // Create the year helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000305 _yearHelper : function () {
306 var year = d.createElement('div');
307 year.classList.add('year');
308
309 // Decrement year
310 year.appendChild(d.createElement('span'))
Akrond5620d42017-12-06 15:30:28 +0100311 .onclick = this.decrYear.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000312
313 this._yElement = year.appendChild(d.createElement('span'));
314 this._yElement.appendChild(document.createTextNode(this._showYear));
315
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000316 this._yElement.onclick = function () {
Akrond5620d42017-12-06 15:30:28 +0100317 this.set(this._showYear);
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000318 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000319 this._selectYear();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000320
Nils Diewalda1228622015-04-25 01:59:10 +0000321 // Increment year
322 year.appendChild(d.createElement('span'))
Akrond5620d42017-12-06 15:30:28 +0100323 .onclick = this.incrYear.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000324
325 return year;
326 },
327
Nils Diewald7148c6f2015-05-04 15:07:53 +0000328 // Update the year helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000329 _updateYear : function () {
330 this._yElement.firstChild.data = this._showYear;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000331 this._selectYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000332 },
333
Nils Diewald7148c6f2015-05-04 15:07:53 +0000334
335 // Check if the viewed year is current
336 _selectYear : function () {
337 if (this._showYear === this.select()['year'])
Akrond5620d42017-12-06 15:30:28 +0100338 this._yElement.classList.add('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000339 else
Akrond5620d42017-12-06 15:30:28 +0100340 this._yElement.classList.remove('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000341 },
342
343
344 // Create the month helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000345 _monthHelper : function () {
346 var month = d.createElement('div');
347 month.classList.add('month');
348
349 // Decrement month
350 month.appendChild(d.createElement('span'))
Akrond5620d42017-12-06 15:30:28 +0100351 .onclick = this.decrMonth.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000352
353 this._mElement = month.appendChild(d.createElement('span'));
354 this._mElement.appendChild(
Akrond5620d42017-12-06 15:30:28 +0100355 document.createTextNode(loc.MONTH[this._showMonth-1])
Nils Diewalda1228622015-04-25 01:59:10 +0000356 );
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000357 this._mElement.onclick = function () {
Akrond5620d42017-12-06 15:30:28 +0100358 this.set(this._showYear, this._showMonth);
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000359 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000360
361 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000362
363 // Increment month
364 month.appendChild(d.createElement('span'))
Akrond5620d42017-12-06 15:30:28 +0100365 .onclick = this.incrMonth.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000366
367 return month;
368 },
369
Nils Diewald7148c6f2015-05-04 15:07:53 +0000370 // Update the month helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000371 _updateMonth : function () {
Akronc59f7322016-04-20 13:46:05 +0200372 if (this._showMonth === undefined || this._showMonth > 12)
Akrond5620d42017-12-06 15:30:28 +0100373 this._showMonth = 1;
Akronc59f7322016-04-20 13:46:05 +0200374
Nils Diewalda1228622015-04-25 01:59:10 +0000375 this._mElement.firstChild.data = loc.MONTH[this._showMonth-1];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000376 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000377 },
378
Nils Diewald7148c6f2015-05-04 15:07:53 +0000379
380 // Check if the viewed month is current
381 _selectMonth : function () {
382 if (this._showYear === this.select()['year'] &&
Akrond5620d42017-12-06 15:30:28 +0100383 this._showMonth === this.select()['month'])
384 this._mElement.classList.add('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000385 else
Akrond5620d42017-12-06 15:30:28 +0100386 this._mElement.classList.remove('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000387 },
388
389
390 // Create the day (calendar) helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000391 _dayHelper : function () {
392 var table = d.createElement('table');
393
Nils Diewald7148c6f2015-05-04 15:07:53 +0000394 // Localized day view
Nils Diewalda1228622015-04-25 01:59:10 +0000395 var tr = table.appendChild(d.createElement('thead'))
Akrond5620d42017-12-06 15:30:28 +0100396 .appendChild(d.createElement('tr'));
Nils Diewalda1228622015-04-25 01:59:10 +0000397 for (var i = 0; i < 7; i++) {
Akrond5620d42017-12-06 15:30:28 +0100398 tr.appendChild(d.createElement('th'))
399 .appendChild(d.createTextNode(loc.WDAY[i]));
Nils Diewalda1228622015-04-25 01:59:10 +0000400 };
401
402 this._dBElement = this._dayBody();
403
404 table.appendChild(this._dBElement);
405 return table;
406 },
407
408 _dayBody : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000409 var showDate = new Date(
Akrond5620d42017-12-06 15:30:28 +0100410 this._showYear,
411 this._showMonth - 1,
412 1,
413 0,
414 0,
415 0,
416 0
Nils Diewald7148c6f2015-05-04 15:07:53 +0000417 );
418 var date = new Date(
Akrond5620d42017-12-06 15:30:28 +0100419 this._showYear,
420 this._showMonth - 1,
421 1,
422 0,
423 0,
424 0,
425 0
Nils Diewald7148c6f2015-05-04 15:07:53 +0000426 );
427 var today = new Date();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000428 var that = this;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000429
430 // What happens, in case someone clicks
431 // on a date
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000432 var click = function () {
Akrond5620d42017-12-06 15:30:28 +0100433 that.set(
434 that._showYear,
435 that._showMonth,
436 parseInt(this.firstChild.data)
437 );
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000438 };
Nils Diewalda1228622015-04-25 01:59:10 +0000439
440 // Skip back to the previous monday (may be in the last month)
441 date.setDate(date.getDate() - ((date.getDay() + 6) % 7));
442
443 var tb = d.createElement('tbody');
444
445 var s = this.select();
446
447 // Iterate over all days of the table
448 while (1) {
449
Akrond5620d42017-12-06 15:30:28 +0100450 // Loop through the week
451 var tr = tb.appendChild(d.createElement('tr'));
452 for (var i = 0; i < 7; i++) {
453 var td = tr.appendChild(d.createElement('td'));
454
455 // Not part of the current month
456 if (date.getMonth() !== showDate.getMonth()) {
457 td.classList.add('out');
458 }
459 else {
460 td.onclick = click;
461 };
462
463 // This is the current day
464 if (date.getDate() === today.getDate() &&
465 date.getMonth() === today.getMonth() &&
466 date.getFullYear() === today.getFullYear()) {
467 td.classList.add('today');
468 };
Nils Diewalda1228622015-04-25 01:59:10 +0000469
Akrond5620d42017-12-06 15:30:28 +0100470 // This is the day selected
471 if (s && s['day']) {
472 if (date.getDate() === s['day'] &&
473 date.getMonth() === s['month']-1 &&
474 date.getFullYear() === s['year']) {
475 td.classList.add('selected');
476 };
477 };
Nils Diewalda1228622015-04-25 01:59:10 +0000478
Akrond5620d42017-12-06 15:30:28 +0100479 // Add the current day to the table
480 td.appendChild(
481 d.createTextNode(date.getDate())
482 );
483
484 // Next day
485 date.setDate(date.getDate() + 1);
486 };
Nils Diewalda1228622015-04-25 01:59:10 +0000487
Akrond5620d42017-12-06 15:30:28 +0100488 if (date.getMonth() !== showDate.getMonth())
489 break;
Nils Diewalda1228622015-04-25 01:59:10 +0000490 };
491 return tb;
492 },
493
Nils Diewald7148c6f2015-05-04 15:07:53 +0000494 // Update the calendar view
Nils Diewalda1228622015-04-25 01:59:10 +0000495 _updateDay : function () {
496 var newBody = this._dayBody();
497 this._dBElement.parentNode.replaceChild(
Akrond5620d42017-12-06 15:30:28 +0100498 newBody,
499 this._dBElement
Nils Diewalda1228622015-04-25 01:59:10 +0000500 );
501 this._dBElement = newBody;
Akron56ea7e32016-04-20 12:25:52 +0200502 },
503
504 fromString : function (v) {
Akronc59f7322016-04-20 13:46:05 +0200505 if (v === undefined)
Akrond5620d42017-12-06 15:30:28 +0100506 return false;
Akron56ea7e32016-04-20 12:25:52 +0200507
Akronc59f7322016-04-20 13:46:05 +0200508 if (!KorAP._validDateRE.test(v))
Akrond5620d42017-12-06 15:30:28 +0100509 return false;
Akron56ea7e32016-04-20 12:25:52 +0200510
Akronc59f7322016-04-20 13:46:05 +0200511 var d = v.split('-', 3);
512 d[0] = parseInt(d[0]);
513 if (d[1]) d[1] = parseInt(d[1]);
514 if (d[2]) d[2] = parseInt(d[2]);
515
516 // Select values
517 this.select(d[0], d[1], d[2]);
518 return true;
Nils Diewalda1228622015-04-25 01:59:10 +0000519 }
520 };
521});