// Display of an outlook style calendar for selecting a date
// Sets continental and ISO formatted form field values according to selected day of calendar
// and syncronises calendar with input in form field (DD.MM.YYYY).
// Additionally calls optional callback function fSetDate() on select of a calendar day.
//
// Continental Date Format
//
// Author:
// Armin Joachimsmeyer 25.09.2000
// Udo Pracht, 16.05.2000
//
// Version 1.2 / 3.12.2001
// Replace eval by []
// CSS extracted to separate file
// Tooltips for TitleBar
// Version 1.1
// Function renaming
// Callback function
// English error messages by global variable sLang
// replace iCalCount by oCals.length
// Version 2.0
// DOM / Mozilla compatible
//
// Call at the place where the calendar should display:
//
// fInitCal(iYear, iMonth, iDay, sFieldName, iCalNo, bAutosubmit);
// iYear, iMonth, iDay, = Start Date or iYear = 0 for no initialisation (preselection)
// sFieldName = name of the MANDATORY form field for the Date
// which is processed by the calendar
// The ISO form field is otional and provides
// only a reformatted output e.g. for direct database use.
// iCalNo = number of calendar in HTML page starting with 0
// bAutosubmit = flag for auto submit on change of selected date, not
// for popup windows
//
// fSetCalendarDate(number_of_calendar_in_page);
// Sets the calendar according to the content of the form field.
//
// Example:
//
//
// The name of the ISO field is the name of the form field with the String "ISO" appended
//
// fSetDate(iYear, iMonth, iDay, iCalNo) is the callback function
//
// Example:
// function fSetDate(iYear, iMonth, iDay, iCalNo)
// {
// SetFormValue(document.myform.jahr, iYear);
// document.myform.monat.selectedIndex = iMonth;
// document.myform.tag.selectedIndex = iDay -1;
// }
//
//////////////////////////////////////////////////////////////////////////////////
//List of functions:
//
// Create a new calendar object with it's attributes
// calendar internal function
// function fCalendarGrid (InitDay, InitDayID, FormFieldName, FlagAutosubmit) {
//
// Init calendar data and output the calendar grid into the HTML page
// called exactly from the place in the HTML document where the calendar grid should be shown
// function fInitCal(iYear, iMonth, iDay, sFieldName, iCalNo, bAutosubmit) {
//
// opens a popup window which contains a calendar
// shref: pathname of the popup html file
// function fOpenCalendarPopoup (shref, oDateFormField){
//
// Change the shown month of a calendar grid
// called from "<<", "<", ">" or ">>" in the calendar heading
// function fChangeCurMonth(iAmount, iCalNo) {
//
// Maintain calendar variables highlight the choosen day, dehighlight the old choice
// and update the form field
// called by clicking a day in the grid
// function fsetSelectedDay(iElementId, iCalNo) {
//
// Set the choosen day to the initial value
// called from the reset button in the HTML form
// function fResetCalendar(iCalNo) {
//
// Set the calendar to the given date (DD.MM.YYYY) and highlight the given day
// could be called from the HTML-Page to set the calendar i.e. from an input field
// function fSetCalendarDate(iCalNo) {
//
// Initialises the date form fields if start date was supplied.
// Called by the onload event Handler setup by fInitCal()
// in order to fill the form fields after they are loaded.
// calendar internal function
// function fInitDateFields() {
//
// Checks for valid date (DD.MM.YYYY) and returns it
// calendar internal function
// function fValidDate(dateStr) {
//
// Build array with days in the given month
// calendar internal function
// function fBuildMonth(iYear, iMonth) {
//
// Update (redraw) the calendar grid
// calendar internal function
// function fUpdateCal(iYear, iMonth, iCalNo) {
//
// Return the year of the given date with 4 digits
// calendar internal function
// function fGetFullYear(dDateValue) {
//
// Return date in DD.MM.YYYY format
// calendar internal function
// function fGetDateFormatted(dDateValue) {
//
// Return date in YYYY-MM-DD ISO format
// calendar internal function
// function fGetDateFormattedISO(dDateValue) {
// "Constants" for displaying the Calendar grid
var sLang = "de"; // de or any other string
//var sLang = "";
if (sLang == "de") {
var textNextMonth = "ein Monat weiter";
var textNextYear = "ein Jahr weiter";
var textPrevMonth = "ein Monat zurück";
var textPrevYear = "ein Jahr zurück";
var aNamesOfMonth = new Array("Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember");
var aNamesOfDays = new Array("Mo","Di","Mi","Do","Fr","Sa","So");
} else {
var textNextMonth = "next month";
var textNextYear = "next year";
var textPrevMonth = "previous month";
var textPrevYear = "previous year";
var aNamesOfMonth = new Array("January","February","March","April","May","June","July","August","September","October","November","December");
var aNamesOfDays = new Array("Mo","Tu","We","Th","Fr","Sa","Su");
}
var aColorsOfDayHeadings = new Array("white","white","white","white","white","darkgray","tomato");
var aColorsOfDays = new Array("black","black","black","black","black","darkgray","tomato");
var sBgColorHighlighted = "silver";
var sBgColorNormal = "whitesmoke";
// Global variables to handle multiple calendar grids
var oCals = new Array(); //Calendar array
var fOriginalOnload; //Store the original onload function
var bOnloadAdded = false; //need to add only one time
//
// Create a new calendar object with it's attributes
// calendar internal function
//
function fCalendarGrid (InitDay, InitDayID, FormFieldName, FlagAutosubmit) {
this.dInitDay = InitDay; //Initialization date
this.iInitDayId = InitDayID; //Array-ID of it - Flag if initialisation was wanted
this.dCurDay = InitDay; //Currently choosen date
this.iCurDayId = InitDayID; //Array-ID of it
this.dCurMonth = new Date(InitDay.getFullYear(), InitDay.getMonth(), 1); //First Day of the displayed month
this.sFormFieldName = FormFieldName; //HTML-Name of the form field to receive the date
this.FlagAutosubmit = FlagAutosubmit; //Submit on change
this.sDate = ""; //Date strings for defered initialisation of form fields
this.sDateISO = "";
this.fSameDocument = true; //Flag if calendar is in a popup window or same window
}
//
// Init calendar data and output the calendar grid into the HTML page
// called exactly from the place in the HTML document where the calendar grid should be shown
//
function fInitCal(iYear, iMonth, iDay, sFieldName, iCalNo, bAutosubmit) {
// Check if 'iCalNr' correspond to the Current Number of Cals on the Page (Global variable 'oCals.length')
if (iCalNo != oCals.length) {
document.write("ERROR in Calendar-JavaScript: Given Calendar Number is: " + iCalNo + " - Expected Calendar Number is: " + oCals.length);
} else {
if (iYear == 0) {
// No initialization date wanted; set today
var dTemp = new Date();
dInitDay = new Date(dTemp.getFullYear(), dTemp.getMonth(), dTemp.getDate());
oCals[iCalNo] = new fCalendarGrid(dInitDay, -1, sFieldName, bAutosubmit);
} else {
// Correct initialization date is passed
dInitDay = new Date(iYear, iMonth - 1, iDay);
oCals[iCalNo] = new fCalendarGrid(dInitDay, 0, sFieldName, bAutosubmit);
}
var myMonth = fBuildMonth(dInitDay.getFullYear(), dInitDay.getMonth() + 1);
// Output the calendar grid
document.write("");
// Row with calendar headline in extra table
document.write(" ");
document.write(" ");
document.write(" ");
document.write(" ");
document.write(" << ");
document.write(" < ");
document.write(" | ");
document.write(" ");
document.write(" " + aNamesOfMonth[dInitDay.getMonth()] + " " + fGetFullYear(dInitDay) + " ");
document.write(" | ");
document.write(" ");
document.write(" > ");
document.write(" >> ");
document.write(" | ");
document.write(" ");
document.write(" | ");
document.write("
");
document.write(" ");
// Row with names of Weekdays
for (i = 0; i < 7; i++) {
document.write(" " + aNamesOfDays[i] + " | ");
}
document.write("
");
document.write(" ");
// 6 Rows containing the days of the current month
for (i = 0; i < 42; i++) {
document.write(" " + ((myMonth[i] != " ") ? myMonth[i] : " "));
document.write(" | ");
if ((i % 7) == 6) document.write("
");
}
document.write("
");
document.write("
");
//store date strings
oCals[iCalNo].sDate = fGetDateFormatted(oCals[iCalNo].dCurDay);
oCals[iCalNo].sDateISO = fGetDateFormattedISO(oCals[iCalNo].dCurDay);
// extend the body.onload eventhandler to fill the date fields,
// which are not existent yet because they normally come later in the HTML file
// and therefore will be loaded later by the browser
// in Mozilla this is not needed
if (document.all) {
if (! bOnloadAdded) {
if(document.body.onload){
fOriginalOnload = document.body.onload;
document.body.onload = new Function("fInitDateFields(); fOriginalOnload();");
} else {
document.body.onload = new Function("fInitDateFields();");
}
bOnloadAdded = true;
}
}
}
}
//
// opens a popup window which contains a calendar
// shref: pathname of the popup html file
//
function fOpenCalendarPopoup (shref, oDateFormField){
if (oDateFormField.value == "") {
// open the calendar unititialized
tPopupWindowHandle = window.open(shref + '?year=0&month=0&day=0&formfieldname=' + oDateFormField.name
,'kalender'
// for xx-small , 'width=180,height=190,resizable=no');
// for x-small
, 'width=215,height=210,resizable=no');
} else {
// open the calendar with initialization data from the form field
tPopupWindowHandle = window.open(shref + '?year=' + oDateFormField.value.substr(6,4)
+ '&month=' + oDateFormField.value.substr(3,2)
+ '&day=' + oDateFormField.value.substr(0,2)
+ '&formfieldname=' + oDateFormField.name
,'kalender'
, 'width=215,height=210,resizable=no');
}
return tPopupWindowHandle;
}
//
// Change the shown month of a calendar grid
// called from "<<", "<", ">" or ">>" in the calendar heading
//
function fChangeCurMonth(iAmount, iCalNo) {
oCals[iCalNo].dCurMonth = new Date(oCals[iCalNo].dCurMonth.getFullYear(), oCals[iCalNo].dCurMonth.getMonth() + iAmount, 1);
//alert ("fUpdateCal(" + fGetFullYear(oCals[iCalNo].dCurMonth) + "," + (oCals[iCalNo].dCurMonth.getMonth() + 1) + "," + iCalNo + ")");
fUpdateCal(fGetFullYear(oCals[iCalNo].dCurMonth), oCals[iCalNo].dCurMonth.getMonth() + 1, iCalNo);
}
//
// Maintain calendar variables highlight the choosen day, dehighlight the old choice
// and update the form field
// called by clicking a day in the grid
//
function fsetSelectedDay(iElementId, iCalNo) {
if (document.all) {
iElementValue = parseInt(document.getElementsByName("calElement" + iCalNo)[iElementId].innerText);
} else {
iElementValue = parseInt(document.getElementsByName("calElement" + iCalNo)[iElementId].textContent);
}
if (!isNaN(iElementValue)) {
// Maintain calendar variables highlight the choosen day, dehighlight the old choice
oCals[iCalNo].dCurDay = new Date(oCals[iCalNo].dCurMonth.getFullYear(), oCals[iCalNo].dCurMonth.getMonth(), iElementValue);
if (oCals[iCalNo].iCurDayId != -1) {
document.getElementsByName("calElement" + iCalNo)[oCals[iCalNo].iCurDayId].bgColor = sBgColorNormal;
}
document.getElementsByName("calElement" + iCalNo)[iElementId].bgColor = sBgColorHighlighted;
oCals[iCalNo].iCurDayId = iElementId;
// update the form data field
// check if the form fields exist in the same document
if (oCals[iCalNo].fSameDocument) {
// fill in form field accordingly
document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].value = fGetDateFormatted(oCals[iCalNo].dCurDay);
// if form field for ISO Format exists set ISO value
if(document.getElementsByName(oCals[iCalNo].sFormFieldName + "ISO")) {
document.getElementsByName(oCals[iCalNo].sFormFieldName + "ISO")[0].value = fGetDateFormattedISO(oCals[iCalNo].dCurDay);
}
// if callback function exists call with ISO value
if(window.fSetDate) {
fSetDate(oCals[iCalNo].dCurMonth.getFullYear(), oCals[iCalNo].dCurMonth.getMonth(), iElementValue, iCalNo);
}
// Submit Form if requested
if (oCals[iCalNo].FlagAutosubmit) {
document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].form.submit();
}
} else { // assume formfields are in calling document
opener.document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].value = fGetDateFormatted(oCals[iCalNo].dCurDay);
if(opener.document.getElementsByName(oCals[iCalNo].sFormFieldName + "ISO")) {
opener.document.getElementsByName(oCals[iCalNo].sFormFieldName + "ISO")[0].value = fGetDateFormattedISO(oCals[iCalNo].dCurDay);
}
if(opener.fSetDate) {
opener.fSetDate(oCals[iCalNo].dCurMonth.getFullYear(), oCals[iCalNo].dCurMonth.getMonth(), iElementValue, iCalNo);
}
// Submit Form if requested and close popup Window
if (oCals[iCalNo].FlagAutosubmit) {
opener.document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].form.submit();
self.close();
}
}
}
}
//
// Set the choosen day to the initial value
// called from the reset button in the HTML form
//
function fResetCalendar(iCalNo) {
oCals[iCalNo].dCurDay = oCals[iCalNo].dInitDay;
// reset month and year
fUpdateCal(oCals[iCalNo].dInitDay.getFullYear(), oCals[iCalNo].dInitDay.getMonth() + 1 , iCalNo)
if (oCals[iCalNo].iInitDayId != -1) { // reselect day
fsetSelectedDay(oCals[iCalNo].iInitDayId, iCalNo);
} else { // only reset Background color of selected day
if (oCals[iCalNo].iCurDayId != -1) {
document.getElementsByName("calElement" + iCalNo)[oCals[iCalNo].iCurDayId].bgColor = sBgColorNormal;
}
}
oCals[iCalNo].iCurDayId = oCals[iCalNo].iInitDayId;
window.focus(); // put focus on the (popup) window
}
//
// Set the calendar to the given date (DD.MM.YYYY) and highlight the given day
// could be called from the HTML-Page to set the calendar i.e. from an input field
//
function fSetCalendarDate(iCalNo) {
// check if the form fields exist in the same document
if (oCals[iCalNo].fSameDocument) {
var sInputDate = document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].value;
} else {
sInputDate = opener.document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].value;
window.focus(); // put focus on the popup window
}
if (sInputDate == "") {
if (oCals[iCalNo].iCurDayId != -1) {
document.getElementsByName("calElement" + iCalNo)[oCals[iCalNo].iCurDayId].bgColor = sBgColorNormal;
}
oCals[iCalNo].iCurDayId = -1;
return true;
} else {
// Check date
dCheckedDate = fValidDate(sInputDate);
if (dCheckedDate != 0) {
oCals[iCalNo].dCurMonth = dCheckedDate;
// redraw calendar
fUpdateCal(fGetFullYear(oCals[iCalNo].dCurMonth), oCals[iCalNo].dCurMonth.getMonth() + 1, iCalNo);
var myMonth = fBuildMonth(dCheckedDate.getFullYear(), dCheckedDate.getMonth() + 1);
// now find the id of the the day and select it
for (var i = 0; i < 42; i++) {
if (dCheckedDate.getDate() == myMonth[i]) {
fsetSelectedDay(i, iCalNo);
}
}
return true;
} else {
// invalid date; set focus to the formfield
if (oCals[iCalNo].fSameDocument) {
document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].focus();
} else {
opener.document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].focus();
}
return false;
}
}
}
//
// Initialises the date form fields if start date was supplied.
// Called by the onload event Handler setup by fInitCal()
// in order to fill the form fields after they are loaded.
// calendar internal function
//
function fInitDateFields() {
//alert("fInitDateFields");
for (iCalNo = 0; iCalNo < oCals.length; iCalNo++) {
//check if same window or popup window by checking if the form fields exist in the same document
oCals[iCalNo].fSameDocument = false;
if (document.getElementsByName(oCals[iCalNo].sFormFieldName).length > 0) {
oCals[iCalNo].fSameDocument = true;
}
if (oCals[iCalNo].iInitDayId != -1) {
// check if the form fields exist in the same document
if (oCals[iCalNo].fSameDocument) {
document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].value = oCals[iCalNo].sDate;
if(document.getElementsByName(oCals[iCalNo].sFormFieldName + "ISO")) {
document.getElementsByName(oCals[iCalNo].sFormFieldName + "ISO")[0].value = oCals[iCalNo].sDateISO;
}
if(window.fSetDate) {
fSetDate(oCals[iCalNo].dCurDay.getFullYear(), oCals[iCalNo].dCurDay.getMonth(), oCals[iCalNo].dCurDay.getDay(), iCalNo);
}
} else { // assume formfields are in calling document
opener.document.getElementsByName(oCals[iCalNo].sFormFieldName)[0].value = oCals[iCalNo].sDate;
if(opener.document.getElementsByName(oCals[iCalNo].sFormFieldName + "ISO")) {
opener.document.getElementsByName(oCals[iCalNo].sFormFieldName + "ISO")[0].value = oCals[iCalNo].sDateISO;
}
if(opener.fSetDate) {
opener.fSetDate(oCals[iCalNo].dCurDay.getFullYear(), oCals[iCalNo].dCurDay.getMonth(), oCals[iCalNo].dCurDay.getDay(), iCalNo);
}
}
}
}
}
//
// Checks for valid date (DD.MM.YYYY) and returns it
// calendar internal function
//
function fValidDate(dateStr) {
var datePat = /^(\d{1,2})(\.)(\d{1,2})\2(\d{4})$/;
var matchArray = dateStr.match(datePat); // is the format ok?
if (matchArray == null) {
if (sLang == "de") {
alert("Das Format des angegebenen Datums\nist nicht korrekt.\n");
} else {
alert("The given format of date declared\nis nor correct.");
}
return 0;
}
day = matchArray[1]; // parse date into variables
month = matchArray[3];
year = matchArray[4];
if (day < 1 || day > 31) {
if (sLang == "de") {
alert("Der Tag muß zwischen 1 und 31 liegen.");
} else {
alert("Value of day must be between 1 and 31.");
}
return 0;
}
if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) {
if (sLang == "de") {
alert("Monat "+month+" hat keine 31 Tage!")
} else {
alert("Month "+month+" has not 31 days!")
}
return 0
}
if (month == 2) { // check for february 29th
var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
if (day > 29 || (day == 29 && !isleap)) {
if (sLang == "de") {
alert("Februar " + year + " hat(te) keine " + day + " Tage!");
} else {
alert("February " + year + " has (had) not " + day + " days!");
}
return 0;
}
}
if (month < 1 || month > 12) { // check month range
if (sLang == "de") {
alert("Der Monat muß zwischen 1 und 12 liegen.");
} else {
alert("Value of month must be between 1 and 12.");
}
return 0;
}
return (new Date(year, month - 1, day)); // date is valid
}
//
// Build array with days in the given month
// calendar internal function
//
function fBuildMonth(iYear, iMonth) {
var iFirstWeekday = (new Date(iYear, iMonth - 1, 1).getDay() + 6) % 7;
var iDaysInMonth = new Date(iYear, iMonth, 0).getDate();
var aMonth = new Array(42);
for (i = 0; i < 42; i++) {
var iDayOfMonth = i - iFirstWeekday;
if ((iDayOfMonth >= 0) && (iDayOfMonth < iDaysInMonth)) {
aMonth[i] = iDayOfMonth + 1;
} else {
aMonth[i] = " ";
}
}
return aMonth;
}
//
// Update (redraw) the calendar grid
// calendar internal function
//
function fUpdateCal(iYear, iMonth, iCalNo) {
myMonth = fBuildMonth(iYear, iMonth);
if (document.all) {
document.getElementById("calHeading" + iCalNo).innerText = aNamesOfMonth[iMonth - 1] + ' ' + iYear;
} else {
document.getElementById("calHeading" + iCalNo).textContent = aNamesOfMonth[iMonth - 1] + ' ' + iYear;
}
for (i = 0; i < 42; i++) {
if (document.all) {
document.getElementsByName("calElement" + iCalNo)[i].innerText = myMonth[i];
} else {
document.getElementsByName("calElement" + iCalNo)[i].textContent = myMonth[i];
}
}
if (oCals[iCalNo].iCurDayId != -1) {
if ((iYear == fGetFullYear(oCals[iCalNo].dCurDay)) &&
(iMonth == (oCals[iCalNo].dCurDay.getMonth() + 1))) {
document.getElementsByName("calElement" + iCalNo)[oCals[iCalNo].iCurDayId].bgColor = sBgColorHighlighted;
} else {
document.getElementsByName("calElement" + iCalNo)[oCals[iCalNo].iCurDayId].bgColor = sBgColorNormal;
}
}
}
//
// Return the year of the given date with 4 digits
// calendar internal function
//
function fGetFullYear(dDateValue) {
if (dDateValue.getFullYear() < 10) { return ("190" + dDateValue.getFullYear()) };
if (dDateValue.getFullYear() < 100) { return ("19" + dDateValue.getFullYear()) };
return dDateValue.getFullYear();
}
//
// Return date in DD.MM.YYYY format
// calendar internal function
//
function fGetDateFormatted(dDateValue) {
iDay = ((dDateValue.getDate() > 9) ? "" : "0") + dDateValue.getDate();
iMonth = (((dDateValue.getMonth() + 1) > 9) ? "" : "0") + (dDateValue.getMonth() + 1);
return iDay + "." + iMonth + "." + fGetFullYear(dDateValue);
}
//
// Return date in YYYY-MM-DD ISO format
// calendar internal function
//
function fGetDateFormattedISO(dDateValue) {
iDay = ((dDateValue.getDate() > 9) ? "" : "0") + dDateValue.getDate();
iMonth = (((dDateValue.getMonth() + 1) > 9) ? "" : "0") + (dDateValue.getMonth() + 1);
return fGetFullYear(dDateValue) + "-" + iMonth + "-" + iDay;
}