/* * Control.DatePicker * * Transforms an ordinary input textbox into an interactive date picker. * When the textbox is clicked (or the down arrow is pressed), a calendar * appears that the user can browse through and select a date. * * Features: * - Allows user to specify a date format * - Easy to localize * - Customizable by CSS * * Written and maintained by Jeremy Jongsma (jeremy@jongsma.org) */ if (window.Control == undefined) Control = {}; Control.DatePicker = Class.create(); Control.DatePicker.activePicker = null; Control.DatePicker.prototype = { initialize: function(element, options) { this.element = $(element); this.i18n = new Control.DatePicker.i18n(options && options.locale ? options.locale : 'en_US'); options = this.i18n.inheritOptions(options); options = Object.extend({ datePicker: true, timePicker: false }, options || {}); this.handlers = { onClick: options.onClick, onHover: options.onHover, onSelect: options.onSelect }; this.options = Object.extend(options || {}, { onClick: this.pickerClicked.bind(this), onHover: this.dateHover.bind(this), onSelect: this.datePicked.bind(this) }); if (this.options.timePicker && this.options.datePicker) this.options.currentFormat = this.options.dateTimeFormat; else if (this.options.timePicker) this.options.currentFormat = this.options.timeFormat; else this.options.currentFormat = this.options.dateFormat; // this.options.currentFormat = this.options.timePicker ? this.options.dateTimeFormat : this.options.dateFormat; this.options.date = DateFormat.parseFormat(this.element.value, this.options.currentFormat); // Lazy load to avoid excessive CPU usage with lots of controls on one page this.datepicker = null; this.originalValue = null; this.hideTimeout = null; if (this.options.icon) { var cont = new Element('div', {'style': 'position: relative;'}); this.element.parentNode.replaceChild(cont, this.element); cont.appendChild(this.element); this.icon = new Element('img', {'src': this.options.icon, 'title': this.tr('Open calendar'), 'className': 'inputExtension'}); var padding = this.options.padding; if (!padding) { // No icon padding specified, default to 3px and calculate // dynamically on image load padding = 3; Event.observe(this.icon, 'load', function() { padding = parseInt(this.element.offsetHeight - this.icon.offsetHeight) / 2; var right = (this.element.offsetParent.offsetWidth - (this.element.offsetLeft + this.element.offsetWidth) + padding) + 'px'; Element.setStyle(this.icon, {'right': right, 'top': padding + 'px'}); }.bind(this)); } var right = (this.element.offsetParent.offsetWidth - (this.element.offsetLeft + this.element.offsetWidth) + padding) + 'px'; Element.setStyle(this.icon, {'position': 'absolute', 'right': right, 'top': padding + 'px'}); cont.appendChild(this.icon); Event.observe(this.icon, 'click', this.togglePicker.bindAsEventListener(this)); } else { Event.observe(this.element, 'click', this.togglePicker.bindAsEventListener(this)); } this.hidePickerListener = this.delayedHide.bindAsEventListener(this); Event.observe(this.element, 'keydown', this.keyHandler.bindAsEventListener(this)); Event.observe(document, 'keydown', this.docKeyHandler.bindAsEventListener(this)); this.pickerActive = false; }, tr: function(str) { return this.i18n.tr(str); }, delayedHide: function(e) { this.hideTimeout = setTimeout(this.hide.bind(this), 100); }, pickerClicked: function() { if (this.hideTimeout) { clearTimeout(this.hideTimeout); this.hideTimeout = null; } if (this.handlers.onClick) this.handlers.onClick(); }, datePicked: function(date) { this.element.value = DateFormat.format(date, this.options.currentFormat); this.element.focus(); this.hide(); if (this.handlers.onSelect) this.handlers.onSelect(date); if (this.element.onchange) this.element.onchange(); }, dateHover: function(date) { if (this.hideTimeout) { clearTimeout(this.hideTimeout); this.hideTimeout = null; } if (this.pickerActive) { this.element.value = DateFormat.format(date, this.options.currentFormat); if (this.handlers.onHover) this.handlers.onHover(date); } }, togglePicker: function(e) { if (this.pickerActive) { this.element.value = this.originalValue; this.hide(); } else { this.show(); } Event.stop(e); return false; }, docKeyHandler: function(e) { if (e.keyCode == Event.KEY_ESC) if (this.pickerActive) { this.element.value = this.originalValue; this.hide(); } }, keyHandler: function(e) { switch (e.keyCode) { case Event.KEY_ESC: if (this.pickerActive) this.element.value = this.originalValue; case Event.KEY_TAB: this.hide(); return; case Event.KEY_DOWN: if (!this.pickerActive) { this.show(); Event.stop(e); } } if (this.pickerActive) return false; }, hide: function() { if(this.pickerActive && !this.element.disabled) { this.datepicker.releaseKeys(); Element.remove(this.datepicker.element); Event.stopObserving(document, 'click', this.hidePickerListener, true); this.pickerActive = false; Control.DatePicker.activePicker = null; } }, show: function () { if (!this.pickerActive) { if (Control.DatePicker.activePicker) Control.DatePicker.activePicker.hide(); this.element.focus(); if (!this.datepicker) this.datepicker = new Control.DatePickerPanel(this.options); this.originalValue = this.element.value; var pos = Position.positionedOffset(this.element); var dim = Element.getDimensions(this.element); var pickerTop = /MSIE/.test(navigator.userAgent) ? (pos[1] + dim.height) + 'px' : (pos[1] + dim.height - 1) + 'px'; this.datepicker.element.style.top = pickerTop; this.datepicker.element.style.left = pos[0] + 'px'; this.datepicker.element.style.zIndex = '99'; this.datepicker.selectDate(DateFormat.parseFormat(this.element.value, this.options.currentFormat)); this.datepicker.captureKeys(); this.element.parentNode.appendChild(this.datepicker.element); Event.observe(document, 'click', this.hidePickerListener, true); this.pickerActive = true; Control.DatePicker.activePicker = this; this.pickerClicked(); } } }; Control.DatePicker.i18n = Class.create(); Object.extend(Control.DatePicker.i18n, { baseLocales: { 'us': { dateTimeFormat: 'MM-dd-yyyy HH:mm', dateFormat: 'MM-dd-yyyy', firstWeekDay: 0, weekend: [0,6], timeFormat: 'HH:mm' }, 'eu': { dateTimeFormat: 'dd-MM-yyyy HH:mm', dateFormat: 'dd-MM-yyyy', firstWeekDay: 1, weekend: [0,6], timeFormat: 'HH:mm' }, 'iso8601': { dateTimeFormat: 'yyyy-MM-dd HH:mm', dateFormat: 'yyyy-MM-dd', firstWeekDay: 1, weekend: [0,6], timeFormat: 'HH:mm' } }, createLocale: function(base, lang) { return Object.extend(Object.clone(Control.DatePicker.i18n.baseLocales[base]), {'language': lang}); } }); Control.DatePicker.i18n.prototype = { initialize: function(code) { var lang = code.charAt(2) == '_' ? code.substring(0,2) : code; var locale = (Control.DatePicker.Locale[code] || Control.DatePicker.Locale[lang]); this.opts = Object.clone(locale || {}); var language = locale ? Control.DatePicker.Language[locale.language] : null; if (language) Object.extend(this.opts, language); }, opts: null, inheritOptions: function(options) { if (!this.opts) this.setLocale('en_US'); return Object.extend(this.opts, options || {}); }, tr: function(str) { return this.opts && this.opts.strings ? this.opts.strings[str] || str : str; } }; Control.DatePicker.Locale = {}; with (Control.DatePicker) { // Full locale definitions not needed if countries use the language default format // Datepicker will fallback to the language default; i.e. 'es_AR' will use 'es' Locale['es'] = i18n.createLocale('eu', 'es'); Locale['en'] = i18n.createLocale('us', 'en'); Locale['en_GB'] = i18n.createLocale('eu', 'en'); Locale['en_AU'] = Locale['en_GB']; Locale['de'] = i18n.createLocale('eu', 'de'); Locale['es_iso8601'] = i18n.createLocale('iso8601', 'es'); Locale['en_iso8601'] = i18n.createLocale('iso8601', 'en'); Locale['de_iso8601'] = i18n.createLocale('iso8601', 'de'); } Control.DatePicker.Language = { 'es': { months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Augosto', 'Septiembre', 'Octubre', 'Novimbre', 'Diciembre'], days: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa'], strings: { 'Now': 'Ahora', 'Today': 'Hoy', 'Time': 'Hora', 'Exact minutes': 'Minuto exacto', 'Select Date and Time': 'Selecciona Dia y Hora', 'Select Time': 'Selecciona Hora', 'Open calendar': 'Abre calendario' } }, 'de': { months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], days: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], strings: { 'Now': 'Jetzt', 'Today': 'Heute', 'Time': 'Zeit', 'Exact minutes': 'Exakte minuten', 'Select Date and Time': 'Zeit und Datum Auswählen', 'Select Time': 'Zeit Auswählen', 'Open calendar': 'Kalender öffnen' } } }; Control.DatePickerPanel = Class.create(); Object.extend(Control.DatePickerPanel.prototype, { initialize: function(options) { this.i18n = new Control.DatePicker.i18n(options && options.locale ? options.locale : 'en_US'); options = this.i18n.inheritOptions(options); this.options = Object.extend({ className: 'datepickerControl', closeOnToday: true, selectToday: true, showOnFocus: false, datePicker: true, timePicker: false, use24hrs: false, firstWeekDay: 0, weekend: [0,6], months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], days: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] }, options || {}); // Make sure first weekday is in the correct range with (this.options) if (isNaN(firstWeekDay*1)) firstWeekDay = 0; else firstWeekDay = firstWeekDay % 7; this.keysCaptured = false; this.calendarCont = null; this.currentDate = this.options.date ? this.options.date : new Date(); this.dayOfWeek = 0; this.minInterval = 5; this.selectedDay = null; this.selectedHour = null; this.selectedMinute = null; this.selectedAmPm = null; this.currentDays = []; this.hourCells = []; this.minuteCells = []; this.otherMinutes = null; this.amCell = null; this.pmCell = null; this.element = this.createPicker(); this.selectDate(this.currentDate); }, createPicker: function() { var elt = document.createElement('div'); elt.style.position = 'absolute'; elt.className = this.options.className; this.calendarCont = this.drawCalendar(elt, this.currentDate); Event.observe(elt, 'click', this.clickHandler.bindAsEventListener(this)); Event.observe(elt, 'dblclick', this.dblClickHandler.bindAsEventListener(this)); this.documentKeyListener = this.keyHandler.bindAsEventListener(this); if (this.options.captureKeys) this.captureKeys(); return elt; }, tr: function(str) { return this.i18n.tr(str); }, captureKeys: function() { Event.observe(document, 'keydown', this.documentKeyListener, true); this.keysCaptured = true; }, releaseKeys: function() { Event.stopObserving(document, 'keydown', this.documentKeyListener, true); this.keysCaptured = false; }, setDate: function(date) { if (date) { // Clear container while (this.element.firstChild) this.element.removeChild(this.element.firstChild); this.calendarCont = this.drawCalendar(this.element, date); } }, drawCalendar: function(container, date) { var calCont = container; if (!this.options.datePicker) { var calTable = document.createElement('table'); calTable.cellSpacing = 0; calTable.cellPadding = 0; calTable.border = 0; } else { var calTable = this.createCalendar(date); } var rowwidth = this.options.use24hrs ? 6 : 7; if (this.options.timePicker) { var timeTable; if (this.options.timePickerAdjacent && this.options.datePicker) { var rows = 0; var adjTable = document.createElement('table'); adjTable.cellSpacing = 0; adjTable.cellPadding = 0; adjTable.border = 0; row = adjTable.insertRow(0); cell = row.insertCell(0); cell.vAlign = 'top'; cell.appendChild(calTable); calCont = cell; cell = row.insertCell(1); cell.style.width = '5px'; cell = row.insertCell(2); cell.vAlign = 'top'; timeTable = document.createElement('table'); timeTable.cellSpacing = 0; timeTable.cellPadding = 0; timeTable.border = 0; cell.appendChild(timeTable); container.appendChild(adjTable); row = timeTable.insertRow(rows++); row.className = 'monthLabel'; cell = row.insertCell(0); cell.colSpan = rowwidth; cell.innerHTML = this.tr('Time'); row = timeTable.insertRow(rows++); cell = row.insertCell(0); cell.colSpan = rowwidth; cell.style.height = '1px'; } else { container.appendChild(calTable); timeTable = calTable; var rows = calTable.rows.length; if (this.options.datePicker) { row = timeTable.insertRow(rows++); cell = row.insertCell(0); cell.colSpan = rowwidth; var hr = document.createElement('hr'); Element.setStyle(hr, {'color': 'gray', 'backgroundColor': 'gray', 'height': '1px', 'border': '0', 'marginTop': '3px', 'marginBottom': '3px', 'padding': '0'}); cell.appendChild(hr); } } var hourrows = this.options.use24hrs ? 4 : 2; for (var j = 0; j < hourrows; ++j) { row = timeTable.insertRow(rows++); for (var i = 0; i < 6; ++i){ cell = row.insertCell(i); cell.className = 'hour'; cell.width = '14%'; cell.innerHTML = (j*6)+i+(this.options.use24hrs?0:1); cell.onclick = this.hourClickedListener((j*6)+i+(this.options.use24hrs?0:1)); this.hourCells[(j*6)+i] = cell; } if (!this.options.use24hrs) { cell = row.insertCell(i); cell.className = 'ampm'; cell.width = '14%'; if (j) { cell.innerHTML = this.tr('PM'); cell.onclick = this.pmClickedListener(); this.pmCell = cell; } else { cell.innerHTML = this.tr('AM'); cell.onclick = this.amClickedListener(); this.amCell = cell; } } } row = timeTable.insertRow(rows++); cell = row.insertCell(0); cell.colSpan = 6; var hr = document.createElement('hr'); Element.setStyle(hr, {'color': '#CCCCCC', 'backgroundColor': '#CCCCCC', 'height': '1px', 'border': '0', 'marginTop': '2px', 'marginBottom': '2px', 'padding': '0'}); cell.appendChild(hr); cell = row.insertCell(1); for (var j = 0; j < (10/this.minInterval); ++j) { row = timeTable.insertRow(rows++); for (var i = 0; i < 6; ++i){ cell = row.insertCell(i); cell.className = 'minute'; cell.width = '14%'; var minval = ((j*6+i)*this.minInterval); if (minval < 10) minval = '0'+minval; cell.innerHTML = ':'+minval; cell.onclick = this.minuteClickedListener(minval); this.minuteCells[(j*6)+i] = cell; } if (!this.options.use24hrs) { cell = row.insertCell(i); cell.width = '14%'; } } row = timeTable.insertRow(rows++); cell = row.insertCell(0); cell.style.textAlign = 'right'; cell.colSpan = 5; cell.innerHTML = ''+this.tr('Exact minutes')+':'; cell = row.insertCell(1); cell.className = 'otherminute'; var otherInput = document.createElement('input'); otherInput.type = 'text'; otherInput.maxLength = 2; otherInput.style.width = '2em'; var inputTimeout = null; otherInput.onkeyup = function(e) { if (!isNaN(otherInput.value)) { this.currentDate.setMinutes(otherInput.value); this.dateChanged(this.currentDate); } }.bindAsEventListener(this); otherInput.onkeydown = function(e) { if (e.keyCode == Event.KEY_RETURN) if (this.options.onSelect) this.options.onSelect(this.currentDate); }.bindAsEventListener(this); // Remove event key capture to allow use of arrow keys otherInput.onfocus = this.releaseKeys.bindAsEventListener(this); otherInput.onblur = this.captureKeys.bindAsEventListener(this); this.otherMinutes = otherInput; cell.appendChild(otherInput); // Padding cell if (!this.options.use24hrs) cell = row.insertCell(2); row = timeTable.insertRow(rows++); cell = row.insertCell(0); cell.colSpan = rowwidth; hr = document.createElement('hr'); Element.setStyle(hr, {'color': 'gray', 'backgroundColor': 'gray', 'height': '1px', 'border': '0', 'marginTop': '3px', 'marginBottom': '3px', 'padding': '0'}); cell.appendChild(hr); row = timeTable.insertRow(rows++); cell = row.insertCell(0); cell.colSpan = rowwidth; selectButton = document.createElement('input'); selectButton.type = 'button'; if (this.options.datePicker) selectButton.value = this.tr('Select Date and Time'); else selectButton.value = this.tr('Select Time'); selectButton.onclick = function(e) { this.options.onSelect && this.options.onSelect(this.currentDate); }.bindAsEventListener(this); cell.appendChild(selectButton); } else { calCont.appendChild(calTable); } return calCont; }, createCalendar: function(date) { this.currentDate = date; this.currentDays = []; var today = new Date(); var previousYear = new Date(date.getFullYear() - 1, date.getMonth(), 1) var previousMonth = new Date(date.getFullYear(), date.getMonth() - 1, 1) var nextMonth = new Date(date.getFullYear(), date.getMonth() + 1, 1) var nextYear = new Date(date.getFullYear() + 1, date.getMonth(), 1) var row; var cell; var rows = 0; var calTable = document.createElement('table'); calTable.cellSpacing = 0; calTable.cellPadding = 0; calTable.border = 0; row = calTable.insertRow(rows++); row.className = 'monthLabel'; cell = row.insertCell(0); cell.colSpan = 7; cell.innerHTML = this.monthName(date.getMonth()) + ' ' + date.getFullYear(); row = calTable.insertRow(rows++); row.className = 'navigation'; cell = row.insertCell(0); cell.className = 'navbutton'; cell.title = this.monthName(previousYear.getMonth()) + ' ' + previousYear.getFullYear(); cell.onclick = this.movePreviousYearListener(); cell.innerHTML = '<<'; cell = row.insertCell(1); cell.className = 'navbutton'; cell.title = this.monthName(previousMonth.getMonth()) + ' ' + previousMonth.getFullYear(); cell.onclick = this.movePreviousMonthListener(); cell.innerHTML = '<'; cell = row.insertCell(2); cell.colSpan = 3; cell.className = 'navbutton'; cell.title = today.getDate() + ' ' + this.monthName(today.getMonth()) + ' ' + today.getFullYear(); cell.onclick = this.dateClickedListener(today, true); if (this.options.timePicker) cell.innerHTML = this.tr('Now'); else cell.innerHTML = this.tr('Today'); cell = row.insertCell(3); cell.className = 'navbutton'; cell.title = this.monthName(nextMonth.getMonth()) + ' ' + nextMonth.getFullYear(); cell.onclick = this.moveNextMonthListener(); cell.innerHTML = '>'; cell = row.insertCell(4); cell.className = 'navbutton'; cell.title = this.monthName(nextYear.getMonth()) + ' ' + nextYear.getFullYear(); cell.onclick = this.moveNextYearListener(); cell.innerHTML = '>>'; row = calTable.insertRow(rows++); row.className = 'dayLabel'; for (var i = 0; i < 7; ++i){ cell = row.insertCell(i); cell.width = '14%'; cell.innerHTML = this.dayName((this.options.firstWeekDay + i) % 7); } row = null; var workDate = new Date(date.getFullYear(), date.getMonth(), 1); var day = workDate.getDay(); var j = 0; // Pad with previous month if (day != this.options.firstWeekDay) { row = calTable.insertRow(rows++); row.className = 'calendarRow'; workDate.setDate(workDate.getDate() - ((day - this.options.firstWeekDay + 7) % 7)); day = workDate.getDay(); while (workDate.getMonth() != date.getMonth()) { cell = row.insertCell(row.cells.length); this.assignDayClasses(cell, 'dayothermonth', workDate); cell.innerHTML = workDate.getDate(); cell.onclick = this.dateClickedListener(workDate); workDate.setDate(workDate.getDate() + 1); day = workDate.getDay(); } } // Display days while (workDate.getMonth() == date.getMonth()) { if (day == this.options.firstWeekDay) { row = calTable.insertRow(rows++); row.className = 'calendarRow'; } cell = row.insertCell(row.cells.length); this.assignDayClasses(cell, 'day', workDate); cell.innerHTML = workDate.getDate(); cell.onclick = this.dateClickedListener(workDate); this.currentDays[workDate.getDate()] = cell; workDate.setDate(workDate.getDate() + 1); day = workDate.getDay(); } // Pad with next month if (day != this.options.firstWeekDay) do { cell = row.insertCell(row.cells.length); this.assignDayClasses(cell, 'dayothermonth', workDate); cell.innerHTML = workDate.getDate(); var thisDate = new Date(workDate.getTime()); cell.onclick = this.dateClickedListener(workDate); workDate.setDate(workDate.getDate() + 1); day = workDate.getDay(); } while (workDate.getDay() != this.options.firstWeekDay); return calTable; }, movePreviousMonthListener: function() { return function(e) { var prevMonth = new Date( this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, this.currentDate.getDate(), this.currentDate.getHours(), this.currentDate.getMinutes()); if (prevMonth.getMonth() != (this.currentDate.getMonth() + 11) % 12) prevMonth.setDate(0); this.selectDate(prevMonth); }.bindAsEventListener(this); }, moveNextMonthListener: function() { return function(e) { var nextMonth = new Date( this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, this.currentDate.getDate(), this.currentDate.getHours(), this.currentDate.getMinutes()); if (nextMonth.getMonth() != (this.currentDate.getMonth() + 1) % 12) nextMonth.setDate(0); this.selectDate(nextMonth); }.bindAsEventListener(this); }, moveNextYearListener: function() { return function(e) { var nextYear = new Date( this.currentDate.getFullYear() + 1, this.currentDate.getMonth(), this.currentDate.getDate(), this.currentDate.getHours(), this.currentDate.getMinutes()); if (nextYear.getMonth() != this.currentDate.getMonth()) nextYear.setDate(0); this.selectDate(nextYear); }.bindAsEventListener(this); }, movePreviousYearListener: function() { return function(e) { var prevYear = new Date( this.currentDate.getFullYear() - 1, this.currentDate.getMonth(), this.currentDate.getDate(), this.currentDate.getHours(), this.currentDate.getMinutes()); if (prevYear.getMonth() != this.currentDate.getMonth()) prevYear.setDate(0); this.selectDate(prevYear); }.bindAsEventListener(this); }, dateClickedListener: function(date, timeOverride) { var dateCopy = new Date(date.getTime()); return function(e) { if (!timeOverride) { dateCopy.setHours(this.currentDate.getHours()); dateCopy.setMinutes(this.currentDate.getMinutes()); } this.dateClicked(dateCopy); }.bindAsEventListener(this); }, hourClickedListener: function(hour) { return function(e) { this.hourClicked(hour); }.bindAsEventListener(this); }, minuteClickedListener: function(minutes) { return function(e) { this.currentDate.setMinutes(minutes); this.dateClicked(this.currentDate); }.bindAsEventListener(this); }, amClickedListener: function() { return function(e) { if (this.selectedAmPm == this.pmCell) { this.currentDate.setHours(this.currentDate.getHours()-12); this.dateClicked(this.currentDate); } }.bindAsEventListener(this); }, pmClickedListener: function() { return function(e) { if (this.selectedAmPm == this.amCell) { this.currentDate.setHours(this.currentDate.getHours()+12); this.dateClicked(this.currentDate); } }.bindAsEventListener(this); }, assignDayClasses: function(cell, baseClass, date) { var today = new Date(); Element.addClassName(cell, baseClass); if (date.getFullYear() == today.getFullYear() && date.getMonth() == today.getMonth() && date.getDate() == today.getDate()) Element.addClassName(cell, 'today'); if (this.options.weekend.include(date.getDay())) Element.addClassName(cell, 'weekend'); }, monthName: function(month) { return this.options.months[month]; }, dayName: function(day) { return this.options.days[day]; }, dblClickHandler: function(e) { if(this.options.onSelect) this.options.onSelect(this.currentDate); Event.stop(e); }, clickHandler: function(e) { if(this.options.onClick) this.options.onClick(); Event.stop(e); }, hoverHandler: function(e) { if(this.options.onHover) this.options.onHover(date); }, keyHandler: function(e) { var days = 0; switch (e.keyCode){ case Event.KEY_RETURN: if (this.options.onSelect) this.options.onSelect(this.currentDate); break; case Event.KEY_LEFT: days = -1; break; case Event.KEY_UP: days = -7; break; case Event.KEY_RIGHT: days = 1; break; case Event.KEY_DOWN: days = 7; break; case 33: // PgUp var lastMonth = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth() - 1, this.currentDate.getDate()); days = -this.getDaysOfMonth(lastMonth); break; case 34: // PgDn days = this.getDaysOfMonth(this.currentDate); break; case 13: // enter-key (forms without submit buttons) this.dateClicked(this.currentDate); break; default: return; } if (days != 0) { var moveDate = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth(), this.currentDate.getDate() + days); moveDate.setHours(this.currentDate.getHours()); moveDate.setMinutes(this.currentDate.getMinutes()); this.selectDate(moveDate); } Event.stop(e); return false; }, getDaysOfMonth: function(date) { var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0); return lastDay.getDate(); }, getNextMonth: function(month, year, increment) { if (p_Month == 11) return [0, year + 1]; else return [month + 1, year]; }, getPrevMonth: function(month, year, increment) { if (p_Month == 0) return [11, year - 1]; else return [month - 1, year]; }, dateClicked: function(date) { if (date) { if (!this.options.timePicker && this.options.onSelect) this.options.onSelect(date); this.selectDate(date); } }, dateChanged: function(date) { if (date) { if ((!this.options.timePicker || !this.options.datePicker) && this.options.onHover) this.options.onHover(date); this.selectDate(date); } }, hourClicked: function(hour) { if (!this.options.use24hrs) { if (hour == 12) { if (this.selectedAmPm == this.amCell) hour = 0; } else if (this.selectedAmPm == this.pmCell) { hour += 12; } } this.currentDate.setHours(hour); this.dateClicked(this.currentDate); }, selectDate: function(date) { if (date) { if (this.options.datePicker) { if (date.getMonth() != this.currentDate.getMonth() || date.getFullYear() != this.currentDate.getFullYear()) this.setDate(date); else this.currentDate = date; if (date.getDate() < this.currentDays.length) { if (this.selectedDay) Element.removeClassName(this.selectedDay, 'current'); this.selectedDay = this.currentDays[date.getDate()]; Element.addClassName(this.selectedDay, 'current'); } } if (this.options.timePicker) { var hours = date.getHours(); if (this.selectedHour) Element.removeClassName(this.selectedHour, 'current'); if (this.options.use24hrs) this.selectedHour = this.hourCells[hours]; else this.selectedHour = this.hourCells[hours % 12 ? (hours % 12) - 1 : 11]; Element.addClassName(this.selectedHour, 'current'); if (this.selectedAmPm) Element.removeClassName(this.selectedAmPm, 'current'); this.selectedAmPm = (hours < 12 ? this.amCell : this.pmCell); Element.addClassName(this.selectedAmPm, 'current'); var minutes = date.getMinutes(); if (this.selectedMinute) Element.removeClassName(this.selectedMinute, 'current'); Element.removeClassName(this.otherMinutes, 'current'); if (minutes % this.minInterval == 0) { this.otherMinutes.value = ''; this.selectedMinute = this.minuteCells[minutes / this.minInterval]; Element.addClassName(this.selectedMinute, 'current'); } else { this.otherMinutes.value = minutes; Element.addClassName(this.otherMinutes, 'current'); } } if (this.options.onHover) this.options.onHover(date); } } });