Another JS Date Picker

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
User avatar
Burrito
Spockulator
Posts: 4715
Joined: Wed Feb 04, 2004 8:15 pm
Location: Eden, Utah

Another JS Date Picker

Post by Burrito »

I hadn't written any JS in eons so last week I decided to whip up a JS calendar / date picker. It took a bit to brush off the JS rust but I got something that worked well and was kinda cool. The original version used a LOT of innerHTML to 'paint' the calendar on the screen. I had Tester Extraordinaire helping me test it and he suggested building the whole thing with the DOM instead of using innerHTML and also suggested that I pull the styles out of the JS and put them into CSS...well thanks to pickle for his wisdom, I decided to tackle both of those feats toward the end of last week and into this one. I also decided to rewrite the whole thing using JSON so I could learning something in the process. I know there are a million and four JS calendar / date pickers out there and this one isn't much different but here it is for your date picking enjoyment.

http://www.burritostand.com/jsonCal.htm

This link has a language selector and a format text field that would not be used in the real deal...the real deal would need to have both of those items statically inserted into the JS file or HTML page in <script> tags (above the call to the JS file)...but the sample above is for demonstration purposes only.

if anyone wants to help me out by adding additional language support, that'd make me happy :D

I have only tested this with IE and firefox so don't count on it working in any other browsers.

I'm also going to re-add the ability to change the styles within JS constants but that will be version 2.

Lastly, I'm going to change the CSS class names to be something more obscure so they don't conflict with any other classes you might have defined, but frankly, I'm too lazy to do that right this moment.

Usage: look at the HTML file sample below. You need to set the id of whatever element it is that you're calling the calendar with to 'cal-%textfield%' where %textfield% is the id of the text field the date should be inserted into. Example: If my textfield has an id of 'birthday' I would need to set the id of the calling element to 'cal-birthday'. See below for a real example:

Code: Select all

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
	<title>Calendar Sample</title>
<script>
calendarLanguage = "spanish";
calendarDateFormat = "%mmmm% %dd%, %yyyy%";
</script>
<script src="cal.js"></script>
<link rel="stylesheet" href="cal.css">
</head>

<body>
<input type="text" name="begindate" id="begindate" size="40">
<img src="calendar.gif" onClick="loadCal(this)" id="cal-begindate"><br>


</body>
</html>

Code: Select all

.dateSelects {
	background-color:#a09e94;
	font-size:10px;
	font-family:tahoma;
	border:1px #000000 solid;
	font-weight:normal;
}
.calTable {
	width:225px;
	border-top:1px #000000 solid;
	border-left:1px #000000 solid;
	margin:0px;
	padding:0px;
	border-spacing:0px;
	border-collapse:collapse;
}

.calTd {
	width:14%;	
	background-color:#eae6dd;	
	height:16px;
	cursor:hand;
	cursor:pointer;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}


.outMonthCalTd {
	width:14%;
	background-color:#eae6dd;
	color:#abaaa6;
	height:16px;
	cursor:hand;
	cursor:pointer;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.weekendCalTd {
	background-color:#bfbdb2;
	width:14%;
	height:16px;
	cursor:hand;
	cursor:pointer;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.weekendOutMonthCalTd {
	background-color:#bfbdb2;
	color:#abaaa6;
	width:14%;
	height:16px;
	cursor:hand;
	cursor:pointer;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}
.headCellTd {
	background-color:#958f6d;
	height:16px;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.headLeftTd {
	border-right:0px;
	background-color:#958f6d;
	height:16px;
	text-align: center;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.headMainTd {
	border-right:0px;
	border-left:0px;
	background-color:#958f6d;
	height:16px;
	text-align: center;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.headCenterTd {
	border-right:0px;
	border-left:0px;
	font-weight:bold;
	background-color:#958f6d;
	height:16px;
	text-align: center;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.headRightTd {
	border-left:0px;
	background-color:#958f6d;
	height:16px;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.topHeadCellTd {
	text-align:right;
	border-bottom:0px;
	font-weight:bold;
	background-color:#958f6d;
	height:16px;
	border-right:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.selectHeadTd {
	text-align:left;
	border:0px;
	font-weight:bold;
	background-color:#958f6d;
	height:16px;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.mouseOverTd {
	background-color:#7e7c6e;
}
.daysOfWeekTd {
	background-color:#efead2;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}
.currentDay {
	background-color:#b5e8c8;
	cursor:hand;
	cursor:pointer;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

.selectedDay {
	background-color:#87c7df;
	cursor:hand;
	cursor:pointer;
	text-align: center;
	border-right:1px #000000 solid;
	border-bottom:1px #000000 solid;
	margin:0px;
	padding:0px;
	font-family:tahoma;
	font-size:9px;
}

Code: Select all

// JSON Calendar By Burrito 04/02/2007 - Released under GPL License 
// feel free to use and distribute this as much as you
// want.  All I ask is that you maintain this comment
// block to give me credit for enjoying cheesecake. 
// mmmmmm....cheesecake



// create the div to house the calendar
document.write("<div id=\"____myCalendar\" style=\"display:none;position:absolute;top:0px;left:0px;filter:alpha(opacity=30);-moz-opacity:0.3;\"></div>");

//loadCal function is called from an element on the page to load the calendar
function loadCal()
{
	if(document.getElementById('____calendar'))
	{
		calTable = document.getElementById('____calendar');
		calTable.parentNode.removeChild(calTable);
	}

	calendar.calCaller = arguments[0]; 
	todaysDate = new Date();
	calendar.month = (arguments[1] != null ? arguments[1] : todaysDate.getMonth());
	calendar.year = (arguments[2] != null ? arguments[2] : todaysDate.getFullYear());
	calendar.init();
	calendar.dateFormat = calendarDateFormat;	
	calendar.language = calendarLanguage;
	
	calendar.set();
	calendar.displayCalendar();
}

//objDisplayMonth object creates the date object to be used for the month/year being displayed also creates todays date information
var objDisplayMonth = {
	// initialize the members
	date : Object,
	element : Object,
	currentDate : null,
	currentMonth : null,
	currentYear : null,
	// init to create the date object for the month / year displayed
	init : function() {
	        this.date = new Date();
			this.currentDate = this.date.getDate();
			this.currentMonth = this.date.getMonth();
			this.currentYear = this.date.getFullYear();
	},
	// setDisplayMonth method sets month and year passed to it
	setDisplayMonth : function() {
		// set date to first day of month so when changing months, the calendar doesn't get screwed up if on a day over the previous months end date and to get padding for first of month
		this.date.setDate(1);
		this.date.setMonth(arguments[0]);
		this.date.setFullYear(arguments[1]);
		return this.getDisplayMonth()   
	},
	// getDisplayMonth method returns the date
	getDisplayMonth : function() {
	        return this.date;
	}
};

// dateInfo object used to format the date properly and to show months and days of week on the calendar
// TODO: add other language support
var dateInfo = {
	english : {
		monthLongNames : ["January","February","March","April","May","June","July","August","September","October","November","December"],
		monthShortNames : ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
		daysShortNames : ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],
		daysLongNames : ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
	},
	spanish : {
		monthLongNames : ["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"],
		monthShortNames : ["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic"],
		daysShortNames : ["Dom","Lun","Mar","Mié","Jue","Vie","Sáb"],
		daysLongNames : ["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"]
	},
	french : {
		monthLongNames : ["Janvier","Février","Mars","Avril","Mai","Juin","Julliet","Août","Septembre","Octobre","Novembre","Décembre"],
		monthShortNames : ["Jan","Fév","Mar","Avr","Mai","Jui","Jul","Aoû","Sep","Oct","Nov","Déc"],
		daysShortNames : ["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"],
		daysLongNames : ["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"]
	},
	monthLeadZero : ["01","02","03","04","05","06","07","08","09","10","11","12"]
};

// calendar object used for the set up of the calendar, to place the calendar on the page, and to add the date to the text field.
var calendar = {
	// initialize the members
	month : null,
	selectYearRange : "1990-2020",
	year : null,
	dateFormat : "",
	fadeIn : true,
	language : "",
	calCaller : Object,
	callerField : Object,
	objMonthYear : Object,
	selectedDate : null,
	selectedDay : null,
	selectedMonth : null,
	selectedYear : null,
	calendarDisplayed : false,
	daysInCurrentMonth : null,
	isIE : false,
	init : function() {
		this.callerField = document.getElementById(this.calCaller.id.substring(4,this.calCaller.id.length));
		if(!this.calendarDisplayed && this.callerField.value != "")
			this.preSelectDate();
		this.objMonthYear = objDisplayMonth;
		this.objMonthYear.init();	
		this.isIE = (navigator.appVersion.toLowerCase().indexOf("msie") > -1 ? true : false);
		if(this.isIE)
			this.showHideSelects(true);
		this.getPlacement();
	},
	// showHideSelects method toggles the visibility property of selects for Internet Explorer
	showHideSelects : function() {
		selArr = document.getElementsByTagName("select");
		for(i=0;i<selArr.length;i++)
		{
			if(selArr[i].id != "____monthSelect" && selArr[i].id != "____yearSelect")
				selArr[i].style.visibility = (arguments[0] ? 'hidden' : 'visible');
		}
	},
	// preSelectDate method selects the date (if possible) that is in the text box on the calendar
	preSelectDate : function() {
		this.selectedDate =  new Date(this.callerField.value);
		if(this.selectedDate.getDate())
		{
			this.selectedDay = this.selectedDate.getDate();
			this.selectedMonth = this.selectedDate.getMonth();
			this.selectedYear = this.selectedDate.getFullYear();
			this.month = this.selectedDate.getMonth();
			this.year = this.selectedDate.getFullYear();
			//alert(this.month+" "+this.year);
		}
		else
			this.selectedDate = null;
	},
	set : function() {
		this.objMonthYear.setDisplayMonth(this.month,this.year);
		// daysInCurrentMonth property is the number of days in the current month
		this.daysInCurrentMonth = this.getDaysInMonth(this.objMonthYear.getDisplayMonth().getMonth(),this.objMonthYear.getDisplayMonth().getFullYear());
	},
	// close method closes the calendar when the 'X' is clicked
	close : function() {
		calendar.calendarDisplayed = false;
		document.getElementById('____myCalendar').style.display = "none";
		calendar.showHideSelects(false);
	},
	//getPlacement method determines where to display the div for the calendar then displays it
	getPlacement : function () {
		theCalDiv = document.getElementById('____myCalendar').style;
		calCallerObjLeft = this.calCaller;
		calCallerObjTop = this.calCaller;
		var left = 0;
		//alert(this.calCaller.id);
		while (calCallerObjLeft)
		{
			left += calCallerObjLeft.offsetLeft;
			calCallerObjLeft = calCallerObjLeft.offsetParent;
		}
		var top = 0;
		while (calCallerObjTop)
		{
			top += calCallerObjTop.offsetTop;
			calCallerObjTop = calCallerObjTop.offsetParent;
		}
		//alert(this.calCaller.id);
		//alert(top);
		theCalDiv.left = left+"px";
		theCalDiv.top = top+"px";
		if(this.fadeIn && !this.calendarDisplayed)
		{
			this.calendarDisplayed = true;
			cDiv = document.getElementById('____myCalendar');
			if(cDiv.filters)
				cDiv.filters.alpha.opacity = 30;
			else
				cDiv.style.MozOpacity = 0.3;			
			this.fadeCalendarIn();			
		}
		else
		{
			this.calendarDisplayed = true;
			cDiv = document.getElementById('____myCalendar');
			if(cDiv.filters)
				cDiv.filters.alpha.opacity = 100;
			else
				cDiv.style.MozOpacity = 1.0;			
			this.fadeCalendarIn();	
			theCalDiv.display = "block";
		}
	},
	// fadeCalendarIn method fades the calendar to 100% opacity
	fadeCalendarIn : function() {
		cDiv = document.getElementById('____myCalendar');
		cDiv.style.display = "block";
		if(cDiv.filters && cDiv.filters.alpha.opacity < 100)
		{
			cDiv.filters.alpha.opacity += 10;
			setTimeout("calendar.fadeCalendarIn()",50);
		}
		
		if(cDiv.style.MozOpacity && cDiv.style.MozOpacity < 1.0)
		{
			cDiv.style.MozOpacity = parseFloat(cDiv.style.MozOpacity) + 0.1;
			setTimeout("calendar.fadeCalendarIn()",50);
		}
	},
	// getDaysInMonth method returns the number of days for the month based on set month and year
	getDaysInMonth : function() {
		// create two arrays for number of days in months (leap year and not)
		// Non-Leap year Month days..
		noLeapMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		// Leap year Month days..
		leapMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		// check for leap years and use appropriate array
		if ((arguments[1] % 4) == 0)
		{
			if ((arguments[1] % 100) == 0 && (arguments[1] % 400) != 0)
			        return noLeapMonth[arguments[0]];       
			return leapMonth[arguments[0]];
		}
		else
			return noLeapMonth[arguments[0]];
	},
	//addDate method adds the date to the form field after being formatted by the dateInfo object
	addDate : function(event) {

		theDiv = document.getElementById('____myCalendar').style;
		event = event || window.event;
		var target = event.srcElement || event.target;
		dateArr = target.id.split("-");
		returnDate = new Date(dateArr[0],dateArr[1],dateArr[2]);
		retDate = calendar.dateFormat.toLowerCase();
		retDate = retDate.replace(/%mmmm%/g,dateInfo[calendar.language].monthLongNames[dateArr[1]]);
		retDate = retDate.replace(/%mmm%/g,dateInfo[calendar.language].monthShortNames[dateArr[1]]);
		retDate = retDate.replace(/%mm%/g,dateInfo.monthLeadZero[dateArr[1]]);
		retDate = retDate.replace(/%m%/g,(parseFloat(dateArr[1])+1));
		retDate = retDate.replace(/%dddd%/g,dateInfo[calendar.language].daysLongNames[returnDate.getDay()]);
		retDate = retDate.replace(/%ddd%/g,dateInfo[calendar.language].daysShortNames[returnDate.getDay()]);
		retDate = retDate.replace(/%dd%/g,(dateArr[2].length == 1 ? "0"+dateArr[2] : dateArr[2]));
		retDate = retDate.replace(/%d%/g,dateArr[2]);
		retDate = retDate.replace(/%yyyy%/g,dateArr[0]);
		retDate = retDate.replace(/%yy%/g,dateArr[0].substring(2));
		calendar.callerField.value = retDate;
		calendar.calendarDisplayed = false;
		theDiv.display = "none";
		calendar.showHideSelects(false);
		
	},
	// getFirstOfMonthPad returns the number of days at the beginning of the month that need to be padded from the previous month
	getFirstOfMonthPad : function() {
		currentMonthYear = this.objMonthYear.getDisplayMonth();
		return currentMonthYear.getDay();
	},
	displayCalendar : function() {
		currentMonthYear = this.objMonthYear.getDisplayMonth();
		theDiv = document.getElementById('____myCalendar');
		theDiv.appendChild(calendarBuilder.build(this.getFirstOfMonthPad(), this.getDaysInMonth((currentMonthYear.getMonth() == 0 ? 11 : (currentMonthYear.getMonth()-1)), currentMonthYear.getFullYear())));              
	}
};

// calendarBuilder object builds the actual calendar using the DOM
var calendarBuilder = {
	table : Object,
	monthEndDay : 0,
	monthDays : 1,
	week : Object,
	// init method initializes all of the properties and objects for each load of the calendar
	init : function() {
	        this.table = document.createElement('table');
			this.monthDays = 1;
			this.week = null;
	},
	// addFirstWeek method builds the first week by padding the first few days with the previous month's end then starts the new month out to finish the week.
	addFirstWeek : function() {
		var firstWeek = this.table.insertRow(3);
		var paddedPrevious = ((arguments[1]+1) - arguments[0]);
		for(var i=0;i<arguments[0];i++)
		{
			daysInFirstWeek = firstWeek.insertCell(i);
			daysInFirstWeek.className = (i==0 ? "weekendOutMonthCalTd" : "outMonthCalTd");
			daysTextNode = document.createTextNode(paddedPrevious);
			daysInFirstWeek.appendChild(daysTextNode);
			daysInFirstWeek.onmouseover = this.changeBackground;
			daysInFirstWeek.onmouseout = this.changeBackgroundBack;
			daysInFirstWeek.id = (objDisplayMonth.getDisplayMonth().getMonth() == 0 ? (objDisplayMonth.getDisplayMonth().getFullYear()-1) : objDisplayMonth.getDisplayMonth().getFullYear())+"-"+(objDisplayMonth.getDisplayMonth().getMonth() == 0 ? 11 : (objDisplayMonth.getDisplayMonth().getMonth()-1))+"-"+paddedPrevious;
			daysInFirstWeek.onclick = calendar.addDate;
			paddedPrevious++;
		}
		for(j=arguments[0];j<7;j++)
		{
			daysInFirstWeek = firstWeek.insertCell(j);
			//alert(objDisplayMonth.currentDate+" "+this.monthDays);
			if(objDisplayMonth.currentDate == this.monthDays && objDisplayMonth.currentMonth == objDisplayMonth.getDisplayMonth().getMonth() && objDisplayMonth.currentYear == objDisplayMonth.getDisplayMonth().getFullYear())
				daysInFirstWeek.className = "currentDay";
			else if(calendar.selectedDate != null && (this.monthDays == calendar.selectedDay && objDisplayMonth.getDisplayMonth().getMonth() == calendar.selectedMonth && objDisplayMonth.getDisplayMonth().getFullYear() == calendar.selectedYear))
				daysInFirstWeek.className = "selectedDay";	
			else
				daysInFirstWeek.className = (j==6 || j==0 ? "weekendCalTd" : "calTd");
			daysTextNode = document.createTextNode(this.monthDays);
			daysInFirstWeek.appendChild(daysTextNode);
			daysInFirstWeek.onmouseover = this.changeBackground;
			daysInFirstWeek.onmouseout = this.changeBackgroundBack;
			daysInFirstWeek.id = objDisplayMonth.getDisplayMonth().getFullYear()+"-"+objDisplayMonth.getDisplayMonth().getMonth()+"-"+this.monthDays;
			daysInFirstWeek.onclick = calendar.addDate;
			this.monthDays++;
		}
	},
	//addAdditionalWeeks method builds the rest of the weeks for the given month
	addAdditionalWeeks : function() {
		var endOfMonth = false;
		for(var j=2;j<7;j++)
		{
			// break out of outer loop if end of month is reached
			if(endOfMonth)
				break;
			// we need to add 2 to the index to take into account the rows that have been added above
			this.week = this.table.insertRow(j+2);
			// create embedded loop to build the cells for each day
			for(var k=0;k<7;k++)
			{
				if(this.monthDays <= calendar.daysInCurrentMonth)
				{
					daysInWeek = this.week.insertCell(k);
					if(objDisplayMonth.currentDate == this.monthDays && objDisplayMonth.currentMonth == objDisplayMonth.getDisplayMonth().getMonth() && objDisplayMonth.currentYear == objDisplayMonth.getDisplayMonth().getFullYear())
						daysInWeek.className = "currentDay";
					else if(calendar.selectedDate != null && (this.monthDays == calendar.selectedDay && objDisplayMonth.getDisplayMonth().getMonth() == calendar.selectedMonth && objDisplayMonth.getDisplayMonth().getFullYear() == calendar.selectedYear))
						daysInWeek.className = "selectedDay";		
					else
						daysInWeek.className = (k==0 || k== 6 ? "weekendCalTd" : "calTd");
					daysTextNode = document.createTextNode(this.monthDays);
					daysInWeek.appendChild(daysTextNode);
					daysInWeek.onmouseover = this.changeBackground;
					daysInWeek.onmouseout = this.changeBackgroundBack;
					daysInWeek.id = objDisplayMonth.getDisplayMonth().getFullYear()+"-"+objDisplayMonth.getDisplayMonth().getMonth()+"-"+this.monthDays;
					daysInWeek.onclick = calendar.addDate;
					this.monthDays++;
					// break out of inner loop and set endOfMonth boolean if days of month is met
				}
				else
				{
					endOfMonth = true;
					break;
				}
			}
		}
		//set monthEndDay property to determine if addLastWeek method needs to be called for next month
		this.monthEndDay = k;
	},
	// addLastWeek method creates the start of the next month on the last week of the calendar
	addLastWeek : function() {
		var numberOfNextDays = (6 - this.monthEndDay);
		//alert(numberOfNextDays);
		//alert(this.monthEndDay);
		var startNextMonth =  1;
		for(var m=this.monthEndDay; m<(numberOfNextDays+this.monthEndDay+1); m++)
		{
			//alert(m);
			lastDaysInWeek = this.week.insertCell(m);
			lastDaysInWeek.className = (m==(numberOfNextDays+this.monthEndDay) ? "weekendOutMonthCalTd" :"outMonthCalTd");
			daysTextNode = document.createTextNode(startNextMonth);
			lastDaysInWeek.appendChild(daysTextNode);
			lastDaysInWeek.onmouseover = this.changeBackground;
			lastDaysInWeek.onmouseout = this.changeBackgroundBack;
			lastDaysInWeek.id = (objDisplayMonth.getDisplayMonth().getMonth() == 11 ? (objDisplayMonth.getDisplayMonth().getFullYear()+1) : objDisplayMonth.getDisplayMonth().getFullYear())+"-"+(objDisplayMonth.getDisplayMonth().getMonth() == 11 ? 0 : (objDisplayMonth.getDisplayMonth().getMonth()+1))+"-"+startNextMonth;
			lastDaysInWeek.onclick = calendar.addDate;
			startNextMonth++;
		}
	},
	// changeBackground method changes the background color for onmouseover events of table cells.
	changeBackground : function(event) {
		event = event || window.event;
		var target = event.srcElement || event.target;
		target.className += " mouseOverTd";
	},
	// changeBackground method changes the background color for onmouseover events of table cells.
	changeBackgroundBack : function(event) {
		event = event || window.event;
		var target = event.srcElement || event.target;
		target.className = target.className.replace("mouseOverTd","");
	},
	// shiftDate method changes the calendar month/year from the spans that list them when clicked
	shiftDate : function(event) {
		event = event || window.event;
		var target = event.srcElement || event.target;
		monthYear = target.id.split(",");
		loadCal(calendar.calCaller,monthYear[0],monthYear[1]);
	},
	// changeByMonthYear method changes the calendar based on the options selected in the month or year select boxes
	changeByMonthYear : function () {
		theMonth = document.getElementById("____monthSelect").value;
		theYear = document.getElementById("____yearSelect").value;
		calTable = document.getElementById('____calendar');
		calTable.parentNode.removeChild(calTable);
		calendar.init();
		calendar.month = theMonth;
		calendar.year = theYear;
		calendar.set();
		calendar.displayCalendar();
	},
	// buildMOnthSelect method creates the select element for the months to be selected in the calendar header
	buildMonthSelect : function() {
		monthSelect = document.createElement("SELECT");
		monthSelect.id = "____monthSelect";
		monthSelect.name = "____monthSelect";
		monthSelect.onchange = this.changeByMonthYear;
		monthSelect.className = "dateSelects";
		for(i=0;i<12;i++)
		{
			monthOption = document.createElement("OPTION");
			monthOption.value = i;
			monthOption.text = dateInfo[calendar.language].monthLongNames[i];
			monthSelect.options.add(monthOption,i);
			if(i == objDisplayMonth.getDisplayMonth().getMonth())
				monthOption.selected = true;
		}
		return monthSelect;
	},
	// buildYearSelect method creates the select element for the years to be selected in the calendar header
	buildYearSelect : function() {
		var yearRange = calendar.selectYearRange.split("-");
		var yearStart = parseInt(yearRange[0]);
		var yearEnd = parseInt(yearRange[1]);
		yearSelect = document.createElement("SELECT");
		yearSelect.id = "____yearSelect";
		yearSelect.name = "____yearSelect";
		yearSelect.onchange = this.changeByMonthYear;
		yearSelect.className = "dateSelects";
		for(i=yearStart;i<yearEnd+1;i++)
		{
			yearOption = document.createElement("OPTION");
			yearOption.value = i;
			yearOption.text = i;
			yearSelect.options.add(yearOption,i);
			if(i == objDisplayMonth.getDisplayMonth().getFullYear())
				yearOption.selected = true;
		}
		return yearSelect;
	},
	// addHeader method adds the calendar header with Month and Year
	addHeader : function() {
		// first row with selects
		var headRow = this.table.insertRow(0);
		var headCell = headRow.insertCell(0);
		headCell.colSpan = 6;
		headCell.className = "selectHeadTd";
		headCell.appendChild(this.buildMonthSelect());
		headCell.appendChild(this.buildYearSelect());
		// add cell to close the calendar
		headCell = headRow.insertCell(1);
		// create the span that will actually close the calendar
		headCellCloseSpan = document.createElement("span");
		headCellCloseSpanText = document.createTextNode("X \u00a0");
		headCellCloseSpan.appendChild(headCellCloseSpanText);
		headCellCloseSpan.style.cursor = "hand";
		headCellCloseSpan.style.cursor = "pointer";
		headCellCloseSpan.onclick = calendar.close;
		headCell.appendChild(headCellCloseSpan);
		headCell.className = "topHeadCellTd";
		
		// second row with month year and date selectors
		headRow = this.table.insertRow(1);
		// add first cell with year selector
		headCell = headRow.insertCell(0);
		headCellSpan = document.createElement("span");
		headCellSpanText = document.createTextNode("\u00ab"+(objDisplayMonth.getDisplayMonth().getFullYear()-1));
		headCellSpan.appendChild(headCellSpanText);
		headCellSpan.style.cursor = "hand";
		headCellSpan.style.cursor = "pointer";
		headCellSpan.id = objDisplayMonth.getDisplayMonth().getMonth()+","+(objDisplayMonth.getDisplayMonth().getFullYear()-1);
		headCellSpan.onclick = this.shiftDate;
		headCell.appendChild(headCellSpan);
		headCell.className = "headLeftTd";

		// add second cell with month selector
		headCell = headRow.insertCell(1);
		headCellSpan = document.createElement("span");
		headCellSpanText = document.createTextNode("\u00ab"+dateInfo[calendar.language].monthShortNames[(objDisplayMonth.getDisplayMonth().getMonth() != 0 ? (objDisplayMonth.getDisplayMonth().getMonth()-1) : 11)]);
		headCellSpan.appendChild(headCellSpanText);
		headCellSpan.style.cursor = "hand";
		headCellSpan.style.cursor = "pointer";
		headCellSpan.id = (objDisplayMonth.getDisplayMonth().getMonth() != 0 ? (objDisplayMonth.getDisplayMonth().getMonth()-1) : 11)+","+(objDisplayMonth.getDisplayMonth().getMonth() != 0 ? objDisplayMonth.getDisplayMonth().getFullYear() : (objDisplayMonth.getDisplayMonth().getFullYear()-1));
		headCellSpan.onclick = this.shiftDate;
		headCell.appendChild(headCellSpan);
		headCell.className = "headMainTd";

		// add third cell with month and year text
		headCell = headRow.insertCell(2);
		headCell.colSpan = 3;
		headCell.className = "headCenterTd";
		headCellText = document.createTextNode(dateInfo[calendar.language].monthLongNames[objDisplayMonth.getDisplayMonth().getMonth()]+" - "+objDisplayMonth.getDisplayMonth().getFullYear());
		headCell.appendChild(headCellText);

		// add fourth cell with month selector
		headCell = headRow.insertCell(3);
		headCellSpan = document.createElement("span");
		headCellSpanText = document.createTextNode(dateInfo[calendar.language].monthShortNames[(objDisplayMonth.getDisplayMonth().getMonth() != 11 ? (objDisplayMonth.getDisplayMonth().getMonth()+1) : 0)]+"\u00bb");
		headCellSpan.appendChild(headCellSpanText);
		headCellSpan.style.cursor = "hand";
		headCellSpan.style.cursor = "pointer";
		headCellSpan.id = (objDisplayMonth.getDisplayMonth().getMonth() != 11 ? (objDisplayMonth.getDisplayMonth().getMonth()+1) : 0)+","+(objDisplayMonth.getDisplayMonth().getMonth() != 11 ? objDisplayMonth.getDisplayMonth().getFullYear() : (objDisplayMonth.getDisplayMonth().getFullYear()+1));
		headCellSpan.onclick = this.shiftDate;
		headCell.appendChild(headCellSpan);
		headCell.className = "headMainTd";
		
		// add fifth cell with year selector
		headCell = headRow.insertCell(4);
		headCellSpan = document.createElement("span");
		headCellSpanText = document.createTextNode((objDisplayMonth.getDisplayMonth().getFullYear()+1)+"\u00bb");
		headCellSpan.appendChild(headCellSpanText);
		headCellSpan.style.cursor = "hand";
		headCellSpan.style.cursor = "pointer";
		headCellSpan.id = objDisplayMonth.getDisplayMonth().getMonth()+","+(objDisplayMonth.getDisplayMonth().getFullYear()+1);
		headCellSpan.onclick = this.shiftDate;
		headCell.appendChild(headCellSpan);
		headCell.className = "headRightTd";
	},
	addDaysOfWeek : function() {
		daysOfWeekRow = this.table.insertRow(2);
		for(u=0;u<7;u++)
		{
			daysOfWeekCell = daysOfWeekRow.insertCell(u);
			daysOfWeekCell.className = "daysOfWeekTd";
			daysOfWeekCellText = document.createTextNode(dateInfo[calendar.language].daysShortNames[u]);
			daysOfWeekCell.appendChild(daysOfWeekCellText);
		}
	},
	// build method builds the actual table and returns it as an object
	build : function() {
		this.init();
		this.addHeader();
		this.addDaysOfWeek();
		this.addFirstWeek(arguments[0],arguments[1]);
		this.addAdditionalWeeks(arguments[0],arguments[1]);
		if(this.monthEndDay)
			this.addLastWeek(arguments[0],arguments[1]);
		this.table.id = "____calendar";
		this.table.className = "calTable";
		return this.table;
	}
};
User avatar
Burrito
Spockulator
Posts: 4715
Joined: Wed Feb 04, 2004 8:15 pm
Location: Eden, Utah

Post by Burrito »

thanks for moving this here feyd...sorry I jumped the gun 8O
User avatar
Burrito
Spockulator
Posts: 4715
Joined: Wed Feb 04, 2004 8:15 pm
Location: Eden, Utah

Post by Burrito »

I just reviewed the code and there are few things that I think I need to change before it goes 'live'.

I've got a few methods in my calendarBuilder object that really should be in the calendar object. The calendarBuilder object really should just build the calendar 'HTML' and that's it. I've got a couple methods that actually do stuff that I need to move (changeBackground, changeBackgroundBack, shiftDate, and changeByMonthYear). Those don't really do anything toward building my table object so they don't really fit well in that object.

I'm heading out of town tomorrow for the weekend but when I get back next week I'll move them where they belong.

Burr
Begby
Forum Regular
Posts: 575
Joined: Wed Dec 13, 2006 10:28 am

Post by Begby »

With regard to your CSS, in order to have it unique you can have one unique id for the table itself, then identify the classes like this:

Code: Select all

#tableid .className
{
  stuff : stuff ;
}
Also, you have a lot of CSS elements that are repeated, you can replace a lot of that with a 'td#tableid' identifier so you don't have to repeat it everywhere.

This also goes for a lot of your code, alot of the JS looks copied and pasted and could be placed into functions to make it easier to maintain/read.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

I haven't read every line, but it certainly looks like you can refactor a lot of the repeated stuff. Things such as setting CSS styles are repeated fairly regularly. There's probably more. I like refactoring oodles of code into readable units of code :)
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

You should consider implementing a setDefaultDate function so the calender begins specifically at a user defined date, or am I missing something?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Jcart wrote:You should consider implementing a setDefaultDate function so the calender begins specifically at a user defined date, or am I missing something?
I quite liked the way I modelled my Java date picker. You set the date simply by passing it a Date object. Changes to the date, made by the user via the View simply updated that Date object so you could read back from it using an API which is just part of the Java core packages. I'm sure you can probably do the same with JavaScript :)
User avatar
CoderGoblin
DevNet Resident
Posts: 1425
Joined: Tue Mar 16, 2004 10:03 am
Location: Aachen, Germany

Post by CoderGoblin »

Rather than tell you direct translations this is a method I used for translating the Jquery calendar plugin. I simply change the locale to the current language and use the following code (written in php rather than javascript):

Code: Select all

$days=array(strftime('%A',mktime(0,0,0,3,11,2007)),
            strftime('%A',mktime(0,0,0,3,12,2007)),
            strftime('%A',mktime(0,0,0,3,13,2007)),
            strftime('%A',mktime(0,0,0,3,14,2007)),
            strftime('%A',mktime(0,0,0,3,15,2007)),
            strftime('%A',mktime(0,0,0,3,16,2007)),
            strftime('%A',mktime(0,0,0,3,17,2007)));
$months=array(strftime('%B',mktime(0,0,0,1,1,2007)),
              strftime('%B',mktime(0,0,0,2,1,2007)),
              strftime('%B',mktime(0,0,0,3,1,2007)),
              strftime('%B',mktime(0,0,0,4,1,2007)),
              strftime('%B',mktime(0,0,0,5,1,2007)),
              strftime('%B',mktime(0,0,0,6,1,2007)),
              strftime('%B',mktime(0,0,0,7,1,2007)),
              strftime('%B',mktime(0,0,0,8,1,2007)),
              strftime('%B',mktime(0,0,0,9,1,2007)),
              strftime('%B',mktime(0,0,0,10,1,2007)),
              strftime('%B',mktime(0,0,0,11,1,2007)),
              strftime('%B',mktime(0,0,0,12,1,2007)));
(I then implode the array to make a comma separated value and store the result in a session var for reuse rather than have to calculate this each time).
The only strings I then need to translate are pure text strings such as "Next", "Previous" etc.

I like the JQuery DatePicker solution of setting the date parameters outside the main code. It means you do not have to have the translation available within the calendar's javascript (especially if it is compressed and you cannot change it).
trassalg
Forum Newbie
Posts: 23
Joined: Fri Jul 27, 2007 3:26 pm

Post by trassalg »

Is there an easy way to change the output of this script to fit the format?:

yyyy-mm-dd

I'd like to have the dates feed into a php script I have that sends a query to a mysql server, but can't figure out where/how the output of dates can be converted to numerical values. I'm ignorant when it comes to javascript, but have to tell you I love this script!
User avatar
Burrito
Spockulator
Posts: 4715
Joined: Wed Feb 04, 2004 8:15 pm
Location: Eden, Utah

Post by Burrito »

yeah just change this:

calendarDateFormat = "%yyyy%-%mm%-%dd%";
Post Reply