테이블 및 테이블을 감싸고 있는 div등을 계속 그리고 있었고 코드가 어지러워서 뭐가 뭔지 파악이 힘들었다. 또한 각 날짜를 anchor로 감싸지 않아 날짜간 tab 이동이 되지 않아 웹표준 그리고 장차법에 위배되는 상황이었다.
그래서 그냥 새로 하나 만들었다. 조금씩 수정해 나가면서 다음에 쓸때가 있을때 다시 써야겠다.
간략한 구조는 날짜에 대한 데이터를 쥐고 있는 calendar 가 있고, 달력을 그리고(draw), 보이고 숨기는 등의 제어 및 달력의 링크에 대한 이벤트(click)을 처리하는 calendarController로 구분하여 만들었다.
그리고 매번 달력을 새로 그리는 것이 아니라 document ready에서 한번만 생성하고 달력 버튼을 클릭할 경우에는 선택된 날짜를 달력에
표시하면서 달력을 보여주는 방식으로 개발 하였다.
/******************** calendar.js ******************** /
/*
strDate: input date (yyyyMMdd): String, required
minYy : input smallest year(yyyy):String, optional
maxYy : input largest year(yyyy):String, optional
strCalendarId: calendar div id
*/
var Calendar = function(strDate,minYy,maxYy,strCalendarId){
this.id = strCalendarId;
this.arrDate = [31,28,31,30,31,30,31,31,30,31,30,31];
this.minYear = minYy;
this.maxYear = maxYy;
//strDate is undefined, then get today date as default
if((strDate=='undeinfed')||(strDate=="")){
var today = new Date();
this.setMonth(today.getMonth()+1);
this.setYear(today.getFullYear());
this.setDate(today.getDate());
this.setMinYear(minYy);
this.setMaxYear(maxYy);
}else{
if((strDate!="")&&(strDate.length!=8)){
throw "input date value is invalid";
}
this.setMonth(strDate.substring(4,6));
this.setYear(strDate.substring(0,4));
this.setDate(strDate.substring(6,8));
this.givenDate =strDate;
if(this.date > this.arrDate[(this.month-1)]){
throw "date value is invalid - bigger than max date of month"+ this.month;
}
this.setMinYear(minYy);
this.setMaxYear(maxYy);
}
}
/*
get calendar div id
*/
Calendar.prototype.getCalendarId = function(){
return this.id;
}
//get the given default date as string (yyyyMMdd)
Calendar.prototype.getGivenDate = function (){
return this.givenDate;
}
//set given date (default date)
Calendar.prototype.setGivenDate = function (strGivenDate){
this.givenDate = strGivenDate;
}
/*getter,setter function for year*/
Calendar.prototype.getYear = function (){
return this.year;
}
Calendar.prototype.setYear = function(yy){
this.year = yy;
if ((this.year % 4 == 0 )&& (this.year % 100 != 0) || (this.year % 400 == 0)){
this.arrDate[1] = 29;
}else{
this.arrDate[1] = 28;
}
this.lastday = this.arrDate[Number(this.month)-1];
}
/*get next year from current year*/
Calendar.prototype.getNextYear = function (){
var nextYear = ""+(Number(this.year)+1);
if(nextYear > this.maxYear){
nextYear = this.maxYear;
}
return nextYear;
}
/*get previous year from current year*/
Calendar.prototype.getPreYear = function (){
var perYear = ""+(Number(this.year)-1);
if((perYear==0)||(perYear < this.minYear)){
perYear = this.minYear;
}
return perYear;
}
//return max year of the calendar
Calendar.prototype.getMaxYear = function (){
return this.maxYear;
}
//return min year of the calendar
Calendar.prototype.getMinYear = function (){
return this.minYear;
}
//set max year of calendar
Calendar.prototype.setMaxYear = function(maxY){
if((maxY!='undeinfed')&&(maxY!="")){
this.maxYear = maxY;
}
}
//set min year of calendar
Calendar.prototype.setMinYear = function(minY){
if((minY!='undeinfed')||(minY!="")){
this.minYear = minY;
}
}
/*getter,setter function for month*/
Calendar.prototype.getMonth = function (){
if((this.month.length < 2)){
this.month = "0"+this.month.toString();
}
return this.month;
}
Calendar.prototype.setMonth = function(m){
if(Number(m)>12){
var nextYear = Number(this.year)+1; //increase year
if(nextYear<10){
this.setYear("0"+nextYear.toString()); //useless code but just in case.
}
this.setYear(nextYear.toString());
m = 1;
}else if(Number(m)<1){
var preYear = Number(this.year)-1; //decrease year
this.setYear(preYear.toString());
m = "12";
}
this.month = (m<10 && m.toString().length < 2)?"0"+m.toString():m.toString();
this.lastday = this.arrDate[Number(this.month)-1];
}
/*getter,setter function for date*/
Calendar.prototype.getDate = function (){
return this.date;
}
Calendar.prototype.setDate = function(dd){
if(dd > this.arrDate[(this.month-1)]){
throw "date value is invalid - bigger than max date of month"+ this.month;
}
this.date = dd;
}
//get full string current date of calendar
Calendar.prototype.getFullDate = function (){
return this.year +""+this.month+""+this.date ;
}
//return last date of current month
Calendar.prototype.getLastDate = function (){
return this.lastday;
}
//return last date of previous month from current month
Calendar.prototype.getLastDayOfLastMon = function (){
var lastMon = Number(this.month)-1;
if(lastMon==0){
lastMon = 12;
}
return this.arrDate[lastMon-1];
}
//return full string of today's date
Calendar.prototype.getCurrentFullDate = function(){
var today = new Date();
var year = today.getFullYear();
var month = today.getMonth()+1;
month = month < 10?"0"+month:""+month;
var date = today.getDate();
date = date < 10?"0"+date:""+date;
return year+""+month+""+date;
}
/*
Calendar controller is doing role for drawing calendar, filling-out date of given month, year and binding button or anchor to event (*mostly click event)
*/
/*
Constructor of CalendarController
calendarObj:Calendar object (* so you need to create Calendar object before creating CalendarController object
callerId:string (mostly, id of anchor or button that shows calendar
tgtInputId:string (id of text input box who takes date value from calendar when specific date is choosen)
*/
var CalendarController = function(calendarObj, callerId,tgtInputId){
var calController = this;
if(!calendarObj){
throw "Invalid calendar - create calendar object first";
}
this.calendar =calendarObj;
if(!$("#"+callerId)){
throw "Invalid caller - there is no such elememt whose id="+ callerId;
}
this.caller = callerId;
if(!$("#"+tgtInputId)){
throw "Invalid target input - there is no such elememt whose id="+ tgtInputId;
}
this.targetInputId = tgtInputId;
/*binding buttons and functions*/
$(document).on('click', '#'+this.calendar.getCalendarId()+' #btnPreYear', function(){
calController.movePreYear();
$(this).focus();
});
$(document).on('click', '#'+this.calendar.getCalendarId()+' #btnNxtYear', function(){
calController.moveNextYear();
$(this).focus();
});
$(document).on('click', '#'+this.calendar.getCalendarId()+' #btnPreMonth', function(){
calController.movePreMonth();
$(this).focus();
});
$(document).on('click', '#'+this.calendar.getCalendarId()+' #btnNextMonth', function(){
calController.moveNextMonth();
$(this).focus();
});
$(document).on('click','#'+this.calendar.getCalendarId()+' #btnMoveToday',function(){
calController.setDateToday();
});
$(document).on('click','#'+this.calendar.getCalendarId()+' #btnCloseCalendar',function(){
calController.closeCalendar();
});
$(document).on('click','#'+this.calendar.getCalendarId()+' #btnCloseCalendar',function(){
calController.closeCalendar();
});
$(document).on('click',"#"+this.callerId,function(){
calController.openCalendar();
});
//binding all date anchor's click event to handler function
var calTableId = "tbl"+this.calendar.getCalendarId();
$(document).on('click',"#"+calTableId +' a',function(){
var fullDate = $(this).attr("id");
calController.getCalendar().setGivenDate(fullDate);
var formattedDate = formatDate(fullDate,'.');
$("#"+calController.getTargetInputId()).val(formattedDate);
calController.closeCalendar();
});
};
//bind calendar object into this calendar controller, I don't think this function is neccessary
CalendarController.prototype.setCalendar = function(calendarObj){
this.calendar = calendarObj;
return this;
};
CalendarController.prototype.getCalendar = function(){
return this.calendar;
};
//getter/setter caller id
CalendarController.prototype.setCallerId = function(callerId){
this.caller = caller;
return this;
};
CalendarController.prototype.getCallerId = function(){
return this.caller;
};
//getter/setter target input box id
CalendarController.prototype.setTargetInputId = function(tgtInputId){
this.targetInputId = tgtInputId;
return this;
};
CalendarController.prototype.getTargetInputId = function(){
return this.targetInputId;
};
//getter/setter css class for dates from previous month or next month
CalendarController.prototype.setOtherDateClass = function(strOtherClass){
this.otherCssClass = strOtherClass;
return this;
};
CalendarController.prototype.getOtherDateClass = function(){
return this.otherCssClass;
};
//getter/setter css class for sunday
CalendarController.prototype.setSunClass = function(strSunClass){
this.sundayClass = strSunClass;
return this;
};
CalendarController.prototype.getSunClass = function(){
return this.sundayClass;
};
//getter/setter css class for saterday
CalendarController.prototype.setSatClass = function(strSatClass){
this.saterdayClass = strSatClass;
return this;
};
CalendarController.prototype.getSatClass = function(){
return this.saterdayClass;
};
//getter/setter css class for today date
CalendarController.prototype.setTodayClass = function(strTodayClass){
this.todayClass = strTodayClass;
return this;
};
//getter/setter css class for normal date
CalendarController.prototype.setDayClass = function(strDayClass){
this.dayClass = strDayClass;
return this;
};
CalendarController.prototype.getDayClass = function(){
return this.dayClass;
};
/****************************start drawing functions****************************/
//get html of first row(* for dates of pre month) of calendar table.
CalendarController.prototype.getFirstWeekTag = function(){
var strFirstWeek = "<tr>"+ "\n";
var classNm = this.otherCssClass;
for(var i=0;i<7;i++){
if(i==6){
classNm = this.saterdayClass;
}
strFirstWeek +="<td class='"+classNm+"'><a href='#none'></a></td>"+ "\n";
}
strFirstWeek +="</tr>"+ "\n";
return strFirstWeek;
};
//get html of middle rows(* for dates of current month) of calendar table.
CalendarController.prototype.getBodyWeekTag = function(){
var strBodyWeeks = "";
for(var i=0;i<4;i++){
strBodyWeeks +="<tr>" + "\n";
for(var j=0;j<7;j++){
if(j==0){
strBodyWeeks += "<td><a href='#none'></a></td>"+"\n";
}else if(j==6){
strBodyWeeks += "<td><a href='#none'></a></td>"+"\n";
}else{
strBodyWeeks += "<td><a href='#none'></a></td>"+"\n";
}
}
strBodyWeeks +="</tr>";
}
return strBodyWeeks;
};
//get html of last row(* for dates of next month) of calendar table.
CalendarController.prototype.getLastWeekTag = function(){
var strLastWeek = "<tr>"+ "\n";
var classNm = this.otherCssClass;
for(var i=0;i<7;i++){
if(i==0){
strLastWeek +="<td><a href='#none'></a></td>"+"\n";
}else if(i==1){
strLastWeek +="<td><a href='#none'></a></td>"+"\n";
}else{
strLastWeek +="<td><a href='#none'></a></td>"+"\n";
}
}
strLastWeek +="</tr>"+ "\n";
return strLastWeek;
};
//get html of whole table of the calendar
CalendarController.prototype.drawCalendarTable = function(){
//to access calendar table with directly, give it id
var tblCalId = "tbl"+this.calendar.getCalendarId();
var strDayOfWeek = "<tr class='day'><td>Sun</td><td>Mon</td><td>Tue</td><td>Wed</td><td>Tur</td><td>Fri</td><td>Sat</td></tr>";
var strFirstWeek = this.getFirstWeekTag();
var strBodyWeeks = this.getBodyWeekTag();
var strLastWeek = this.getLastWeekTag();
var fullTableTag = "<table id='"+tblCalId+"' class='calCss'>";
fullTableTag += strDayOfWeek;
fullTableTag += strFirstWeek;
fullTableTag += strBodyWeeks;
fullTableTag += strLastWeek;
fullTableTag += "</table>";
return fullTableTag;
};
//generate html of wrapper divs of calendar table and append the html after caller
CalendarController.prototype.drawCalendarFrame = function(preSiblingId){
var calendarId = this.calendar.getCalendarId();
var tblCalWrapperDivId = "tblWrapper"+calendarId;
var strCalFullHtml = "<div class=calendar id='"+calendarId+"'>" + "\n";
strCalFullHtml +=" <div class='calHead'>"+ "\n";
strCalFullHtml +=" <div class='year'>"+ "\n";
strCalFullHtml +=" <a href='#' id='btnPreYear'><img src='../images/left_arrow.png' alt='Previous Year' /></a>"+ "\n";
strCalFullHtml +=" <strong id='stnYear'></strong>";
strCalFullHtml +=" <a href='#' id='btnNxtYear'><img src='../images/right_arrow.png' alt='Next Year' /></a>"+ "\n";
strCalFullHtml +=" </div>"+ "\n";
strCalFullHtml +=" <div class='month'>"+ "\n";
strCalFullHtml +=" <a href='#' id='btnPreMonth'><img src='../images/left_arrow.png' alt='Previous Month' /></a>"+ "\n";
strCalFullHtml +=" <strong id='stnMonth'></strong>"+ "\n";
strCalFullHtml +=" <a href='#' id='btnNextMonth'><img src='../images/right_arrow.png' alt='Next Month' /></a>"+ "\n";
strCalFullHtml +=" </div>"+ "\n";
strCalFullHtml +=" </div>"+ "\n"; // end of head
strCalFullHtml +=" <div class='calCover' id='"+tblCalWrapperDivId+"'>"+ "\n";
strCalFullHtml += this.drawCalendarTable(calendarId);
strCalFullHtml +=" </div>"+ "\n";
strCalFullHtml +=" <div class='foot'>"+ "\n";
strCalFullHtml +=" <a href='#' class='btnToday' id='btnMoveToday'>Today</a>"+ "\n";
strCalFullHtml +=" <a href='#' class='btnClose' id='btnCloseCalendar'>Close</a>"+ "\n";
strCalFullHtml +=" </div>"+ "\n"; // end of footer
strCalFullHtml +="</div>"+ "\n";; // end of outter
$("#"+this.getCallerId()).after(strCalFullHtml);
$("#"+calendarId).hide();
}
//fill-out dates of calendar
CalendarController.prototype.fillOutCalendarBody = function(){
var calId =this.calendar.getCalendarId();
var tblCalId = "tbl"+calId;
var curYear = this.calendar.getYear();
var curMonth = this.calendar.getMonth();
$("#"+calId+" #stnYear").text(curYear);
$("#"+calId+" #stnMonth").text(curMonth);
//calculate rest dates from previous month
var firstDateCurMon = new Date();
firstDateCurMon.setFullYear(curYear,curMonth-1,1);
var lastMonStartDay = (firstDateCurMon.getDay() -1)<0?6:(firstDateCurMon.getDay() -1);
var lastMonthDate = this.calendar.getLastDayOfLastMon() - lastMonStartDay;
var restDateOfNextMonth = 42- Number(this.calendar.getLastDate());
var tbIdx = 7; //skip index of td in day row
var selMonth = Number(curMonth)-1;
selMonth = selMonth==0?12:selMonth;
selMonth = (Number(selMonth)<10&&selMonth.length<2)?"0"+selMonth:""+selMonth;
/*start - fill date the first week of month, that including dates from last month*/
for(i=lastMonStartDay;i>=0;i--){
var eachDate = lastMonthDate++;
var fullDate = "";
if(selMonth==12){
fullDate = this.calendar.getPreYear() + "" + selMonth + "" + eachDate;
}else{
fullDate = this.calendar.getYear() + "" + selMonth + "" + eachDate;
}
$("#" + tblCalId + " td:eq(" + tbIdx + ")").removeClass();
$("#" + tblCalId + " td:eq(" + tbIdx + ")").addClass("other");
$("#" + tblCalId + " td:eq(" + tbIdx + ") a").text(eachDate).attr("id", fullDate);
tbIdx++;
}
/*end - fill date the first week of month, that including dates from last month */
/*start - fill out date of current month*/
selMonth = this.calendar.getMonth();
selMonth = (Number(selMonth) < 10 && selMonth.length < 2) ? "0" + selMonth
: "" + selMonth;
var todayDate = this.calendar.getCurrentFullDate();
var givenDate = this.calendar.getGivenDate();
// fill out date current month
$("#" + tblCalId).find('a').removeClass("today");
for (var i = 1; i <= this.calendar.getLastDate(); i++) {
var eachDate = i < 10 ? "0" + i : "" + i;
var fullDate = this.calendar.getYear() + "" + selMonth + "" + eachDate;
$("#" + tblCalId + " td:eq(" + tbIdx + ")").removeClass("other");
if ((fullDate == todayDate)) {
$("#" + tblCalId + " a").removeClass("today");
$("#" + tblCalId + " td:eq(" + tbIdx + ") a").text(i).attr("id",fullDate).addClass("today");
}else if(fullDate==givenDate){
$("#" + tblCalId + " a").removeClass("selDay");
$("#" + tblCalId + " td:eq(" + tbIdx + ") a").text(i).attr("id",fullDate).addClass("selDay");
}
else {
$("#" + tblCalId + " td:eq(" + tbIdx + ") a").text(i).attr("id",fullDate).removeClass("today");
$("#" + tblCalId + " td:eq(" + tbIdx + ") a").text(i).attr("id",fullDate).removeClass("selDay");
}
tbIdx++;
}
/*end - fill out date of current month*/
/*start - fill out dates from next month*/
selMonth = Number(this.calendar.getMonth()) + 1;
selMonth = selMonth == 13 ? 1 : selMonth;
selMonth = (Number(selMonth) < 10 ) ? "0" + selMonth.toString(): "" + selMonth.toString();
// fill date of the last week of month, that including dates from next month;
for (i = 1; i <= restDateOfNextMonth; i++) {
var fullDate ="";
var eachDate = i < 10 ? "0" + i : "" + i;
if(selMonth==1){
fullDate = this.calendar.getNextYear() + "" + selMonth + "" + eachDate;
}else{
fullDate = this.calendar.getYear() + "" + selMonth + "" + eachDate;
}
$("#" + tblCalId + " td:eq(" + tbIdx + ") a").text(i).attr("id", fullDate);
$("#" + tblCalId + " td:eq(" + tbIdx + ")").removeClass();
$("#" + tblCalId + " td:eq(" + tbIdx + ")").addClass("other");
tbIdx++;
}
/*end - fill out dates from next month*/
}; // end of fillOutCalendarBody
/****************************end drawing functions****************************/
//set today and move the today date.(* actually re-filling out the calendar table
CalendarController.prototype.setDateToday = function(){
var date = new Date();
this.calendar.setYear(date.getFullYear());
this.calendar.setMonth(date.getMonth()+1);
this.calendar.setDate(date.getDate());
this.fillOutCalendarBody();
date = null; //release date object
};
//move next year and re-filling out the calendar table
CalendarController.prototype.moveNextYear = function(){
var nextYear = Number(this.calendar.getYear()) + 1;
this.calendar.setYear(nextYear);
this.fillOutCalendarBody();
};
//move pre year and re-filling out the calendar table
CalendarController.prototype.movePreYear = function(){
var nextYear = Number(this.calendar.getYear()) - 1;
this.calendar.setYear(nextYear);
this.fillOutCalendarBody();
};
//move pre month and re-filling out the calendar table
CalendarController.prototype.movePreMonth = function(){
var preMonth = Number(this.calendar.getMonth())-1;
this.calendar.setMonth(preMonth);
this.fillOutCalendarBody();
};
//move next month and re-filling out the calendar table
CalendarController.prototype.moveNextMonth = function(){
var nextMonth = Number(this.calendar.getMonth())+1;
this.calendar.setMonth(nextMonth);
this.fillOutCalendarBody();
};
//hide calendar and move focus to caller
CalendarController.prototype.closeCalendar = function(){
$("#"+this.calendar.getCalendarId()).hide();
$("#"+this.getCallerId()).focus();
};
CalendarController.prototype.toggleCalendar = function(){
$cal_elem = $("#"+this.calendar.getCalendarId());
var isVisible = $cal_elem.is(":visible");
if (!isVisible) {
this.openCalendar();
}else{
this.closeCalendar();
}
}
//show calendar and keep focus on caller
CalendarController.prototype.openCalendar = function(){
$cal_elem = $("#"+this.calendar.getCalendarId());
var isVisible = $cal_elem.is(":visible");
var alink_left = $("#"+this.getCallerId()).position().left;
var alink_top = $("#"+this.getCallerId()).position().top;
$cal_elem.css({
left : alink_left,
top : alink_top + 20,
display : 'block',
position:'absolute'
});
$cal_elem.show();
$("#"+this.getCallerId()).focus();
$cal_elem.find("a").removeClass("selDay");
$cal_elem.find("a[id='"+this.getCalendar().getGivenDate()+"']").removeClass().addClass("selDay");
};
//just util function to format date with given delimeter
function formatDate(strDate,delimeter){
var year = strDate.substring(0,4);
var month = strDate.substring(4,6);
var date = strDate.substring(6,8);
return year + delimeter + month + delimeter + date;
}
/******************** calendar.html ******************** /
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ko" xml:lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Sample Calendar</title>
<link rel="stylesheet" type="text/css" href="../css/calendar.css" />
<script type="text/javascript" src="../js/jquery.js"></script>
<script type="text/javascript" src="../js/calendar.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var calendar1 = new Calendar("",1900,2500,"calendar1");
var calendar2 = new Calendar("",1900,2500,"calendar2");
var calendarController1 = new CalendarController(calendar1,'start_DateCal_calIcon','start_Date');
calendarController1.drawCalendarFrame('calendarWrap');
calendarController1.fillOutCalendarBody();
var calendarController2 = new CalendarController(calendar2,'end_DateCal_calIcon','end_Date');
calendarController2.drawCalendarFrame('calendar2');
calendarController2.fillOutCalendarBody();
$("#start_DateCal_calIcon").click(function(){
calendarController1.openCalendar();
});
$("#end_DateCal_calIcon").click(function(){
calendarController2.openCalendar();
});
$("#btnReleaseCal").click(function(){
destroyCalendar();
});
function destroyCalendar(){
calendarController1.closeCalendar();
calendarController2.closeCalendar();
calendarController1 = null;
calendar1 = null;
calendarController2 = null;
calendar2 = null;
}
});
</script>
</head>
<body>
<div class="container" style="padding-top:40px;">
<div class="wrapper">
<!-- content start -->
<div id="contents" class="contents">
<div id="calendarWrap" class="calendarWrap">
<input class="text readonly" type="text" id="start_Date" title="start date for search" readonly="readonly" >
<a href="#none" id="start_DateCal_calIcon" class="imageIcon">
<img class="vm" src="../images/calendar.png" alt="open calendar for start date" />
</a>
~
<input class="text readonly" type="text" id="end_Date" title="end date for search" readonly="readonly" >
<a href="#calendar2" id="end_DateCal_calIcon" class="imageIcon">
<img class="vm" src="../images/calendar.png" alt="open calendar for end date" />
</a>
</div>
</div>
</div>
</div>
<div>
<input type="button" value="release cal" id="btnReleaseCal"/>
</div>
</body>
</html>
전체 소스(css,javascript, html) calendar_sample.zip



덧글