blob: f11db3c24fce542c8067a981dc9055749042529b [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
Akron0b489ad2018-02-02 16:49:32 +010079
Akron56ea7e32016-04-20 12:25:52 +020080 store : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +000081 if (this._click !== undefined)
Akrond5620d42017-12-06 15:30:28 +010082 this._click(this._selected);
Nils Diewald7148c6f2015-05-04 15:07:53 +000083 else
Akrond5620d42017-12-06 15:30:28 +010084 console.dir(this._selected);
Nils Diewald7148c6f2015-05-04 15:07:53 +000085 },
Akron0b489ad2018-02-02 16:49:32 +010086
Akrond5620d42017-12-06 15:30:28 +010087
Nils Diewald7148c6f2015-05-04 15:07:53 +000088 /**
89 * Set the action for clicking as a callback.
90 * The callback will retrieve a an object with
91 * an optional year attribute,
92 * an optional month attribute,
93 * and an optional day attribute
94 */
95 onclick : function (cb) {
96 this._click = cb;
97 },
98
Akron516b6f92018-01-03 17:46:59 +010099
100 input : function () {
101 return this._input;
102 },
Akron56ea7e32016-04-20 12:25:52 +0200103
Akron0b489ad2018-02-02 16:49:32 +0100104
Nils Diewald7148c6f2015-05-04 15:07:53 +0000105 /**
106 * Show the datepicker.
107 * Will either show the selected year/month
108 * or the current date.
109 * Will return the element for appending to the dom.
110 */
Nils Diewalda1228622015-04-25 01:59:10 +0000111 show : function (year, month) {
Akron56ea7e32016-04-20 12:25:52 +0200112
Nils Diewald7148c6f2015-05-04 15:07:53 +0000113 var e = this._element = d.createElement('div');
114 e.setAttribute('tabindex', 0);
115 e.style.outline = 0;
116 e.classList.add('datepicker');
Akrond5620d42017-12-06 15:30:28 +0100117
Nils Diewald7148c6f2015-05-04 15:07:53 +0000118 var today = new Date();
119
120 // Show year
Akron56ea7e32016-04-20 12:25:52 +0200121 this._showYear = (year !== undefined) ? year :
Akrond5620d42017-12-06 15:30:28 +0100122 (this._selected['year'] ? this._selected['year'] :
123 today.getYear() + 1900);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000124
125 // Show month
126 this._showMonth = month ? month :
Akrond5620d42017-12-06 15:30:28 +0100127 (this._selected['month'] ? this._selected['month'] :
128 (today.getMonth() + 1));
Nils Diewald7148c6f2015-05-04 15:07:53 +0000129
130 // Append all helpers
Akron516b6f92018-01-03 17:46:59 +0100131 e.appendChild(this._monthHelper());
132 e.appendChild(this._yearHelper());
133 e.appendChild(this._dayHelper());
134 this._input = e.appendChild(this._stringHelper());
135
136 // Always focus
137 e.addEventListener(
138 'mousedown',
139 function (ev) {
140 this._inField = true
141 }.bind(this)
142 );
143
144 e.addEventListener(
145 'mouseup',
146 function (ev) {
147 this._inField = false;
148 this._input.focus();
149 }.bind(this)
150 );
151
152 this._input.addEventListener(
153 'blur',
154 function (ev) {
155 if (!this._inField) {
156 if (this.fromString(this._input.value)) {
157 this.store();
158 };
159 };
160 ev.halt();
161 }.bind(this)
162 );
163
164 this._input.focus();
Akron56ea7e32016-04-20 12:25:52 +0200165
Nils Diewald87507832015-05-01 23:36:41 +0000166 return this._element;
167 },
168
Akronc59f7322016-04-20 13:46:05 +0200169 _stringHelper : function () {
Akron56ea7e32016-04-20 12:25:52 +0200170
171 // Create element
Akron56ea7e32016-04-20 12:25:52 +0200172 // Add input field
Akron0b489ad2018-02-02 16:49:32 +0100173 var input = d.createElement('input');
Akronc59f7322016-04-20 13:46:05 +0200174 input.value = this.toString();
175 input.setAttribute('tabindex', 0);
Akron56ea7e32016-04-20 12:25:52 +0200176
Akronc59f7322016-04-20 13:46:05 +0200177 input.addEventListener(
Akrond5620d42017-12-06 15:30:28 +0100178 'keyup',
179 function (e) {
180 if (this.fromString(input.value)) {
181 this._updateYear();
182 this._updateMonth();
183 this._updateDay();
184 };
185 }.bind(this)
Akron56ea7e32016-04-20 12:25:52 +0200186 );
187
Akrond5620d42017-12-06 15:30:28 +0100188 input.addEventListener(
189 'keypress',
190 function (e) {
191 if (e.keyCode == 13) {
192 if (this.fromString(input.value))
193 this.store();
194
195 e.halt();
196 return false;
197 }
198 }.bind(this)
199 )
200
Akronc59f7322016-04-20 13:46:05 +0200201 return input;
Akron56ea7e32016-04-20 12:25:52 +0200202 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000203
Nils Diewald7148c6f2015-05-04 15:07:53 +0000204 /**
205 * Get the HTML element associated with the datepicker.
206 */
Nils Diewald87507832015-05-01 23:36:41 +0000207 element : function () {
208 return this._element;
Nils Diewalda1228622015-04-25 01:59:10 +0000209 },
210
Akron0b489ad2018-02-02 16:49:32 +0100211
Nils Diewald845282c2015-05-14 07:53:03 +0000212 /**
213 * Get the current date in string format.
214 */
215 today : function () {
216 var today = new Date();
217 var str = today.getYear() + 1900;
218 var m = today.getMonth() + 1;
219 var d = today.getDate();
220 str += '-' + (m < 10 ? '0' + m : m);
221 str += '-' + (d < 10 ? '0' + d : d);
222 return str;
223 },
Nils Diewald7148c6f2015-05-04 15:07:53 +0000224
Akron0b489ad2018-02-02 16:49:32 +0100225
Akron56ea7e32016-04-20 12:25:52 +0200226 toString : function () {
227 // There are values selected
228 var v = '';
229 var s = this._selected;
230 if (s['year']) {
Akrond5620d42017-12-06 15:30:28 +0100231 v += s['year'];
232 if (s['month']) {
233 v += '-';
234 v += s['month'] < 10 ? '0' + s['month'] : s['month'];
235 if (s['day']) {
236 v += '-';
237 v += s['day'] < 10 ? '0' + s['day'] : s['day'];
238 };
239 };
Akron56ea7e32016-04-20 12:25:52 +0200240 };
241 return v;
242 },
Nils Diewalda79b2682015-05-18 18:34:06 +0000243
Akron0b489ad2018-02-02 16:49:32 +0100244
Nils Diewald7148c6f2015-05-04 15:07:53 +0000245 /**
246 * Increment the year.
247 */
Nils Diewalda1228622015-04-25 01:59:10 +0000248 incrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000249 if (this._showYear < 9999) {
Akrond5620d42017-12-06 15:30:28 +0100250 this._showYear++;
251 this._updateYear();
252 this._updateMonth();
253 this._updateDay();
254 return this;
Nils Diewalda79b2682015-05-18 18:34:06 +0000255 };
Nils Diewalda1228622015-04-25 01:59:10 +0000256 return;
257 },
258
Nils Diewalda79b2682015-05-18 18:34:06 +0000259
Nils Diewald7148c6f2015-05-04 15:07:53 +0000260 /**
261 * Decrement the year.
262 */
Nils Diewalda1228622015-04-25 01:59:10 +0000263 decrYear : function () {
Nils Diewalda79b2682015-05-18 18:34:06 +0000264 if (this._showYear > 0) {
Akrond5620d42017-12-06 15:30:28 +0100265 this._showYear--;
266 this._updateYear();
267 this._updateMonth();
268 this._updateDay();
269 return this;
Nils Diewalda79b2682015-05-18 18:34:06 +0000270 };
Nils Diewalda1228622015-04-25 01:59:10 +0000271 return;
272 },
273
Nils Diewalda79b2682015-05-18 18:34:06 +0000274
Nils Diewald7148c6f2015-05-04 15:07:53 +0000275 /**
276 * Increment the month.
277 */
Nils Diewalda1228622015-04-25 01:59:10 +0000278 incrMonth : function () {
279 this._showMonth++;
280 if (this._showMonth > 12) {
Akrond5620d42017-12-06 15:30:28 +0100281 this._showMonth = 1;
282 this.incrYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000283 }
284 else {
Akrond5620d42017-12-06 15:30:28 +0100285 this._updateMonth();
286 this._updateDay();
Nils Diewalda1228622015-04-25 01:59:10 +0000287 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000288 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000289 },
290
Nils Diewalda79b2682015-05-18 18:34:06 +0000291
Nils Diewald7148c6f2015-05-04 15:07:53 +0000292 /**
293 * Decrement the month.
294 */
Nils Diewalda1228622015-04-25 01:59:10 +0000295 decrMonth : function () {
296 this._showMonth--;
297 if (this._showMonth < 1) {
Akrond5620d42017-12-06 15:30:28 +0100298 this._showMonth = 12;
299 this.decrYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000300 }
301 else {
Akrond5620d42017-12-06 15:30:28 +0100302 this._updateMonth();
303 this._updateDay();
Nils Diewalda1228622015-04-25 01:59:10 +0000304 };
Nils Diewalda79b2682015-05-18 18:34:06 +0000305
306 return this;
Nils Diewalda1228622015-04-25 01:59:10 +0000307 },
308
Nils Diewald7148c6f2015-05-04 15:07:53 +0000309
310 // Create the year helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000311 _yearHelper : function () {
312 var year = d.createElement('div');
313 year.classList.add('year');
314
315 // Decrement year
Akron0b489ad2018-02-02 16:49:32 +0100316 year.addE('span')
Akrond5620d42017-12-06 15:30:28 +0100317 .onclick = this.decrYear.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000318
Akron0b489ad2018-02-02 16:49:32 +0100319 this._yElement = year.addE('span');
320 this._yElement.addT(this._showYear);
Nils Diewalda1228622015-04-25 01:59:10 +0000321
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000322 this._yElement.onclick = function () {
Akrond5620d42017-12-06 15:30:28 +0100323 this.set(this._showYear);
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000324 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000325 this._selectYear();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000326
Nils Diewalda1228622015-04-25 01:59:10 +0000327 // Increment year
Akron0b489ad2018-02-02 16:49:32 +0100328 year.addE('span')
Akrond5620d42017-12-06 15:30:28 +0100329 .onclick = this.incrYear.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000330
331 return year;
332 },
333
Nils Diewald7148c6f2015-05-04 15:07:53 +0000334 // Update the year helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000335 _updateYear : function () {
336 this._yElement.firstChild.data = this._showYear;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000337 this._selectYear();
Nils Diewalda1228622015-04-25 01:59:10 +0000338 },
339
Nils Diewald7148c6f2015-05-04 15:07:53 +0000340
341 // Check if the viewed year is current
342 _selectYear : function () {
343 if (this._showYear === this.select()['year'])
Akrond5620d42017-12-06 15:30:28 +0100344 this._yElement.classList.add('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000345 else
Akrond5620d42017-12-06 15:30:28 +0100346 this._yElement.classList.remove('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000347 },
348
349
350 // Create the month helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000351 _monthHelper : function () {
352 var month = d.createElement('div');
353 month.classList.add('month');
354
355 // Decrement month
Akron0b489ad2018-02-02 16:49:32 +0100356 month.addE('span')
Akrond5620d42017-12-06 15:30:28 +0100357 .onclick = this.decrMonth.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000358
Akron0b489ad2018-02-02 16:49:32 +0100359 this._mElement = month.addE('span');
360 this._mElement.addT(loc.MONTH[this._showMonth-1]);
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000361 this._mElement.onclick = function () {
Akrond5620d42017-12-06 15:30:28 +0100362 this.set(this._showYear, this._showMonth);
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000363 }.bind(this);
Nils Diewald7148c6f2015-05-04 15:07:53 +0000364
365 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000366
367 // Increment month
Akron0b489ad2018-02-02 16:49:32 +0100368 month.addE('span')
Akrond5620d42017-12-06 15:30:28 +0100369 .onclick = this.incrMonth.bind(this);
Nils Diewalda1228622015-04-25 01:59:10 +0000370
371 return month;
372 },
373
Nils Diewald7148c6f2015-05-04 15:07:53 +0000374 // Update the month helper view.
Nils Diewalda1228622015-04-25 01:59:10 +0000375 _updateMonth : function () {
Akronc59f7322016-04-20 13:46:05 +0200376 if (this._showMonth === undefined || this._showMonth > 12)
Akrond5620d42017-12-06 15:30:28 +0100377 this._showMonth = 1;
Akronc59f7322016-04-20 13:46:05 +0200378
Nils Diewalda1228622015-04-25 01:59:10 +0000379 this._mElement.firstChild.data = loc.MONTH[this._showMonth-1];
Nils Diewald7148c6f2015-05-04 15:07:53 +0000380 this._selectMonth();
Nils Diewalda1228622015-04-25 01:59:10 +0000381 },
382
Nils Diewald7148c6f2015-05-04 15:07:53 +0000383
384 // Check if the viewed month is current
385 _selectMonth : function () {
386 if (this._showYear === this.select()['year'] &&
Akrond5620d42017-12-06 15:30:28 +0100387 this._showMonth === this.select()['month'])
388 this._mElement.classList.add('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000389 else
Akrond5620d42017-12-06 15:30:28 +0100390 this._mElement.classList.remove('selected');
Nils Diewald7148c6f2015-05-04 15:07:53 +0000391 },
392
393
394 // Create the day (calendar) helper element.
Nils Diewalda1228622015-04-25 01:59:10 +0000395 _dayHelper : function () {
396 var table = d.createElement('table');
397
Nils Diewald7148c6f2015-05-04 15:07:53 +0000398 // Localized day view
Akron0b489ad2018-02-02 16:49:32 +0100399 var tr = table.addE('thead').addE('tr');
Nils Diewalda1228622015-04-25 01:59:10 +0000400 for (var i = 0; i < 7; i++) {
Akron0b489ad2018-02-02 16:49:32 +0100401 tr.addE('th').addT(loc.WDAY[i]);
Nils Diewalda1228622015-04-25 01:59:10 +0000402 };
403
404 this._dBElement = this._dayBody();
405
406 table.appendChild(this._dBElement);
407 return table;
408 },
409
410 _dayBody : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000411 var showDate = new Date(
Akrond5620d42017-12-06 15:30:28 +0100412 this._showYear,
413 this._showMonth - 1,
414 1,
415 0,
416 0,
417 0,
418 0
Nils Diewald7148c6f2015-05-04 15:07:53 +0000419 );
420 var date = new Date(
Akrond5620d42017-12-06 15:30:28 +0100421 this._showYear,
422 this._showMonth - 1,
423 1,
424 0,
425 0,
426 0,
427 0
Nils Diewald7148c6f2015-05-04 15:07:53 +0000428 );
429 var today = new Date();
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000430 var that = this;
Nils Diewald7148c6f2015-05-04 15:07:53 +0000431
432 // What happens, in case someone clicks
433 // on a date
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000434 var click = function () {
Akrond5620d42017-12-06 15:30:28 +0100435 that.set(
436 that._showYear,
437 that._showMonth,
438 parseInt(this.firstChild.data)
439 );
Nils Diewaldbdf79c52015-04-29 23:47:13 +0000440 };
Nils Diewalda1228622015-04-25 01:59:10 +0000441
442 // Skip back to the previous monday (may be in the last month)
443 date.setDate(date.getDate() - ((date.getDay() + 6) % 7));
444
445 var tb = d.createElement('tbody');
446
447 var s = this.select();
448
449 // Iterate over all days of the table
450 while (1) {
451
Akrond5620d42017-12-06 15:30:28 +0100452 // Loop through the week
Akron0b489ad2018-02-02 16:49:32 +0100453 var tr = tb.addE('tr');
Akrond5620d42017-12-06 15:30:28 +0100454 for (var i = 0; i < 7; i++) {
Akron0b489ad2018-02-02 16:49:32 +0100455 var td = tr.addE('td');
Akrond5620d42017-12-06 15:30:28 +0100456
457 // Not part of the current month
458 if (date.getMonth() !== showDate.getMonth()) {
459 td.classList.add('out');
460 }
461 else {
462 td.onclick = click;
463 };
464
465 // This is the current day
466 if (date.getDate() === today.getDate() &&
467 date.getMonth() === today.getMonth() &&
468 date.getFullYear() === today.getFullYear()) {
469 td.classList.add('today');
470 };
Nils Diewalda1228622015-04-25 01:59:10 +0000471
Akrond5620d42017-12-06 15:30:28 +0100472 // This is the day selected
473 if (s && s['day']) {
474 if (date.getDate() === s['day'] &&
475 date.getMonth() === s['month']-1 &&
476 date.getFullYear() === s['year']) {
477 td.classList.add('selected');
478 };
479 };
Nils Diewalda1228622015-04-25 01:59:10 +0000480
Akrond5620d42017-12-06 15:30:28 +0100481 // Add the current day to the table
Akron0b489ad2018-02-02 16:49:32 +0100482 td.addT(date.getDate());
Akrond5620d42017-12-06 15:30:28 +0100483
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});