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); } } };