Calendar

배고픈 징징이 ㅣ 2023. 10. 27. 14:09

1. Calendar

기간이 선택가능하고, 이벤트를 사용자 임의로 설정 가능한 달력.

시작일 이전의 기간은 선택이 불가능하다.

공휴일을 지정할 수 있다.

 

2. Code

type CalendarModel = {
    listener? : any;
}

export class Calendar{
    model : CalendarModel;
    parent : HTMLElement;
    holiday : any = {"0101" : true, "0121" : true, "0122" : true, "0123" : true, "0124" : true, "0301" : true, "0505" : true, "0527" : true, "0606" : true
        , "0815" : true, "0928" : true, "0929" : true, "0930" : true, "1003" : true, "1009" : true, "1225" : true,
    };

    constructor(model : CalendarModel, parent : HTMLElement) {
        this.model = model;
        this.parent = parent;

        this.load();
    }

    async load(){
        let selected = new Date();
        let selectedYear : any, selectedMonth : any, startDate : any, endDate : any;

        let selectedStartDate : any = null;
        let selectedEndDate : any = null;

        const drawCalendar = () => {
            this.parent.innerHTML = "";
            settingDay();

            const calendarDiv = document.createElement("calendar-div");
            const table = document.createElement("table");
            const thead = document.createElement("thead");
            const theadTr1 = document.createElement("tr");
            const theadTr2 = document.createElement("tr");
            const prevMonth = document.createElement("td");
            const dateInfo = document.createElement("td");
            const nextMonth = document.createElement("td");

            prevMonth.append("<");
            prevMonth.style.cursor = "pointer";
            prevMonth.addEventListener("click", () => {monthClick("prev");});
            nextMonth.append(">");
            nextMonth.style.cursor = "pointer";
            nextMonth.addEventListener("click", () => {monthClick("next");});

            dateInfo.colSpan = 5;
            dateInfo.innerHTML = `<span id="infoYear">${selectedYear}</span>년 <span id="infoMonth">${selectedMonth + 1}</span>월`;

            theadTr1.append(prevMonth);
            theadTr1.append(dateInfo);
            theadTr1.append(nextMonth);
            theadTr2.innerHTML = "<td>일</td><td>월</td><td>화</td><td>수</td><td>목</td><td>금</td><td>토</td>"
            thead.append(theadTr1);
            thead.append(theadTr2);
            table.append(thead);
            table.append(document.createElement("tbody"));
            calendarDiv.append(table);
            this.parent.append(calendarDiv);

            const body = document.querySelector("calendar-div tbody") as HTMLTableElement;
            let row = body.insertRow();

            for (let i = 0; i < startDate.getDay(); i++){
                row.insertCell();
            }

            for (let i = startDate; i <= endDate; i.setDate(i.getDate() + 1)){
                let cell = row.insertCell();
                cell.id = "calendar_" + i.getDate();
                const date = i.getDate();
                cell.innerHTML = date.toString();
                cell.addEventListener("click", ()  => {
                    dayClick(cell, new Date(selectedYear, selectedMonth, date));
                });

                if (i.getDay() == 0) cell.style.color = "red";
                if (i.getDay() == 6){
                    cell.style.color = "gray";
                    row = body.insertRow();
                }
                
                const key = parseInt("" + doubleDigit(i.getMonth() + 1) + doubleDigit(i.getDate()));
                if(this.holiday[key] == true) cell.style.color = "red";
            }

            const tds = body.getElementsByTagName("td");

            if(selectedStartDate){
                settingDay();
                if(selectedStartDate.getFullYear() == selectedYear && selectedStartDate.getMonth() == selectedMonth){
                    for (let i = startDate; i <= endDate; i.setDate(i.getDate() + 1)){
                        if(selectedStartDate <= i && selectedStartDate >= i){
                            document.getElementById("calendar_" + i.getDate())?.classList.add("selected");
                        }
                        if(!selectedEndDate && i < selectedStartDate){
                            document.getElementById("calendar_" + i.getDate())?.classList.add("disabled");
                        }
                    }
                }else if(!selectedEndDate && (selectedStartDate.getFullYear() > selectedYear || selectedStartDate.getMonth() > selectedMonth)){
                    for(let i = 0; i < tds.length; i ++){
                        tds[i].classList.add("disabled");
                    }
                }

                if(selectedEndDate){
                    const afterStart = selectedStartDate.getFullYear() <= selectedYear && selectedStartDate.getMonth() <= selectedMonth;
                    const beforeEnd = selectedEndDate.getFullYear() >= selectedYear && selectedEndDate.getMonth() >= selectedMonth;

                    if(afterStart && beforeEnd){
                        settingDay();
                        for (let i = startDate; i <= endDate; i.setDate(i.getDate() + 1)){
                            if(i >= selectedStartDate && i <= selectedEndDate){
                                document.getElementById("calendar_" + i.getDate())?.classList.add("selected");
                            }
                        }
                    }
                }
            }

            const monthClick = (type : string) => {
                if(type == "prev"){
                    selected = new Date(selectedYear, selectedMonth - 1, selected.getDate());
                }else if(type == "next"){
                    selected = new Date(selectedYear, selectedMonth + 1, selected.getDate());
                }

                drawCalendar();
            };

            const dayClick = (day : HTMLTableCellElement, data : Date) => {
                settingDay();

                if(day.classList.contains("disabled")) return;
                if(selectedEndDate){
                    for(let i = 0; i < tds.length; i ++){
                        tds[i].classList.remove("disabled", "selected");
                    }

                    selectedStartDate = data;
                    day.classList.add("selected");

                    for (let i = startDate; i <= endDate; i.setDate(i.getDate() + 1)){
                        if(i < selectedStartDate){
                            document.getElementById("calendar_" + i.getDate())?.classList.add("disabled");
                        }
                    }

                    selectedEndDate = null;
                }else{
                    if(!selectedStartDate){
                        selectedStartDate = data;
                        day.classList.add("selected");

                        for (let i = startDate; i <= endDate; i.setDate(i.getDate() + 1)){
                            if(i < selectedStartDate) document.getElementById("calendar_" + i.getDate())?.classList.add("disabled");
                        }
                    }else{
                        selectedEndDate = data;
                        for(let i = 0; i < tds.length; i ++){
                            tds[i].classList.remove("disabled");
                        }

                        for (let i = startDate; i <= endDate; i.setDate(i.getDate() + 1)){
                            if(selectedStartDate < i && i <= selectedEndDate) document.getElementById("calendar_" + i.getDate())?.classList.add("selected");
                        }

                        if(this.model.listener) this.model.listener({startDate : selectedStartDate, endDate : selectedEndDate});
                    }
                }
            };
        }

        const settingDay = () => {
            selectedYear = selected.getFullYear();
            selectedMonth = selected.getMonth();
            startDate = new Date(selectedYear, selectedMonth, 1);
            endDate = new Date(selectedYear, selectedMonth + 1, 0);
        }

        drawCalendar();
        
        function doubleDigit(number : number){
            if(number < 10) return "0" + number;
            else return number
        }
    }
}

 

3. How To Use

class AssetHistoryCell extends View{
	constructor(parent? : View) {
		super("asset-history", parent);
		this.load();
	}
    
	async load(){
		new Calendar({listener : (result : any) => {
			console.log(result);
		}}, left.el);
	}
}

 

4. Download

calendar.scss
0.00MB
calendar.ts
0.01MB
calendar.js
0.01MB

반응형

'Client Side > - Type Script' 카테고리의 다른 글

Tip  (0) 2024.07.18
Enum, Union Type, Tree Shaking  (0) 2023.10.30
Type & Interface  (0) 2023.02.01