[evolvis-commits] r7082: add the Control. DatePicker ECMAscript library files↵ written by Jeremy Jongsma <jeremy at jongsma.org> under GNU GPL↵

mirabilos at evolvis.org mirabilos at evolvis.org
Wed Nov 17 16:15:24 CET 2010


Author: mirabilos
Date: 2010-11-17 16:15:23 +0100 (Wed, 17 Nov 2010)
New Revision: 7082

Added:
   trunk/gforge_base/evolvisforge/gforge/www/js/datepicker.js
   trunk/gforge_base/evolvisforge/gforge/www/js/prototype-base-extensions.js
   trunk/gforge_base/evolvisforge/gforge/www/js/prototype-date-extensions.js
   trunk/gforge_base/evolvisforge/gforge/www/themes/css/datepicker.css
Log:
add the Control.DatePicker ECMAscript library files
written by Jeremy Jongsma <jeremy at jongsma.org> under GNU GPL


Added: trunk/gforge_base/evolvisforge/gforge/www/js/datepicker.js
===================================================================
--- trunk/gforge_base/evolvisforge/gforge/www/js/datepicker.js	                        (rev 0)
+++ trunk/gforge_base/evolvisforge/gforge/www/js/datepicker.js	2010-11-17 15:15:23 UTC (rev 7082)
@@ -0,0 +1,923 @@
+/*
+ * 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 at jongsma.org)
+ * Published under the GNU GPL
+ */
+
+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) {
+			this.element.style.background = '#fff url('+this.options.icon+') right center no-repeat';
+			// Prevent text writing over icon
+			this.element.style.paddingRight = '20px';
+		}
+		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) {
+			if(this.element.onchange)
+				this.element.onchange();
+			this.datepicker.releaseKeys();
+			Element.remove(this.datepicker.element);
+			Event.stopObserving(document, 'click', this.hidePickerListener, true);
+			this.pickerActive = false;
+			Control.DatePicker.activePicker = null;
+		}
+	},
+	scrollOffset: function(element) {
+		var valueT = 0, valueL = 0;
+		do {
+			if (element.tagName == 'BODY') break;
+			valueT += element.scrollTop  || 0;
+			valueL += element.scrollLeft || 0;
+			element = element.parentNode;
+		} while (element);
+		return Element._returnOffset(valueL, valueT);
+	},
+	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;
+
+			// Find real page position
+			/*
+			var pos = this.element.cumulativeOffset();
+			if (!/MSIE 8/.test(navigator.userAgent)) {
+				// IE seems to account for scrollTop in offsetTop already
+				var scroll = this.scrollOffset(this.element);
+				pos[0] -= scroll[0] + document.body.scrollTop;
+				pos[1] -= scroll[1] + document.body.scrollLeft;
+			}
+			*/
+			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.position = 'absolute';
+			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'
+		},
+		'din5008_optional': {
+			dateTimeFormat: 'dd.MM.yyyy HH:mm',
+			dateFormat: 'dd.MM.yyyy',
+			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['de_optional'] = i18n.createLocale('din5008_optional', '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 = '<i>'+this.tr('Exact minutes')+':</i>';
+
+			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)) {
+							inputTimeout = setTimeout(function() {
+									this.currentDate.setMinutes(otherInput.value);
+									this.dateChanged(this.currentDate);
+								}.bind(this), 500);
+						}
+					}.bindAsEventListener(this);
+			otherInput.onkeydown = function(e) {
+						if (e.keyCode == Event.KEY_RETURN)
+							if (this.options.onSelect) this.options.onSelect(this.currentDate);
+						if (inputTimeout)
+							clearTimeout(inputTimeout)
+					}.bindAsEventListener(this);
+			// Remove event key capture to allow use of arrow keys
+			otherInput.onclick = otherInput.select;
+			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 = '&lt;&lt;';
+
+		cell = row.insertCell(1);
+		cell.className = 'navbutton';
+		cell.title = this.monthName(previousMonth.getMonth()) + ' ' + previousMonth.getFullYear();
+		cell.onclick = this.movePreviousMonthListener();
+		cell.innerHTML = '&lt;';
+
+		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 = '&gt;';
+
+		cell = row.insertCell(4);
+		cell.className = 'navbutton';
+		cell.title = this.monthName(nextYear.getMonth()) + ' ' + nextYear.getFullYear();
+		cell.onclick = this.moveNextYearListener();
+		cell.innerHTML = '&gt;&gt;';
+
+		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);
+		}
+	}
+});

Added: trunk/gforge_base/evolvisforge/gforge/www/js/prototype-base-extensions.js
===================================================================
--- trunk/gforge_base/evolvisforge/gforge/www/js/prototype-base-extensions.js	                        (rev 0)
+++ trunk/gforge_base/evolvisforge/gforge/www/js/prototype-base-extensions.js	2010-11-17 15:15:23 UTC (rev 7082)
@@ -0,0 +1,27 @@
+/**
+ * extensions to the Prototype library
+ * by Jeremy Jongsma
+ */
+
+Hash.prototype.without = function() {
+    var values = $A(arguments);
+	var retHash = $H();
+    this.each(function(entry) {
+		if(!values.include(entry.key))
+			retHash.set(entry.key, entry.value);
+    });
+	return retHash;
+}
+
+Element.insertAfter = function(insert, element) {
+	if (element.nextSibling) element.parentNode.insertBefore(insert, element.nextSibling);
+	else element.parentNode.appendChild(insert);
+}
+
+// Fix exceptions thrown thrown when removing an element with no parent
+Element._remove = Element.remove;
+Element.remove = function(element) {
+	element = $(element);
+	if (element.parentNode)
+		return Element._remove(element);
+}

Added: trunk/gforge_base/evolvisforge/gforge/www/js/prototype-date-extensions.js
===================================================================
--- trunk/gforge_base/evolvisforge/gforge/www/js/prototype-date-extensions.js	                        (rev 0)
+++ trunk/gforge_base/evolvisforge/gforge/www/js/prototype-date-extensions.js	2010-11-17 15:15:23 UTC (rev 7082)
@@ -0,0 +1,232 @@
+/* part of datepicker */
+
+DateFormat = Class.create();
+Object.extend(DateFormat, {
+	MONTH_NAMES: ['January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
+	DAY_NAMES: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
+	LZ: function(x) {return(x<0||x>9?"":"0")+x},
+	compareDates: function(date1,dateformat1,date2,dateformat2) {
+		var d1=DateFormat.parseFormat(date1,dateformat1);
+		var d2=DateFormat.parseFormat(date2,dateformat2);
+		if (d1==0 || d2==0) return -1;
+		else if (d1 > d2) return 1;
+		return 0;
+	},
+	format: function(date,format) {
+		format=format+"";
+		var result="";
+		var i_format=0;
+		var c="";
+		var token="";
+		var y=date.getYear()+"";
+		var M=date.getMonth()+1;
+		var d=date.getDate();
+		var E=date.getDay();
+		var H=date.getHours();
+		var m=date.getMinutes();
+		var s=date.getSeconds();
+		var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
+		// Convert real date parts into formatted versions
+		var value=new Object();
+		if (y.length < 4) {y=""+(y-0+1900);}
+		value["y"]=""+y;
+		value["yyyy"]=y;
+		value["yy"]=y.substring(2,4);
+		value["M"]=M;
+		value["MM"]=DateFormat.LZ(M);
+		value["MMM"]=DateFormat.MONTH_NAMES[M-1];
+		value["NNN"]=DateFormat.MONTH_NAMES[M+11];
+		value["d"]=d;
+		value["dd"]=DateFormat.LZ(d);
+		value["E"]=DateFormat.DAY_NAMES[E+7];
+		value["EE"]=DateFormat.DAY_NAMES[E];
+		value["H"]=H;
+		value["HH"]=DateFormat.LZ(H);
+		if (H==0){value["h"]=12;}
+		else if (H>12){value["h"]=H-12;}
+		else {value["h"]=H;}
+		value["hh"]=DateFormat.LZ(value["h"]);
+		if (H>11){value["K"]=H-12;} else {value["K"]=H;}
+		value["k"]=H+1;
+		value["KK"]=DateFormat.LZ(value["K"]);
+		value["kk"]=DateFormat.LZ(value["k"]);
+		if (H > 11) { value["a"]="PM"; }
+		else { value["a"]="AM"; }
+		value["m"]=m;
+		value["mm"]=DateFormat.LZ(m);
+		value["s"]=s;
+		value["ss"]=DateFormat.LZ(s);
+		while (i_format < format.length) {
+			c=format.charAt(i_format);
+			token="";
+			while ((format.charAt(i_format)==c) && (i_format < format.length))
+				token += format.charAt(i_format++);
+			if (value[token] != null) result += value[token];
+			else result += token;
+		}
+		return result;
+	},
+	_isInteger: function(val) {
+		var digits="1234567890";
+		for (var i=0; i < val.length; i++)
+			if (digits.indexOf(val.charAt(i))==-1) return false;
+		return true;
+	},
+	_getInt: function(str,i,minlength,maxlength) {
+		for (var x=maxlength; x>=minlength; x--) {
+			var token=str.substring(i,i+x);
+			if (token.length < minlength) return null;
+			if (DateFormat._isInteger(token)) return token;
+		}
+		return null;
+	},
+	parseFormat: function(val,format) {
+		val=val+"";
+		format=format+"";
+		var i_val=0;
+		var i_format=0;
+		var c="";
+		var token="";
+		var token2="";
+		var x,y;
+		var now=new Date();
+		var year=now.getYear();
+		var month=now.getMonth()+1;
+		var date=1;
+		var hh=now.getHours();
+		var mm=now.getMinutes();
+		var ss=now.getSeconds();
+		var ampm="";
+		
+		while (i_format < format.length) {
+			// Get next token from format string
+			c=format.charAt(i_format);
+			token="";
+			while ((format.charAt(i_format)==c) && (i_format < format.length))
+				token += format.charAt(i_format++);
+			// Extract contents of value based on format token
+			if (token=="yyyy" || token=="yy" || token=="y") {
+				if (token=="yyyy") x=4;y=4;
+				if (token=="yy") x=2;y=2;
+				if (token=="y") x=2;y=4;
+				year=DateFormat._getInt(val,i_val,x,y);
+				if (year==null) return 0;
+				i_val += year.length;
+				if (year.length==2) {
+					if (year > 70) year=1900+(year-0);
+					else year=2000+(year-0);
+				}
+			} else if (token=="MMM"||token=="NNN") {
+				month=0;
+				for (var i=0; i<DateFormat.MONTH_NAMES.length; i++) {
+					var month_name=DateFormat.MONTH_NAMES[i];
+					if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
+						if (token=="MMM"||(token=="NNN"&&i>11)) {
+							month=i+1;
+							if (month>12) month -= 12;
+							i_val += month_name.length;
+							break;
+						}
+					}
+				}
+				if ((month < 1)||(month>12)) return 0;
+			} else if (token=="EE"||token=="E") {
+				for (var i=0; i<DateFormat.DAY_NAMES.length; i++) {
+					var day_name=DateFormat.DAY_NAMES[i];
+					if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
+						i_val += day_name.length;
+						break;
+					}
+				}
+			} else if (token=="MM"||token=="M") {
+				month=DateFormat._getInt(val,i_val,token.length,2);
+				if(month==null||(month<1)||(month>12)) return 0;
+				i_val+=month.length;
+			} else if (token=="dd"||token=="d") {
+				date=DateFormat._getInt(val,i_val,token.length,2);
+				if(date==null||(date<1)||(date>31)) return 0;
+				i_val+=date.length;
+			} else if (token=="hh"||token=="h") {
+				hh=DateFormat._getInt(val,i_val,token.length,2);
+				if(hh==null||(hh<1)||(hh>12)) return 0;
+				i_val+=hh.length;
+			} else if (token=="HH"||token=="H") {
+				hh=DateFormat._getInt(val,i_val,token.length,2);
+				if(hh==null||(hh<0)||(hh>23)) return 0;
+				i_val+=hh.length;
+			} else if (token=="KK"||token=="K") {
+				hh=DateFormat._getInt(val,i_val,token.length,2);
+				if(hh==null||(hh<0)||(hh>11)) return 0;
+				i_val+=hh.length;
+			} else if (token=="kk"||token=="k") {
+				hh=DateFormat._getInt(val,i_val,token.length,2);
+				if(hh==null||(hh<1)||(hh>24)) return 0;
+				i_val+=hh.length;hh--;
+			} else if (token=="mm"||token=="m") {
+				mm=DateFormat._getInt(val,i_val,token.length,2);
+				if(mm==null||(mm<0)||(mm>59)) return 0;
+				i_val+=mm.length;
+			} else if (token=="ss"||token=="s") {
+				ss=DateFormat._getInt(val,i_val,token.length,2);
+				if(ss==null||(ss<0)||(ss>59)) return 0;
+				i_val+=ss.length;
+			} else if (token=="a") {
+				if (val.substring(i_val,i_val+2).toLowerCase()=="am") ampm="AM";
+				else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") ampm="PM";
+				else return 0;
+				i_val+=2;
+			} else {
+				if (val.substring(i_val,i_val+token.length)!=token) return 0;
+				else i_val+=token.length;
+			}
+		}
+		// If there are any trailing characters left in the value, it doesn't match
+		if (i_val != val.length) return 0;
+		// Is date valid for month?
+		if (month==2) {
+			// Check for leap year
+			if (((year%4==0)&&(year%100 != 0)) || (year%400==0)) { // leap year
+				if (date > 29) return 0;
+			} else if (date > 28) {
+				return 0;
+			}
+		}
+		if ((month==4)||(month==6)||(month==9)||(month==11))
+			if (date > 30) return 0;
+		// Correct hours value
+		if (hh<12 && ampm=="PM") hh=hh-0+12;
+		else if (hh>11 && ampm=="AM") hh-=12;
+		var newdate=new Date(year,month-1,date,hh,mm,ss);
+		return newdate;
+	},
+	parse: function(val, format) {
+		if (format) {
+			return DateFormat.parseFormat(val, format);
+		} else {
+			var preferEuro=(arguments.length==2)?arguments[1]:false;
+			var generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
+			var monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
+			var dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
+			var checkList=[generalFormats,preferEuro?dateFirst:monthFirst,preferEuro?monthFirst:dateFirst];
+			var d=null;
+			for (var i=0; i<checkList.length; i++) {
+				var l=checkList[i];
+				for (var j=0; j<l.length; j++) {
+					d=DateFormat.parseFormat(val,l[j]);
+					if (d!=0) return new Date(d);
+				}
+			}
+			return null;
+		}
+	}
+});
+
+DateFormat.prototype = {
+	initialize: function(format) { this.format = format; },
+	parse: function(value) { return DateFormat.parseFormat(value, this.format); },
+	format: function(value) { return DateFormat.format(value, this.format); }
+}
+
+Date.prototype.format = function(format) {
+	return DateFormat.format(this, format);
+}

Added: trunk/gforge_base/evolvisforge/gforge/www/themes/css/datepicker.css
===================================================================
--- trunk/gforge_base/evolvisforge/gforge/www/themes/css/datepicker.css	                        (rev 0)
+++ trunk/gforge_base/evolvisforge/gforge/www/themes/css/datepicker.css	2010-11-17 15:15:23 UTC (rev 7082)
@@ -0,0 +1,113 @@
+/**
+ * Styles for DatePicker
+ * see www/js/datepicker.js for details
+ */
+
+.datepickerControl {
+	border:				1px solid #999999;
+	background-color:		#EEEEEE;
+	padding:			5px;
+}
+
+.datepickerControl td {
+	text-align:			center;
+	font-family:			sans-serif;
+	font-size:			11px;
+	padding:			1px;
+}
+
+.datepickerControl tr.monthLabel td {
+
+	color:				#000000;
+	background-color:		#FFFFFF;
+	border:				1px solid #999999;
+	font-weight:			bold;
+}
+
+.datepickerControl tr.navigation td {
+	cursor:				pointer;
+}
+
+.datepickerControl tr.navigation td:hover {
+	text-decoration:		underline;
+}
+
+.datepickerControl tr.dayLabel td {
+	/*
+	border:				1px solid #C0D8EA;
+	background-color:		#C0D8EA;
+	 */
+	border:				1px solid #003366;
+	background-color:		#003366;
+	color:				white;
+	font-weight:			bold;
+}
+
+.datepickerControl td.day,
+.datepickerControl td.dayothermonth {
+	color:				#000000;
+	cursor:				pointer;
+	background-color:		#FFFFFF;
+	border:				1px solid #EEEEEE;
+	width:				2em;
+}
+
+.datepickerControl td.dayothermonth {
+	color:				#999999;
+	font-style:			italic;
+}
+
+.datepickerControl td.day:hover {
+	background-color:		#EBE4C0;
+}
+
+.datepickerControl td.weekend {
+	background-color:		#CCCCCC;
+	font-style:			italic;
+}
+
+.datepickerControl td.today {
+	font-weight:			bold;
+}
+
+.datepickerControl td.hour {
+	cursor:				pointer;
+	background-color:		#FFFFFF;
+	border:				1px solid #EEEEEE;
+	width:				2em;
+}
+
+.datepickerControl td.minute {
+	cursor:				pointer;
+	background-color:		#FFFFFF;
+	border:				1px solid #EEEEEE;
+	width:				2em;
+}
+
+.datepickerControl td input,
+.datepickerControl td button {
+	font-size:			11px;
+	padding:			0;
+	border:				1px solid #999999;
+	text-align:			center;
+}
+
+.datepickerControl td.ampm {
+	cursor:				pointer;
+	background-color:		#CCCCCC;
+	border:				1px solid #EEEEEE;
+	width:				2em;
+}
+
+.datepickerControl td.current {
+	font-weight:			bold;
+	background-color:		#EBC2C0;
+}
+
+.datepickerControl input.current {
+	background-color:		#EBC2C0;
+}
+
+.datepickerControl td.current:hover {
+	background-color:		#EBC2C0;
+}



More information about the evolvis-commits mailing list