You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2006/03/11 21:55:35 UTC

svn commit: r385164 [15/32] - in /jakarta/tapestry/trunk: ./ .settings/ annotations/src/java/org/apache/tapestry/annotations/ annotations/src/test/org/apache/tapestry/annotations/ config/ contrib/src/documentation/content/xdocs/tapestry-contrib/Compone...

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/DatePicker.js.merge-left.r384672
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/DatePicker.js.merge-left.r384672?rev=385164&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/DatePicker.js.merge-left.r384672 (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/DatePicker.js.merge-left.r384672 Sat Mar 11 12:54:27 2006
@@ -0,0 +1,1024 @@
+//
+// calendar -- a javascript date picker designed for easy localization.
+//
+//
+//
+// Author: Per Norrman (pernorrman@telia.com)
+// 
+// Based on Tapestry 2.3-beta1 Datepicker by Paul Geerts
+// 
+// Thanks to:
+//     Vladimir [vyc@quorus-ms.ru] for fixing the IE6 zIndex problem.
+//
+// The normal setup would be to have one text field for displaying the 
+// selected date, and one button to show/hide the date picker control.
+// This is  the recommended javascript code:
+// 
+//	<script language="javascript">
+//		var cal;
+//
+//		function init() {
+//			cal = new Calendar();
+//			cal.setIncludeWeek(true);
+//			cal.setFormat("yyyy-MM-dd");
+//			cal.setMonthNames(.....);
+//			cal.setShortMonthNames(....);
+//			cal.create();
+//			
+//			document.form.button1.onclick = function() {
+//				cal.toggle(document.form.button1);
+//			}
+//			cal.onchange = function() {
+//				document.form.textfield1.value  = cal.formatDate();
+//			}
+//		}
+//	</script>
+//
+// The init function is invoked when the body is loaded.
+//
+//
+
+function Calendar(date) {
+	if (arguments.length == 0) {
+		this._currentDate = new Date();
+		this._selectedDate = null;
+	}
+	else {
+		this._currentDate = new Date(date);
+		this._selectedDate = new Date(date);
+	}
+
+	// Accumulated days per month, for normal and for leap years.
+	// Used in week number calculations.	
+    Calendar.NUM_DAYS = [0,31,59,90,120,151,181,212,243,273,304,334];
+    
+    Calendar.LEAP_NUM_DAYS = [0,31,60,91,121,152,182,213,244,274,305,335];
+    
+
+	this._bw = new bw_check();
+	this._showing = false;	
+	this._includeWeek = false;
+	this._hideOnSelect = true;
+	this._alwaysVisible = false;
+	
+	this._dateSlot = new Array(42);
+	this._weekSlot = new Array(6);
+	
+	this._firstDayOfWeek = 1;
+	this._minimalDaysInFirstWeek = 4;
+	
+	this._monthNames = [	
+		"January",		"February",		"March",	"April",
+		"May",			"June",			"July",		"August",
+		"September",	"October",		"November",	"December"
+	];
+	
+	this._shortMonthNames = [ 
+		"jan", "feb", "mar", "apr", "may", "jun", 
+		"jul", "aug", "sep", "oct", "nov", "dec"
+	];
+	
+	// Week days start with Sunday=0, ... Saturday=6
+	this._weekDayNames = [
+		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" 
+	];
+	
+	this._shortWeekDayNames = 
+		["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];
+	
+	this._defaultFormat = "yyyy-MM-dd";
+	
+	this._format = this._defaultFormat; 
+
+	this._calDiv = null;
+	
+	this._clearButtonLabel = "Clear";
+	
+}
+
+/**
+ *	CREATE the Calendar DOM element
+ */
+Calendar.prototype.create = function() {
+	var div;
+	var table;
+	var tbody;
+	var tr;
+	var td;
+	var dp = this;
+	
+	// Create the top-level div element
+	this._calDiv = document.createElement("div");
+	this._calDiv.className = "calendar";
+	this._calDiv.style.position = "absolute";
+	this._calDiv.style.display = "none";
+	this._calDiv.style.border = "1px solid WindowText";
+	this._calDiv.style.textAlign = "center";
+	this._calDiv.style.background = "Window";
+	this._calDiv.style.zIndex = "400";
+	
+	
+	// header div
+	div = document.createElement("div");
+	div.className = "calendarHeader";
+	div.style.background = "ActiveCaption";
+	div.style.padding = "3px";
+	div.style.borderBottom = "1px solid WindowText";
+	this._calDiv.appendChild(div);
+	
+	table = document.createElement("table");
+	table.style.cellSpacing = 0;
+	div.appendChild(table);
+	
+	tbody = document.createElement("tbody");
+	table.appendChild(tbody);
+	
+	tr = document.createElement("tr");
+	tbody.appendChild(tr);
+	
+	// Previous Month Button
+	td = document.createElement("td");
+	this._previousMonth = document.createElement("button");
+	this._previousMonth.className = "prevMonthButton"
+	this._previousMonth.appendChild(document.createTextNode("<<"));
+	//this._previousMonth.appendChild(document.createTextNode(String.fromCharCode(9668)));
+	td.appendChild(this._previousMonth);
+	tr.appendChild(td);
+	
+	
+	
+	//
+	// Create the month drop down 
+	//
+	td = document.createElement("td");
+	td.className = "labelContainer";
+	tr.appendChild(td);
+	this._monthSelect = document.createElement("select");
+    for (var i = 0 ; i < this._monthNames.length ; i++) {
+        var opt = document.createElement("option");
+        opt.innerHTML = this._monthNames[i];
+        opt.value = i;
+        if (i == this._currentDate.getMonth()) {
+            opt.selected = true;
+        }
+        this._monthSelect.appendChild(opt);
+    }
+	td.appendChild(this._monthSelect);
+	
+
+	// 
+	// Create the year drop down
+	//
+	td = document.createElement("td");
+	td.className = "labelContainer";
+	tr.appendChild(td);
+	this._yearSelect = document.createElement("select");
+	for(var i=1920; i < 2050; ++i) {
+		var opt = document.createElement("option");
+		opt.innerHTML = i;
+		opt.value = i;
+		if (i == this._currentDate.getFullYear()) {
+			opt.selected = false;
+		}
+		this._yearSelect.appendChild(opt);
+	}
+	td.appendChild(this._yearSelect);
+	
+	
+	td = document.createElement("td");
+	this._nextMonth = document.createElement("button");
+	this._nextMonth.appendChild(document.createTextNode(">>"));
+	//this._nextMonth.appendChild(document.createTextNode(String.fromCharCode(9654)));
+	this._nextMonth.className = "nextMonthButton";
+	td.appendChild(this._nextMonth);
+	tr.appendChild(td);
+	
+	// Calendar body
+	div = document.createElement("div");
+	div.className = "calendarBody";
+	this._calDiv.appendChild(div);
+	this._table = div;
+	
+	// Create the inside of calendar body	
+	
+	var text;
+	table = document.createElement("table");
+	//table.style.width="100%";
+	table.className = "grid";
+	table.style.font 	 	= "small-caption";
+	table.style.fontWeight 	= "normal";
+	table.style.textAalign	= "center";
+	table.style.color		= "WindowText";
+	table.style.cursor		= "default";
+	table.cellPadding		= "3";
+	table.cellSpacing		= "0";
+	
+    div.appendChild(table);
+	var thead = document.createElement("thead");
+	table.appendChild(thead);
+	tr = document.createElement("tr");
+	thead.appendChild(tr);
+	
+	// weekdays header
+	if (this._includeWeek) {
+		td = document.createElement("th");
+		text = document.createTextNode("w");
+		td.appendChild(text);
+		td.className = "weekNumberHead";
+		td.style.textAlign = "left";
+		tr.appendChild(td);
+	}
+	for(i=0; i < 7; ++i) {
+		td = document.createElement("th");
+		text = document.createTextNode(this._shortWeekDayNames[(i+this._firstDayOfWeek)%7]);
+		td.appendChild(text);
+		td.className = "weekDayHead";
+		td.style.fontWeight = "bold";
+		td.style.borderBottom = "1px solid WindowText";
+		tr.appendChild(td);
+	}
+	
+	// Date grid
+	tbody = document.createElement("tbody");
+	table.appendChild(tbody);
+	
+	for(week=0; week<6; ++week) {
+		tr = document.createElement("tr");
+		tbody.appendChild(tr);
+
+		if (this._includeWeek) {
+			td = document.createElement("td");
+			td.className = "weekNumber";
+			td.style.fontWeight = "normal";
+			td.style.borderRight = "1px solid WindowText";
+			td.style.textAlign = "left";
+			text = document.createTextNode(String.fromCharCode(160));
+			td.appendChild(text);
+            //setCursor(td);
+            td.align="center";
+			tr.appendChild(td);
+			var tmp = new Object();
+			tmp.tag = "WEEK";
+			tmp.value = -1;
+			tmp.data = text;
+			this._weekSlot[week] = tmp;
+		}
+
+		for(day=0; day<7; ++day) {
+			td = document.createElement("td");
+			text = document.createTextNode(String.fromCharCode(160));
+			td.appendChild(text);
+            setCursor(td);
+            td.align="center";
+            td.style.fontWeight="normal";
+            
+			tr.appendChild(td);
+			var tmp = new Object();
+			tmp.tag = "DATE";
+			tmp.value = -1;
+			tmp.data = text;
+			this._dateSlot[(week*7)+day] = tmp;
+			
+		}
+	}
+	
+	// Calendar Footer
+	div = document.createElement("div");
+	div.className = "calendarFooter";
+	this._calDiv.appendChild(div);
+	
+	table = document.createElement("table");
+	//table.style.width="100%";
+	table.className = "footerTable";
+	table.cellSpacing = 0;
+	div.appendChild(table);
+	
+	tbody = document.createElement("tbody");
+	table.appendChild(tbody);
+	
+	tr = document.createElement("tr");
+	tbody.appendChild(tr);
+
+	//
+	// The TODAY button	
+	//
+	td = document.createElement("td");
+	this._todayButton = document.createElement("button");
+	var today = new Date();
+	var buttonText = today.getDate() + " " + this._monthNames[today.getMonth()] + ", " + today.getFullYear();
+	this._todayButton.appendChild(document.createTextNode(buttonText));
+	td.appendChild(this._todayButton);
+	tr.appendChild(td);
+	
+	//
+	// The CLEAR button
+	//
+	td = document.createElement("td");
+	this._clearButton = document.createElement("button");
+	var today = new Date();
+	this._clearButton.appendChild(document.createTextNode(this._clearButtonLabel));
+	td.appendChild(this._clearButton);
+	tr.appendChild(td);
+	
+	
+	this._update();
+	this._updateHeader();
+	
+
+
+	// IE55+ extension		
+	this._previousMonth.hideFocus = true;
+	this._nextMonth.hideFocus = true;
+	this._todayButton.hideFocus = true;
+	// end IE55+ extension
+	
+	// hook up events
+	// buttons
+	this._previousMonth.onclick = function () {
+		dp.prevMonth();
+	};
+
+	this._nextMonth.onclick = function () {
+		dp.nextMonth();
+	};
+
+	this._todayButton.onclick = function () {
+		dp.setSelectedDate(new Date());
+		dp.hide();
+	};
+
+	this._clearButton.onclick = function () {
+		dp.clearSelectedDate();
+		dp.hide();
+	};
+	
+
+	this._calDiv.onselectstart = function () {
+		return false;
+	};
+	
+	this._table.onclick = function (e) {
+		// find event
+		if (e == null) e = document.parentWindow.event;
+		
+		// find td
+		var el = e.target != null ? e.target : e.srcElement;
+		while (el.nodeType != 1)
+			el = el.parentNode;
+		while (el != null && el.tagName && el.tagName.toLowerCase() != "td")
+			el = el.parentNode;
+		
+		// if no td found, return
+		if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td")
+			return;
+		
+		var d = new Date(dp._currentDate);
+		var n = Number(el.firstChild.data);
+		if (isNaN(n) || n <= 0 || n == null)
+			return;
+		
+		if (el.className == "weekNumber")
+			return;
+			
+		d.setDate(n);
+		dp.setSelectedDate(d);
+
+		if (!dp._alwaysVisible && dp._hideOnSelect) {
+			dp.hide();
+		}
+		
+	};
+	
+	
+	this._calDiv.onkeydown = function (e) {
+		if (e == null) e = document.parentWindow.event;
+		var kc = e.keyCode != null ? e.keyCode : e.charCode;
+
+		if(kc == 13) {
+			var d = new Date(dp._currentDate).valueOf();
+			dp.setSelectedDate(d);
+
+			if (!dp._alwaysVisible && dp._hideOnSelect) {
+				dp.hide();
+			}
+			return false;
+		}
+			
+		
+		if (kc < 37 || kc > 40) return true;
+		
+		var d = new Date(dp._currentDate).valueOf();
+		if (kc == 37) // left
+			d -= 24 * 60 * 60 * 1000;
+		else if (kc == 39) // right
+			d += 24 * 60 * 60 * 1000;
+		else if (kc == 38) // up
+			d -= 7 * 24 * 60 * 60 * 1000;
+		else if (kc == 40) // down
+			d += 7 * 24 * 60 * 60 * 1000;
+
+		dp.setCurrentDate(new Date(d));
+		return false;
+	}
+	
+	// ie6 extension
+	this._calDiv.onmousewheel = function (e) {
+		if (e == null) e = document.parentWindow.event;
+		var n = - e.wheelDelta / 120;
+		var d = new Date(dp._currentDate);
+		var m = d.getMonth() + n;
+		d.setMonth(m);
+		
+		
+		dp.setCurrentDate(d);
+		
+		return false;
+	}
+
+	this._monthSelect.onchange = function(e) {
+		if (e == null) e = document.parentWindow.event;
+		e = getEventObject(e);
+		dp.setMonth(e.value);
+	}
+
+	this._monthSelect.onclick = function(e) {
+		if (e == null) e = document.parentWindow.event;
+		e = getEventObject(e);
+		e.cancelBubble = true;
+	}
+	
+	this._yearSelect.onchange = function(e) {
+		if (e == null) e = document.parentWindow.event;
+		e = getEventObject(e);
+		dp.setYear(e.value);
+	}
+
+
+	document.body.appendChild(this._calDiv);
+	
+	
+	return this._calDiv;
+}
+
+Calendar.prototype._update = function() {
+
+
+	// Calculate the number of days in the month for the selected date
+	var date = this._currentDate;
+	var today = toISODate(new Date());
+	
+	
+	var selected = "";
+	if (this._selectedDate != null) {
+		selected = toISODate(this._selectedDate);
+	}
+	var current = toISODate(this._currentDate);
+	var d1 = new Date(date.getFullYear(), date.getMonth(), 1);
+	var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1);
+	var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000));
+	
+	// Find out the weekDay index for the first of this month
+	var firstIndex = (d1.getDay() - this._firstDayOfWeek) % 7 ;
+    if (firstIndex < 0) {
+    	firstIndex += 7;
+    }
+	
+	var index = 0;
+	while (index < firstIndex) {
+		this._dateSlot[index].value = -1;
+		this._dateSlot[index].data.data = String.fromCharCode(160);
+		this._dateSlot[index].data.parentNode.className = "";
+		this._dateSlot[index].data.parentNode.style.fontWeight = "normal";
+		this._dateSlot[index].data.parentNode.style.border= "none";
+		index++;
+	}
+        
+    for (i = 1; i <= monthLength; i++, index++) {
+		this._dateSlot[index].value = i;
+		this._dateSlot[index].data.data = i;
+		this._dateSlot[index].data.parentNode.className = "";
+		this._dateSlot[index].data.parentNode.style.fontWeight = "normal";
+		this._dateSlot[index].data.parentNode.style.border= "none";
+		if (toISODate(d1) == today) {
+			this._dateSlot[index].data.parentNode.className = "today";
+			this._dateSlot[index].data.parentNode.style.fontWeight = "bold";
+		}
+		if (toISODate(d1) == current) {
+			this._dateSlot[index].data.parentNode.className += " current";
+			this._dateSlot[index].data.parentNode.style.border= "1px dotted WindowText";
+		}
+		if (toISODate(d1) == selected) {
+			this._dateSlot[index].data.parentNode.className += " selected";
+			this._dateSlot[index].data.parentNode.style.border= "1px solid WindowText";
+		}
+		d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1);
+	}
+	
+	var lastDateIndex = index;
+        
+    while(index < 42) {
+		this._dateSlot[index].value = -1;
+		this._dateSlot[index].data.data = String.fromCharCode(160);
+		this._dateSlot[index].data.parentNode.className = "";
+		this._dateSlot[index].data.parentNode.style.fontWeight = "normal";
+		this._dateSlot[index].data.parentNode.style.border= "none";
+		++index;
+	}
+	
+	// Week numbers
+	if (this._includeWeek) {
+		d1 = new Date(date.getFullYear(), date.getMonth(), 1);
+		for (i=0; i < 6; ++i) {
+			if (i == 5 && lastDateIndex < 36) {
+				this._weekSlot[i].data.data = String.fromCharCode(160);
+				this._weekSlot[i].data.parentNode.style.borderRight = "none";
+			} else {
+				week = weekNumber(this, d1);
+				this._weekSlot[i].data.data = week;
+				this._weekSlot[i].data.parentNode.style.borderRight = "1px solid WindowText";
+			}
+			d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+7);
+		}
+	}
+}
+
+Calendar.prototype.show = function(element) {
+	if(!this._showing) {
+		var p = getPoint(element);
+		this._calDiv.style.display = "block";
+		this._calDiv.style.top = (p.y + element.offsetHeight + 1) + "px";
+		this._calDiv.style.left = p.x + "px";
+		this._showing = true;
+		
+		/* -------- */
+	   	if( this._bw.ie6 )
+	   	{
+	     	dw = this._calDiv.offsetWidth;
+	     	dh = this._calDiv.offsetHeight;
+	     	var els = document.getElementsByTagName("body");
+	     	var body = els[0];
+	     	if( !body ) return;
+	 
+	    	//paste iframe under the modal
+		     var underDiv = this._calDiv.cloneNode(false); 
+		     underDiv.style.zIndex="390";
+		     underDiv.style.margin = "0px";
+		     underDiv.style.padding = "0px";
+		     underDiv.style.display = "block";
+		     underDiv.style.width = dw;
+		     underDiv.style.height = dh;
+		     underDiv.style.border = "1px solid WindowText";
+		     underDiv.innerHTML = "<iframe width=\"100%\" height=\"100%\" frameborder=\"0\"></iframe>";
+		     body.appendChild(underDiv);
+		     this._underDiv = underDiv;
+	   }
+		/* -------- */
+
+        if (this._calDiv.focus)
+          this._calDiv.focus();
+		
+	}
+};
+
+Calendar.prototype.hide = function() {   
+	if(this._showing) {
+		this._calDiv.style.display = "none";
+		this._showing = false;
+		if( this._bw.ie6 ) {
+		    if( this._underDiv ) this._underDiv.removeNode(true);
+		}
+	}
+}
+
+Calendar.prototype.toggle = function(element) {
+	if(this._showing) {
+		this.hide(); 
+	} else {
+		this.show(element);
+	}
+}
+
+
+
+Calendar.prototype.onchange = function() {};
+
+
+Calendar.prototype.setCurrentDate = function(date) {
+	if (date == null) {
+		return;
+	}
+
+	// if string or number create a Date object
+	if (typeof date == "string" || typeof date == "number") {
+		date = new Date(date);
+	}
+	
+	
+	// do not update if not really changed
+	if (this._currentDate.getDate() != date.getDate() ||
+		this._currentDate.getMonth() != date.getMonth() || 
+		this._currentDate.getFullYear() != date.getFullYear()) {
+		
+		this._currentDate = new Date(date);
+	
+		this._updateHeader();
+		this._update();
+		
+	}
+	
+}
+
+Calendar.prototype.setSelectedDate = function(date) {
+	this._selectedDate = new Date(date);
+	this.setCurrentDate(this._selectedDate);
+	if (typeof this.onchange == "function") {
+		this.onchange();
+	}
+}
+
+Calendar.prototype.clearSelectedDate = function() {
+	this._selectedDate = null;
+	if (typeof this.onchange == "function") {
+		this.onchange();
+	}
+}
+
+Calendar.prototype.getElement = function() {
+	return this._calDiv;
+}
+
+Calendar.prototype.setIncludeWeek = function(v) {
+	if (this._calDiv == null) {
+		this._includeWeek = v;
+	}
+}
+
+Calendar.prototype.setClearButtonLabel = function(v) {
+  this._clearButtonLabel = v;
+}
+
+Calendar.prototype.getSelectedDate = function () {
+	if (this._selectedDate == null) {
+		return null;
+	} else {
+		return new Date(this._selectedDate);
+	}
+}
+
+Calendar.prototype.initialize = function(monthNames, shortMonthNames, weekDayNames, shortWeekDayNames, format,
+  firstDayOfWeek, includeWeek, minimalDaysInFirstWeek, clearButtonLabel)
+{
+  this.setMonthNames(monthNames);
+  this.setShortMonthNames(shortMonthNames);
+  this.setWeekDayNames(weekDayNames);
+  this.setShortWeekDayNames(shortWeekDayNames);
+  this.setFormat(format);
+  this.setFirstDayOfWeek(firstDayOfWeek);
+  this.setIncludeWeek(includeWeek);
+  this.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
+  this.setClearButtonLabel(clearButtonLabel);
+  
+  this.create();
+}
+
+
+Calendar.prototype._updateHeader = function () {
+
+	// 
+	var options = this._monthSelect.options;
+	var m = this._currentDate.getMonth();
+	for(var i=0; i < options.length; ++i) {
+		options[i].selected = false;
+		if (options[i].value == m) {
+			options[i].selected = true;
+		}
+	}
+	
+	options = this._yearSelect.options;
+	var year = this._currentDate.getFullYear();
+	for(var i=0; i < options.length; ++i) {
+		options[i].selected = false;
+		if (options[i].value == year) {
+			options[i].selected = true;
+		}
+	}
+	
+}
+
+Calendar.prototype.setYear = function(year) {
+	var d = new Date(this._currentDate);
+	d.setFullYear(year);
+	this.setCurrentDate(d);
+}
+
+Calendar.prototype.setMonth = function (month) {
+	var d = new Date(this._currentDate);
+	d.setMonth(month);
+	this.setCurrentDate(d);
+}
+
+Calendar.prototype.nextMonth = function () {
+	this.setMonth(this._currentDate.getMonth()+1);
+}
+
+Calendar.prototype.prevMonth = function () {
+	this.setMonth(this._currentDate.getMonth()-1);
+}
+
+Calendar.prototype.setFirstDayOfWeek = function (nFirstWeekDay) {
+	this._firstDayOfWeek = nFirstWeekDay;
+}
+
+Calendar.prototype.getFirstDayOfWeek = function () {
+	return this._firstDayOfWeek;
+}
+
+Calendar.prototype.setMinimalDaysInFirstWeek = function(n) {
+	this._minimalDaysInFirstWeek = n;
+}
+
+
+Calendar.prototype.getMinimalDaysInFirstWeek = function () {
+	return this._minimalDaysInFirstWeek;
+}
+
+Calendar.prototype.setMonthNames = function(a) {
+	// sanity test
+	this._monthNames = a;
+}
+
+Calendar.prototype.setShortMonthNames = function(a) {
+	// sanity test
+	this._shortMonthNames = a;
+}
+
+Calendar.prototype.setWeekDayNames = function(a) {
+	// sanity test
+	this._weekDayNames = a;
+}
+
+Calendar.prototype.setShortWeekDayNames = function(a) {
+	// sanity test
+	this._shortWeekDayNames = a;
+}
+
+Calendar.prototype.getFormat = function() {
+	return this._format;
+}
+	
+Calendar.prototype.setFormat = function(f) {
+	this._format = f;
+}
+
+Calendar.prototype.formatDate = function() {  
+	if (this._selectedDate == null) {
+		return "";
+	}
+	
+    var bits = new Array();
+    // work out what each bit should be
+    var date = this._selectedDate;
+    bits['d'] = date.getDate();
+    bits['dd'] = pad(date.getDate(),2);
+    bits['ddd'] = this._shortWeekDayNames[date.getDay()];
+    bits['dddd'] = this._weekDayNames[date.getDay()];
+
+    bits['M'] = date.getMonth()+1;
+    bits['MM'] = pad(date.getMonth()+1,2);
+    bits['MMM'] = this._shortMonthNames[date.getMonth()];
+    bits['MMMM'] = this._monthNames[date.getMonth()];
+    
+    var yearStr = "" + date.getFullYear();
+    yearStr = (yearStr.length == 2) ? '19' + yearStr: yearStr;
+    bits['yyyy'] = yearStr;
+    bits['yy'] = bits['yyyy'].toString().substr(2,2);
+
+    bits['s'] = date.getSeconds();
+    bits['ss'] = pad(date.getSeconds(),2);
+    
+    bits['m'] = date.getMinutes();
+    bits['mm'] = pad(date.getMinutes(),2);
+    
+    bits['H'] = date.getHours();
+    bits['HH'] = pad(date.getHours(),2); 
+
+    // do some funky regexs to replace the format string
+    // with the real values
+    var frm = new String(this._format);
+    // TAPESTRY-669: Have to be very explicit about keys, to keep functions added
+    // to Array (by the Prototype library, if its around) from getting mixed in.
+    var keys = new Array('dddd','ddd','dd','d','MMMM','MMM','MM','M','yyyy','yy', 'ss', 's', 'mm',
+        'm', 'HH', 'H');
+    for (var i = 0; i < keys.length; i++) {
+       frm = eval("frm.replace(/" + keys[i] + "/,\"" + bits[keys[i]] + "\");");      
+    }     
+
+    return frm;
+}
+	
+                                                                                                       
+function isLeapYear(year) {
+	return ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0)));
+}
+
+function yearLength(year) {
+	if (isLeapYear(year))
+		return 366;
+	else
+		return 365;
+}
+
+function dayOfYear(date) {
+	var a = Calendar.NUM_DAYS;
+	if (isLeapYear(date.getFullYear())) {
+		a = Calendar.LEAP_NUM_DAYS;
+	}
+	var month = date.getMonth();
+	
+	return a[month] + date.getDate();
+}
+
+// ---------------------------------------------
+// Week number stuff
+// ---------------------------------------------
+
+function weekNumber(cal, date) {
+
+	var dow = date.getDay();
+	var doy = dayOfYear(date);
+	var year = date.getFullYear();
+
+	// Compute the week of the year.  Valid week numbers run from 1 to 52
+	// or 53, depending on the year, the first day of the week, and the
+	// minimal days in the first week.  Days at the start of the year may
+	// fall into the last week of the previous year; days at the end of
+	// the year may fall into the first week of the next year.
+	var relDow = (dow + 7 - cal.getFirstDayOfWeek()) % 7; // 0..6
+	var relDowJan1 = (dow - doy + 701 - cal.getFirstDayOfWeek()) % 7; // 0..6
+	var week = Math.floor((doy - 1 + relDowJan1) / 7); // 0..53
+	if ((7 - relDowJan1) >= cal.getMinimalDaysInFirstWeek()) {
+		++week;
+	}
+
+	if (doy > 359) { // Fast check which eliminates most cases
+		// Check to see if we are in the last week; if so, we need
+		// to handle the case in which we are the first week of the
+		// next year.
+		var lastDoy = yearLength(year);
+		var lastRelDow = (relDow + lastDoy - doy) % 7;
+		if (lastRelDow < 0) {
+			lastRelDow += 7;
+		}
+		if (((6 - lastRelDow) >= cal.getMinimalDaysInFirstWeek())
+			&& ((doy + 7 - relDow) > lastDoy)) {
+			week = 1;
+		}
+	} else if (week == 0) {
+		// We are the last week of the previous year.
+		var prevDoy = doy + yearLength(year - 1);
+		week = weekOfPeriod(cal, prevDoy, dow);
+	}
+
+	return week;
+}
+
+function weekOfPeriod(cal, dayOfPeriod, dayOfWeek) {
+	// Determine the day of the week of the first day of the period
+	// in question (either a year or a month).  Zero represents the
+	// first day of the week on this calendar.
+	var periodStartDayOfWeek =
+		(dayOfWeek - cal.getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
+	if (periodStartDayOfWeek < 0) {
+		periodStartDayOfWeek += 7;
+	}
+
+	// Compute the week number.  Initially, ignore the first week, which
+	// may be fractional (or may not be).  We add periodStartDayOfWeek in
+	// order to fill out the first week, if it is fractional.
+	var weekNo = Math.floor((dayOfPeriod + periodStartDayOfWeek - 1) / 7);
+
+	// If the first week is long enough, then count it.  If
+	// the minimal days in the first week is one, or if the period start
+	// is zero, we always increment weekNo.
+	if ((7 - periodStartDayOfWeek) >= cal.getMinimalDaysInFirstWeek()) {
+		++weekNo;
+	}
+
+	return weekNo;
+}
+
+
+
+
+function getEventObject(e) {  // utility function to retrieve object from event
+    if (navigator.appName == "Microsoft Internet Explorer") {
+        return e.srcElement;
+    } else {  // is mozilla/netscape
+        // need to crawl up the tree to get the first "real" element
+        // i.e. a tag, not raw text
+        var o = e.target;
+        while (!o.tagName) {
+            o = o.parentNode;
+        }
+        return o;
+    }
+}
+
+function addEvent(name, obj, funct) { // utility function to add event handlers
+
+    if (navigator.appName == "Microsoft Internet Explorer") {
+        obj.attachEvent("on"+name, funct);
+    } else {  // is mozilla/netscape
+        obj.addEventListener(name, funct, false);
+    }
+}
+
+
+function deleteEvent(name, obj, funct) { // utility function to delete event handlers
+
+    if (navigator.appName == "Microsoft Internet Explorer") {
+        obj.detachEvent("on"+name, funct);
+    } else {  // is mozilla/netscape
+        obj.removeEventListener(name, funct, false);
+    }
+}
+
+function setCursor(obj) {
+   if (navigator.appName == "Microsoft Internet Explorer") {
+        obj.style.cursor = "hand";
+    } else {  // is mozilla/netscape
+        obj.style.cursor = "pointer";
+    }
+}
+
+function Point(iX, iY)
+{
+   this.x = iX;
+   this.y = iY;
+}
+
+
+function getPoint(aTag)
+{
+   var oTmp = aTag;  
+   var point = new Point(0,0);
+  
+   do 
+   {
+      point.x += oTmp.offsetLeft;
+      point.y += oTmp.offsetTop;
+      oTmp = oTmp.offsetParent;
+   } 
+   while (oTmp.tagName != "BODY" && oTmp.tagName != "HTML");
+
+   return point;
+}
+
+function toISODate(date) {
+	var s = date.getFullYear();
+	var m = date.getMonth() + 1;
+	if (m < 10) {
+		m = "0" + m;
+	}
+	var day = date.getDate();
+	if (day < 10) {
+		day = "0" + day;
+	}
+	return String(s) + String(m) + String(day);
+	
+}
+
+function pad(number,X) {   // utility function to pad a number to a given width
+	X = (!X ? 2 : X);
+	number = ""+number;
+	while (number.length < X) {
+	    number = "0" + number;
+	}
+	return number;
+}
+
+function bw_check()
+{
+    var is_major = parseInt( navigator.appVersion );
+    this.nver = is_major;
+    this.ver = navigator.appVersion;
+    this.agent = navigator.userAgent;
+    this.dom = document.getElementById ? 1 : 0;
+    this.opera = window.opera ? 1 : 0;
+    this.ie5 = ( this.ver.indexOf( "MSIE 5" ) > -1 && this.dom && !this.opera ) ? 1 : 0;
+    this.ie6 = ( this.ver.indexOf( "MSIE 6" ) > -1 && this.dom && !this.opera ) ? 1 : 0;
+    this.ie4 = ( document.all && !this.dom && !this.opera ) ? 1 : 0;
+    this.ie = this.ie4 || this.ie5 || this.ie6;
+    this.mac = this.agent.indexOf( "Mac" ) > -1;
+    this.ns6 = ( this.dom && parseInt( this.ver ) >= 5 ) ? 1 : 0;
+    this.ie3 = ( this.ver.indexOf( "MSIE" ) && ( is_major < 4 ) );
+    this.hotjava = ( this.agent.toLowerCase().indexOf( 'hotjava' ) != -1 ) ? 1 : 0;
+    this.ns4 = ( document.layers && !this.dom && !this.hotjava ) ? 1 : 0;
+    this.bw = ( this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera );
+    this.ver3 = ( this.hotjava || this.ie3 );
+    this.opera7 = ( ( this.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( this.agent.toLowerCase().indexOf( 'opera/7' ) > -1 ) );
+    this.operaOld = this.opera && !this.opera7;
+    return this;
+};
+
+

Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/DatePicker.js.merge-right.r384672
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/DatePicker.js.merge-right.r384672?rev=385164&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/DatePicker.js.merge-right.r384672 (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/DatePicker.js.merge-right.r384672 Sat Mar 11 12:54:27 2006
@@ -0,0 +1,1024 @@
+//
+// calendar -- a javascript date picker designed for easy localization.
+//
+//
+//
+// Author: Per Norrman (pernorrman@telia.com)
+// 
+// Based on Tapestry 2.3-beta1 Datepicker by Paul Geerts
+// 
+// Thanks to:
+//     Vladimir [vyc@quorus-ms.ru] for fixing the IE6 zIndex problem.
+//
+// The normal setup would be to have one text field for displaying the 
+// selected date, and one button to show/hide the date picker control.
+// This is  the recommended javascript code:
+// 
+//	<script language="javascript">
+//		var cal;
+//
+//		function init() {
+//			cal = new Calendar();
+//			cal.setIncludeWeek(true);
+//			cal.setFormat("yyyy-MM-dd");
+//			cal.setMonthNames(.....);
+//			cal.setShortMonthNames(....);
+//			cal.create();
+//			
+//			document.form.button1.onclick = function() {
+//				cal.toggle(document.form.button1);
+//			}
+//			cal.onchange = function() {
+//				document.form.textfield1.value  = cal.formatDate();
+//			}
+//		}
+//	</script>
+//
+// The init function is invoked when the body is loaded.
+//
+//
+
+function Calendar(date) {
+	if (arguments.length == 0) {
+		this._currentDate = new Date();
+		this._selectedDate = null;
+	}
+	else {
+		this._currentDate = new Date(date);
+		this._selectedDate = new Date(date);
+	}
+
+	// Accumulated days per month, for normal and for leap years.
+	// Used in week number calculations.	
+    Calendar.NUM_DAYS = [0,31,59,90,120,151,181,212,243,273,304,334];
+    
+    Calendar.LEAP_NUM_DAYS = [0,31,60,91,121,152,182,213,244,274,305,335];
+    
+
+	this._bw = new bw_check();
+	this._showing = false;	
+	this._includeWeek = false;
+	this._hideOnSelect = true;
+	this._alwaysVisible = false;
+	
+	this._dateSlot = new Array(42);
+	this._weekSlot = new Array(6);
+	
+	this._firstDayOfWeek = 1;
+	this._minimalDaysInFirstWeek = 4;
+	
+	this._monthNames = [	
+		"January",		"February",		"March",	"April",
+		"May",			"June",			"July",		"August",
+		"September",	"October",		"November",	"December"
+	];
+	
+	this._shortMonthNames = [ 
+		"jan", "feb", "mar", "apr", "may", "jun", 
+		"jul", "aug", "sep", "oct", "nov", "dec"
+	];
+	
+	// Week days start with Sunday=0, ... Saturday=6
+	this._weekDayNames = [
+		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" 
+	];
+	
+	this._shortWeekDayNames = 
+		["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];
+	
+	this._defaultFormat = "yyyy-MM-dd";
+	
+	this._format = this._defaultFormat; 
+
+	this._calDiv = null;
+	
+	this._clearButtonLabel = "Clear";
+	
+}
+
+/**
+ *	CREATE the Calendar DOM element
+ */
+Calendar.prototype.create = function() {
+	var div;
+	var table;
+	var tbody;
+	var tr;
+	var td;
+	var dp = this;
+	
+	// Create the top-level div element
+	this._calDiv = document.createElement("div");
+	this._calDiv.className = "calendar";
+	this._calDiv.style.position = "absolute";
+	this._calDiv.style.display = "none";
+	this._calDiv.style.border = "1px solid WindowText";
+	this._calDiv.style.textAlign = "center";
+	this._calDiv.style.background = "Window";
+	this._calDiv.style.zIndex = "400";
+	
+	
+	// header div
+	div = document.createElement("div");
+	div.className = "calendarHeader";
+	div.style.background = "ActiveCaption";
+	div.style.padding = "3px";
+	div.style.borderBottom = "1px solid WindowText";
+	this._calDiv.appendChild(div);
+	
+	table = document.createElement("table");
+	table.style.cellSpacing = 0;
+	div.appendChild(table);
+	
+	tbody = document.createElement("tbody");
+	table.appendChild(tbody);
+	
+	tr = document.createElement("tr");
+	tbody.appendChild(tr);
+	
+	// Previous Month Button
+	td = document.createElement("td");
+	this._previousMonth = document.createElement("button");
+	this._previousMonth.className = "prevMonthButton"
+	this._previousMonth.appendChild(document.createTextNode("<<"));
+	//this._previousMonth.appendChild(document.createTextNode(String.fromCharCode(9668)));
+	td.appendChild(this._previousMonth);
+	tr.appendChild(td);
+	
+	
+	
+	//
+	// Create the month drop down 
+	//
+	td = document.createElement("td");
+	td.className = "labelContainer";
+	tr.appendChild(td);
+	this._monthSelect = document.createElement("select");
+    for (var i = 0 ; i < this._monthNames.length ; i++) {
+        var opt = document.createElement("option");
+        opt.innerHTML = this._monthNames[i];
+        opt.value = i;
+        if (i == this._currentDate.getMonth()) {
+            opt.selected = true;
+        }
+        this._monthSelect.appendChild(opt);
+    }
+	td.appendChild(this._monthSelect);
+	
+
+	// 
+	// Create the year drop down
+	//
+	td = document.createElement("td");
+	td.className = "labelContainer";
+	tr.appendChild(td);
+	this._yearSelect = document.createElement("select");
+	for(var i=1920; i < 2050; ++i) {
+		var opt = document.createElement("option");
+		opt.innerHTML = i;
+		opt.value = i;
+		if (i == this._currentDate.getFullYear()) {
+			opt.selected = false;
+		}
+		this._yearSelect.appendChild(opt);
+	}
+	td.appendChild(this._yearSelect);
+	
+	
+	td = document.createElement("td");
+	this._nextMonth = document.createElement("button");
+	this._nextMonth.appendChild(document.createTextNode(">>"));
+	//this._nextMonth.appendChild(document.createTextNode(String.fromCharCode(9654)));
+	this._nextMonth.className = "nextMonthButton";
+	td.appendChild(this._nextMonth);
+	tr.appendChild(td);
+	
+	// Calendar body
+	div = document.createElement("div");
+	div.className = "calendarBody";
+	this._calDiv.appendChild(div);
+	this._table = div;
+	
+	// Create the inside of calendar body	
+	
+	var text;
+	table = document.createElement("table");
+	//table.style.width="100%";
+	table.className = "grid";
+	table.style.font 	 	= "small-caption";
+	table.style.fontWeight 	= "normal";
+	table.style.textAalign	= "center";
+	table.style.color		= "WindowText";
+	table.style.cursor		= "default";
+	table.cellPadding		= "3";
+	table.cellSpacing		= "0";
+	
+    div.appendChild(table);
+	var thead = document.createElement("thead");
+	table.appendChild(thead);
+	tr = document.createElement("tr");
+	thead.appendChild(tr);
+	
+	// weekdays header
+	if (this._includeWeek) {
+		td = document.createElement("th");
+		text = document.createTextNode("w");
+		td.appendChild(text);
+		td.className = "weekNumberHead";
+		td.style.textAlign = "left";
+		tr.appendChild(td);
+	}
+	for(i=0; i < 7; ++i) {
+		td = document.createElement("th");
+		text = document.createTextNode(this._shortWeekDayNames[(i+this._firstDayOfWeek)%7]);
+		td.appendChild(text);
+		td.className = "weekDayHead";
+		td.style.fontWeight = "bold";
+		td.style.borderBottom = "1px solid WindowText";
+		tr.appendChild(td);
+	}
+	
+	// Date grid
+	tbody = document.createElement("tbody");
+	table.appendChild(tbody);
+	
+	for(week=0; week<6; ++week) {
+		tr = document.createElement("tr");
+		tbody.appendChild(tr);
+
+		if (this._includeWeek) {
+			td = document.createElement("td");
+			td.className = "weekNumber";
+			td.style.fontWeight = "normal";
+			td.style.borderRight = "1px solid WindowText";
+			td.style.textAlign = "left";
+			text = document.createTextNode(String.fromCharCode(160));
+			td.appendChild(text);
+            //setCursor(td);
+            td.align="center";
+			tr.appendChild(td);
+			var tmp = new Object();
+			tmp.tag = "WEEK";
+			tmp.value = -1;
+			tmp.data = text;
+			this._weekSlot[week] = tmp;
+		}
+
+		for(day=0; day<7; ++day) {
+			td = document.createElement("td");
+			text = document.createTextNode(String.fromCharCode(160));
+			td.appendChild(text);
+            setCursor(td);
+            td.align="center";
+            td.style.fontWeight="normal";
+            
+			tr.appendChild(td);
+			var tmp = new Object();
+			tmp.tag = "DATE";
+			tmp.value = -1;
+			tmp.data = text;
+			this._dateSlot[(week*7)+day] = tmp;
+			
+		}
+	}
+	
+	// Calendar Footer
+	div = document.createElement("div");
+	div.className = "calendarFooter";
+	this._calDiv.appendChild(div);
+	
+	table = document.createElement("table");
+	//table.style.width="100%";
+	table.className = "footerTable";
+	table.cellSpacing = 0;
+	div.appendChild(table);
+	
+	tbody = document.createElement("tbody");
+	table.appendChild(tbody);
+	
+	tr = document.createElement("tr");
+	tbody.appendChild(tr);
+
+	//
+	// The TODAY button	
+	//
+	td = document.createElement("td");
+	this._todayButton = document.createElement("button");
+	var today = new Date();
+	var buttonText = today.getDate() + " " + this._monthNames[today.getMonth()] + ", " + today.getFullYear();
+	this._todayButton.appendChild(document.createTextNode(buttonText));
+	td.appendChild(this._todayButton);
+	tr.appendChild(td);
+	
+	//
+	// The CLEAR button
+	//
+	td = document.createElement("td");
+	this._clearButton = document.createElement("button");
+	var today = new Date();
+	this._clearButton.appendChild(document.createTextNode(this._clearButtonLabel));
+	td.appendChild(this._clearButton);
+	tr.appendChild(td);
+	
+	
+	this._update();
+	this._updateHeader();
+	
+
+
+	// IE55+ extension		
+	this._previousMonth.hideFocus = true;
+	this._nextMonth.hideFocus = true;
+	this._todayButton.hideFocus = true;
+	// end IE55+ extension
+	
+	// hook up events
+	// buttons
+	this._previousMonth.onclick = function () {
+		dp.prevMonth();
+	};
+
+	this._nextMonth.onclick = function () {
+		dp.nextMonth();
+	};
+
+	this._todayButton.onclick = function () {
+		dp.setSelectedDate(new Date());
+		dp.hide();
+	};
+
+	this._clearButton.onclick = function () {
+		dp.clearSelectedDate();
+		dp.hide();
+	};
+	
+
+	this._calDiv.onselectstart = function () {
+		return false;
+	};
+	
+	this._table.onclick = function (e) {
+		// find event
+		if (e == null) e = document.parentWindow.event;
+		
+		// find td
+		var el = e.target != null ? e.target : e.srcElement;
+		while (el.nodeType != 1)
+			el = el.parentNode;
+		while (el != null && el.tagName && el.tagName.toLowerCase() != "td")
+			el = el.parentNode;
+		
+		// if no td found, return
+		if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td")
+			return;
+		
+		var d = new Date(dp._currentDate);
+		var n = Number(el.firstChild.data);
+		if (isNaN(n) || n <= 0 || n == null)
+			return;
+		
+		if (el.className == "weekNumber")
+			return;
+			
+		d.setDate(n);
+		dp.setSelectedDate(d);
+
+		if (!dp._alwaysVisible && dp._hideOnSelect) {
+			dp.hide();
+		}
+		
+	};
+	
+	
+	this._calDiv.onkeydown = function (e) {
+		if (e == null) e = document.parentWindow.event;
+		var kc = e.keyCode != null ? e.keyCode : e.charCode;
+
+		if(kc == 13) {
+			var d = new Date(dp._currentDate).valueOf();
+			dp.setSelectedDate(d);
+
+			if (!dp._alwaysVisible && dp._hideOnSelect) {
+				dp.hide();
+			}
+			return false;
+		}
+			
+		
+		if (kc < 37 || kc > 40) return true;
+		
+		var d = new Date(dp._currentDate).valueOf();
+		if (kc == 37) // left
+			d -= 24 * 60 * 60 * 1000;
+		else if (kc == 39) // right
+			d += 24 * 60 * 60 * 1000;
+		else if (kc == 38) // up
+			d -= 7 * 24 * 60 * 60 * 1000;
+		else if (kc == 40) // down
+			d += 7 * 24 * 60 * 60 * 1000;
+
+		dp.setCurrentDate(new Date(d));
+		return false;
+	}
+	
+	// ie6 extension
+	this._calDiv.onmousewheel = function (e) {
+		if (e == null) e = document.parentWindow.event;
+		var n = - e.wheelDelta / 120;
+		var d = new Date(dp._currentDate);
+		var m = d.getMonth() + n;
+		d.setMonth(m);
+		
+		
+		dp.setCurrentDate(d);
+		
+		return false;
+	}
+
+	this._monthSelect.onchange = function(e) {
+		if (e == null) e = document.parentWindow.event;
+		e = getEventObject(e);
+		dp.setMonth(e.value);
+	}
+
+	this._monthSelect.onclick = function(e) {
+		if (e == null) e = document.parentWindow.event;
+		e = getEventObject(e);
+		e.cancelBubble = true;
+	}
+	
+	this._yearSelect.onchange = function(e) {
+		if (e == null) e = document.parentWindow.event;
+		e = getEventObject(e);
+		dp.setYear(e.value);
+	}
+
+
+	document.body.appendChild(this._calDiv);
+	
+	
+	return this._calDiv;
+}
+
+Calendar.prototype._update = function() {
+
+
+	// Calculate the number of days in the month for the selected date
+	var date = this._currentDate;
+	var today = toISODate(new Date());
+	
+	
+	var selected = "";
+	if (this._selectedDate != null) {
+		selected = toISODate(this._selectedDate);
+	}
+	var current = toISODate(this._currentDate);
+	var d1 = new Date(date.getFullYear(), date.getMonth(), 1);
+	var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1);
+	var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000));
+	
+	// Find out the weekDay index for the first of this month
+	var firstIndex = (d1.getDay() - this._firstDayOfWeek) % 7 ;
+    if (firstIndex < 0) {
+    	firstIndex += 7;
+    }
+	
+	var index = 0;
+	while (index < firstIndex) {
+		this._dateSlot[index].value = -1;
+		this._dateSlot[index].data.data = String.fromCharCode(160);
+		this._dateSlot[index].data.parentNode.className = "";
+		this._dateSlot[index].data.parentNode.style.fontWeight = "normal";
+		this._dateSlot[index].data.parentNode.style.border= "none";
+		index++;
+	}
+        
+    for (i = 1; i <= monthLength; i++, index++) {
+		this._dateSlot[index].value = i;
+		this._dateSlot[index].data.data = i;
+		this._dateSlot[index].data.parentNode.className = "";
+		this._dateSlot[index].data.parentNode.style.fontWeight = "normal";
+		this._dateSlot[index].data.parentNode.style.border= "none";
+		if (toISODate(d1) == today) {
+			this._dateSlot[index].data.parentNode.className = "today";
+			this._dateSlot[index].data.parentNode.style.fontWeight = "bold";
+		}
+		if (toISODate(d1) == current) {
+			this._dateSlot[index].data.parentNode.className += " current";
+			this._dateSlot[index].data.parentNode.style.border= "1px dotted WindowText";
+		}
+		if (toISODate(d1) == selected) {
+			this._dateSlot[index].data.parentNode.className += " selected";
+			this._dateSlot[index].data.parentNode.style.border= "1px solid WindowText";
+		}
+		d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1);
+	}
+	
+	var lastDateIndex = index;
+        
+    while(index < 42) {
+		this._dateSlot[index].value = -1;
+		this._dateSlot[index].data.data = String.fromCharCode(160);
+		this._dateSlot[index].data.parentNode.className = "";
+		this._dateSlot[index].data.parentNode.style.fontWeight = "normal";
+		this._dateSlot[index].data.parentNode.style.border= "none";
+		++index;
+	}
+	
+	// Week numbers
+	if (this._includeWeek) {
+		d1 = new Date(date.getFullYear(), date.getMonth(), 1);
+		for (i=0; i < 6; ++i) {
+			if (i == 5 && lastDateIndex < 36) {
+				this._weekSlot[i].data.data = String.fromCharCode(160);
+				this._weekSlot[i].data.parentNode.style.borderRight = "none";
+			} else {
+				week = weekNumber(this, d1);
+				this._weekSlot[i].data.data = week;
+				this._weekSlot[i].data.parentNode.style.borderRight = "1px solid WindowText";
+			}
+			d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+7);
+		}
+	}
+}
+
+Calendar.prototype.show = function(element) {
+	if(!this._showing) {
+		var p = getPoint(element);
+		this._calDiv.style.display = "block";
+		this._calDiv.style.top = (p.y + element.offsetHeight + 1) + "px";
+		this._calDiv.style.left = p.x + "px";
+		this._showing = true;
+		
+		/* -------- */
+	   	if( this._bw.ie6 )
+	   	{
+	     	dw = this._calDiv.offsetWidth;
+	     	dh = this._calDiv.offsetHeight;
+	     	var els = document.getElementsByTagName("body");
+	     	var body = els[0];
+	     	if( !body ) return;
+	 
+	    	//paste iframe under the modal
+		     var underDiv = this._calDiv.cloneNode(false); 
+		     underDiv.style.zIndex="390";
+		     underDiv.style.margin = "0px";
+		     underDiv.style.padding = "0px";
+		     underDiv.style.display = "block";
+		     underDiv.style.width = dw;
+		     underDiv.style.height = dh;
+		     underDiv.style.border = "1px solid WindowText";
+		     underDiv.innerHTML = "<iframe width=\"100%\" height=\"100%\" frameborder=\"0\"></iframe>";
+		     body.appendChild(underDiv);
+		     this._underDiv = underDiv;
+	   }
+		/* -------- */
+
+        if (this._calDiv.focus)
+          this._calDiv.focus();
+		
+	}
+};
+
+Calendar.prototype.hide = function() {   
+	if(this._showing) {
+		this._calDiv.style.display = "none";
+		this._showing = false;
+		if( this._bw.ie6 ) {
+		    if( this._underDiv ) this._underDiv.removeNode(true);
+		}
+	}
+}
+
+Calendar.prototype.toggle = function(element) {
+	if(this._showing) {
+		this.hide(); 
+	} else {
+		this.show(element);
+	}
+}
+
+
+
+Calendar.prototype.onchange = function() {};
+
+
+Calendar.prototype.setCurrentDate = function(date) {
+	if (date == null) {
+		return;
+	}
+
+	// if string or number create a Date object
+	if (typeof date == "string" || typeof date == "number") {
+		date = new Date(date);
+	}
+	
+	
+	// do not update if not really changed
+	if (this._currentDate.getDate() != date.getDate() ||
+		this._currentDate.getMonth() != date.getMonth() || 
+		this._currentDate.getFullYear() != date.getFullYear()) {
+		
+		this._currentDate = new Date(date);
+	
+		this._updateHeader();
+		this._update();
+		
+	}
+	
+}
+
+Calendar.prototype.setSelectedDate = function(date) {
+	this._selectedDate = new Date(date);
+	this.setCurrentDate(this._selectedDate);
+	if (typeof this.onchange == "function") {
+		this.onchange();
+	}
+}
+
+Calendar.prototype.clearSelectedDate = function() {
+	this._selectedDate = null;
+	if (typeof this.onchange == "function") {
+		this.onchange();
+	}
+}
+
+Calendar.prototype.getElement = function() {
+	return this._calDiv;
+}
+
+Calendar.prototype.setIncludeWeek = function(v) {
+	if (this._calDiv == null) {
+		this._includeWeek = v;
+	}
+}
+
+Calendar.prototype.setClearButtonLabel = function(v) {
+  this._clearButtonLabel = v;
+}
+
+Calendar.prototype.getSelectedDate = function () {
+	if (this._selectedDate == null) {
+		return null;
+	} else {
+		return new Date(this._selectedDate);
+	}
+}
+
+Calendar.prototype.initialize = function(monthNames, shortMonthNames, weekDayNames, shortWeekDayNames, format,
+  firstDayOfWeek, includeWeek, minimalDaysInFirstWeek, clearButtonLabel)
+{
+  this.setMonthNames(monthNames);
+  this.setShortMonthNames(shortMonthNames);
+  this.setWeekDayNames(weekDayNames);
+  this.setShortWeekDayNames(shortWeekDayNames);
+  this.setFormat(format);
+  this.setFirstDayOfWeek(firstDayOfWeek);
+  this.setIncludeWeek(includeWeek);
+  this.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
+  this.setClearButtonLabel(clearButtonLabel);
+  
+  this.create();
+}
+
+
+Calendar.prototype._updateHeader = function () {
+
+	// 
+	var options = this._monthSelect.options;
+	var m = this._currentDate.getMonth();
+	for(var i=0; i < options.length; ++i) {
+		options[i].selected = false;
+		if (options[i].value == m) {
+			options[i].selected = true;
+		}
+	}
+	
+	options = this._yearSelect.options;
+	var year = this._currentDate.getFullYear();
+	for(var i=0; i < options.length; ++i) {
+		options[i].selected = false;
+		if (options[i].value == year) {
+			options[i].selected = true;
+		}
+	}
+	
+}
+
+Calendar.prototype.setYear = function(year) {
+	var d = new Date(this._currentDate);
+	d.setFullYear(year);
+	this.setCurrentDate(d);
+}
+
+Calendar.prototype.setMonth = function (month) {
+	var d = new Date(this._currentDate);
+	d.setMonth(month);
+	this.setCurrentDate(d);
+}
+
+Calendar.prototype.nextMonth = function () {
+	this.setMonth(this._currentDate.getMonth()+1);
+}
+
+Calendar.prototype.prevMonth = function () {
+	this.setMonth(this._currentDate.getMonth()-1);
+}
+
+Calendar.prototype.setFirstDayOfWeek = function (nFirstWeekDay) {
+	this._firstDayOfWeek = nFirstWeekDay;
+}
+
+Calendar.prototype.getFirstDayOfWeek = function () {
+	return this._firstDayOfWeek;
+}
+
+Calendar.prototype.setMinimalDaysInFirstWeek = function(n) {
+	this._minimalDaysInFirstWeek = n;
+}
+
+
+Calendar.prototype.getMinimalDaysInFirstWeek = function () {
+	return this._minimalDaysInFirstWeek;
+}
+
+Calendar.prototype.setMonthNames = function(a) {
+	// sanity test
+	this._monthNames = a;
+}
+
+Calendar.prototype.setShortMonthNames = function(a) {
+	// sanity test
+	this._shortMonthNames = a;
+}
+
+Calendar.prototype.setWeekDayNames = function(a) {
+	// sanity test
+	this._weekDayNames = a;
+}
+
+Calendar.prototype.setShortWeekDayNames = function(a) {
+	// sanity test
+	this._shortWeekDayNames = a;
+}
+
+Calendar.prototype.getFormat = function() {
+	return this._format;
+}
+	
+Calendar.prototype.setFormat = function(f) {
+	this._format = f;
+}
+
+Calendar.prototype.formatDate = function() {  
+	if (this._selectedDate == null) {
+		return "";
+	}
+	
+    var bits = new Array();
+    // work out what each bit should be
+    var date = this._selectedDate;
+    bits['d'] = date.getDate();
+    bits['dd'] = pad(date.getDate(),2);
+    bits['ddd'] = this._shortWeekDayNames[date.getDay()];
+    bits['dddd'] = this._weekDayNames[date.getDay()];
+
+    bits['M'] = date.getMonth()+1;
+    bits['MM'] = pad(date.getMonth()+1,2);
+    bits['MMM'] = this._shortMonthNames[date.getMonth()];
+    bits['MMMM'] = this._monthNames[date.getMonth()];
+    
+    var yearStr = "" + date.getFullYear();
+    yearStr = (yearStr.length == 2) ? '19' + yearStr: yearStr;
+    bits['yyyy'] = yearStr;
+    bits['yy'] = bits['yyyy'].toString().substr(2,2);
+
+    bits['s'] = date.getSeconds();
+    bits['ss'] = pad(date.getSeconds(),2);
+    
+    bits['m'] = date.getMinutes();
+    bits['mm'] = pad(date.getMinutes(),2);
+    
+    bits['H'] = date.getHours();
+    bits['HH'] = pad(date.getHours(),2); 
+
+    // do some funky regexs to replace the format string
+    // with the real values
+    var frm = new String(this._format);
+    // TAPESTRY-669: Have to be very explicit about keys, to keep functions added
+    // to Array (by the Prototype library, if its around) from getting mixed in.
+    var keys = new Array('d','dd','ddd','dddd','M','MM','MMM','MMMM','yyyy','yy', 's', 'ss', 'm',
+        'mm', 'H', 'HH');
+    for (var i = 0; i < keys.length; i++) {
+       frm = eval("frm.replace(/\\b" + keys[i] + "\\b/,\"" + bits[keys[i]] + "\");");      
+    }     
+
+    return frm;
+}
+	
+                                                                                                       
+function isLeapYear(year) {
+	return ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0)));
+}
+
+function yearLength(year) {
+	if (isLeapYear(year))
+		return 366;
+	else
+		return 365;
+}
+
+function dayOfYear(date) {
+	var a = Calendar.NUM_DAYS;
+	if (isLeapYear(date.getFullYear())) {
+		a = Calendar.LEAP_NUM_DAYS;
+	}
+	var month = date.getMonth();
+	
+	return a[month] + date.getDate();
+}
+
+// ---------------------------------------------
+// Week number stuff
+// ---------------------------------------------
+
+function weekNumber(cal, date) {
+
+	var dow = date.getDay();
+	var doy = dayOfYear(date);
+	var year = date.getFullYear();
+
+	// Compute the week of the year.  Valid week numbers run from 1 to 52
+	// or 53, depending on the year, the first day of the week, and the
+	// minimal days in the first week.  Days at the start of the year may
+	// fall into the last week of the previous year; days at the end of
+	// the year may fall into the first week of the next year.
+	var relDow = (dow + 7 - cal.getFirstDayOfWeek()) % 7; // 0..6
+	var relDowJan1 = (dow - doy + 701 - cal.getFirstDayOfWeek()) % 7; // 0..6
+	var week = Math.floor((doy - 1 + relDowJan1) / 7); // 0..53
+	if ((7 - relDowJan1) >= cal.getMinimalDaysInFirstWeek()) {
+		++week;
+	}
+
+	if (doy > 359) { // Fast check which eliminates most cases
+		// Check to see if we are in the last week; if so, we need
+		// to handle the case in which we are the first week of the
+		// next year.
+		var lastDoy = yearLength(year);
+		var lastRelDow = (relDow + lastDoy - doy) % 7;
+		if (lastRelDow < 0) {
+			lastRelDow += 7;
+		}
+		if (((6 - lastRelDow) >= cal.getMinimalDaysInFirstWeek())
+			&& ((doy + 7 - relDow) > lastDoy)) {
+			week = 1;
+		}
+	} else if (week == 0) {
+		// We are the last week of the previous year.
+		var prevDoy = doy + yearLength(year - 1);
+		week = weekOfPeriod(cal, prevDoy, dow);
+	}
+
+	return week;
+}
+
+function weekOfPeriod(cal, dayOfPeriod, dayOfWeek) {
+	// Determine the day of the week of the first day of the period
+	// in question (either a year or a month).  Zero represents the
+	// first day of the week on this calendar.
+	var periodStartDayOfWeek =
+		(dayOfWeek - cal.getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
+	if (periodStartDayOfWeek < 0) {
+		periodStartDayOfWeek += 7;
+	}
+
+	// Compute the week number.  Initially, ignore the first week, which
+	// may be fractional (or may not be).  We add periodStartDayOfWeek in
+	// order to fill out the first week, if it is fractional.
+	var weekNo = Math.floor((dayOfPeriod + periodStartDayOfWeek - 1) / 7);
+
+	// If the first week is long enough, then count it.  If
+	// the minimal days in the first week is one, or if the period start
+	// is zero, we always increment weekNo.
+	if ((7 - periodStartDayOfWeek) >= cal.getMinimalDaysInFirstWeek()) {
+		++weekNo;
+	}
+
+	return weekNo;
+}
+
+
+
+
+function getEventObject(e) {  // utility function to retrieve object from event
+    if (navigator.appName == "Microsoft Internet Explorer") {
+        return e.srcElement;
+    } else {  // is mozilla/netscape
+        // need to crawl up the tree to get the first "real" element
+        // i.e. a tag, not raw text
+        var o = e.target;
+        while (!o.tagName) {
+            o = o.parentNode;
+        }
+        return o;
+    }
+}
+
+function addEvent(name, obj, funct) { // utility function to add event handlers
+
+    if (navigator.appName == "Microsoft Internet Explorer") {
+        obj.attachEvent("on"+name, funct);
+    } else {  // is mozilla/netscape
+        obj.addEventListener(name, funct, false);
+    }
+}
+
+
+function deleteEvent(name, obj, funct) { // utility function to delete event handlers
+
+    if (navigator.appName == "Microsoft Internet Explorer") {
+        obj.detachEvent("on"+name, funct);
+    } else {  // is mozilla/netscape
+        obj.removeEventListener(name, funct, false);
+    }
+}
+
+function setCursor(obj) {
+   if (navigator.appName == "Microsoft Internet Explorer") {
+        obj.style.cursor = "hand";
+    } else {  // is mozilla/netscape
+        obj.style.cursor = "pointer";
+    }
+}
+
+function Point(iX, iY)
+{
+   this.x = iX;
+   this.y = iY;
+}
+
+
+function getPoint(aTag)
+{
+   var oTmp = aTag;  
+   var point = new Point(0,0);
+  
+   do 
+   {
+      point.x += oTmp.offsetLeft;
+      point.y += oTmp.offsetTop;
+      oTmp = oTmp.offsetParent;
+   } 
+   while (oTmp.tagName != "BODY" && oTmp.tagName != "HTML");
+
+   return point;
+}
+
+function toISODate(date) {
+	var s = date.getFullYear();
+	var m = date.getMonth() + 1;
+	if (m < 10) {
+		m = "0" + m;
+	}
+	var day = date.getDate();
+	if (day < 10) {
+		day = "0" + day;
+	}
+	return String(s) + String(m) + String(day);
+	
+}
+
+function pad(number,X) {   // utility function to pad a number to a given width
+	X = (!X ? 2 : X);
+	number = ""+number;
+	while (number.length < X) {
+	    number = "0" + number;
+	}
+	return number;
+}
+
+function bw_check()
+{
+    var is_major = parseInt( navigator.appVersion );
+    this.nver = is_major;
+    this.ver = navigator.appVersion;
+    this.agent = navigator.userAgent;
+    this.dom = document.getElementById ? 1 : 0;
+    this.opera = window.opera ? 1 : 0;
+    this.ie5 = ( this.ver.indexOf( "MSIE 5" ) > -1 && this.dom && !this.opera ) ? 1 : 0;
+    this.ie6 = ( this.ver.indexOf( "MSIE 6" ) > -1 && this.dom && !this.opera ) ? 1 : 0;
+    this.ie4 = ( document.all && !this.dom && !this.opera ) ? 1 : 0;
+    this.ie = this.ie4 || this.ie5 || this.ie6;
+    this.mac = this.agent.indexOf( "Mac" ) > -1;
+    this.ns6 = ( this.dom && parseInt( this.ver ) >= 5 ) ? 1 : 0;
+    this.ie3 = ( this.ver.indexOf( "MSIE" ) && ( is_major < 4 ) );
+    this.hotjava = ( this.agent.toLowerCase().indexOf( 'hotjava' ) != -1 ) ? 1 : 0;
+    this.ns4 = ( document.layers && !this.dom && !this.hotjava ) ? 1 : 0;
+    this.bw = ( this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera );
+    this.ver3 = ( this.hotjava || this.ie3 );
+    this.opera7 = ( ( this.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( this.agent.toLowerCase().indexOf( 'opera/7' ) > -1 ) );
+    this.operaOld = this.opera && !this.opera7;
+    return this;
+};
+
+

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.java
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.java?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.java (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.java Sat Mar 11 12:54:27 2006
@@ -1,4 +1,4 @@
-// Copyright 2004, 2005, 2006 The Apache Software Foundation
+// Copyright 2004, 2005 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry.form;
 
+import org.apache.hivemind.ApplicationRuntimeException;
 import org.apache.hivemind.Location;
 import org.apache.tapestry.AbstractComponent;
 import org.apache.tapestry.IActionListener;
@@ -35,47 +36,38 @@
 import org.apache.tapestry.web.WebResponse;
 
 /**
- * Component which contains form element components. Forms use the action or
- * direct services to handle the form submission. A Form will wrap other
- * components and static HTML, including form components such as
- * {@link TextArea}, {@link TextField}, {@link Checkbox}, etc. [ <a
+ * Component which contains form element components. Forms use the action or direct services to
+ * handle the form submission. A Form will wrap other components and static HTML, including form
+ * components such as {@link TextArea}, {@link TextField}, {@link Checkbox}, etc. [ <a
  * href="../../../../../ComponentReference/Form.html">Component Reference </a>]
  * <p>
- * When a form is submitted, it continues through the rewind cycle until
- * <em>after</em> all of its wrapped elements have renderred. As the form
- * component render (in the rewind cycle), they will be updating properties of
- * the containing page and notifying thier listeners. Again: each form component
- * is responsible not only for rendering HTML (to present the form), but for
- * handling it's share of the form submission.
+ * When a form is submitted, it continues through the rewind cycle until <em>after</em> all of its
+ * wrapped elements have renderred. As the form component render (in the rewind cycle), they will be
+ * updating properties of the containing page and notifying thier listeners. Again: each form
+ * component is responsible not only for rendering HTML (to present the form), but for handling it's
+ * share of the form submission.
  * <p>
  * Only after all that is done will the Form notify its listener.
  * <p>
- * Starting in release 1.0.2, a Form can use either the direct service or the
- * action service. The default is the direct service, even though in earlier
- * releases, only the action service was available.
+ * Starting in release 1.0.2, a Form can use either the direct service or the action service. The
+ * default is the direct service, even though in earlier releases, only the action service was
+ * available.
  * <p>
- * Release 4.0 adds two new listeners, {@link #getCancel()} and
- * {@link #getRefresh()} and corresponding client-side behavior to force a form
- * to refresh (update, bypassing input field validation) or cancel (update
- * immediately).
+ * Release 4.0 adds two new listeners, {@link #getCancel()} and {@link #getRefresh()} and
+ * corresponding client-side behavior to force a form to refresh (update, bypassing input field
+ * validation) or cancel (update immediately).
  * 
  * @author Howard Lewis Ship, David Solis
  */
 
 public abstract class Form extends AbstractComponent implements IForm, IDirect
 {
-
     private String _name;
 
     private FormSupport _formSupport;
 
-    /**
-     * Inner class to render informal parameters, passed to the
-     * {@link FormSupport}.
-     */
     private class RenderInformalParameters implements IRender
     {
-
         public void render(IMarkupWriter writer, IRequestCycle cycle)
         {
             renderInformalParameters(writer, cycle);
@@ -85,22 +77,20 @@
     private IRender _renderInformalParameters;
 
     /**
-     * Returns the currently active {@link IForm}, or null if no form is
-     * active. This is a convienience method, the result will be null, or an
-     * instance of {@link IForm}, but not necessarily a <code>Form</code>.
+     * Returns the currently active {@link IForm}, or null if no form is active. This is a
+     * convienience method, the result will be null, or an instance of {@link IForm}, but not
+     * necessarily a <code>Form</code>.
      * 
-     * @deprecated Use {@link TapestryUtils#getForm(IRequestCycle, IComponent)}
-     *             instead.
+     * @deprecated Use {@link TapestryUtils#getForm(IRequestCycle, IComponent)} instead.
      */
 
     public static IForm get(IRequestCycle cycle)
     {
-        return (IForm)cycle.getAttribute(ATTRIBUTE_NAME);
+        return (IForm) cycle.getAttribute(ATTRIBUTE_NAME);
     }
 
     /**
-     * Indicates to any wrapped form components that they should respond to the
-     * form submission.
+     * Indicates to any wrapped form components that they should respond to the form submission.
      * 
      * @throws ApplicationRuntimeException
      *             if not rendering.
@@ -108,7 +98,8 @@
 
     public boolean isRewinding()
     {
-        if (!isRendering()) throw Tapestry.createRenderOnlyPropertyException(this, "rewinding");
+        if (!isRendering())
+            throw Tapestry.createRenderOnlyPropertyException(this, "rewinding");
 
         return _formSupport.isRewinding();
     }
@@ -132,8 +123,7 @@
     /**
      * Returns true if this Form is configured to use the direct service.
      * <p>
-     * This is derived from the direct parameter, and defaults to true if not
-     * bound.
+     * This is derived from the direct parameter, and defaults to true if not bound.
      * 
      * @since 1.0.2
      */
@@ -141,8 +131,8 @@
     public abstract boolean isDirect();
 
     /**
-     * Returns true if the stateful parameter is bound to a true value. If
-     * stateful is not bound, also returns the default, true.
+     * Returns true if the stateful parameter is bound to a true value. If stateful is not bound,
+     * also returns the default, true.
      * 
      * @since 1.0.1
      */
@@ -153,12 +143,12 @@
     }
 
     /**
-     * Constructs a unique identifier (within the Form). The identifier consists
-     * of the component's id, with an index number added to ensure uniqueness.
+     * Constructs a unique identifier (within the Form). The identifier consists of the component's
+     * id, with an index number added to ensure uniqueness.
      * <p>
      * Simply invokes
-     * {@link #getElementId(org.apache.tapestry.form.IFormComponent, java.lang.String)}with
-     * the component's id.
+     * {@link #getElementId(org.apache.tapestry.form.IFormComponent, java.lang.String)}with the
+     * component's id.
      * 
      * @since 1.0.2
      */
@@ -169,11 +159,11 @@
     }
 
     /**
-     * Constructs a unique identifier from the base id. If possible, the id is
-     * used as-is. Otherwise, a unique identifier is appended to the id.
+     * Constructs a unique identifier from the base id. If possible, the id is used as-is.
+     * Otherwise, a unique identifier is appended to the id.
      * <p>
-     * This method is provided simply so that some components ({@link ImageSubmit})
-     * have more specific control over their names.
+     * This method is provided simply so that some components ({@link ImageSubmit}) have more
+     * specific control over their names.
      * 
      * @since 1.0.3
      */
@@ -184,16 +174,15 @@
     }
 
     /**
-     * Returns the name generated for the form. This is used to faciliate
-     * components that write JavaScript and need to access the form or its
-     * contents.
+     * Returns the name generated for the form. This is used to faciliate components that write
+     * JavaScript and need to access the form or its contents.
      * <p>
-     * This value is generated when the form renders, and is not cleared. If the
-     * Form is inside a {@link org.apache.tapestry.components.Foreach}, this
-     * will be the most recently generated name for the Form.
+     * This value is generated when the form renders, and is not cleared. If the Form is inside a
+     * {@link org.apache.tapestry.components.Foreach}, this will be the most recently generated
+     * name for the Form.
      * <p>
-     * This property is exposed so that sophisticated applications can write
-     * JavaScript handlers for the form and components within the form.
+     * This property is exposed so that sophisticated applications can write JavaScript handlers for
+     * the form and components within the form.
      * 
      * @see AbstractFormComponent#getName()
      */
@@ -220,7 +209,8 @@
 
         IValidationDelegate delegate = getDelegate();
 
-        if (delegate != null) delegate.setFormComponent(null);
+        if (delegate != null)
+            delegate.setFormComponent(null);
 
         super.cleanupAfterRender(cycle);
     }
@@ -252,11 +242,12 @@
 
         _name = baseName + getResponse().getNamespace();
 
-        if (_renderInformalParameters == null) _renderInformalParameters = new RenderInformalParameters();
+        if (_renderInformalParameters == null)
+            _renderInformalParameters = new RenderInformalParameters();
 
         ILink link = getLink(cycle, actionId);
-
-        _formSupport.render(getMethod(), _renderInformalParameters, link, getScheme());
+        
+        _formSupport.render(getMethod(), _renderInformalParameters, link, getScheme(), getPort());
     }
 
     IActionListener findListener(String mode)
@@ -267,20 +258,22 @@
             result = getCancel();
         else if (mode.equals(FormConstants.SUBMIT_REFRESH))
             result = getRefresh();
-        else if (!getDelegate().getHasErrors()) result = getSuccess();
+        else if (!getDelegate().getHasErrors())
+            result = getSuccess();
 
         // If not success, cancel or refresh, or the corresponding listener
         // is itself null, then use the default listener
         // (which may be null as well!).
 
-        if (result == null) result = getListener();
+        if (result == null)
+            result = getListener();
 
         return result;
     }
 
     /**
-     * Construct a form name for use with the action service. This
-     * implementation returns "Form" appended with the actionId.
+     * Construct a form name for use with the action service. This implementation returns "Form"
+     * appended with the actionId.
      * 
      * @since 4.0
      */
@@ -291,10 +284,9 @@
     }
 
     /**
-     * Constructs a form name for use with the direct service. This
-     * implementation bases the form name on the form component's id (but
-     * ensures it is unique). Remember that Tapestry assigns an "ugly" id if an
-     * explicit component id is not provided.
+     * Constructs a form name for use with the direct service. This implementation bases the form
+     * name on the form component's id (but ensures it is unique). Remember that Tapestry assigns an
+     * "ugly" id if an explicit component id is not provided.
      * 
      * @since 4.0
      */
@@ -347,8 +339,7 @@
     }
 
     /**
-     * Builds the EngineServiceLink for the form, using either the direct or
-     * action service.
+     * Builds the EngineServiceLink for the form, using either the direct or action service.
      * 
      * @since 1.0.3
      */
@@ -398,6 +389,9 @@
 
     /** scheme parameter, may be null */
     public abstract String getScheme();
+    
+    /** port , may be null */
+    public abstract Integer getPort();
 
     public void setEncodingType(String encodingType)
     {

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.js?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.js (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.js Sat Mar 11 12:54:27 2006
@@ -85,14 +85,22 @@
 
 Tapestry.set_focus = function (field)
 {
-	if (typeof field == "string")
-	  field = this.find(field);
-	
-	if (field.focus)
-		field.focus();
-    
-    if (field.select)
-        field.select();
+	if (typeof field == "string") {
+	    field = this.find(field);
+		
+        if (field) {
+            if (!field.disabled && field.clientWidth > 0) {
+            	if (field.focus) {
+	            	field.focus();
+                }
+                if (field.isContentEditable || field.isContentEditable == null) {
+                    if (field.select) {
+                        field.select();
+                    }
+                }
+            }
+        }
+    }
 }
 
 Tapestry.trim_field_value = function(fieldId)

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.jwc
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.jwc?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.jwc (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/Form.jwc Sat Mar 11 12:54:27 2006
@@ -109,6 +109,13 @@
     </description>
   </parameter>    
   
+  <parameter name="port">
+    <description>
+    Forces the link to be generated as an absolute URL with the given port
+    (unless the port matches the port for the current request).
+    </description>
+  </parameter>    
+  
   <reserved-parameter name="action"/>
   <reserved-parameter name="name"/>
   <reserved-parameter name="onsubmit"/>

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormEventType.java
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormEventType.java?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormEventType.java (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormEventType.java Sat Mar 11 12:54:27 2006
@@ -1,4 +1,4 @@
-// Copyright 2004, 2005, 2006 The Apache Software Foundation
+// Copyright 2004, 2005 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
  *             a future release of Tapestry.
  */
 
-public final class FormEventType
+public class FormEventType
 {
     /**
      * Form event triggered when the form is submitted. Allows an event handler to perform any final

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormMessages.java
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormMessages.java?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormMessages.java (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormMessages.java Sat Mar 11 12:54:27 2006
@@ -1,4 +1,4 @@
-// Copyright 2005, 2006 The Apache Software Foundation
+// Copyright 2005 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
 package org.apache.tapestry.form;
 
 import org.apache.hivemind.HiveMind;
-import org.apache.hivemind.Messages;
 import org.apache.hivemind.impl.MessageFormatter;
 import org.apache.tapestry.IComponent;
 
@@ -23,48 +22,51 @@
  * @author Howard M. Lewis Ship
  * @since 4.0
  */
-final class FormMessages
+class FormMessages
 {
-
-    private final static Messages MESSAGES = new MessageFormatter(FormMessages.class);
-
-    /** @since 4.1 */
-    private FormMessages()
-    {
-    }
+    private final static MessageFormatter _formatter = new MessageFormatter(FormMessages.class);
 
     static String formTooManyIds(IComponent form, int actualCount, IComponent component)
     {
-        return MESSAGES.format("form-too-many-ids", form.getExtendedId(), new Integer(actualCount), component
-                .getExtendedId());
+        return _formatter.format(
+                "form-too-many-ids",
+                form.getExtendedId(),
+                new Integer(actualCount),
+                component.getExtendedId());
     }
 
-    static String formIdMismatch(IComponent form, int mismatchIndex, String expectedId, String actualId,
-            IComponent component)
-    {
-        return MESSAGES.format("form-id-mismatch", new Object[] { form.getExtendedId(), new Integer(mismatchIndex + 1),
-                expectedId, actualId, component.getExtendedId() });
+    static String formIdMismatch(IComponent form, int mismatchIndex, String expectedId,
+            String actualId, IComponent component)
+    {
+        return _formatter.format("form-id-mismatch", new Object[]
+        { form.getExtendedId(), new Integer(mismatchIndex + 1), expectedId, actualId,
+                component.getExtendedId() });
     }
 
     static String formTooFewIds(IComponent form, int remainingCount, String nextExpectedId)
     {
-        return MESSAGES.format("form-too-few-ids", form.getExtendedId(), new Integer(remainingCount), nextExpectedId);
+        return _formatter.format("form-too-few-ids", form.getExtendedId(), new Integer(
+                remainingCount), nextExpectedId);
     }
 
-    static String encodingTypeContention(IComponent form, String establishedEncodingType, String newEncodingType)
+    static String encodingTypeContention(IComponent form, String establishedEncodingType,
+            String newEncodingType)
     {
-        return MESSAGES.format("encoding-type-contention", form.getExtendedId(), establishedEncodingType,
+        return _formatter.format(
+                "encoding-type-contention",
+                form.getExtendedId(),
+                establishedEncodingType,
                 newEncodingType);
     }
 
     static String fieldAlreadyPrerendered(IComponent field)
     {
-        return MESSAGES.format("field-already-prerendered", field);
+        return _formatter.format("field-already-prerendered", field);
     }
 
     static String linkSubmitMayNotNest(IComponent inner, IComponent outer)
     {
-        return MESSAGES.format("link-submit-may-not-nest", inner.getExtendedId(), outer.getExtendedId(), HiveMind
-                .getLocationString(outer));
+        return _formatter.format("link-submit-may-not-nest", inner.getExtendedId(), outer
+                .getExtendedId(), HiveMind.getLocationString(outer));
     }
-}
+}
\ No newline at end of file

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormSupport.java
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormSupport.java?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormSupport.java (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormSupport.java Sat Mar 11 12:54:27 2006
@@ -44,7 +44,7 @@
      *            non-null, and the scheme does not match the current request's scheme, then an
      *            absolute URL with the specified scheme will be generated, rather than a URI.
      */
-    public void render(String method, IRender informalParametersRenderer, ILink link, String scheme);
+    public void render(String method, IRender informalParametersRenderer, ILink link, String scheme, Integer port);
 
     /**
      * Invoked to rewind the form, which renders the body of the form, allowing form element
@@ -55,4 +55,4 @@
      *         {@link FormConstants#SUBMIT_CANCEL} or {@link FormConstants#SUBMIT_REFRESH}.
      */
     public String rewind();
-}
\ No newline at end of file
+}

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/FormSupportImpl.java Sat Mar 11 12:54:27 2006
@@ -78,14 +78,14 @@
 
     public static final String SCRIPT = "/org/apache/tapestry/form/Form.js";
 
+    private final static Set _standardReservedIds;
+
     /**
      * Attribute set to true when a field has been focused; used to prevent conflicting JavaScript
      * for field focusing from being emitted.
      */
 
     public static final String FIELD_FOCUS_ATTRIBUTE = "org.apache.tapestry.field-focused";
-    
-    private static final Set RESERVED_IDS;
 
     static
     {
@@ -97,10 +97,10 @@
         set.add(SUBMIT_MODE);
         set.add(FormConstants.SUBMIT_NAME_PARAMETER);
 
-        RESERVED_IDS = Collections.unmodifiableSet(set);
+        _standardReservedIds = Collections.unmodifiableSet(set);
     }
 
-    private static final Set SUBMIT_MODES;
+    private final static Set _submitModes;
 
     static
     {
@@ -109,7 +109,7 @@
         set.add(FormConstants.SUBMIT_NORMAL);
         set.add(FormConstants.SUBMIT_REFRESH);
 
-        SUBMIT_MODES = Collections.unmodifiableSet(set);
+        _submitModes = Collections.unmodifiableSet(set);
     }
 
     /**
@@ -253,7 +253,7 @@
 
             // Reserve the name.
 
-            if (!RESERVED_IDS.contains(name))
+            if (!_standardReservedIds.contains(name))
             {
                 _elementIdAllocator.allocateId(name);
 
@@ -459,8 +459,9 @@
         for (int i = 0; i < ids.length; i++)
             _elementIdAllocator.allocateId(ids[i]);
     }
-
-    public void render(String method, IRender informalParametersRenderer, ILink link, String scheme)
+    
+    public void render(String method, IRender informalParametersRenderer, ILink link, 
+    		String scheme, Integer port)
     {
         String formId = _form.getName();
 
@@ -486,9 +487,10 @@
         _form.renderBody(nested, _cycle);
 
         runDeferredRunnables();
-
-        writeTag(_writer, method, link.getURL(scheme, null, 0, null, false));
-
+        
+        int portI = (port == null) ? 0 : port.intValue();
+        writeTag(_writer, method, link.getURL(scheme, null, portI, null, false));
+        
         // For HTML compatibility
         _writer.attribute("name", formId);
 
@@ -579,7 +581,7 @@
 
         runDeferredRunnables();
 
-        if (SUBMIT_MODES.contains(mode))
+        if (_submitModes.contains(mode))
             return mode;
 
         // Either something wacky on the client side, or a client without
@@ -739,4 +741,4 @@
         _delegate.registerForFocus(field, priority);
     }
 
-}
+}
\ No newline at end of file

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/IPropertySelectionModel.java
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/IPropertySelectionModel.java?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/IPropertySelectionModel.java (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/IPropertySelectionModel.java Sat Mar 11 12:54:27 2006
@@ -41,20 +41,20 @@
      * Returns the number of possible options.
      */
 
-    int getOptionCount();
+    public int getOptionCount();
 
     /**
      * Returns one possible option that will be assigned to the server-side property.
      */
 
-    Object getOption(int index);
+    public Object getOption(int index);
 
     /**
      * Returns the label for an option. It is the responsibility of the adaptor to make this value
      * localized.
      */
 
-    String getLabel(int index);
+    public String getLabel(int index);
 
     /**
      * Returns a String used to represent the option in the HTML (as the value of an &lt;option&gt;
@@ -62,12 +62,12 @@
      * into an array.
      */
 
-    String getValue(int index);
+    public String getValue(int index);
 
     /**
      * Returns the option corresponding to a value. This is used when interpreting submitted form
      * parameters.
      */
 
-    Object translateValue(String value);
-}
+    public Object translateValue(String value);
+}
\ No newline at end of file

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/IPropertySelectionRenderer.java
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/IPropertySelectionRenderer.java?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/IPropertySelectionRenderer.java (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/IPropertySelectionRenderer.java Sat Mar 11 12:54:27 2006
@@ -32,14 +32,14 @@
      *
      **/
 
-    void beginRender(PropertySelection component, IMarkupWriter writer, IRequestCycle cycle);
+    public void beginRender(PropertySelection component, IMarkupWriter writer, IRequestCycle cycle);
 
     /**
      *  Invoked for each element obtained from the {@link IPropertySelectionModel model}.
      *
      **/
 
-    void renderOption(
+    public void renderOption(
         PropertySelection component,
         IMarkupWriter writer,
         IRequestCycle cycle,
@@ -53,5 +53,5 @@
      *
      **/
 
-    void endRender(PropertySelection component, IMarkupWriter writer, IRequestCycle cycle);
-}
+    public void endRender(PropertySelection component, IMarkupWriter writer, IRequestCycle cycle);
+}
\ No newline at end of file

Modified: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/ImageSubmit.jwc
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/ImageSubmit.jwc?rev=385164&r1=385163&r2=385164&view=diff
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/ImageSubmit.jwc (original)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/form/ImageSubmit.jwc Sat Mar 11 12:54:27 2006
@@ -57,19 +57,15 @@
   
   <parameter name="listener">
   	<description>
-          A listener that is notified when this component is triggered. 
-          The listener is notified immediately when the component is identified as clicked.
-          This behaviour is useful when the component is in a loop, but not all elements
-          enclosed by the Form would have had a chance to update their properties at the
-          time of the listener invocation. Please see the 'action' parameter as an alternative.
+  	Notified when the button is clicked.
   	</description>
   </parameter>
   
   <parameter name="action">
       <description>
-          A listener that is notified when this component is triggered.
-          The listener notification is delayed until all components enclosed by the Form 
-          have had a chance to update their properties.
+          A listener that is notified if this component is triggered
+          just before the form's listener, after all components 
+          enclosed by the Form have had a chance to update their properties.
       </description>
   </parameter>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org