blob: c2b0570d70cfcf06211bf9e965f5d2c06009c7a1 [file] [log] [blame]
/**
* Date picker for the
* Virtual Collection builder.
*
* @author Nils Diewald
*/
"use strict";
define(['util'], function () {
KorAP._validDateMatchRE = new RegExp("^(?:[lg]?eq|ne)$");
KorAP._validDateRE = new RegExp("^(?:\\d{4})(?:-\\d\\d(?:-\\d\\d)?)?$");
/*
* Localizations
*/
const loc = KorAP.Locale;
loc.WDAY = loc.WDAY || [
'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'
];
loc.MONTH = loc.MONTH || [
'January', 'February', 'March', 'April',
'May', 'June', 'July', 'August',
'September', 'October', 'November',
'December'
];
const d = document;
// The datepicker class
return {
/**
* Create a new datepicker view.
*/
create : function () {
return Object.create(this)._init();
},
// Init datepicker
_init : function () {
this._selected = [];
return this;
},
/**
* Get or select a specific date.
*/
select : function (year, month, day) {
const t = this;
if (arguments.length >= 1) {
t._selected = {'year' : year};
t._showYear = year;
if (arguments.length >= 2) {
t._selected['month'] = month;
t._showMonth = month;
if (arguments.length >= 3) {
t._selected['day'] = day;
t._showDay = day;
};
};
return t;
};
return t._selected;
},
/**
* Select a specific date and
* init the accompanied action.
*/
set : function (year, month, day) {
this.select(year, month, day);
this._store();
},
// Store the selected value
_store : function () {
if (this._click !== undefined)
this._click(this._selected);
else
console.dir(this._selected);
},
/**
* Set the action for clicking as a callback.
* The callback will retrieve a an object with
* an optional year attribute,
* an optional month attribute,
* and an optional day attribute
*/
onclick : function (cb) {
this._click = cb;
},
/**
* The associated input field.
*/
input : function () {
return this._input;
},
/**
* Show the datepicker.
* Will either show the selected year/month
* or the current date.
* Will return the element for appending to the dom.
*/
show : function (year, month) {
const e = this._el = d.createElement('div');
e.setAttribute('tabindex', 0);
e.style.outline = 0;
e.classList.add('datepicker');
const today = new Date();
const t = this;
// Show year
t._showYear = (year !== undefined) ? year :
(t._selected['year'] ? this._selected['year'] :
today.getYear() + 1900);
// Show month
t._showMonth = month ? month :
(t._selected['month'] ? t._selected['month'] :
(today.getMonth() + 1));
// Append all helpers
e.appendChild(t._monthHelper());
e.appendChild(t._yearHelper());
e.appendChild(t._dayHelper());
t._input = e.appendChild(t._stringHelper());
// Always focus
e.addEventListener(
'mousedown',
function (ev) {
this._inField = true
}.bind(t)
);
e.addEventListener(
'mouseup',
function (ev) {
this._inField = false;
this._input.focus();
}.bind(t)
);
t._input.addEventListener(
'blur',
function (ev) {
if (!this._inField) {
if (this.fromString(this._input.value)) {
this._store();
};
};
ev.halt();
}.bind(t)
);
t._input.focus();
return t._el;
},
_stringHelper : function () {
// Create element
// Add input field
const input = d.createElement('input');
input.value = this.toString();
input.setAttribute('tabindex', 0);
input.addEventListener(
'keyup',
function (e) {
if (this.fromString(input.value)) {
this._updateYear();
this._updateMonth();
this._updateDay();
};
}.bind(this)
);
input.addEventListener(
'keypress',
function (e) {
if (e.keyCode == 13) {
if (this.fromString(input.value))
this._store();
e.halt();
return false;
}
}.bind(this)
)
return input;
},
/**
* Get the HTML element associated with the datepicker.
*/
element : function () {
return this._el;
},
/**
* Get the current date in string format.
*/
today : function () {
const today = new Date();
let str = today.getYear() + 1900;
const m = today.getMonth() + 1;
const d = today.getDate();
str += '-' + (m < 10 ? '0' + m : m);
str += '-' + (d < 10 ? '0' + d : d);
return str;
},
/**
* Stringification
*/
toString : function () {
// There are values selected
let v = '';
const s = this._selected;
if (s['year']) {
v += s['year'];
if (s['month']) {
v += '-';
v += s['month'] < 10 ? '0' + s['month'] : s['month'];
if (s['day']) {
v += '-';
v += s['day'] < 10 ? '0' + s['day'] : s['day'];
};
};
};
return v;
},
/**
* Increment the year.
*/
incrYear : function () {
const t = this;
if (t._showYear < 9999) {
t._showYear++;
t._updateYear();
t._updateMonth();
t._updateDay();
return t;
};
return;
},
/**
* Decrement the year.
*/
decrYear : function () {
const t = this;
if (t._showYear > 0) {
t._showYear--;
t._updateYear();
t._updateMonth();
t._updateDay();
return t;
};
return;
},
/**
* Increment the month.
*/
incrMonth : function () {
const t = this;
t._showMonth++;
if (t._showMonth > 12) {
t._showMonth = 1;
t.incrYear();
}
else {
t._updateMonth();
t._updateDay();
};
return t;
},
/**
* Decrement the month.
*/
decrMonth : function () {
const t = this;
t._showMonth--;
if (t._showMonth < 1) {
t._showMonth = 12;
t.decrYear();
}
else {
t._updateMonth();
t._updateDay();
};
return t;
},
// Create the year helper element.
_yearHelper : function () {
const t = this;
const year = d.createElement('div');
year.classList.add('year');
// Decrement year
year.addE('span')
.onclick = t.decrYear.bind(t);
t._yElement = year.addE('span');
t._yElement.addT(t._showYear);
t._yElement.onclick = function () {
t.set(t._showYear);
}.bind(t);
t._selectYear();
// Increment year
year.addE('span')
.onclick = t.incrYear.bind(t);
return year;
},
// Update the year helper view.
_updateYear : function () {
this._yElement.firstChild.data = this._showYear;
this._selectYear();
},
// Check if the viewed year is current
_selectYear : function () {
if (this._showYear === this.select()['year'])
this._yElement.classList.add('selected');
else
this._yElement.classList.remove('selected');
},
// Create the month helper element.
_monthHelper : function () {
const t = this;
const month = d.createElement('div');
month.classList.add('month');
// Decrement month
month.addE('span')
.onclick = t.decrMonth.bind(t);
t._mElement = month.addE('span');
t._mElement.addT(loc.MONTH[t._showMonth-1]);
t._mElement.onclick = function () {
this.set(this._showYear, this._showMonth);
}.bind(t);
t._selectMonth();
// Increment month
month.addE('span')
.onclick = t.incrMonth.bind(t);
return month;
},
// Update the month helper view.
_updateMonth : function () {
if (this._showMonth === undefined || this._showMonth > 12)
this._showMonth = 1;
this._mElement.firstChild.data = loc.MONTH[this._showMonth-1];
this._selectMonth();
},
// Check if the viewed month is current
_selectMonth : function () {
const t = this;
if (t._showYear === t.select()['year'] &&
t._showMonth === t.select()['month'])
t._mElement.classList.add('selected');
else
t._mElement.classList.remove('selected');
},
// Create the day (calendar) helper element.
_dayHelper : function () {
const table = d.createElement('table');
// Localized day view
const tr = table.addE('thead').addE('tr');
for (let i = 0; i < 7; i++) {
tr.addE('th').addT(loc.WDAY[i]);
};
this._dBElement = this._dayBody();
table.appendChild(this._dBElement);
return table;
},
// Create day body for calendar table
_dayBody : function () {
const showDate = new Date(
this._showYear,
this._showMonth - 1,
1,
0,
0,
0,
0
);
const date = new Date(
this._showYear,
this._showMonth - 1,
1,
0,
0,
0,
0
);
const today = new Date();
const that = this;
// What happens, in case someone clicks
// on a date
const click = function () {
that.set(
that._showYear,
that._showMonth,
parseInt(this.firstChild.data)
);
};
// Skip back to the previous monday (may be in the last month)
date.setDate(date.getDate() - ((date.getDay() + 6) % 7));
const tb = d.createElement('tbody');
const s = this.select();
let tr, i, td;
// Iterate over all days of the table
while (1) {
// Loop through the week
tr = tb.addE('tr');
for (i = 0; i < 7; i++) {
td = tr.addE('td');
// Not part of the current month
if (date.getMonth() !== showDate.getMonth()) {
td.classList.add('out');
}
else {
td.onclick = click;
};
// This is the current day
if (date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear()) {
td.classList.add('today');
};
// This is the day selected
if (s && s['day']) {
if (date.getDate() === s['day'] &&
date.getMonth() === s['month']-1 &&
date.getFullYear() === s['year']) {
td.classList.add('selected');
};
};
// Add the current day to the table
td.addT(date.getDate());
// Next day
date.setDate(date.getDate() + 1);
};
if (date.getMonth() !== showDate.getMonth())
break;
};
return tb;
},
// Update the calendar view
_updateDay : function () {
const newBody = this._dayBody();
this._dBElement.parentNode.replaceChild(
newBody,
this._dBElement
);
this._dBElement = newBody;
},
/**
* Parse date from string.
*/
fromString : function (v) {
if (v === undefined)
return false;
if (!KorAP._validDateRE.test(v))
return false;
const d = v.split('-', 3);
d[0] = parseInt(d[0]);
if (d[1]) d[1] = parseInt(d[1]);
if (d[2]) d[2] = parseInt(d[2]);
// Select values
this.select(d[0], d[1], d[2]);
return true;
}
};
});