/*======================================= // jsCalendar // textbox에 연계해서 날짜를 입력한다 // 작성일 : 2008-02-25 // 수정일 : 2008-02-25 10 AM // 수정일 : 2008-06-03 // 수정일 : 2008-07-07 #js_calendar 와 다른점 네이밍 반식이 바뀌었고 CSS로 99% 디자인이 가능합니다. 버튼은 더이상 기본으로 생성되지 않습니다.(수동으로 지정해주셔야합니다.) #동작 : open 버튼을 누르면 달력이 보인다. 년,월을 변경할 수 있다 날짜를 선택하면, 해당 textbox의 onchage 이밴트에 등록된 스크립트를 실행한다(없으면 무시~) #사용법 : var calendar = new jsCalendar([TextBox],[Button]); [TextBox] : 값이 전달되는 텍스트 박스 (필수) [Button] : 달력 오픈 버튼 (선택)(지정 안할 경우 텍스트박스가 버튼역활도 함) #예 : var cal0 = new jsCalendar(document.getElementById('ipt00'),document.getElementById('btn00')); #설정 var calendar = new jsCalendar([TextBox],[Button]); calendar.cfg.startWDay:0 //0(기존값):일요일부터시작,1:월요일,2:화요일~6:토요일 calendar.cfg.useOtherMonthDay:true //true:해당 월 이외의 날짜도 표시, false:해당 월의 날짜만 표시 calendar.cfg.wDayType:'kr' //요일글짜: kr:한글, cn:한문, enShort:영어악어 , en:영어 calendar.cfg.dateFormat:'Y-m-d' //날짜표현식 calendar.cfg.language:'kr' //언어형식, kr:년,월,일 , en:영어, cn:한문 calendar.cfg.mLeft:0 //left 수정값 calendar.cfg.mTop:0 //top 수정값 calendar.cfg.onSelectFN:function(date){thisC.targetElement.value = date;} //날짜를 선택할 때 동작할 함수 //임의로 지정할 수 있습니다. calendar.cfg.limitTSTMPST:null // 최소날짜 제한일(Date.getTime()형식), 직접 지정보다는 setPeriod()를 사용 calendar.cfg.limitTSTMPED:null // 최대날짜 제한일(Date.getTime()형식) 직접 지정보다는 setPeriod()를 사용 calendar.cfg.onSelectFN = function(date){alert(date);} calendar.cfg.divClassName = 'divLayout' //최외각 div의 class 이름 calendar.setPeriod([최소날짜 제한일],[최대날짜 제한일]); //[최소날짜 제한일] : '2008-10-21' 처럼 지정, null로 지정하면 제한이 사라진다. //[최대날짜 제한일] : '2008-10-21' 처럼 지정, null로 지정하면 제한이 사라진다. #제한 .js 파일은 수정할 수 없습니다. .css는 원하는 형태로 수정해서 사용하세요. #연계 js_date.js : 날짜 계산을 위해서 사용 jsCalendar.css : CSS파일 //=======================================*/ function jsCalendar(targetElement,buttonElement){ var thisC = this; this.targetElement = null; //대상 textbox this.buttonElement = null; //버튼 엘레맨트 this.selectedValue = null; //선택된 값, textbox의 값 this.selectedDate = null; //선택된 값의 Date형 this.todayValue = null; //오늘의 값 this.calendar = null; //칼렌더 this.upDownTimer = null; //날짜 증가,감소 타이머 this.aClose = null; //메뉴 : 닫기 this.autoCloseTimer = null; //자동닫기 타이머 this.over = null; //마우스 오버 감지 this.cfg = { startWDay:0 //0(기존값):일요일부터시작,1:월요일,2:화요일~6:토요일 ,useOtherMonthDay:true //true:해당 월 이외의 날짜도 표시, false:해당 월의 날짜만 표시 ,wDayType:'kr' //요일글짜: kr:한글, cn:한문, enShort:영어악어 , en:영어 ,dateFormat:'Y-m-d' //날짜표현식 ,language:'kr' //언어형식, kr:년,월,일 , en:영어, cn:한문 ,mLeft:0 //left 조정값 ,mTop:0 //top 조정값 ,autoClose:true //자동 닫기 설정, 포커스를 잃으면 자동으로 사라진다. ,autoCloseTimeout:200 //자동 닫기에 걸리는 시간, 1000가 1초 지정된 시간이 충분하지 않으면 연결된 onChange 함수가 동작 못할 수 있다. ,upDownTimeout:300 //날짜 증가,감소 반복딜레이 ,limitTSTMPST:null // 최소날짜 제한일(Date.getTime()형식), 직접 지정보다는 setPeriod()를 사용 ,limitTSTMPED:null // 최대날짜 제한일(Date.getTime()형식) 직접 지정보다는 setPeriod()를 사용 ,onSelectFN:function(date){thisC.targetElement.value = date;} ,divClassName:'divLayout' //최외각 div의 class 이름 }; this.wDays ={ enShort:['SUN','MON','TUE','WED','THU','FRI','SAT'] //영어 약어형 ,en:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'] //영어 풀네임 ,kr:['일','월','화','수','목','금','토'] //한글 ,cn:['日','月','火','水','木','金','土'] //한문 } this.dateWord ={ kr:{year:'년',month:'월',date:'일',today:'오늘',close:'닫기'} ,en:{year:'year',month:'month',date:'date',today:'Today',close:'close'} ,cn:{year:'年',month:'月',date:'日',today:'今日',close:'close'} } this.jsCalendar(targetElement,buttonElement); //생성자 } jsCalendar.prototype.jsCalendar = function(targetElement,buttonElement){ //생성자 var thisC = this; this.targetElement = targetElement; if(!this.targetElement){ alert("지정된 대상이 없습니다"); return false; } this.selectedDate = new Date(); if(this.targetElement.value) this.selectedDate.setTime(this.selectedDate.str_setTime(this.targetElement.value)); this.selectedValue = this.selectedDate.date(this.cfg.dateFormat); //=== 버튼처리 if(!buttonElement) this.buttonElement = this.targetElement else this.buttonElement = buttonElement; this.buttonElement.onclick = function(){thisC.toggleCalendar()} } jsCalendar.prototype.showCalendar = function(){ if(this.targetElement.value) this.selectedDate.str_setTime(this.targetElement.value); this.selectedValue = this.selectedDate.date(this.cfg.dateFormat); var dTMP = new Date(); this.todayValue = dTMP.date(this.cfg.dateFormat); var scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight); var scrollWidth = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth); var targetRect = this.getBounds(this.targetElement) if(!this.calendar ){ this.calendar = this.createCalendar(this.selectedDate.getFullYear(),(this.selectedDate.getMonth()+1)); document.body.appendChild(this.calendar); this.calendar.style.left = targetRect.left+this.cfg.mLeft+'px'; this.calendar.style.top = targetRect.top+this.cfg.mTop+targetRect.height+'px'; }else{ this.changeCalendar(this.selectedDate.getFullYear(),(this.selectedDate.getMonth()+1)); } //===위치 재설정 /* var calendarRect = this.getBounds(this.calendar); if(scrollHeight < (calendarRect.top +calendarRect.height)){ this.calendar.style.top = this.cfg.mLeft+(calendarRect.top - calendarRect.height - targetRect.height)+'px'; } if(scrollWidth < (calendarRect.left +calendarRect.width)){ this.calendar.style.left = this.cfg.mTop+(scrollWidth-calendarRect.width)+'px'; } */ this.calendar.style.display=''; //===== 닫기 버튼에 포커스 if(this.cfg.autoClose){ //자동 닫기를 사용할 때 this.aClose.focus(); } } jsCalendar.prototype.autoCloseStopCalendar = function(){ this.over = 0; if(this.autoCloseTimer != null){ clearTimeout(this.autoCloseTimer); } } jsCalendar.prototype.autoCloseStartCalendar = function(){ var thisC = this; var fn = function(){ if(thisC.over <=0 ) thisC.hideCalendar(); } this.autoCloseTimer = setTimeout(fn,this.cfg.autoCloseTimeout); } jsCalendar.prototype.hideCalendar = function(){ if(this.calendar){ this.calendar.style.display='none'; clearTimeout(this.autoCloseTimer); clearInterval(this.upDownTimer); } } jsCalendar.prototype.toggleCalendar = function(){ if(this.calendar){ if(this.calendar.style.display=='none') this.showCalendar(); else this.hideCalendar(); }else{ this.showCalendar(); } } jsCalendar.prototype.onSelectDate = function(date){ //달력을 만든다. this.cfg.onSelectFN(date); if(this.targetElement.onchange){this.targetElement.onchange();} this.hideCalendar(); } jsCalendar.prototype.createCalendar = function(year,month){ //달력을 만든다. this.divLayout = this.createCalendarLayout(); this.taFrame = this.createCalendarFrame(year,month); var taHead = this.createCalendarHead(year,month); this.taBody = this.createCalendarBody(year,month); var taFoot = this.createCalendarFoot(year,month); this.taFrame.taFrameTrHeadTdHead.appendChild(taHead); this.taFrame.taFrameTrBodyTdBody.appendChild(this.taBody); this.taFrame.taFrameTrFootTdFoot.appendChild(taFoot); this.divLayout.appendChild(this.taFrame); return this.divLayout; } jsCalendar.prototype.changeCalendar = function(year,month){ //달력을 만든다. var d = new Date(year,(month-1),1); var y = d.getFullYear(); var m = (d.getMonth()+1); this.taFrame.taFrameTrBodyTdBody.removeChild(this.taBody); this.taBody = this.createCalendarBody(y,m); this.taFrame.taFrameTrBodyTdBody.appendChild(this.taBody ); this.iptYear.value=y; this.iptMonth.value=m; } jsCalendar.prototype.onBTNOpen = function(){ //달력을 만든다. this.toggleCalendar(); } jsCalendar.prototype.onBTNToday = function(){ //달력을 만든다. var d = new Date(); var y = d.getFullYear(); var m = (d.getMonth()+1); if(isNaN(y) || isNaN(m) ){ alert("잘못된 날짜입니다."); return false; } this.changeCalendar(y,m); } jsCalendar.prototype.onBTNYearDown = function(year,month){ //달력을 만든다. var y = parseInt(year); var m = parseInt(month); if(isNaN(y) || isNaN(m) ){ alert("잘못된 날짜입니다."); return false; } this.changeCalendar((y-1),m); } jsCalendar.prototype.onBTNYearUp = function(year,month){ //달력을 만든다. var y = parseInt(year); var m = parseInt(month); if(isNaN(y) || isNaN(m) ){ alert("잘못된 날짜입니다."); return false; } this.changeCalendar((y+1),m); } jsCalendar.prototype.onBTNMonthDown = function(year,month){ //달력을 만든다. var y = parseInt(year); var m = parseInt(month); if(isNaN(y) || isNaN(m) ){ alert("잘못된 날짜입니다."); return false; } this.changeCalendar(y,(m-1)); } jsCalendar.prototype.onBTNMonthUp = function(year,month){ //달력을 만든다. var y = parseInt(year); var m = parseInt(month); if(isNaN(y) || isNaN(m) ){ alert("잘못된 날짜입니다."); return false; } this.changeCalendar(y,(m+1)); } jsCalendar.prototype.createCalendarLayout = function(){ //달력의 DIV 레이아웃 부분 var divLayout = document.createElement('div'); divLayout.className = this.cfg.divClassName || 'divLayout'; return divLayout; } jsCalendar.prototype.createCalendarFrame = function(year,month){ //달력의 프레임 부분 //========== 프레임 테이블 생성 var taFrame = document.createElement('table'); taFrame.border="0" ; taFrame.cellSpacing="0" ; taFrame.cellPadding="0"; taFrame.className='taFrame'; //=== tr var taFrameTrHead = taFrame.insertRow(-1); taFrameTrHead.className='taFrameTrHead'; var taFrameTrBody = taFrame.insertRow(-1); taFrameTrBody.className='taFrameTrBody'; var taFrameTrFoot = taFrame.insertRow(-1); taFrameTrFoot.className='taFrameTrFoot'; taFrame.taFrameTrHead = taFrameTrHead; taFrame.taFrameTrBody = taFrameTrBody; taFrame.taFrameTrFoot = taFrameTrFoot; //===td var taFrameTrHeadTdHead = taFrameTrHead.insertCell(0); taFrameTrHeadTdHead.className='taFrameTrHeadTdHead'; var taFrameTrBodyTdBody = taFrameTrBody.insertCell(0); taFrameTrBodyTdBody.className='taFrameTrBodyTdBody'; var taFrameTrFootTdFoot = taFrameTrFoot.insertCell(0); taFrameTrFootTdFoot.className='taFrameTrFootTdFoot'; taFrame.taFrameTrHeadTdHead = taFrameTrHeadTdHead; taFrame.taFrameTrBodyTdBody = taFrameTrBodyTdBody; taFrame.taFrameTrFootTdFoot = taFrameTrFootTdFoot; //=== for test //taFrameTrHeadTdHead.innerHTML = "해더부분"; return taFrame; } jsCalendar.prototype.createCalendarHead = function(year,month){ //달력의 머리, 메뉴부분 var thisC = this; //========== 메뉴 테이블 생성 var taHead = document.createElement('table'); taHead.border="0" ; taHead.cellSpacing="0" ; taHead.cellPadding="0"; taHead.className='taHead'; //=== tr var taHeadTr0 = taHead.insertRow(-1); taHeadTr0.className='taHeadTr0'; var taHeadTr1 = taHead.insertRow(-1); taHeadTr1.className='taHeadTr1'; //===td var taHeadTr0Td0 = taHeadTr0.insertCell(0); taHeadTr0Td0.className='taHeadTr0Td0'; var taHeadTr1Td0 = taHeadTr1.insertCell(0); taHeadTr1Td0.className='taHeadTr1Td0'; //=== 내용넣기 //=오늘로 var aToday = document.createElement('a'); aToday.className = "aToday"; aToday.href='javascript:void(0);'; aToday.onmousedown=function(){thisC.over++;} aToday.onmouseup=function(){thisC.onBTNToday();thisC.aClose.focus(); } aToday.innerHTML = this.dateWord[this.cfg.language].today; aToday.title = this.dateWord[this.cfg.language].today; taHeadTr0Td0.appendChild(aToday); //=닫기 var aClose = document.createElement('a'); aClose.className = "aClose"; aClose.href='javascript:void(0);'; aClose.onclick=function(){thisC.hideCalendar();} aClose.innerHTML = "X"; aClose.title = this.dateWord[this.cfg.language].close; taHeadTr0Td0.appendChild(aClose); if(this.cfg.autoClose){ aClose.onfocus=function(){thisC.autoCloseStopCalendar();} aClose.onblur=function(){thisC.autoCloseStartCalendar();} } this.aClose = aClose; //=년 var iptYear = document.createElement('input'); iptYear.size=4; iptYear.className = "iptYear"; iptYear.value = year; iptYear.readOnly = true; taHeadTr1Td0.appendChild(iptYear); this.iptYear = iptYear; //=a링크 기본형 var aSTD = document.createElement('a'); aSTD.className = "aButton"; aSTD.href='javascript:void(0);'; //=년도 잠소,증가 var aYearDown = aSTD.cloneNode(true); aYearDown.innerHTML = '▼'; var aYearUp = aSTD.cloneNode(true); aYearUp.innerHTML = '▲'; taHeadTr1Td0.appendChild(aYearDown); taHeadTr1Td0.appendChild(aYearUp); taHeadTr1Td0.appendChild(document.createTextNode(this.dateWord[this.cfg.language].year+' ')); //=월 var iptMonth = document.createElement('input'); iptMonth.size=2; iptMonth.className = "iptMonth"; iptMonth.value = month; iptMonth.readOnly = true; taHeadTr1Td0.appendChild(iptMonth); this.iptMonth = iptMonth; //=월 잠소,증가 var aMonthDown = aSTD.cloneNode(true); aMonthDown.innerHTML = '▼'; var aMonthUp = aSTD.cloneNode(true); aMonthUp.innerHTML = '▲'; taHeadTr1Td0.appendChild(aMonthDown); taHeadTr1Td0.appendChild(aMonthUp); taHeadTr1Td0.appendChild(document.createTextNode(this.dateWord[this.cfg.language].month)); //=== 이밴트 aYearDown.onmousedown = function(){ thisC.over++; thisC.onBTNYearDown(iptYear.value,iptMonth.value); var fn = function(){ thisC.onBTNYearDown(iptYear.value,iptMonth.value); } thisC.upDownTimer = setInterval(fn,thisC.cfg.upDownTimeout); thisC.aClose.focus(); } aYearUp.onmousedown = function(){ thisC.over++; thisC.onBTNYearUp(iptYear.value,iptMonth.value); var fn = function(){ thisC.onBTNYearUp(iptYear.value,iptMonth.value); } thisC.upDownTimer = setInterval(fn,thisC.cfg.upDownTimeout); thisC.aClose.focus(); } aMonthDown.onmousedown = function(){ thisC.over++; thisC.onBTNMonthDown(iptYear.value,iptMonth.value); var fn = function(){ thisC.onBTNMonthDown(iptYear.value,iptMonth.value); } thisC.upDownTimer = setInterval(fn,thisC.cfg.upDownTimeout); thisC.aClose.focus(); } aMonthUp.onmousedown = function(){ thisC.over++; thisC.onBTNMonthUp(iptYear.value,iptMonth.value); var fn = function(){ thisC.onBTNMonthUp(iptYear.value,iptMonth.value); } thisC.upDownTimer = setInterval(fn,thisC.cfg.upDownTimeout); thisC.aClose.focus(); } var eventMouseUp = function(){clearInterval(thisC.upDownTimer); thisC.aClose.focus();} aYearDown.onmouseup = eventMouseUp; aYearUp.onmouseup =eventMouseUp; aMonthDown.onmouseup = eventMouseUp; aMonthUp.onmouseup = eventMouseUp; aYearDown.onmouseout = eventMouseUp; aYearUp.onmouseout =eventMouseUp; aMonthDown.onmouseout = eventMouseUp; aMonthUp.onmouseout = eventMouseUp; return taHead; } jsCalendar.prototype.createCalendarFoot = function(year,month){ //달력의 바닥글 //제거 수정 금지!, Don't Remove! AND Don't Modify //========== 메뉴 테이블 생성 var taFoot = document.createElement('table'); taFoot.border="0" ; taFoot.cellSpacing="0" ; taFoot.cellPadding="0"; taFoot.className='taFoot'; //=== tr var taFootTr0 = taFoot.insertRow(-1); taFootTr0.className='taFootTr0'; //===td var taFootTr0Td0 = taFootTr0.insertCell(0); taFootTr0Td0.className='taFootTr0Td0'; //=== 내용넣기 //=링크 /* var aLink = document.createElement('a'); aLink.className = "aLink"; aLink.href='http://domain.com'; aLink.target='_blank'; aLink.onclick=function(){alert("클릭시 알림글");} aLink.innerHTML = "사이트명"; aLink.title = "title"; taFootTr0Td0.appendChild(aLink); */ return taFoot; } jsCalendar.prototype.createCalendarBody = function(year,month){ //달력의 몸통글 var thisC = this; //==========기초 설정 var wDay = this.wDays[this.cfg.wDayType]; //요일형식 //========== 바디 테이블 생성 var taBody = document.createElement('table'); taBody.border="0" ; taBody.cellSpacing="0" ; taBody.cellPadding="0"; taBody.className='taBody'; //=== tr //=요일부분 var taBodyTrHead = taBody.insertRow(-1); taBodyTrHead.className='taBodyTrHead'; var wi = 0 ; var td = null; for(var i = 0;i<7;i++){ wi = (i + this.cfg.startWDay)%7; td = taBodyTrHead.insertCell(i); td.innerHTML = wDay[wi]; if(wi==0) td.className='tdSUN'; else if(wi==6) td.className='tdSAT'; } //=날짜부분 var dST = new Date(year,(month-1),1); var temp = dST.getTime(); var dED = new Date(year,month,1,0,0,-1); dST.setDate(dST.getDate()-1*(dST.getDay())%14+this.cfg.startWDay); //시작일로 설정 var dSTTSTMP = dST.getTime(); if(dSTTSTMP > temp){ dSTTSTMP -= 7*86400000; } var dEDTSTMP = dED.getTime(); var dTMP = new Date(); //임시 날짜 처리용 var dTMPSTR ='' ;//년-월-일 var taBodyTrDate = null; var t = new Date(); while(dSTTSTMP<=dEDTSTMP){ taBodyTrDate = taBody.insertRow(-1); taBodyTrDate.className='taBodyTrDate'; for(var i = 0; i < 7 ; i ++){ td = taBodyTrDate.insertCell(i); dTMP.setTime(dSTTSTMP); dTMPSTR = dTMP.date(this.cfg.dateFormat); wi = dTMP.getDay(); if((this.cfg.limitTSTMPST!= null && this.cfg.limitTSTMPST > dSTTSTMP) || (this.cfg.limitTSTMPED!= null && this.cfg.limitTSTMPED < dSTTSTMP)) { var aDate = document.createElement('span'); aDate.className = "aDate"; aDate.innerHTML = dTMP.getDate(); aDate.title=dTMPSTR; }else{ var aDate = document.createElement('a'); aDate.className = "aDate"; aDate.href='javascript:void(0);'; aDate.onclick=function(){thisC.onSelectDate(this.title);} aDate.innerHTML = dTMP.getDate(); aDate.title=dTMPSTR; } if((dTMP.getMonth()+1) != month){ if(wi==0) td.className='tdOrderDateSUN'; else if(wi==6) td.className='tdOrderDateSAT'; else td.className = 'tdOrderDate'; if(this.cfg.useOtherMonthDay) td.appendChild(aDate); else td.innerHTML = ' '; }else{ td.appendChild(aDate); if(this.targetElement.value && this.selectedValue == dTMPSTR){ td.className='tdSelectedDay'; }else if(this.todayValue == dTMPSTR){ td.className='tdToday'; }else { if(wi==0) td.className='tdSUN'; else if(wi==6) td.className='tdSAT'; else if((this.cfg.limitTSTMPST!= null && this.cfg.limitTSTMPST > dSTTSTMP) || (this.cfg.limitTSTMPED!= null && this.cfg.limitTSTMPED < dSTTSTMP)){ td.className = 'tdOrderDate'; } } } dSTTSTMP+=86400000; } } var t = new Date(dSTTSTMP); return taBody; } jsCalendar.prototype.setPeriod = function(dateST,dateED) //입력 제한기간 설정. { var d = new Date(); if(dateST != null){ if(d.str_setTime(dateST)!= -1) this.cfg.limitTSTMPST = d.getTime(); }else{ this.cfg.limitTSTMPST = null; } if(dateED != null){ if(d.str_setTime(dateED)!= -1) this.cfg.limitTSTMPED = d.getTime(); }else{ this.cfg.limitTSTMPED = null; } } jsCalendar.prototype.getBounds = function(obj) //대상의 위치 구하기 { var ret = new Object(); var bodyElement = document.documentElement.scrollLeft?document.documentElement:document.body; if(obj.getBoundingClientRect){ //IE8,FF3 용 var rect = obj.getBoundingClientRect(); ret.left = rect.left + bodyElement.scrollLeft; ret.top = rect.top + bodyElement.scrollTop; ret.width = rect.right - rect.left; ret.height = rect.bottom - rect.top; }else if(document.getBoxObjectFor){ //FF2 var box = document.getBoxObjectFor(obj); ret.left = box.x; ret.top = box.y; ret.width = box.width; ret.height = box.height; }else if(document.all && obj.getBoundingClientRect) { //IE var rect = obj.getBoundingClientRect(); ret.left = rect.left + bodyElement.scrollLeft; ret.top = rect.top + bodyElement.scrollTop; ret.width = rect.right - rect.left; ret.height = rect.bottom - rect.top; }else{ //OPERA,SAFARI 용(그외는 무시 var rect = new Object(); ret.left = obj.offsetLeft; ret.top = obj.offsetTop; var parent = obj.offsetParent; while(parent != bodyElement && parent){ ret.left += parent.offsetLeft; ret.top += parent.offsetTop; parent = parent.offsetParent; } // ret.top -= bodyElement.scrollTop; ret.width = obj.offsetWidth; ret.height = obj.offsetHeight; } return ret; }