/**************************** * datePicker.js * create * 2023.08.08 * son tae-jin ****************************/ const dayArr = [ "일", "월", "화", "수", "목", "금", "토" ]; const month = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; const isValidDate = d => { return d instanceof Date && !isNaN(d); } const detectOutsideClick = (caller, container, handler) => { const clickOb = () => { if(!container.contains(event.target) && caller != event.target) { container.remove(); window.removeEventListener('click', clickOb, false); handler(); } } window.addEventListener('click',clickOb, false); } const datePicker = (event) => { if(event.target.dataset.picker) return; const element = event.target; element.dataset.picker = true; const container = document.createElement('div'); container.classList.add('datepicker'); element.parentElement.append(container); container.style.top = element.offsetTop + element.offsetHeight + 'px'; container.style.left = element.offsetLeft + 'px'; detectOutsideClick(element, container, () => {element.removeAttribute('data-picker')}); const dateObj = new Object(); const datePropertys = ['type', 'value', 'min', 'max', 'step']; datePropertys.forEach(el => { if(element[el]) dateObj[el] = element[el]; }); initDataPicker(container, dateObj); } const initDataPicker = (container,property) => { console.log(container, property); switch(property.type) { default: initCalendar(container, property); break; case "month": initMonth(container, property); break; } } const generateCalendar = (container, property, date) => { const ul = container.querySelector('.calendar-con') ? container.querySelector('.calendar-con') : document.createElement('ul'); if(ul.classList.contains('calendar-con')) { ul.innerHTML = ''; } else { ul.classList.add('calendar-con'); container.append(ul); } const today = new Date(); const ny = today.getFullYear(), nm = today.getMonth(), nd = today.getDate(); const cYear = date.getFullYear(); const cMonth = date.getMonth(); const lastDate = new Date(cYear, cMonth + 1, 0).getDate(); const startDay = new Date(cYear, cMonth, 1).getDay(); const beforeLastDate = new Date(cYear, cMonth, 0).getDate(); const selectedDate = property.value ? new Date(property.value) : null; const selectedDateStr = selectedDate ? `${selectedDate.getFullYear()}-${selectedDate.getMonth().toString().padStart(2, '0')}-${selectedDate.getDate().toString().padStart(2, '0')}` : ''; const genDateLi = (date) => { const li = document.createElement('li'); const dateNm = document.createElement('button'); dateNm.type = "button"; dateNm.textContent = new Date(date).getDate(); li.appendChild(dateNm); dateNm.dataset.date = `${date.getFullYear()}-${date.getMonth().toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`; return li; } // 이전달 날짜 for (let k = 0; k < startDay; k++) { const date = new Date(cYear, cMonth-1, beforeLastDate - startDay + 1 + k); const li = genDateLi(date); ul.appendChild(li); li.classList.add('before'); } // 이번달 날짜 표시 for (let i = 0; i < lastDate; i++) { const date = new Date(cYear, cMonth, i+1); const li = genDateLi(date); ul.appendChild(li); if (selectedDate && selectedDateStr == li.querySelector('button').dataset.date) { li.classList.add('selected'); } else if(!selectedDate) { if (ny == cYear && nm == cMonth && nd == i + 1) { li.classList.add('today'); } else if (nd == i + 1) { li.classList.add('sameday'); } } } // 다음달 날짜 표시 const leftAfterDates = 42 - ul.querySelectorAll('li').length; for (let j = 0; j < leftAfterDates; j++){ const date = new Date(cYear, cMonth + 1, j+1); const li = genDateLi(date); ul.appendChild(li); li.classList.add('after'); } return ul; } const initCalendar = (container, property) => { const valueDate = isValidDate(new Date(property.value)) ? new Date(property.value) : new Date(); const ymNavCon = document.createElement('div'); ymNavCon.classList.add('ym-nav-con'); container.append(ymNavCon); const ymSelector = document.createElement('input'); ymSelector.type = 'month'; ymSelector.value = `${valueDate.getFullYear()}-${(valueDate.getMonth()+1).toString().padStart(2, '0')}`; ymSelector.classList.add('custom-datepicker'); ymSelector.onchange = event => { console.log('onchange', event.target); generateCalendar(container, property, new Date(ymSelector.value)); } ymSelector.onclick = event => datePicker(event); ymNavCon.append(ymSelector); const ymPrev = document.createElement('button'); ymPrev.type = "button"; ymPrev.textContent = "이전"; ymPrev.classList.add('btn','prev', 'ico-pv', 'icon-only'); ymNavCon.prepend(ymPrev); ymPrev.onclick = () => ymNav(); const ymNext = document.createElement('button'); ymNext.type = "button"; ymNext.textContent = "다음"; ymNext.classList.add('btn','next', 'ico-fw', 'icon-only'); ymNavCon.append(ymNext); ymNext.onclick = () => ymNav(); const ul = generateCalendar(container, property, new Date(ymSelector.value)); } const ymNav = () => { const ymInput = event.target.parentElement.querySelector('input'); const now = new Date(ymInput.value); if(event.target.classList.contains('prev')) { now.setMonth(now.getMonth() - 1); } else { now.setMonth(now.getMonth() + 1); } ymInput.value = `${now.getFullYear()}-${(now.getMonth()+1).toString().padStart(2, '0')}`; ymInput.dispatchEvent(new Event('change')); } const initMonth = (container, property) => { console.log(container, property); } document.querySelectorAll('input[type=date], input[type=time], input[type=month], input[type=week], input[type=datetime-local]').forEach(el => { el.onchange = () => { if(el.value == '') { el.removeAttribute('value'); } else { el.setAttribute('value',el.value); } } }); document.querySelectorAll('input.custom-datepicker').forEach(el => { el.onclick = (event) => { datePicker(event); } }); // document.querySelectorAll('.custom-datepicker:not(input)').forEach(el => { // initDataPicker(el); // })