/* * (c) 2005-2009 Richard Cowin (http://openrico.org) * (c) 2005-2009 Matt Brown (http://dowdybrown.com) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ // Inspired by code originally written by Tan Ling Wee on 2 Dec 2001 Rico.CalendarControl = function(id,options) { this.initialize(id,options); }; Rico.CalendarControl.prototype = { /** * @class Implements a pop-up Gregorian calendar. * Dates of adoption of the Gregorian calendar vary by country - accurate as a US & British calendar from 14 Sept 1752 to present. * Mark special dates with calls to addHoliday() * @extends Rico.Popup * @constructs * @param id unique identifier * @param options object may contain any of the following:
*
startAt
week starts with 0=sunday, 1=monday? default=0
*
showWeekNumber
show week number in first column? default=0
*
showToday
show "Today is..." in footer? default=1
*
dateFmt
date format for return value (one of values accepted by {@link Date#formatDate}), default=ISO8601
*
minDate
earliest selectable date? default=today-50 years
*
maxDate
last selectable date? default=today+50 years
*
*/ initialize: function(id,options) { this.id=id; var today=new Date(); Rico.extend(this, new Rico.Popup()); Rico.extend(this.options, { ignoreClicks:true, startAt : 0, showWeekNumber : 0, showToday : 1, dateFmt : 'ISO8601', minDate : new Date(today.getFullYear()-50,0,1), maxDate : new Date(today.getFullYear()+50,11,31) }); Rico.extend(this.options, options || {}); /** * alias for closePopup * @function */ this.close=this.closePopup; this.bPageLoaded=false; this.img=[]; this.Holidays={}; this.weekString=Rico.getPhraseById("calWeekHdg"); this.re=/^\s*(\w+)(\W)(\w+)(\W)(\w+)/i; this.setDateFmt(this.options.dateFmt); }, setDateFmt: function(fmt) { this.dateFmt=(fmt=='rico') ? Rico.dateFmt : fmt; Rico.log(this.id+' date format set to '+this.dateFmt); this.dateParts={}; if (this.re.exec(this.dateFmt)) { this.dateParts[RegExp.$1]=0; this.dateParts[RegExp.$3]=1; this.dateParts[RegExp.$5]=2; } }, /** * Call before displaying calendar to highlight special days * @param d day (1-31) * @param m month (1-12) * @param y year (0 implies a repeating holiday) * @param desc description * @param bgColor background color for cell displaying this day (CSS value, defaults to '#DDF') * @param txtColor text color for cell displaying this day (CSS value), if not specified it is displayed with the same color as other days */ addHoliday : function(d, m, y, desc, bgColor, txtColor) { this.Holidays[this.holidayKey(y,m-1,d)]={desc:desc, txtColor:txtColor, bgColor:bgColor || '#DDF'}; }, /** @private */ holidayKey : function(y,m,d) { return 'h'+Rico.zFill(y,4)+Rico.zFill(m,2)+Rico.zFill(d,2); }, atLoad : function() { Rico.log('Calendar#atLoad: '+this.id); var div=Rico.$(this.id); if (div) { this.setDiv(div); } else { this.createContainer(); this.container.id=this.id; } Rico.addClass(this.content, Rico.theme.calendar || 'ricoCalContainer'); this.content.style.display='block'; // override jquery ui this.maintab=document.createElement("table"); this.maintab.cellSpacing=2; this.maintab.cellPadding=0; this.maintab.border=0; this.maintab.style.borderCollapse='separate'; this.maintab.className='ricoCalTab'; if (Rico.theme.calendarTable) Rico.addClass(this.maintab,Rico.theme.calendarTable) this.tbody=Rico.getTBody(this.maintab); var r,c,i,j,img,dow,a,s,tab; this.colStart=this.options.showWeekNumber ? 1 : 0; for (i=0; i<7; i++) { r=this.tbody.insertRow(-1); r.className='row'+i; for (c=0; c<7+this.colStart; c++) { r.insertCell(-1); } } r=this.tbody.rows[0]; r.className='ricoCalDayNames'; if (this.options.showWeekNumber) { r.cells[0].innerHTML=this.weekString; for (i=0; i<7; i++) { this.tbody.rows[i].cells[0].className='ricoCalWeekNum'; } } this.styles=[]; for (i=0; i<7; i++) { dow=(i+this.options.startAt) % 7; r.cells[i+this.colStart].innerHTML=Rico.dayAbbr(dow); this.styles[i]='ricoCal'+dow; } // Navigation controls this.heading=this.content.appendChild(document.createElement("div")); this.heading.className='RicoCalHeading'; if (Rico.theme.calendarHeading) Rico.addClass(this.heading,Rico.theme.calendarHeading) var d2=this.heading.appendChild(document.createElement("div")); d2.className='RicoCalHeadingInner'; d2.appendChild(this._createTitleSection('Month')); d2.appendChild(this._createTitleSection('Year')); new Rico.HoverSet(this.heading.getElementsByTagName('a')); new Rico.HoverSet(this.tbody.getElementsByTagName('td'),{ hoverNodes: function(e) { return e.innerHTML.match(/^\d+$/) ? [e] : []; } }); if (this.position == 'absolute') this.heading.appendChild(Rico.closeButton(Rico.eventHandle(this,'close'))); // table footer (today) if (this.options.showToday) { this.tfoot=this.maintab.createTFoot(); r=this.tfoot.insertRow(-1); this.todayCell=r.insertCell(-1); this.todayCell.colSpan=7+this.colStart; if (Rico.theme.calendarFooter) Rico.addClass(this.todayCell,Rico.theme.calendarFooter); Rico.eventBind(this.todayCell,"click", Rico.eventHandle(this,'selectNow'), false); } this.content.appendChild(this.maintab); // month selector this.monthPopup=new Rico.Popup(document.createElement("div")); this.monthPopup.closePopup(); tab=document.createElement("table"); tab.className='ricoCalMenu'; if (Rico.theme.calendarPopdown) Rico.addClass(tab,Rico.theme.calendarPopdown); tab.cellPadding=2; tab.cellSpacing=0; tab.border=0; tab.style.borderCollapse='separate'; tab.style.margin='0px'; for (i=0; i<4; i++) { r=tab.insertRow(-1); for (j=0; j<3; j++) { c=r.insertCell(-1); a=document.createElement("a"); a.innerHTML=Rico.monthAbbr(i*3+j); a.name=i*3+j; if (Rico.theme.calendarDay) Rico.addClass(a,Rico.theme.calendarDay); c.appendChild(a); Rico.eventBind(a,"click", Rico.eventHandle(this,'selectMonth'), false); } } new Rico.HoverSet(tab.getElementsByTagName('a')); this.monthPopup.content.appendChild(tab); this.container.appendChild(this.monthPopup.container); // year selector this.yearPopup=new Rico.Popup(document.createElement("div")); this.yearPopup.closePopup(); this.yearPopup.content.className='ricoCalYearPrompt'; if (Rico.theme.calendarPopdown) Rico.addClass(this.yearPopup.content,Rico.theme.calendarPopdown); var tab=document.createElement("table"); tab.cellPadding=2; tab.cellSpacing=0; tab.border=0; tab.style.borderCollapse='separate'; tab.style.margin='0px'; r=tab.insertRow(-1); this.yearLabel=r.insertCell(-1); this.yearLabel.colSpan=3; this.yearLabel.innerHTML=Rico.getPhraseById("calYearRange",this.options.minDate.getFullYear(),this.options.maxDate.getFullYear()); r=tab.insertRow(-1); c=r.insertCell(-1); this.yearInput=c.appendChild(document.createElement("input")); this.yearInput.maxlength=4; this.yearInput.size=4; Rico.eventBind(this.yearInput,"keyup", Rico.eventHandle(this,'yearKey'), false); c=r.insertCell(-1); var a=Rico.floatButton('Checkmark', Rico.eventHandle(this,'processPopUpYear')); Rico.setStyle(a.firstChild,{ margin:"0px", padding:"0px", border:"none" }); c.appendChild(a); c=r.insertCell(-1); a=Rico.floatButton('Cancel', Rico.eventHandle(this,'popDownYear')); Rico.setStyle(a.firstChild,{ margin:"0px", padding:"0px", border:"none" }); c.appendChild(a); this.yearPopup.content.appendChild(tab); this.container.appendChild(this.yearPopup.container); this.yearPopup.container.style.left=''; this.yearPopup.container.style.right='5px'; this.yearPopup.container.style.zIndex=10; // fix anchors so they work in IE6 a=this.content.getElementsByTagName('a'); for (i=0; i this.options.maxDate.getFullYear()) return false; if (yr == this.options.maxDate.getFullYear() && mo > this.options.maxDate.getMonth()) return false; return true; }, incMonth : function() { var newMonth=this.monthSelected+1; var newYear=this.yearSelected; if (newMonth>11) { newMonth=0; newYear++; } if (!this.isValidMonth(newYear,newMonth)) return; this.monthSelected=newMonth; this.yearSelected=newYear; this.constructCalendar(); }, decMonth : function() { var newMonth=this.monthSelected-1; var newYear=this.yearSelected; if (newMonth<0) { newMonth=11; newYear--; } if (!this.isValidMonth(newYear,newMonth)) return; this.monthSelected=newMonth; this.yearSelected=newYear; this.constructCalendar(); }, /** @private */ selectMonth : function(e) { var el=Rico.eventElement(e); this.monthSelected=parseInt(el.name,10); this.constructCalendar(); Rico.eventStop(e); }, popUpMonth : function(e) { Rico.eventStop(e); if (this.monthPopup.visible()) { this.popDownMonth(); return; } this.popDownYear(); if (Rico.isIE && Rico.ieVersion < 7) { // fix position absolute inside container without hasLayout this.monthPopup.openPopup(null, this.heading.offsetHeight+2); this.monthPopup.container.style.left=''; } else { this.monthPopup.openPopup(3, this.heading.offsetHeight+2); } return false; }, popDownMonth : function() { this.monthPopup.closePopup(); }, popDownYear : function() { this.yearPopup.closePopup(); this.yearInput.disabled=true; // make sure this does not get submitted }, /** * Prompt for year */ popUpYear : function(e) { Rico.eventStop(e); if (this.yearPopup.visible()) { this.popDownYear(); return; } this.popDownMonth(); this.yearPopup.openPopup(null, this.heading.offsetHeight+2); this.yearInput.disabled=false; this.yearInput.value=''; // this.yearSelected this.yearInput.focus(); return false; }, yearKey : function(e) { switch (Rico.eventKey(e)) { case 27: this.popDownYear(); Rico.eventStop(e); return false; case 13: this.processPopUpYear(); Rico.eventStop(e); return false; } return true; }, processPopUpYear : function() { var newYear=this.yearInput.value; newYear=parseInt(newYear,10); if (isNaN(newYear) || newYearthis.options.maxDate.getFullYear()) { alert(Rico.getPhraseById("calInvalidYear")); } else { this.yearSelected=newYear; this.popDownYear(); this.constructCalendar(); } }, incYear : function() { if (this.yearSelected>=this.options.maxDate.getFullYear()) return; this.yearSelected++; this.constructCalendar(); }, decYear : function() { if (this.yearSelected<=this.options.minDate.getFullYear()) return; this.yearSelected--; this.constructCalendar(); }, // tried a number of different week number functions posted on the net // this is the only one that produced consistent results when comparing week numbers for December and the following January WeekNbr : function(year,month,day) { var when = new Date(year,month,day); var newYear = new Date(year,0,1); var offset = 7 + 1 - newYear.getDay(); if (offset == 8) offset = 1; var daynum = ((Date.UTC(year,when.getMonth(),when.getDate(),0,0,0) - Date.UTC(year,0,1,0,0,0)) /1000/60/60/24) + 1; var weeknum = Math.floor((daynum-offset+7)/7); if (weeknum == 0) { year--; var prevNewYear = new Date(year,0,1); var prevOffset = 7 + 1 - prevNewYear.getDay(); weeknum = (prevOffset == 2 || prevOffset == 8) ? 53 : 52; } return weeknum; }, constructCalendar : function() { var aNumDays = [31,0,31,30,31,30,31,31,30,31,30,31]; var startDate = new Date (this.yearSelected,this.monthSelected,1); var endDate,numDaysInMonth,i,colnum; if (typeof this.monthSelected!='number' || this.monthSelected>=12 || this.monthSelected<0) { alert('ERROR in calendar: monthSelected='+this.monthSelected); return; } if (this.monthSelected==1) { endDate = new Date (this.yearSelected,this.monthSelected+1,1); endDate = new Date (endDate - (24*60*60*1000)); numDaysInMonth = endDate.getDate(); } else { numDaysInMonth = aNumDays[this.monthSelected]; } var dayPointer = startDate.getDay() - this.options.startAt; if (dayPointer<0) dayPointer+=7; this.popDownMonth(); this.popDownYear(); //this.bgcolor=Rico.getStyle(this.tbody,'background-color'); //this.bgcolor=this.bgcolor.replace(/\"/g,''); if (this.options.showWeekNumber) { for (i=1; i<7; i++) { this.tbody.rows[i].cells[0].innerHTML=' '; } } for ( i=0; i maxyr) this.oyearSelected-=100; } } else { if (curval) { alert('ERROR: invalid date passed to calendar ('+curval+')'); } } if (this.oyearSelected > 0) { this.dateSelected=this.odateSelected; this.monthSelected=this.omonthSelected; this.yearSelected=this.oyearSelected; } else { this.dateSelected=this.dateNow; this.monthSelected=this.monthNow; this.yearSelected=this.yearNow; } this.constructCalendar(); this.openPopup(); } };