var picker = {
// (A) COMMON MONTH NAMES
months : ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
// (B) ATTACH DATEPICKER TO TARGET
// target: field to populate
// container: generate datepicker in here (for inline datepicker)
// startmon: start on mon? (optional, default false)
// yrange: year select range (optional, default 10)
// disableday: days to disable, e.g. [2,7] to disable tue and sun (optional)
// onpick : function to call on select date (optional)
attach : instance => {
// (B1) SET DEFAULT OPTIONS
instance.target.readOnly = true; // prevent onscreen keyboard
instance.startmon = instance.startmon ? true : false;
instance.yrange = instance.yrange ? instance.yrange : 10;
// (B2) CURRENT MONTH YEAR (UTC+0)
var today = new Date(),
thisMonth = today.getUTCMonth(), // jan is 0
thisYear = today.getUTCFullYear(); // yyyy
// (B3) GENERATE HTML
// (B3-1) DATEPICKER WRAPPER + BASIC STRUCTURE
instance.hWrap = document.createElement("div");
instance.hWrap.classList.add("picker-wrap");
instance.hWrap.innerHTML =
`
`;
instance.hMonth = instance.hWrap.querySelector(".picker-m");
instance.hYear = instance.hWrap.querySelector(".picker-y");
instance.hDays = instance.hWrap.querySelector(".picker-d");
// (B3-2) SHIFT PERIOD
instance.hWrap.querySelector(".picker-b").onclick = () => picker.shift(instance);
instance.hWrap.querySelector(".picker-n").onclick = () => picker.shift(instance, 1);
// (B3-3) MONTH SELECTOR
for (let m in picker.months) {
let o = document.createElement("option");
o.value = +m + 1;
o.text = picker.months[m];
instance.hMonth.appendChild(o);
}
instance.hMonth.selectedIndex = thisMonth;
instance.hMonth.onchange = () => picker.draw(instance);
// (B3-4) YEAR SELECTOR
for (let y = thisYear-instance.yrange; y < thisYear+instance.yrange; y++) {
let o = document.createElement("option");
o.value = y;
o.text = y;
instance.hYear.appendChild(o);
}
instance.hYear.selectedIndex = instance.yrange;
instance.hYear.onchange = () => picker.draw(instance);
// (B4) INLINE DATEPICKER - ATTACH INTO CONTAINER
if (instance.container) { instance.container.appendChild(instance.hWrap); }
// (B5) POPUP DATEPICKER - ATTACH INTO HTML BODY
else {
instance.hWrap.classList.add("popup");
instance.target.onfocus = () => instance.hWrap.classList.add("show");
instance.hWrap.onclick = e => { if (e.target == instance.hWrap) { instance.hWrap.classList.remove("show"); }};
document.body.appendChild(instance.hWrap);
}
// (B6) INIT DRAW
picker.draw(instance);
},
// (C) SHIFT PERIOD (BY 1 MONTH)
shift : (instance, next) => {
var m = +instance.hMonth.value, y = +instance.hYear.value;
if (next) {
m++;
if (m>12) { m = 1; y++; }
let max = instance.hYear.querySelector("option:last-child").value;
if (y>max) { m = 12; y = max; }
} else {
m--;
if (m<1) { m = 12; y--; }
let min = instance.hYear.querySelector("option:first-child").value;
if (y {
// (D1) A LOT OF CALCULATIONS
// (D1-1) SELECTED MONTH YEAR
var month = instance.hMonth.value,
year = instance.hYear.value;
// (D1-2) DATE RANGE CALCULATION (UTC+0)
var daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate(),
startDay = new Date(Date.UTC(year, month-1, 1)).getUTCDay(), // sun is 0
endDay = new Date(Date.UTC(year, month-1, daysInMonth)).getUTCDay();
startDay = startDay==0 ? 7 : startDay,
endDay = endDay==0 ? 7 : endDay;
// (D1-3) TODAY (FOR HIGHLIGHTING "TODAY")
var today = new Date(), todayDate = null;
if (today.getUTCMonth()+1 == month && today.getUTCFullYear() == year) {
todayDate = today.getUTCDate();
}
// (D1-4) DAY NAMES
var daynames = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
if (instance.startmon) { daynames.push("Sun"); }
else { daynames.unshift("Sun"); }
// (D2) CALCULATE DATE SQUARES
// (D2-1) EMPTY SQUARES BEFORE FIRST DAY OF MONTH
var squares = [];
if (instance.startmon && startDay!=1) {
for (let i=1; i picker.pick(instance, squares[i][0]);
}
}
instance.hDays.appendChild(cell);
}
},
// (E) CHOOSE A DATE
pick : (instance, d) => {
// (E1) GET MONTH YEAR
let m = instance.hMonth.value,
y = instance.hYear.value;
// (E2) FORMAT & SET SELECTED DAY (YYYY-MM-DD)
if (+m<10) { m = "0" + m; }
if (+d<10) { d = "0" + d; }
let formatted = `${y}-${m}-${d}`;
instance.target.value = formatted;
// (E3) POPUP ONLY - CLOSE
if (instance.hWrap.classList.contains("popup")) {
instance.hWrap.classList.remove("show");
}
// (E4) CALL ON PICK IF DEFINED
if (instance.onpick) { instance.onpick(formatted); }
}
};