(function($) { var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; function getToday() { var date = new Date(); return new Date(date.getFullYear(), date.getMonth(), date.getDate()); } function areDatesEqual(date1, date2) { return String(date1) == String(date2); } function daysInMonth(year, month) { if (year instanceof Date) return daysInMonth(year.getFullYear(), year.getMonth()); if (month == 1) { var leapYear = (year % 4 == 0) && (!(year % 100 == 0) || (year % 400 == 0)); return leapYear ? 29 : 28; } else if (month == 3 || month == 5 || month == 8 || month == 10) { return 30; } else { return 31; } } function dayAfter(date) { var year = date.getFullYear(); var month = date.getMonth(); var day = date.getDate(); var lastDay = daysInMonth(date); return (day == lastDay) ? ((month == 11) ? new Date(year + 1, 0, 1) : new Date(year, month + 1, 1) ) : new Date(year, month, day + 1); } function dayBefore(date) { var year = date.getFullYear(); var month = date.getMonth(); var day = date.getDate(); return (day == 1) ? ((month == 0) ? new Date(year - 1, 11, daysInMonth(year - 1, 11)) : new Date(year, month - 1, daysInMonth(year, month - 1)) ) : new Date(year, month, day - 1); } function monthAfter(year, month) { return (month == 11) ? new Date(year + 1, 0, 1) : new Date(year, month + 1, 1); } function formatDate(date, usa) { return (usa ? ((date.getMonth() + 1) + '/' + date.getDate()) : (date.getDate() + '/' + (date.getMonth() + 1)) ) + '/' + date.getFullYear(); } function parseDate(date, usa) { if (usa) return new Date(date); a = date.split(/[\.\-\/]/); var day = a.shift(); var month = a.shift(); a.unshift(day); a.unshift(month); return new Date(a.join('/')); } function formatTime(hour, minute, options) { var printMinute = minute; if (minute < 10) printMinute = '0' + minute; if (options.isoTime) { var printHour = hour if (printHour < 10) printHour = '0' + hour; return printHour + ':' + printMinute; } else { var printHour = hour % 12; if (printHour == 0) printHour = 12; if (options.meridiemUpperCase) { var half = (hour < 12) ? 'AM' : 'PM'; } else { var half = (hour < 12) ? 'am' : 'pm'; } return printHour + ':' + printMinute + half; } } function parseTime(text) { var match = match = /(\d+)\s*[:\-\.,]\s*(\d+)\s*(am|pm)?/i.exec(text); if (match && match.length >= 3) { var hour = Number(match[1]); var minute = Number(match[2]) if (hour == 12 && match[3]) hour -= 12; if (match[3] && match[3].toLowerCase() == 'pm') hour += 12; return { hour: hour, minute: minute }; } else { return null; } } function timeToMinutes(time) { return time && (time.hour * 60 + time.minute); } /** * Generates calendar header, with month name, << and >> controls, and * initials for days of the week. */ function renderCalendarHeader(element, year, month, options) { //Prepare thead element var thead = $(''); var titleRow = $('').appendTo(thead); //Generate << (back a month) link $('').addClass('monthCell').append( $('«') .addClass('prevMonth') .mousedown(function(e) { renderCalendarPage(element, month == 0 ? (year - 1) : year, month == 0 ? 11 : (month - 1), options ); e.preventDefault(); }) ).appendTo(titleRow); //Generate month title $('').addClass('monthCell').attr('colSpan', 5).append( $('' + monthNames[month] + ' ' + year + '').addClass('monthName') ).appendTo(titleRow); //Generate >> (forward a month) link $('').addClass('monthCell').append( $('»') .addClass('nextMonth') .mousedown(function() { renderCalendarPage(element, month == 11 ? (year + 1) : year, month == 11 ? 0 : (month + 1), options ); }) ).appendTo(titleRow); //Generate weekday initials row var dayNames = $('').appendTo(thead); $.each(String('SMTWTFS').split(''), function(k, v) { $('').addClass('dayName').append(v).appendTo(dayNames); }); return thead; } function renderCalendarPage(element, year, month, options) { options = options || {}; var today = getToday(); var date = new Date(year, month, 1); //Wind end date forward to saturday week after month var endDate = monthAfter(year, month); var ff = 6 - endDate.getDay(); if (ff < 6) ff += 7; for (var i = 0; i < ff; i++) endDate = dayAfter(endDate); var table = $(''); renderCalendarHeader(element, year, month, options).appendTo(table); var tbody = $('').appendTo(table); var row = $(''); //Rewind date to monday week before month var rewind = date.getDay() + 7; for (var i = 0; i < rewind; i++) date = dayBefore(date); while (date <= endDate) { var td = $(''); } date = dayAfter(date); } if (row.children().length) { tbody.append(row); } else { row.remove(); } element.empty().append(table); } function renderTimeSelect(element, options) { var minTime = timeToMinutes(options.minTime); var maxTime = timeToMinutes(options.maxTime); var defaultTime = timeToMinutes(options.defaultTime); var selection = options.selection && timeToMinutes(parseTime(options.selection)); //Round selection to nearest time interval so that it matches a list item selection = selection && ( ( Math.floor((selection - minTime) / options.timeInterval) * options.timeInterval ) + minTime ); var scrollTo; //Element to scroll the dropdown box to when shown var ul = $('
') .addClass('day') .append( $('' + date.getDate() + '' ).click((function() { var thisDate = date; return function() { if (options && options.selectDate) { options.selectDate(thisDate); } } }())) ) .appendTo(row); var isToday = areDatesEqual(date, today); var isSelected = options.selected && areDatesEqual(options.selected, date); if (isToday) td.addClass('today'); if (isSelected) td.addClass('selected'); if (isToday && isSelected) td.addClass('today_selected'); if (date.getMonth() != month) td.addClass('nonMonth'); dow = date.getDay(); if (dow == 6) { tbody.append(row); row = $('