You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rave.apache.org by zh...@apache.org on 2011/04/01 02:29:38 UTC

svn commit: r1087520 [27/35] - in /incubator/rave/donations/ogce-gadget-container: ./ config/ config/shindig-1.1-BETA5/ config/shindig-2.0.0/ db-cleaner/ examples/ examples/src/ examples/src/main/ examples/src/main/java/ examples/src/main/java/cgl/ exa...

Added: incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/tmtjs/tmt_form.js
URL: http://svn.apache.org/viewvc/incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/tmtjs/tmt_form.js?rev=1087520&view=auto
==============================================================================
--- incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/tmtjs/tmt_form.js (added)
+++ incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/tmtjs/tmt_form.js Fri Apr  1 00:29:22 2011
@@ -0,0 +1,447 @@
+/** 
+* Copyright 2006-2008 massimocorner.com
+* License: http://www.massimocorner.com/license.htm
+* @author      Massimo Foti (massimo@massimocorner.com)
+* @version     0.5.3, 2008-06-30
+* @require     tmt_core.js
+*/
+
+if(typeof(tmt) == "undefined"){
+	alert("Error: tmt.core JavaScript library missing");
+}
+
+tmt.form = {};
+
+// Constants
+tmt.form.MESSAGE_CLASS = "tmtFormMessage";
+tmt.form.ERROR_MESSAGE_CLASS = "tmtFormErrorMessage";
+
+/**
+* Check a set of form fields (radio or checkboxes)
+*/
+tmt.form.checkFields = function(){
+	tmt.setNodeAttribute(arguments, "checked", true);
+}
+
+/**
+* Uncheck a set of form fields (radio or checkboxes)
+*/
+tmt.form.uncheckFields = function(){
+	tmt.setNodeAttribute(arguments, "checked", false);
+}
+
+/**
+* Toggle the checked attribute on a set of form fields. If it's true it set it to false and viceversa
+*/
+tmt.form.toggleCheckFields = function(){
+	for(var i=0; i<arguments.length; i++){
+		var fieldNode = tmt.get(arguments[i]);
+		if(fieldNode){
+			fieldNode.checked ? fieldNode.checked = false : fieldNode.checked = true;
+		}
+	}
+}
+
+/**
+* Programmatically select options inside a <select> tag
+* The first argument can be a DOM node, the id or the name of the <select>
+* In case of multiple tags sharing the same name the first fund in the document will be used
+* The second argument can be a simple value or a comma-delimited list (for select-multiple)
+*/
+tmt.form.checkSelect = function(theNode, values){
+	// Split in case we got a comma-separated list (for select-multiple)
+	var valueArray = values.split(",");
+	var selectNode = tmt.get(theNode);
+	// If what we get is a name, use the first node matching the name
+	if(selectNode == null){
+		selectNode = document.getElementsByName(theNode)[0];
+	}
+	for(var i=0; i<selectNode.options.length; i++){
+		for(var j=0; j<valueArray.length; j++){
+			if(valueArray[j] == tmt.form.getOptionNodeValue(selectNode.options[i])){
+				selectNode.options[i].selected = true;
+			}
+		}
+	}
+}
+
+/**
+* Programmatically de-select options inside a <select> tag
+* The first argument can be a DOM node, the id or the name of the <select>
+* In case of multiple tags sharing the same name the first fund in the document will be used
+*/
+tmt.form.resetSelect = function(theNode){
+	var selectNode = tmt.get(theNode);
+	// If what we get is a name, use the first node matching the name
+	if(selectNode == null){
+		selectNode = document.getElementsByName(theNode)[0];
+	}
+	for(var i=0; i<selectNode.options.length; i++){
+		selectNode.options[i].selected = false;
+	}
+}
+
+/**
+* Programmatically check radio buttons or checkboxes based on their values
+* The first argument is the name of the group
+* The second argument can be a simple value or a comma-delimited list (for checkboxes)
+*/
+tmt.form.checkGroup = function(groupName, values){
+	// Split in case we got a comma-separated list (for checkboxes)
+	var valueArray = values.split(",");
+	var groupNodes = document.getElementsByName(groupName);
+	for(var i=0; i<groupNodes.length; i++){
+		for(var j=0; j<valueArray.length; j++){
+			if(groupNodes[i].value == valueArray[j]){
+				groupNodes[i].checked = true;
+			}
+		}
+	}
+}
+
+/**
+* Uncheck a whole group of radio buttons or checkboxes
+*/
+tmt.form.resetGroup = function(groupName){
+	var groupNodes = document.getElementsByName(groupName);
+	for(var i=0; i<groupNodes.length; i++){
+		groupNodes[i].checked = false;
+	}
+}
+
+/**
+* Disable a set of form fields
+*/
+tmt.form.disableFields = function(){
+	tmt.setNodeAttribute(arguments, "disabled", true);
+}
+
+/**
+* Enable a set of form fields
+*/
+tmt.form.enableFields = function(){
+	tmt.setNodeAttribute(arguments, "disabled", false);
+}
+
+/**
+* Toggle the disabled attribute on a set of form fields. If it's true it set it to false and viceversa
+*/
+tmt.form.toggleEnableFields = function(){
+	for(var i=0; i<arguments.length; i++){
+		var fieldNode = tmt.get(arguments[i]);
+		if(fieldNode){
+			fieldNode.disabled ? fieldNode.disabled = false : fieldNode.disabled = true;
+		}
+	}
+}
+
+/**
+* Returns the container form node of a given node. Returns false if the node isn't contained inside a form
+*/
+tmt.form.getParentForm = function(startNode){
+	var parentObj = startNode.parentNode;
+	while(parentObj){
+		if(parentObj.tagName.toLowerCase() == "body"){
+			return false;
+		}
+		if(parentObj.tagName.toLowerCase() == "form"){
+			return parentObj;
+		}
+		else{
+			parentObj = parentObj.parentNode;
+			continue;
+		}
+	}
+	// The field is outside of a form
+	return false; 
+}
+
+/**
+* Given an option node, return its value. If no value is available, returns its text
+*/
+tmt.form.getOptionNodeValue = function(optionNode){
+	// Special case for IE
+	if(window.ActiveXObject){
+		if(optionNode.attributes["value"].specified){
+			return optionNode.value;
+		}
+	}
+	else {
+		if(optionNode.hasAttribute("value")){
+			return optionNode.value;
+		}
+	}
+	return optionNode.text;
+}
+
+// Private helper function, undocumented
+// Check if a given node is a form field
+tmt.form.isFormField = function(fieldNode){
+	//var fieldType = fieldNode.type.toLowerCase();
+	if(!fieldNode.type){
+		return false;
+	}
+	// Skip "reset" and "button"
+	if((fieldNode.type.toLowerCase() == "reset") || (fieldNode.type.toLowerCase() == "button") || (fieldNode.tagName.toLowerCase() == "button")){
+		return false;
+	}
+	return true
+}
+
+/**
+* Returns an array, containing all the form fields contained inside a given start node
+* Returns an empty array if no fields are available
+*/
+tmt.form.getChildFields = function(startNode){
+	var childFields = [];
+	var childNodes = tmt.getAllNodes(startNode);
+	for(var i=0; i<childNodes.length; i++){
+		if(tmt.form.isFormField(childNodes[i])){
+			childFields.push(childNodes[i]);
+		}
+	}
+	return childFields;
+}
+
+/**
+* Returns an array of submit button nodes contained inside a given node
+*/
+tmt.form.getSubmitNodes = function(startNode){
+	var inputNodes = startNode.getElementsByTagName("input");
+	return tmt.filterNodesByAttributeValue("type", "submit", inputNodes);
+}
+
+/**
+* Given a form field, return all fields contained inside the same form that share the same name
+* Handy to retrieve a whole set of radio/checkboxes
+*/
+tmt.form.getFieldGroup = function(fieldNode){
+	var boxes = [];
+	if(fieldNode.name){
+		boxes = tmt.getNodesByAttributeValue("name", fieldNode.name, fieldNode.form);
+	}
+	return boxes;
+}
+
+/**
+* Returns the value of a given form field
+* Accepts either ids (strings) or DOM node references
+* If getGroupValue argument is set to true (default to false) and fieldNode is either a radio or a checkbox; returns the value of the whole group of fields
+* In order to make getGroupValue work as expected checkboxes and radio must have a "name" attribute
+*/
+tmt.form.getValue = function(field, getGroupValue){
+	var retValue = "";
+	var fieldNode = tmt.get(field);
+	var fieldType = fieldNode.type.toLowerCase();	
+	// Handle different kind of fields
+	switch(fieldType){
+		case "select-multiple":
+			for(var j = 0; j < fieldNode.options.length; j++){
+				if(fieldNode.options[j].selected){
+					if(retValue == ""){
+						retValue = tmt.form.getOptionNodeValue(fieldNode.options[j]);
+					}
+					else{
+						retValue += ",";
+						retValue += tmt.form.getOptionNodeValue(fieldNode.options[j]);
+					}
+				}
+			}
+			break;
+		case "select-one":
+			for(var k = 0; k < fieldNode.options.length; k++){
+				if(fieldNode.options[k].selected){
+					retValue = tmt.form.getOptionNodeValue(fieldNode.options[k])
+					break;
+				}
+			}
+			break;
+		// Radio and checkboxes get handled the same way
+		case "radio":
+		case "checkbox":
+			if(!getGroupValue || !fieldNode.name){
+				// Get only the value of this specific box, not its whole group
+				if(fieldNode.checked){
+					retValue = fieldNode.value;
+				}
+			}
+			else{
+				// Collect the value out of the whole group
+				var boxes = tmt.form.getFieldGroup(fieldNode);
+				retValue = tmt.form.getGroupValue(boxes);
+			}
+			break;
+		// Skip reset
+		case "reset":
+			break;
+		// Skip buttons
+		case "button":
+			break;
+		// default handles all the text fields
+		default:
+			retValue = fieldNode.value;
+			break;
+	}
+	return retValue;
+}
+
+// Helper, private function, undocumented
+// Collect values out of a group of checkboxes/radio
+// Don't use for other kind of fields!
+tmt.form.getGroupValue = function(boxes){
+	var values = [];
+	for(var i = 0; i < boxes.length; i++){
+		if(boxes[i].checked){
+			values.push(boxes[i].value);
+		}	
+	}
+	return values.toString();
+}
+
+/**
+* Assembles field name/value pairs from a given form, returns an object
+*/
+tmt.form.hashForm = function(formNode, demoronize){
+	var valueObj = {};
+	for(var i = 0; i < formNode.elements.length; i++){
+		var fieldNode = formNode.elements[i];
+		// Skip fieldsets and field without name attribute
+		if(!fieldNode || !fieldNode.name || fieldNode.tagName.toLowerCase() == "fieldset"){
+			continue;
+		}
+		var fieldName = fieldNode.name;
+		valueObj[fieldName] = tmt.form.getValue(fieldNode, true);
+	}
+	return valueObj;
+}
+
+/**
+* Assembles field name/value pairs from a given form, returns an encoded string
+*/
+tmt.form.serializeForm = function(formNode, demoronize){
+	return tmt.hashToEncodeURI(tmt.form.hashForm(formNode, demoronize));
+}
+
+/**
+* Reset the values of each element in a given form to blank
+*/
+tmt.form.clearForm = function(formNode){
+	for(var i = 0; i < formNode.elements.length; i++){
+		var fieldNode = formNode.elements[i];
+		// Skip fieldsets
+		if(!fieldNode || fieldNode.tagName.toLowerCase() == "fieldset"){
+			continue;
+		}
+		var fieldType = fieldNode.type.toLowerCase();	
+		// Handle different kind of fields
+		switch(fieldType){
+			case "select-multiple":
+			case "select-one":
+				fieldNode.selectedIndex = -1;
+				break;
+			// Radio and checkboxes get handled the same way
+			case "radio":
+			case "checkbox":
+				fieldNode.checked = false;
+				break;
+			// Skip reset
+			case "reset":
+				break;
+			// Skip buttons
+			case "button":
+				break;
+			// default handles all the text fields
+			default:
+				fieldNode.value = "";
+				break;
+		}
+	}
+}
+
+tmt.form.MSG_BOX_ID = "tmtFormMessageBox";
+
+// Private helper function, undocumented
+// Generate an id that will identify the box who belongs to the given form
+tmt.form.generateBoxId = function(formNode){
+	var errorId = tmt.form.MSG_BOX_ID
+	if(formNode.getAttribute("id")){
+		errorId += formNode.getAttribute("id");
+	}
+	else if(formNode.getAttribute("name")){
+		errorId += formNode.getAttribute("name");
+	}
+	return errorId;
+}
+
+/**
+* Display a message a message associated with a given form node
+*/
+tmt.form.displayMessage = function(formNode, html){
+	tmt.form.displayBox(formNode, html, tmt.form.MESSAGE_CLASS);
+}
+
+/**
+* Display a message an error message associated with a given form node
+*/
+tmt.form.displayErrorMessage = function(formNode, html){
+	tmt.form.displayBox(formNode, html, tmt.form.ERROR_MESSAGE_CLASS);
+}
+
+/**
+* Display a box with a message associated with a given form node
+* Overwrite this method if you want to change the way tmt.form.displayMessage and tmt.form.displayErrorMessage behaves
+*/
+tmt.form.displayBox = function(formNode, html, cssClass){
+	if(!cssClass){
+		cssClass = tmt.form.MESSAGE_CLASS;
+	}
+	// Create a <div> that will act as an error display
+	var displayNode = document.createElement("div");
+	// Create an id that will identify the box who belongs to this specific form and assign it to the <div>
+	var errorId = tmt.form.generateBoxId(formNode);
+	displayNode.setAttribute("id", errorId);
+	displayNode.className = cssClass;
+	displayNode.innerHTML = html;		
+	var oldDisplay = tmt.get(errorId);
+	// If an error display is already there, we replace it, if not, we create one from scratch 
+	if(oldDisplay){
+		formNode.parentNode.replaceChild(displayNode, oldDisplay);
+	}
+	else{
+		formNode.parentNode.insertBefore(displayNode, formNode);
+	}
+}
+
+/**
+* Remove a message box (if any) associated with a given form node
+*/
+tmt.form.removeDisplayBox = function(formNode){
+	var errorId = tmt.form.generateBoxId(formNode);
+	var oldDisplay = tmt.get(errorId);
+	// If an error display is already there, get rid of it
+	if(oldDisplay){
+		oldDisplay.parentNode.removeChild(oldDisplay);
+	}
+}
+
+/**
+* Replace MS Word's non-ISO characters with plausible substitutes
+*/
+tmt.form.stringDemoronizer = function(str){
+	str = str.replace(new RegExp(String.fromCharCode(710), "g"), "^");
+	str = str.replace(new RegExp(String.fromCharCode(732), "g"), "~");
+	// Evil "smarty" quotes
+	str = str.replace(new RegExp(String.fromCharCode(8216), "g"), "'");
+	str = str.replace(new RegExp(String.fromCharCode(8217), "g"), "'");
+	str = str.replace(new RegExp(String.fromCharCode(8220), "g"), '"');
+	str = str.replace(new RegExp(String.fromCharCode(8221), "g"), '"');
+	// More garbage
+	str = str.replace(new RegExp(String.fromCharCode(8211), "g"), "-");
+	str = str.replace(new RegExp(String.fromCharCode(8212), "g"), "--");
+	str = str.replace(new RegExp(String.fromCharCode(8218), "g"), ",");
+	str = str.replace(new RegExp(String.fromCharCode(8222), "g"), ",,");
+	str = str.replace(new RegExp(String.fromCharCode(8226), "g"), "*");
+	str = str.replace(new RegExp(String.fromCharCode(8230), "g"), "...");
+	str = str.replace(new RegExp(String.fromCharCode(8364), "g"), "€");
+	return str;
+}
\ No newline at end of file

Added: incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/tmtjs/tmt_validator.js
URL: http://svn.apache.org/viewvc/incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/tmtjs/tmt_validator.js?rev=1087520&view=auto
==============================================================================
--- incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/tmtjs/tmt_validator.js (added)
+++ incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/tmtjs/tmt_validator.js Fri Apr  1 00:29:22 2011
@@ -0,0 +1,837 @@
+/** 
+* Copyright 2005-2008 massimocorner.com
+* @author      Massimo Foti (massimo@massimocorner.com)
+* @version     2.0.1, 2008-07-29
+* @require     tmt_core.js
+* @require     tmt_form.js
+*/
+
+if(typeof(tmt) == "undefined"){
+	alert("Error: tmt.core JavaScript library missing");
+}
+
+if(typeof(tmt.form) == "undefined"){
+	alert("Error: tmt.form JavaScript library missing");
+}
+
+tmt.validator = {};
+tmt.validator.DEFAULT_DATE_PATTERN = "YYYY-MM-DD";
+tmt.validator.DEFAULT_CALLBACK = "tmt.validator.defaultCallback";
+tmt.validator.DEFAULT_CALLBACK_MULTISECTION = "tmt.validator.multiSectionDefaultCallback";
+
+/**
+* Initialize the library
+*/
+tmt.validator.init = function(){
+	var formNodes = tmt.filterNodesByAttributeValue("tmt:validate", "true", document.getElementsByTagName("form"));
+	for(var i=0; i<formNodes.length; i++){
+		formNodes[i].tmt_validator = true;
+		var fields = formNodes[i].elements;
+		for(var x = 0; x < fields.length; x++){
+			if(fields[x].getAttribute("tmt:filters")){
+				// Call the filters on the onkeyup and onblur events
+				tmt.addEvent(fields[x], "keyup", function(){tmt.validator.filterField(this);});
+				tmt.addEvent(fields[x], "blur", function(){tmt.validator.filterField(this);});
+			}
+		}
+		// Set the form node's onsubmit event 
+		// We use a gigantic hack to preserve exiting calls attached to the onsubmit event (most likely validation routines)
+		if(typeof formNodes[i].onsubmit != "function"){
+			formNodes[i].onsubmit = function(){
+				return tmt.validator.validateForm(this);
+			}
+		}
+		else{
+			// Store a reference to the old function
+			formNodes[i].tmt_oldSubmit = formNodes[i].onsubmit;
+			formNodes[i].onsubmit = function(){
+				// If the existing function return true, validate the form
+				if(this.tmt_oldSubmit()){
+					return tmt.validator.validateForm(this);
+				}
+				return false;
+			}
+		}
+	}
+}
+
+/**
+* Validate a form 
+* Accepts either an id (string) or a DOM node reference
+*/
+tmt.validator.validateForm = function(form){
+	var formNode = tmt.get(form);
+	formNode.tmt_validator = true;
+	var formValidator = tmt.validator.formValidatorFactory(formNode);
+	var activeValidators = tmt.validator.executeValidators(formValidator.validators);
+	// Forward errors to the callback
+	eval(formValidator.callback + "(formNode, activeValidators)");	
+	if(activeValidators.length == 0){
+		// Everything is fine, disable form submission to avoid multiple submits
+		formValidator.blockSubmit();
+	}
+	return activeValidators.length == 0; 
+}
+
+/**
+* Validate an array of form fields
+* Array's elements can contain either an id (string) or a DOM node reference
+* Second argument is an optional callback
+* Returns true if no field contains errors, false otherwise
+*/
+tmt.validator.validateFields = function(fieldsArray, callback){
+	if(fieldsArray.length == 0){
+		return true;
+	}
+	// If no callback, use form's callback
+	if(!callback){
+		callback = tmt.validator.getCallback(tmt.get(fieldsArray[0]).form);
+	}
+	// Get the form node out of the first field
+	var formNode = tmt.get(fieldsArray[0]).form;
+	var validators = [];
+	for(var i = 0; i < fieldsArray.length; i++){
+		var fieldNode = tmt.get(fieldsArray[i]);
+		if(tmt.form.isFormField(fieldNode)){
+			validators.push(tmt.validator.fieldValidatorFactory(fieldNode));
+		}
+	}
+	// Store all the field validators that contains errors
+	var activeValidators = tmt.validator.executeValidators(validators);
+	// Forward errors to the callback
+	eval(callback + "(formNode, activeValidators)");
+	return activeValidators.length == 0;
+}
+
+/**
+* Validate all the fields contained inside a given start node
+* Start node can be either an id (string) or a DOM node reference
+* Second argument is an optional callback
+* Returns true if no field contains errors, false otherwise
+*/
+tmt.validator.validateChildFields = function(startNode, callback){
+	var fieldsArray = tmt.form.getChildFields(startNode);
+	return tmt.validator.validateFields(fieldsArray, callback);
+}
+
+/**
+* Validate a form field
+* Accepts either an id (string) or a DOM node reference and an optional callback
+* Returns true if the field contains no errors, false otherwise
+*/
+tmt.validator.validateField = function(field, callback){
+	var fieldNode = tmt.get(field);
+	if(!tmt.form.isFormField(fieldNode)){
+		return false;
+	}
+	if(!callback){
+		callback = "tmt.validator.defaultFieldCallback";
+	}
+	var fieldType = fieldNode.type.toLowerCase();
+	// Skip fieldsets
+	if(fieldNode.tagName.toLowerCase() == "fieldset"){
+		return;
+	}
+	var validator = tmt.validator.fieldValidatorFactory(fieldNode);
+	var haveError = validator.validate();
+	
+	if(haveError){
+		eval(callback + "(fieldNode, validator)");
+	}
+	else{
+		eval(callback + "(fieldNode, null)");
+	}
+	return haveError;
+}
+
+// Execute multiple validators. Returns an array of validators containing errors
+// Returns and empty array if no errors
+tmt.validator.executeValidators = function(validators){
+	var validatedFields = {};
+	// Store all the field validators that contains errors
+	var activeValidators = [];
+	// Validate all the fields
+	for(var i=0; i<validators.length; i++){
+		if(validatedFields[validators[i].name]){
+			// Already validated checkbox or radio, skip it
+			continue;
+		}
+		if(validators[i].validate()){
+			activeValidators[activeValidators.length] = validators[i];
+		}
+		// Keep track of validated fields
+		validatedFields[validators[i].name] = true;
+	}
+	return activeValidators;
+}
+
+/* Object factories */
+
+// Create a form validator
+tmt.validator.formValidatorFactory = function(formNode){
+	var obj = {};
+	// Store all the field validators inside an array
+	obj.validators = [];
+	obj.callback = tmt.validator.getCallback(formNode);
+	for(var i = 0; i < formNode.elements.length; i++){
+		if(tmt.form.isFormField(formNode.elements[i])){
+			obj.validators.push(tmt.validator.fieldValidatorFactory(formNode.elements[i]));
+		}
+	}
+	// Retrieve all the submit buttons
+	obj.buttons = tmt.form.getSubmitNodes(formNode);
+	// Define a method that can block multiple submits
+	obj.blockSubmit = function(){
+		// Check to see if have to disable submit buttons
+		if(!formNode.getAttribute("tmt:blocksubmit") && !(formNode.getAttribute("tmt:blocksubmit") == "false")){
+			// Disable each submit button
+			for(var i=0; i<obj.buttons.length; i++){
+				if(obj.buttons[i].getAttribute("tmt:waitmessage")){
+					obj.buttons[i].value = obj.buttons[i].getAttribute("tmt:waitmessage");
+				}
+				obj.buttons[i].disabled = true;
+			}
+		}
+	}
+	
+	return obj;
+}
+
+// Generate a field validator
+tmt.validator.fieldValidatorFactory = function(fieldNode){
+	var fieldType = fieldNode.type.toLowerCase();
+	var validator = {};
+	// Skip fieldsets
+	if(fieldNode.tagName.toLowerCase() == "fieldset"){
+		return validator;
+	}
+	// Handle different kind of fields
+	switch(fieldType){
+		case "select-multiple":
+			validator = tmt.validator.selectValidatorFactory(fieldNode);
+			break;
+		case "select-one":
+			validator = tmt.validator.selectValidatorFactory(fieldNode);
+			break;
+		case "radio":
+			validator = tmt.validator.radioValidatorFactory(tmt.form.getFieldGroup(fieldNode));
+			break;
+		case "checkbox":
+			validator = tmt.validator.boxValidatorFactory(tmt.form.getFieldGroup(fieldNode));
+			break;
+		// Skip reset
+		case "reset":
+			return validator;
+			break;
+		// Skip buttons
+		case "button":
+			return validator;
+			break;
+		// default handles all the text fields
+		default:
+			validator = tmt.validator.textValidatorFactory(fieldNode);
+			break;
+	}
+	return validator;
+}
+
+// Create an abstract field validator, to be extended/decorated for specific needs
+tmt.validator.abstractValidatorFactory = function(fieldNode){
+	var obj = {};
+	obj.message = "";
+	obj.name = "";
+	if(fieldNode.name){
+		obj.name = fieldNode.name;
+	}
+	else if(fieldNode.id){
+		obj.name = fieldNode.id;
+	}
+	obj.errorClass = "";
+	if(fieldNode.getAttribute("tmt:message")){
+		obj.message = fieldNode.getAttribute("tmt:message");
+	}
+	if(fieldNode.getAttribute("tmt:errorclass")){
+		obj.errorClass = fieldNode.getAttribute("tmt:errorclass");
+	}
+	obj.flagInvalid = function(){
+		// Append the CSS class to the existing one
+		if(obj.errorClass){
+			tmt.addClass(fieldNode, obj.errorClass);
+		}
+		// Set the title attribute in order to show a tootip
+		fieldNode.setAttribute("title", obj.message);
+	}
+	obj.flagValid = function(){
+		// Remove the CSS class
+		if(obj.errorClass){
+			tmt.removeClass(fieldNode, obj.errorClass);
+		}
+		fieldNode.removeAttribute("title");
+	}
+	obj.validate = function(){
+		// If the field contains error, flag it as invalid and return false
+		// Be careful, this method contains multiple exit points!!!
+		if(fieldNode.disabled){
+			// Disabled fields are always valid
+			obj.flagValid();
+			return false;
+		}
+		if(!obj.isValid()){
+			obj.flagInvalid();
+			return true;
+		}
+		else{
+			obj.flagValid();
+			return false;
+		}
+	}
+	
+	return obj;
+}
+
+// Create a validator for text and texarea fields
+tmt.validator.textValidatorFactory = function(fieldNode){
+	var obj = tmt.validator.abstractValidatorFactory(fieldNode);
+	obj.type = "text";
+	// Put focus and cursor inside the field
+	obj.getFocus = function(){
+		// This try block is required to solve an obscure issue with IE and hidden fields
+		try{
+			fieldNode.focus();
+			fieldNode.select();
+		}
+		catch(exception){
+		}
+	}
+	// Check if the field is empty
+	obj.isEmpty = function(){
+		return fieldNode.value == "";
+	}
+	// Check if the field is required
+	obj.isRequired = function(){
+		var requiredAtt = fieldNode.getAttribute("tmt:required");
+		if(requiredAtt){
+			// Plain vanilla validation, true/false
+			if((requiredAtt == "true") || (requiredAtt == "false")){
+				return eval(requiredAtt);
+			}
+			// It's a conditional validation. Invoke the relevant function
+			return(eval(requiredAtt + "(fieldNode)"));
+		}
+		return false;
+	}
+	// Check if the field satisfy the rules associated with it
+	// Be careful, this method contains multiple exit points!!!
+	obj.isValid = function(){
+		if(obj.isEmpty()){
+			if(obj.isRequired()){
+				return false;
+			}
+			else{
+				return true;
+			}
+		}
+		else{
+			// It's empty. Loop over all the available rules
+			for(var rule in tmt.validator.rules){
+				// Check if the current rule is required for the field
+				if(fieldNode.getAttribute("tmt:" + rule)){
+					// Invoke the rule
+					if(!eval("tmt.validator.rules." + rule + "(fieldNode)")){
+						return false;
+					}
+				}
+			}
+		}
+		return true;
+	}
+	
+	return obj;
+}
+
+// Create a validator for <select> fields
+tmt.validator.selectValidatorFactory = function(selectNode){
+	var obj = tmt.validator.abstractValidatorFactory(selectNode);
+	obj.type = "select";
+	var invalidIndex;
+	if(selectNode.getAttribute("tmt:invalidindex")){
+		invalidIndex = selectNode.getAttribute("tmt:invalidindex");
+	}
+	var invalidValue;
+	if(selectNode.getAttribute("tmt:invalidvalue") != null){
+		invalidValue = selectNode.getAttribute("tmt:invalidvalue");
+	}
+	// Check if the field satisfy the rules associated with it
+	// Be careful, this method contains multiple exit points!!!
+	obj.isValid = function(){
+		// Whenever a "size" attribute is available, the browser reports -1 as selectedIndex
+		// Fix this weirdness
+		if(selectNode.selectedIndex == -1){
+			selectNode.selectedIndex = 0;
+		}
+		// Check for index
+		if(selectNode.selectedIndex == invalidIndex){
+			return false;
+		}
+		// Check for value
+		if(selectNode.value == invalidValue){
+			return false;
+		}
+		// Loop over all the available rules
+		for(var rule in tmt.validator.rules){
+			// Check if the current rule is required for the field
+			if(selectNode.getAttribute("tmt:" + rule)){
+				// Invoke the rule
+				if(!eval("tmt.validator.rules." + rule + "(selectNode)")){
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+	
+	return obj;
+}
+
+// Create generic validator for grouped fields (radio and checkboxes)
+tmt.validator.groupValidatorFactory = function(buttonGroup){
+	var obj = {};
+	obj.name = buttonGroup[0].name;
+	obj.message = "";
+	obj.errorClass = "";
+	// Since fields from the same group can have conflicting attribute values, the last one win
+	for(var i=0; i<buttonGroup.length; i++){
+		if(buttonGroup[i].getAttribute("tmt:message")){
+			obj.message = buttonGroup[i].getAttribute("tmt:message");
+		}
+		if(buttonGroup[i].getAttribute("tmt:errorclass")){
+			obj.errorClass = buttonGroup[i].getAttribute("tmt:errorclass");
+		}
+	}
+	obj.flagInvalid = function(){
+		// Append the CSS class to the existing one
+		if(obj.errorClass){
+			for(var i=0; i<buttonGroup.length; i++){
+				tmt.addClass(buttonGroup[i], obj.errorClass);
+				buttonGroup[i].setAttribute("title", obj.message);
+			}
+		}
+	}
+	obj.flagValid = function(){
+		// Remove the CSS class
+		if(obj.errorClass){
+			for(var i=0; i<buttonGroup.length; i++){
+				tmt.removeClass(buttonGroup[i], obj.errorClass);
+				buttonGroup[i].removeAttribute("title");
+			}
+		}
+	}
+	obj.validate = function(){
+		//var errorMsg = "";
+		// If the field group contains error, flag it as invalid and return false
+		if(obj.isValid()){
+			obj.flagValid();
+			return false;
+		}
+		else{
+			obj.flagInvalid();
+			return true;
+		}
+	}
+	
+	return obj;
+}
+
+// Create a checkbox validator (out of a group of boxes sharing the same name)
+tmt.validator.boxValidatorFactory = function(boxGroup){
+	var obj = tmt.validator.groupValidatorFactory(boxGroup);
+	obj.type = "checkbox";
+	var minchecked = 0;
+	var maxchecked = boxGroup.length;
+	// Since checkboxes from the same group can have conflicting attribute values, the last one win
+	for(var i=0; i<boxGroup.length; i++){
+		if(boxGroup[i].getAttribute("tmt:minchecked")){
+			minchecked = boxGroup[i].getAttribute("tmt:minchecked");
+		}
+		if(boxGroup[i].getAttribute("tmt:maxchecked")){
+			maxchecked = boxGroup[i].getAttribute("tmt:maxchecked");
+		}
+	}
+	// Check if the boxes validate
+	obj.isValid = function(){
+		var checkCounter = 0;
+		for(var i=0; i<boxGroup.length; i++){
+		    // For each checked box, increase the counter
+			if(boxGroup[i].checked){
+				checkCounter++;
+			}
+		}
+		return (checkCounter >=  minchecked) && (checkCounter <= maxchecked);
+	}
+	
+	return obj;
+}
+
+// Create a radio validator (out of a group of radios sharing the same name)
+tmt.validator.radioValidatorFactory = function(radioGroup){
+	var obj = tmt.validator.groupValidatorFactory(radioGroup);
+	obj.type = "radio";
+	obj.isRequired = function(){
+		var requiredFlag = false;
+		// Since radios from the same group can have conflicting attribute values, the last one win
+		for(var i=0; i<radioGroup.length; i++){
+			if(radioGroup[i].disabled == false){
+				if(radioGroup[i].getAttribute("tmt:required")){
+					requiredFlag = radioGroup[i].getAttribute("tmt:required");
+				}
+			}
+		}
+		return requiredFlag;
+	}
+	
+	// Check if the radio validate
+	obj.isValid = function(){
+		if(obj.isRequired()){
+			for(var i=0; i<radioGroup.length; i++){
+				// As soon as one is checked, we are fine
+				if(radioGroup[i].checked){
+					return true;
+				}
+			}
+			return false;
+		}
+		// It's not required, fine anyway
+		else{
+			return true;
+		}
+	}
+	return obj;
+}
+
+// This object stores all the validation rules
+// Every rule is stored as a method that accepts the field node as argument and return a boolean
+tmt.validator.rules = {};
+
+tmt.validator.rules.datepattern = function(fieldNode){
+	var datObj = tmt.validator.dateStrToObj(fieldNode.value, fieldNode.getAttribute("tmt:datepattern"));
+	if(datObj){
+		return true;
+	}
+	return false;
+}
+
+tmt.validator.rules.maxdate = function(fieldNode){
+	var pattern = tmt.validator.DEFAULT_DATE_PATTERN;
+	if(fieldNode.getAttribute("tmt:datepattern")){
+		pattern = fieldNode.getAttribute("tmt:datepattern");
+	}
+	var valueDate = tmt.validator.dateStrToObj(fieldNode.value, pattern);
+	var maxDate = tmt.validator.dateStrToObj(fieldNode.getAttribute("tmt:maxdate"), pattern);
+	if(valueDate && maxDate){
+		return valueDate <= maxDate;
+	}
+	return false;
+}
+
+tmt.validator.rules.mindate = function(fieldNode){
+	var pattern = tmt.validator.DEFAULT_DATE_PATTERN;
+	if(fieldNode.getAttribute("tmt:datepattern")){
+		pattern = fieldNode.getAttribute("tmt:datepattern");
+	}
+	var valueDate = tmt.validator.dateStrToObj(fieldNode.value, pattern);	
+	var minDate = tmt.validator.dateStrToObj(fieldNode.getAttribute("tmt:mindate"), pattern);
+	if(valueDate && minDate){
+		return valueDate >= minDate;
+	}
+	return false;
+}
+
+tmt.validator.rules.equalto = function(fieldNode){
+	var twinNode = document.getElementById(fieldNode.getAttribute("tmt:equalto"));
+	return twinNode.value == fieldNode.value;
+}
+
+tmt.validator.rules.maxlength = function(fieldNode){
+	if(fieldNode.value.length > fieldNode.getAttribute("tmt:maxlength")){
+		return false;
+	}
+	return true;
+}
+
+tmt.validator.rules.maxnumber = function(fieldNode){
+	if(parseFloat(fieldNode.value) > fieldNode.getAttribute("tmt:maxnumber")){
+		return false;
+	}
+	return true;
+}
+
+tmt.validator.rules.minlength = function(fieldNode){
+	if(fieldNode.value.length < fieldNode.getAttribute("tmt:minlength")){
+		return false;
+	}
+	return true;
+}
+
+tmt.validator.rules.minnumber = function(fieldNode){
+	if(parseFloat(fieldNode.value) < fieldNode.getAttribute("tmt:minnumber")){
+		return false;
+	}
+	return true;
+}
+
+tmt.validator.rules.pattern = function(fieldNode){
+	var reg = tmt.validator.patterns[fieldNode.getAttribute("tmt:pattern")];
+	if(reg){
+		return reg.test(fieldNode.value);
+	}
+	else{
+		// If the pattern is missing, skip it
+		return true;
+	}
+}
+
+// This object stores all the RegExp patterns for strings
+tmt.validator.patterns = {};
+tmt.validator.patterns.email = new RegExp("^[\\w\\.=-]+@[\\w\\.-]+\\.[\\w\\.-]{2,4}$");
+tmt.validator.patterns.lettersonly = new RegExp("^[a-zA-Z]*$");
+tmt.validator.patterns.alphanumeric = new RegExp("^\\w*$");
+tmt.validator.patterns.integer = new RegExp("^-?\\d\\d*$");
+tmt.validator.patterns.positiveinteger = new RegExp("^\\d\\d*$");
+tmt.validator.patterns.number = new RegExp("^-?(\\d\\d*\\.\\d*$)|(^-?\\d\\d*$)|(^-?\\.\\d\\d*$)");
+tmt.validator.patterns.filepath_pdf = new RegExp("\\\\[\\w_]*\\.([pP][dD][fF])$");
+tmt.validator.patterns.filepath_jpg_gif = new RegExp("\\\\[\\w_]*\\.([gG][iI][fF])|([jJ][pP][eE]?[gG])$");
+tmt.validator.patterns.filepath_jpg = new RegExp("\\\\[\\w_]*\\.([jJ][pP][eE]?[gG])$");
+tmt.validator.patterns.filepath_zip = new RegExp("\\\\[\\w_]*\\.([zZ][iI][pP])$");
+tmt.validator.patterns.filepath = new RegExp("\\\\[\\w_]*\\.\\w{3}$");
+
+// This objects stores all the info required for date validation
+tmt.validator.datePatterns = {};
+
+// Create an object that stores date validation's info
+tmt.validator.createDatePattern = function(rex, year, month, day, separator){
+	var infoObj = {};
+	infoObj.rex = new RegExp(rex);
+	infoObj.y = year;
+	infoObj.m = month;
+	infoObj.d = day;
+	infoObj.s = separator;
+	return infoObj;
+}
+
+tmt.validator.datePatterns["YYYY-MM-DD"] = tmt.validator.createDatePattern("^\([0-9]{4}\)\\-\([0-1][0-9]\)\\-\([0-3][0-9]\)$", 0, 1, 2, "-");
+tmt.validator.datePatterns["YYYY-M-D"] = tmt.validator.createDatePattern("^\([0-9]{4}\)\\-\([0-1]?[0-9]\)\\-\([0-3]?[0-9]\)$", 0, 1, 2, "-");
+tmt.validator.datePatterns["MM.DD.YYYY"] = tmt.validator.createDatePattern("^\([0-1][0-9]\)\\.\([0-3][0-9]\)\\.\([0-9]{4}\)$", 2, 0, 1, ".");
+tmt.validator.datePatterns["M.D.YYYY"] = tmt.validator.createDatePattern("^\([0-1]?[0-9]\)\\.\([0-3]?[0-9]\)\\.\([0-9]{4}\)$", 2, 0, 1, ".");
+tmt.validator.datePatterns["MM/DD/YYYY"] = tmt.validator.createDatePattern("^\([0-1][0-9]\)\/\([0-3][0-9]\)\/\([0-9]{4}\)$", 2, 0, 1, "/");
+tmt.validator.datePatterns["M/D/YYYY"] = tmt.validator.createDatePattern("^\([0-1]?[0-9]\)\/\([0-3]?[0-9]\)\/\([0-9]{4}\)$", 2, 0, 1, "/");
+tmt.validator.datePatterns["MM-DD-YYYY"] = tmt.validator.createDatePattern("^\([0-21][0-9]\)\\-\([0-3][0-9]\)\\-\([0-9]{4}\)$", 2, 0, 1, "-");
+tmt.validator.datePatterns["M-D-YYYY"] = tmt.validator.createDatePattern("^\([0-1]?[0-9]\)\\-\([0-3]?[0-9]\)\\-\([0-9]{4}\)$", 2, 0, 1, "-");
+tmt.validator.datePatterns["DD.MM.YYYY"] = tmt.validator.createDatePattern("^\([0-3][0-9]\)\\.\([0-1][0-9]\)\\.\([0-9]{4}\)$", 2, 1, 0, ".");
+tmt.validator.datePatterns["D.M.YYYY"] = tmt.validator.createDatePattern("^\([0-3]?[0-9]\)\\.\([0-1]?[0-9]\)\\.\([0-9]{4}\)$", 2, 1, 0, ".");
+tmt.validator.datePatterns["DD/MM/YYYY"] = tmt.validator.createDatePattern("^\([0-3][0-9]\)\/\([0-1][0-9]\)\/\([0-9]{4}\)$", 2, 1, 0, "/");
+tmt.validator.datePatterns["D/M/YYYY"] = tmt.validator.createDatePattern("^\([0-3]?[0-9]\)\/\([0-1]?[0-9]\)\/\([0-9]{4}\)$", 2, 1, 0, "/");
+tmt.validator.datePatterns["DD-MM-YYYY"] = tmt.validator.createDatePattern("^\([0-3][0-9]\)\\-\([0-1][0-9]\)\\-\([0-9]{4}\)$", 2, 1, 0, "-");
+tmt.validator.datePatterns["D-M-YYYY"] = tmt.validator.createDatePattern("^\([0-3]?[0-9]\)\\-\([0-1]?[0-9]\)\\-\([0-9]{4}\)$", 2, 1, 0, "-");
+
+// This object stores all the info required for filters
+tmt.validator.filters = {};
+
+// Create an object that stores filters's info
+tmt.validator.createFilter = function(rex, replaceStr){
+	var infoObj = {};
+	infoObj.rex = new RegExp(rex, "g");
+	infoObj.str = replaceStr;
+	return infoObj;
+}
+
+tmt.validator.filters.ltrim = tmt.validator.createFilter ("^(\\s*)(\\b[\\w\\W]*)$", "$2");
+tmt.validator.filters.rtrim = tmt.validator.createFilter ("^([\\w\\W]*)(\\b\\s*)$", "$1");
+tmt.validator.filters.nospaces = tmt.validator.createFilter ("\\s*", "");
+tmt.validator.filters.nocommas = tmt.validator.createFilter (",", "");
+tmt.validator.filters.nodots = tmt.validator.createFilter ("\\.", "");
+tmt.validator.filters.noquotes = tmt.validator.createFilter ("'", "");
+tmt.validator.filters.nodoublequotes = tmt.validator.createFilter ('"', "");
+tmt.validator.filters.nohtml = tmt.validator.createFilter ("<[^>]*>", "");
+tmt.validator.filters.alphanumericonly = tmt.validator.createFilter ("[^\\w]", "");
+tmt.validator.filters.numbersonly = tmt.validator.createFilter ("[^\\d]", "");
+tmt.validator.filters.lettersonly = tmt.validator.createFilter ("[^a-zA-Z]", "");
+tmt.validator.filters.commastodots = tmt.validator.createFilter (",", ".");
+tmt.validator.filters.dotstocommas = tmt.validator.createFilter ("\\.", ",");
+tmt.validator.filters.numberscommas = tmt.validator.createFilter ("[^\\d,]", "");
+tmt.validator.filters.numbersdots = tmt.validator.createFilter ("[^\\d\\.]", "");
+
+// Clean up the field based on filter's info
+tmt.validator.filterField = function(fieldNode){
+	var filtersArray = fieldNode.getAttribute("tmt:filters").split(",");
+	// Skip arrow keys in Safari and IE
+	if(window.event){
+		var code = window.event.keyCode;
+		if((code == 37) || (code == 38) || (code == 39) || (code == 40)){
+			return;
+		}
+	}
+	for(var i=0; i<filtersArray.length; i++){
+		var filtObj = tmt.validator.filters[filtersArray[i]];
+		// Be sure we have the filter's data, then clean up
+		if(filtObj){
+			fieldNode.value = fieldNode.value.replace(filtObj.rex, filtObj.str)
+		}
+		// We handle demoroziner as a special case
+		if(filtersArray[i] == "demoronizer"){
+			fieldNode.value = tmt.form.stringDemoronizer(fieldNode.value);
+		}
+	}
+}
+
+/* Helper functions */
+
+// Create a Date object out of a string, based on a given RegExp pattern
+tmt.validator.dateStrToObj = function(dateStr, datePattern){
+	var globalObj = tmt.validator.datePatterns[datePattern];
+	if(globalObj){
+		// Split the date into 3 different bits using the separator
+		var dateBits = dateStr.split(globalObj.s);
+		// First try to create a new date out of the bits
+		var testDate = new Date(dateBits[globalObj.y], (dateBits[globalObj.m]-1), dateBits[globalObj.d]);
+		// Make sure values match after conversion
+		var isDate = (testDate.getFullYear() == dateBits[globalObj.y])
+				 && (testDate.getMonth() == dateBits[globalObj.m]-1)
+				 && (testDate.getDate() == dateBits[globalObj.d]);
+		// If it's a date and it matches the RegExp, it's a go
+		if(isDate && globalObj.rex.test(dateStr)){
+			return testDate;
+		}
+		return null;
+	}
+	return null;
+}
+
+// Get the relevant callback out of a form node
+// Second argument is optional
+tmt.validator.getCallback = function(formNode){
+	if(formNode.getAttribute("tmt:callback")){
+		return formNode.getAttribute("tmt:callback");
+	}
+	return tmt.validator.DEFAULT_CALLBACK;	
+}
+
+/* Callbacks for error display */
+ 
+/**
+* Default form callback. Display error messages inside alert
+*/
+tmt.validator.defaultCallback = function(formNode, validators){
+	var errorMsg = "";
+	var focusGiven = false;
+	for(var i=0; i<validators.length; i++){
+		// Append to the global error string
+		errorMsg += validators[i].message + "\n";
+		// Give focus to the first invalid text/textarea field
+		if(!focusGiven && (validators[i].getFocus)){
+			validators[i].getFocus();
+			focusGiven = true;
+		}
+	}
+	if(errorMsg != ""){
+		// We have errors, alert them
+		alert(errorMsg);
+	}
+}
+
+/**
+* Additional form callback. Display errors inside a box above the form
+*/
+tmt.validator.errorBoxCallback = function(formNode, validators){
+	// Clean-up any existing box
+	if(validators.length == 0){
+		tmt.form.removeDisplayBox(formNode);
+		return;
+	}
+	var focusGiven = false;
+	var htmlStr = "<ul>";
+	// Create a <ul> for each error
+	for(var i=0;i<validators.length;i++){
+		htmlStr += "<li><em>" + validators[i].name + ": </em> "+ validators[i].message + "</li>";
+		// Give focus to the first invalid text/textarea field
+		if(!focusGiven && (validators[i].getFocus)){
+			validators[i].getFocus();
+			focusGiven = true;
+		}
+	}
+	htmlStr += "</ul>";
+	tmt.form.displayErrorMessage(formNode, htmlStr);
+}
+
+/**
+* Default form callback
+* To be used for multi-section forms, with tabs, accordions or the like
+*/
+tmt.validator.multiSectionDefaultCallback = function(formNode, hasErrors, sectionResults){
+	var errorMsg = "";
+	for(var i=0;i<sectionResults.length;i++){
+		// This section has no errors, skip it
+		if(sectionResults[i].validators.length == 0){
+			continue;
+		}
+		var validators = sectionResults[i].validators;
+		for(var k=0;k<validators.length;k++){
+			errorMsg += validators[k].message + "\n";
+		}
+	}
+	if(errorMsg != ""){
+		// We have errors, alert them
+		alert(errorMsg);
+	}
+}
+
+/**
+* Additional form callback
+* To be used for multi-section forms, with tabs, accordions or the like
+*/
+tmt.validator.multiSectionBoxCallback = function(formNode, hasErrors, sectionResults){
+	// No errors, just clean up
+	if(!hasErrors){
+		tmt.form.removeDisplayBox(formNode);
+		return;
+	}
+	var htmlStr = "<ul>";
+	// Generate nested XHTML lists for each panel
+	for(var i=0;i<sectionResults.length;i++){
+		// This section has no errors, skip it
+		if(sectionResults[i].validators.length == 0){
+			continue;
+		}
+		htmlStr += "<li><strong>" + sectionResults[i].label + "</strong>";
+		var validators = sectionResults[i].validators;
+		htmlStr += "<ul>";
+		for(var k=0;k<validators.length;k++){
+			htmlStr += "<li><em>" + validators[k].name + ": </em> "+ validators[k].message + "</li>";
+		}
+		htmlStr += "</ul></li>";
+	}
+	htmlStr += "</ul>";
+	tmt.form.displayErrorMessage(formNode, htmlStr);
+}
+
+/**
+* Default field callback. Display error message inside alert
+*/
+tmt.validator.defaultFieldCallback = function(fieldNode, validator){
+	if(validator){
+		tmt.validator.defaultCallback(fieldNode.form, [validator]);
+	}
+}
+
+/**
+* Additional field callback. Display error inside a box above the form
+*/
+tmt.validator.errorBoxFieldCallback = function(fieldNode, validator){
+	if(validator){
+		tmt.validator.errorBoxCallback(fieldNode.form, [validator]);
+	}
+	else{
+		tmt.validator.errorBoxCallback(fieldNode.form, []);
+	}
+}
+
+tmt.addEvent(window, "load", tmt.validator.init);
\ No newline at end of file

Added: incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/trimpath-template-1.0.38.js
URL: http://svn.apache.org/viewvc/incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/trimpath-template-1.0.38.js?rev=1087520&view=auto
==============================================================================
--- incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/trimpath-template-1.0.38.js (added)
+++ incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/trimpath-template-1.0.38.js Fri Apr  1 00:29:22 2011
@@ -0,0 +1,397 @@
+/**
+ * TrimPath Template. Release 1.0.38.
+ * Copyright (C) 2004, 2005 Metaha.
+ * 
+ * TrimPath Template is licensed under the GNU General Public License
+ * and the Apache License, Version 2.0, as follows:
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed WITHOUT ANY WARRANTY; without even the 
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+ * See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var TrimPath;
+
+// TODO: Debugging mode vs stop-on-error mode - runtime flag.
+// TODO: Handle || (or) characters and backslashes.
+// TODO: Add more modifiers.
+
+(function() {               // Using a closure to keep global namespace clean.
+    if (TrimPath == null)
+        TrimPath = new Object();
+    if (TrimPath.evalEx == null)
+        TrimPath.evalEx = function(src) { return eval(src); };
+
+    var UNDEFINED;
+    if (Array.prototype.pop == null)  // IE 5.x fix from Igor Poteryaev.
+        Array.prototype.pop = function() {
+            if (this.length === 0) {return UNDEFINED;}
+            return this[--this.length];
+        };
+    if (Array.prototype.push == null) // IE 5.x fix from Igor Poteryaev.
+        Array.prototype.push = function() {
+            for (var i = 0; i < arguments.length; ++i) {this[this.length] = arguments[i];}
+            return this.length;
+        };
+
+    TrimPath.parseTemplate = function(tmplContent, optTmplName, optEtc) {
+        if (optEtc == null)
+            optEtc = TrimPath.parseTemplate_etc;
+        var funcSrc = parse(tmplContent, optTmplName, optEtc);
+        var func = TrimPath.evalEx(funcSrc, optTmplName, 1);
+        if (func != null)
+            return new optEtc.Template(optTmplName, tmplContent, funcSrc, func, optEtc);
+        return null;
+    }
+    
+    try {
+        String.prototype.process = function(context, optFlags) {
+            var template = TrimPath.parseTemplate(this, null);
+            if (template != null)
+                return template.process(context, optFlags);
+            return this;
+        }
+    } catch (e) { // Swallow exception, such as when String.prototype is sealed.
+    }
+    
+    TrimPath.parseTemplate_etc = {};            // Exposed for extensibility.
+    TrimPath.parseTemplate_etc.statementTag = "forelse|for|if|elseif|else|var|macro";
+    TrimPath.parseTemplate_etc.statementDef = { // Lookup table for statement tags.
+        "if"     : { delta:  1, prefix: "if (", suffix: ") {", paramMin: 1 },
+        "else"   : { delta:  0, prefix: "} else {" },
+        "elseif" : { delta:  0, prefix: "} else if (", suffix: ") {", paramDefault: "true" },
+        "/if"    : { delta: -1, prefix: "}" },
+        "for"    : { delta:  1, paramMin: 3, 
+                     prefixFunc : function(stmtParts, state, tmplName, etc) {
+                        if (stmtParts[2] != "in")
+                            throw new etc.ParseError(tmplName, state.line, "bad for loop statement: " + stmtParts.join(' '));
+                        var iterVar = stmtParts[1];
+                        var listVar = "__LIST__" + iterVar;
+                        return [ "var ", listVar, " = ", stmtParts[3], ";",
+                             // Fix from Ross Shaull for hash looping, make sure that we have an array of loop lengths to treat like a stack.
+                             "var __LENGTH_STACK__;",
+                             "if (typeof(__LENGTH_STACK__) == 'undefined' || !__LENGTH_STACK__.length) __LENGTH_STACK__ = new Array();", 
+                             "__LENGTH_STACK__[__LENGTH_STACK__.length] = 0;", // Push a new for-loop onto the stack of loop lengths.
+                             "if ((", listVar, ") != null) { ",
+                             "var ", iterVar, "_ct = 0;",       // iterVar_ct variable, added by B. Bittman     
+                             "for (var ", iterVar, "_index in ", listVar, ") { ",
+                             iterVar, "_ct++;",
+                             "if (typeof(", listVar, "[", iterVar, "_index]) == 'function') {continue;}", // IE 5.x fix from Igor Poteryaev.
+                             "__LENGTH_STACK__[__LENGTH_STACK__.length - 1]++;",
+                             "var ", iterVar, " = ", listVar, "[", iterVar, "_index];" ].join("");
+                     } },
+        "forelse" : { delta:  0, prefix: "} } if (__LENGTH_STACK__[__LENGTH_STACK__.length - 1] == 0) { if (", suffix: ") {", paramDefault: "true" },
+        "/for"    : { delta: -1, prefix: "} }; delete __LENGTH_STACK__[__LENGTH_STACK__.length - 1];" }, // Remove the just-finished for-loop from the stack of loop lengths.
+        "var"     : { delta:  0, prefix: "var ", suffix: ";" },
+        "macro"   : { delta:  1, 
+                      prefixFunc : function(stmtParts, state, tmplName, etc) {
+                          var macroName = stmtParts[1].split('(')[0];
+                          return [ "var ", macroName, " = function", 
+                                   stmtParts.slice(1).join(' ').substring(macroName.length),
+                                   "{ var _OUT_arr = []; var _OUT = { write: function(m) { if (m) _OUT_arr.push(m); } }; " ].join('');
+                     } }, 
+        "/macro"  : { delta: -1, prefix: " return _OUT_arr.join(''); };" }
+    }
+    TrimPath.parseTemplate_etc.modifierDef = {
+        "eat"        : function(v)    { return ""; },
+        "escape"     : function(s)    { return String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); },
+        "capitalize" : function(s)    { return String(s).toUpperCase(); },
+        "default"    : function(s, d) { return s != null ? s : d; }
+    }
+    TrimPath.parseTemplate_etc.modifierDef.h = TrimPath.parseTemplate_etc.modifierDef.escape;
+
+    TrimPath.parseTemplate_etc.Template = function(tmplName, tmplContent, funcSrc, func, etc) {
+        this.process = function(context, flags) {
+            if (context == null)
+                context = {};
+            if (context._MODIFIERS == null)
+                context._MODIFIERS = {};
+            if (context.defined == null)
+                context.defined = function(str) { return (context[str] != undefined); };
+            for (var k in etc.modifierDef) {
+                if (context._MODIFIERS[k] == null)
+                    context._MODIFIERS[k] = etc.modifierDef[k];
+            }
+            if (flags == null)
+                flags = {};
+            var resultArr = [];
+            var resultOut = { write: function(m) { resultArr.push(m); } };
+            try {
+                func(resultOut, context, flags);
+            } catch (e) {
+                if (flags.throwExceptions == true)
+                    throw e;
+                var result = new String(resultArr.join("") + "[ERROR: " + e.toString() + (e.message ? '; ' + e.message : '') + "]");
+                result["exception"] = e;
+                return result;
+            }
+            return resultArr.join("");
+        }
+        this.name       = tmplName;
+        this.source     = tmplContent; 
+        this.sourceFunc = funcSrc;
+        this.toString   = function() { return "TrimPath.Template [" + tmplName + "]"; }
+    }
+    TrimPath.parseTemplate_etc.ParseError = function(name, line, message) {
+        this.name    = name;
+        this.line    = line;
+        this.message = message;
+    }
+    TrimPath.parseTemplate_etc.ParseError.prototype.toString = function() { 
+        return ("TrimPath template ParseError in " + this.name + ": line " + this.line + ", " + this.message);
+    }
+    
+    var parse = function(body, tmplName, etc) {
+        body = cleanWhiteSpace(body);
+        var funcText = [ "var TrimPath_Template_TEMP = function(_OUT, _CONTEXT, _FLAGS) { with (_CONTEXT) {" ];
+        var state    = { stack: [], line: 1 };                              // TODO: Fix line number counting.
+        var endStmtPrev = -1;
+        while (endStmtPrev + 1 < body.length) {
+            var begStmt = endStmtPrev;
+            // Scan until we find some statement markup.
+            begStmt = body.indexOf("{", begStmt + 1);
+            while (begStmt >= 0) {
+                var endStmt = body.indexOf('}', begStmt + 1);
+                var stmt = body.substring(begStmt, endStmt);
+                var blockrx = stmt.match(/^\{(cdata|minify|eval)/); // From B. Bittman, minify/eval/cdata implementation.
+                if (blockrx) {
+                    var blockType = blockrx[1]; 
+                    var blockMarkerBeg = begStmt + blockType.length + 1;
+                    var blockMarkerEnd = body.indexOf('}', blockMarkerBeg);
+                    if (blockMarkerEnd >= 0) {
+                        var blockMarker;
+                        if( blockMarkerEnd - blockMarkerBeg <= 0 ) {
+                            blockMarker = "{/" + blockType + "}";
+                        } else {
+                            blockMarker = body.substring(blockMarkerBeg + 1, blockMarkerEnd);
+                        }                        
+                        
+                        var blockEnd = body.indexOf(blockMarker, blockMarkerEnd + 1);
+                        if (blockEnd >= 0) {                            
+                            emitSectionText(body.substring(endStmtPrev + 1, begStmt), funcText);
+                            
+                            var blockText = body.substring(blockMarkerEnd + 1, blockEnd);
+                            if (blockType == 'cdata') {
+                                emitText(blockText, funcText);
+                            } else if (blockType == 'minify') {
+                                emitText(scrubWhiteSpace(blockText), funcText);
+                            } else if (blockType == 'eval') {
+                                if (blockText != null && blockText.length > 0) // From B. Bittman, eval should not execute until process().
+                                    funcText.push('_OUT.write( (function() { ' + blockText + ' })() );');
+                            }
+                            begStmt = endStmtPrev = blockEnd + blockMarker.length - 1;
+                        }
+                    }                        
+                } else if (body.charAt(begStmt - 1) != '$' &&               // Not an expression or backslashed,
+                           body.charAt(begStmt - 1) != '\\') {              // so check if it is a statement tag.
+                    var offset = (body.charAt(begStmt + 1) == '/' ? 2 : 1); // Close tags offset of 2 skips '/'.
+                                                                            // 10 is larger than maximum statement tag length.
+                    if (body.substring(begStmt + offset, begStmt + 10 + offset).search(TrimPath.parseTemplate_etc.statementTag) == 0) 
+                        break;                                              // Found a match.
+                }
+                begStmt = body.indexOf("{", begStmt + 1);
+            }
+            if (begStmt < 0)                              // In "a{for}c", begStmt will be 1.
+                break;
+            var endStmt = body.indexOf("}", begStmt + 1); // In "a{for}c", endStmt will be 5.
+            if (endStmt < 0)
+                break;
+            emitSectionText(body.substring(endStmtPrev + 1, begStmt), funcText);
+            emitStatement(body.substring(begStmt, endStmt + 1), state, funcText, tmplName, etc);
+            endStmtPrev = endStmt;
+        }
+        emitSectionText(body.substring(endStmtPrev + 1), funcText);
+        if (state.stack.length != 0)
+            throw new etc.ParseError(tmplName, state.line, "unclosed, unmatched statement(s): " + state.stack.join(","));
+        funcText.push("}}; TrimPath_Template_TEMP");
+        return funcText.join("");
+    }
+    
+    var emitStatement = function(stmtStr, state, funcText, tmplName, etc) {
+        var parts = stmtStr.slice(1, -1).split(' ');
+        var stmt = etc.statementDef[parts[0]]; // Here, parts[0] == for/if/else/...
+        if (stmt == null) {                    // Not a real statement.
+            emitSectionText(stmtStr, funcText);
+            return;
+        }
+        if (stmt.delta < 0) {
+            if (state.stack.length <= 0)
+                throw new etc.ParseError(tmplName, state.line, "close tag does not match any previous statement: " + stmtStr);
+            state.stack.pop();
+        } 
+        if (stmt.delta > 0)
+            state.stack.push(stmtStr);
+
+        if (stmt.paramMin != null &&
+            stmt.paramMin >= parts.length)
+            throw new etc.ParseError(tmplName, state.line, "statement needs more parameters: " + stmtStr);
+        if (stmt.prefixFunc != null)
+            funcText.push(stmt.prefixFunc(parts, state, tmplName, etc));
+        else 
+            funcText.push(stmt.prefix);
+        if (stmt.suffix != null) {
+            if (parts.length <= 1) {
+                if (stmt.paramDefault != null)
+                    funcText.push(stmt.paramDefault);
+            } else {
+                for (var i = 1; i < parts.length; i++) {
+                    if (i > 1)
+                        funcText.push(' ');
+                    funcText.push(parts[i]);
+                }
+            }
+            funcText.push(stmt.suffix);
+        }
+    }
+
+    var emitSectionText = function(text, funcText) {
+        if (text.length <= 0)
+            return;
+        var nlPrefix = 0;               // Index to first non-newline in prefix.
+        var nlSuffix = text.length - 1; // Index to first non-space/tab in suffix.
+        while (nlPrefix < text.length && (text.charAt(nlPrefix) == '\n'))
+            nlPrefix++;
+        while (nlSuffix >= 0 && (text.charAt(nlSuffix) == ' ' || text.charAt(nlSuffix) == '\t'))
+            nlSuffix--;
+        if (nlSuffix < nlPrefix)
+            nlSuffix = nlPrefix;
+        if (nlPrefix > 0) {
+            funcText.push('if (_FLAGS.keepWhitespace == true) _OUT.write("');
+            var s = text.substring(0, nlPrefix).replace('\n', '\\n'); // A macro IE fix from BJessen.
+            if (s.charAt(s.length - 1) == '\n')
+            	s = s.substring(0, s.length - 1);
+            funcText.push(s);
+            funcText.push('");');
+        }
+        var lines = text.substring(nlPrefix, nlSuffix + 1).split('\n');
+        for (var i = 0; i < lines.length; i++) {
+            emitSectionTextLine(lines[i], funcText);
+            if (i < lines.length - 1)
+                funcText.push('_OUT.write("\\n");\n');
+        }
+        if (nlSuffix + 1 < text.length) {
+            funcText.push('if (_FLAGS.keepWhitespace == true) _OUT.write("');
+            var s = text.substring(nlSuffix + 1).replace('\n', '\\n');
+            if (s.charAt(s.length - 1) == '\n')
+            	s = s.substring(0, s.length - 1);
+            funcText.push(s);
+            funcText.push('");');
+        }
+    }
+    
+    var emitSectionTextLine = function(line, funcText) {
+        var endMarkPrev = '}';
+        var endExprPrev = -1;
+        while (endExprPrev + endMarkPrev.length < line.length) {
+            var begMark = "${", endMark = "}";
+            var begExpr = line.indexOf(begMark, endExprPrev + endMarkPrev.length); // In "a${b}c", begExpr == 1
+            if (begExpr < 0)
+                break;
+            if (line.charAt(begExpr + 2) == '%') {
+                begMark = "${%";
+                endMark = "%}";
+            }
+            var endExpr = line.indexOf(endMark, begExpr + begMark.length);         // In "a${b}c", endExpr == 4;
+            if (endExpr < 0)
+                break;
+            emitText(line.substring(endExprPrev + endMarkPrev.length, begExpr), funcText);                
+            // Example: exprs == 'firstName|default:"John Doe"|capitalize'.split('|')
+            var exprArr = line.substring(begExpr + begMark.length, endExpr).replace(/\|\|/g, "#@@#").split('|');
+            for (var k in exprArr) {
+                if (exprArr[k].replace) // IE 5.x fix from Igor Poteryaev.
+                    exprArr[k] = exprArr[k].replace(/#@@#/g, '||');
+            }
+            funcText.push('_OUT.write(');
+            emitExpression(exprArr, exprArr.length - 1, funcText); 
+            funcText.push(');');
+            endExprPrev = endExpr;
+            endMarkPrev = endMark;
+        }
+        emitText(line.substring(endExprPrev + endMarkPrev.length), funcText); 
+    }
+    
+    var emitText = function(text, funcText) {
+        if (text == null ||
+            text.length <= 0)
+            return;
+        text = text.replace(/\\/g, '\\\\');
+        text = text.replace(/\n/g, '\\n');
+        text = text.replace(/"/g,  '\\"');
+        funcText.push('_OUT.write("');
+        funcText.push(text);
+        funcText.push('");');
+    }
+    
+    var emitExpression = function(exprArr, index, funcText) {
+        // Ex: foo|a:x|b:y1,y2|c:z1,z2 is emitted as c(b(a(foo,x),y1,y2),z1,z2)
+        var expr = exprArr[index]; // Ex: exprArr == [firstName,capitalize,default:"John Doe"]
+        if (index <= 0) {          // Ex: expr    == 'default:"John Doe"'
+            funcText.push(expr);
+            return;
+        }
+        var parts = expr.split(':');
+        funcText.push('_MODIFIERS["');
+        funcText.push(parts[0]); // The parts[0] is a modifier function name, like capitalize.
+        funcText.push('"](');
+        emitExpression(exprArr, index - 1, funcText);
+        if (parts.length > 1) {
+            funcText.push(',');
+            funcText.push(parts[1]);
+        }
+        funcText.push(')');
+    }
+
+    var cleanWhiteSpace = function(result) {
+        result = result.replace(/\t/g,   "    ");
+        result = result.replace(/\r\n/g, "\n");
+        result = result.replace(/\r/g,   "\n");
+        result = result.replace(/^(\s*\S*(\s+\S+)*)\s*$/, '$1'); // Right trim by Igor Poteryaev.
+        return result;
+    }
+
+    var scrubWhiteSpace = function(result) {
+        result = result.replace(/^\s+/g,   "");
+        result = result.replace(/\s+$/g,   "");
+        result = result.replace(/\s+/g,   " ");
+        result = result.replace(/^(\s*\S*(\s+\S+)*)\s*$/, '$1'); // Right trim by Igor Poteryaev.
+        return result;
+    }
+
+    // The DOM helper functions depend on DOM/DHTML, so they only work in a browser.
+    // However, these are not considered core to the engine.
+    //
+    TrimPath.parseDOMTemplate = function(elementId, optDocument, optEtc) {
+        if (optDocument == null)
+            optDocument = document;
+        var element = optDocument.getElementById(elementId);
+        var content = element.value;     // Like textarea.value.
+        if (content == null)
+            content = element.innerHTML; // Like textarea.innerHTML.
+        content = content.replace(/&lt;/g, "<").replace(/&gt;/g, ">");
+        return TrimPath.parseTemplate(content, elementId, optEtc);
+    }
+
+    TrimPath.processDOMTemplate = function(elementId, context, optFlags, optDocument, optEtc) {
+        return TrimPath.parseDOMTemplate(elementId, optDocument, optEtc).process(context, optFlags);
+    }
+}) ();

Added: incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/userinfo.jsp
URL: http://svn.apache.org/viewvc/incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/userinfo.jsp?rev=1087520&view=auto
==============================================================================
--- incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/userinfo.jsp (added)
+++ incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/main/webapp/www/userinfo.jsp Fri Apr  1 00:29:22 2011
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<jsp:directive.page import="cgl.shindig.usermanage.User"/>
+<base href="${site.ishindig.base}/www/">
+
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<title>Sign up form</title>
+<meta name="keywords" content="" />
+<meta name="description" content="" />
+<link rel="stylesheet" type="text/css" href="default.css" />
+<link rel="stylesheet" type="text/css" href="style_form.css" />
+<script type="text/javascript" src="tmtjs/tmt_core.js"></script>
+<script type="text/javascript" src="tmtjs/tmt_form.js"></script>
+<script type="text/javascript" src="tmtjs/tmt_validator.js"></script>
+<script type="text/javascript">
+</script>
+</head>
+<body>
+
+<div id="outer">
+    <div id="outer2">
+    
+        <div id="header">
+            <h1>CGL</h1>
+            <h2>Community Grid Laboratory</h2>
+        </div>
+    
+        <div id="menu">
+            <fieldset style="border:none;">
+            <jsp:scriptlet>
+                Object action = request.getAttribute("action");
+                if( action != null ){
+                    String act = (String)action;
+                    if( act.compareTo("signin") == 0 ){
+                        Object state = request.getAttribute("state");
+                        if( state  != null ){
+                            switch ((Integer)state){
+                                case 0:
+                                User user = (User)request.getAttribute("user");
+            </jsp:scriptlet>
+                                <h2>User Information</h2><br>
+                                Screen Name:<%=user.getScreenName()%><br>
+                                First Name:<%=user.getFirstName()%><br>
+                                Last Name:<%=user.getLastName()%><br>
+                                Age:<%=user.getAge()%>
+            <jsp:scriptlet>
+                                break;
+                                default:
+                                    break;
+                            }
+                        }
+                    }
+                }
+            </jsp:scriptlet>
+            <jsp:directive.include file="signinup.html.part"/>
+            </fieldset>
+        </div>
+
+        
+    </div>
+    <jsp:directive.include file="footer.html.part"/>
+</div>
+
+</body>
+</html>

Added: incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/test/java/cgl/shindig/common/UriBuilderTest.java
URL: http://svn.apache.org/viewvc/incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/test/java/cgl/shindig/common/UriBuilderTest.java?rev=1087520&view=auto
==============================================================================
--- incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/test/java/cgl/shindig/common/UriBuilderTest.java (added)
+++ incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/test/java/cgl/shindig/common/UriBuilderTest.java Fri Apr  1 00:29:22 2011
@@ -0,0 +1,314 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ */
+package cgl.shindig.common;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static junitx.framework.Assert.assertNotEquals;
+
+/**
+ * Tests for UriBuilder
+ */
+public class UriBuilderTest {
+
+  @Test
+  public void allPartsUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noSchemeUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("//apache.org/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noAuthorityUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("http:/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noPathUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("http://apache.org?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noQueryUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig#foo", builder.toString());
+  }
+
+  @Test
+  public void noFragmentUsed() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setQuery("hello=world");
+    assertEquals("http://apache.org/shindig?hello=world", builder.toString());
+  }
+
+  @Test
+  public void hostRelativePaths() {
+    UriBuilder builder = new UriBuilder()
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void relativePaths() {
+    UriBuilder builder = new UriBuilder()
+        .setPath("foo")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("foo?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void noPathNoHostNoAuthority() {
+    UriBuilder builder = new UriBuilder()
+        .setQuery("hello=world")
+        .setFragment("foo");
+    assertEquals("?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void justSchemeAndAuthority() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org");
+    assertEquals("http://apache.org", builder.toString());
+  }
+
+  @Test
+  public void justPath() {
+    UriBuilder builder = new UriBuilder()
+        .setPath("/shindig");
+    assertEquals("/shindig", builder.toString());
+  }
+
+  @Test
+  public void justAuthorityAndPath() {
+    UriBuilder builder = new UriBuilder()
+        .setAuthority("apache.org")
+        .setPath("/shindig");
+    assertEquals("//apache.org/shindig", builder.toString());
+  }
+
+  @Test
+  public void justQuery() {
+    UriBuilder builder = new UriBuilder()
+        .setQuery("hello=world");
+    assertEquals("?hello=world", builder.toString());
+  }
+
+  @Test
+  public void justFragment() {
+    UriBuilder builder = new UriBuilder()
+        .setFragment("foo");
+    assertEquals("#foo", builder.toString());
+  }
+
+  @Test
+  public void addSingleQueryParameter() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameter("hello", "world")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void addTwoQueryParameters() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameter("hello", "world")
+        .addQueryParameter("foo", "bar")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world&foo=bar#foo", builder.toString());
+  }
+
+  @Test
+  public void iterableQueryParameters() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .putQueryParameter("hello", Lists.newArrayList("world", "monde"))
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world&hello=monde#foo", builder.toString());
+  }
+ 
+  @Test
+  public void removeQueryParameter() {
+    UriBuilder uri = UriBuilder.parse("http://www.example.com/foo?bar=baz&quux=baz");
+    uri.removeQueryParameter("bar");
+    assertEquals("http://www.example.com/foo?quux=baz", uri.toString());
+    uri.removeQueryParameter("quux");
+    assertEquals("http://www.example.com/foo", uri.toString());
+  }
+
+  @Test
+  public void addIdenticalParameters() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameter("hello", "world")
+        .addQueryParameter("hello", "goodbye")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello=world&hello=goodbye#foo", builder.toString());
+  }
+
+  @Test
+  public void addBatchParameters() {
+    Map<String, String> params = Maps.newLinkedHashMap();
+    params.put("foo", "bar");
+    params.put("hello", "world");
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameters(params)
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?foo=bar&hello=world#foo", builder.toString());
+  }
+
+  @Test
+  public void queryStringIsUnescaped() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .setQuery("hello+world=world%26bar");
+    assertEquals("world&bar", builder.getQueryParameter("hello world"));
+  }
+
+  @Test
+  public void queryParamsAreEscaped() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("apache.org")
+        .setPath("/shindig")
+        .addQueryParameter("hello world", "foo&bar")
+        .setFragment("foo");
+    assertEquals("http://apache.org/shindig?hello+world=foo%26bar#foo", builder.toString());
+    assertEquals("hello+world=foo%26bar", builder.getQuery());
+  }
+
+  @Test
+  public void parse() {
+    UriBuilder builder = UriBuilder.parse("http://apache.org/shindig?foo=bar%26baz&foo=three#blah");
+
+    assertEquals("http", builder.getScheme());
+    assertEquals("apache.org", builder.getAuthority());
+    assertEquals("/shindig", builder.getPath());
+    assertEquals("foo=bar%26baz&foo=three", builder.getQuery());
+    assertEquals("blah", builder.getFragment());
+
+    assertEquals("bar&baz", builder.getQueryParameter("foo"));
+
+    List<String> values = Arrays.asList("bar&baz", "three");
+    assertEquals(values, builder.getQueryParameters("foo"));
+  }
+
+  @Test
+  public void constructFromUriAndBack() {
+    Uri uri = Uri.parse("http://apache.org/foo/bar?foo=bar#foo");
+    UriBuilder builder = new UriBuilder(uri);
+
+    assertEquals(uri, builder.toUri());
+  }
+
+  @Test
+  public void constructFromUriAndModify() {
+    Uri uri = Uri.parse("http://apache.org/foo/bar?foo=bar#foo");
+    UriBuilder builder = new UriBuilder(uri);
+
+    builder.setAuthority("example.org");
+    builder.addQueryParameter("bar", "foo");
+
+    assertEquals("http://example.org/foo/bar?foo=bar&bar=foo#foo", builder.toString());
+  }
+
+  @Test
+  public void equalsAndHashCodeOk() {
+    UriBuilder uri = UriBuilder.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    UriBuilder uri2 = new UriBuilder(Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo"));
+
+    assertEquals(uri, uri2);
+    assertEquals(uri2, uri);
+
+    assertEquals(uri, uri);
+
+    assertNotNull(uri);
+    assertNotEquals(uri, "http://example.org/foo/bar/baz?blah=blah#boo");
+    assertNotEquals(uri, Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo"));
+
+    assertEquals(uri.hashCode(), uri2.hashCode());
+  }
+
+  @Test
+  public void urlTemplateLeCheck() {
+    UriBuilder builder = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("{apache}.org")
+        .setPath("/shindig")
+        .setQuery("hello=world")
+        .setFragment("foo");
+    System.out.println("-----------------------------------------------");
+    System.out.println(builder.toString());
+  }
+}

Added: incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/test/java/cgl/shindig/common/UriTest.java
URL: http://svn.apache.org/viewvc/incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/test/java/cgl/shindig/common/UriTest.java?rev=1087520&view=auto
==============================================================================
--- incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/test/java/cgl/shindig/common/UriTest.java (added)
+++ incubator/rave/donations/ogce-gadget-container/ishindig-webapp/src/test/java/cgl/shindig/common/UriTest.java Fri Apr  1 00:29:22 2011
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ */
+package cgl.shindig.common;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.Ignore;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Tests for Uri.
+ */
+public class UriTest {
+  @Test
+  public void parseFull() {
+    Uri uri = Uri.parse("http://apache.org/foo?a=b&a=c&b=d+e#blah");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    Collection<String> params = Arrays.asList("b", "c");
+    assertEquals(params, uri.getQueryParameters("a"));
+    assertEquals("b", uri.getQueryParameter("a"));
+    assertEquals("d e", uri.getQueryParameter("b"));
+    assertEquals("blah", uri.getFragment());
+
+    assertEquals("http://apache.org/foo?a=b&a=c&b=d+e#blah", uri.toString());
+  }
+
+  @Test
+  public void parseNoScheme() {
+    Uri uri = Uri.parse("//apache.org/foo?a=b&a=c&b=d+e#blah");
+
+    assertNull(uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    Collection<String> params = Arrays.asList("b", "c");
+    assertEquals(params, uri.getQueryParameters("a"));
+    assertEquals("b", uri.getQueryParameter("a"));
+    assertEquals("d e", uri.getQueryParameter("b"));
+    assertEquals("blah", uri.getFragment());
+  }
+
+  @Test
+  public void parseNoAuthority() {
+    Uri uri = Uri.parse("http:/foo?a=b&a=c&b=d+e#blah");
+
+    assertEquals("http", uri.getScheme());
+    assertNull(uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    Collection<String> params = Arrays.asList("b", "c");
+    assertEquals(params, uri.getQueryParameters("a"));
+    assertEquals("b", uri.getQueryParameter("a"));
+    assertEquals("d e", uri.getQueryParameter("b"));
+    assertEquals("blah", uri.getFragment());
+  }
+
+  @Test
+  public void parseNoPath() {
+    Uri uri = Uri.parse("http://apache.org?a=b&a=c&b=d+e#blah");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    // Path is never null.
+    assertEquals("", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    Collection<String> params = Arrays.asList("b", "c");
+    assertEquals(params, uri.getQueryParameters("a"));
+    assertEquals("b", uri.getQueryParameter("a"));
+    assertEquals("d e", uri.getQueryParameter("b"));
+    assertEquals("blah", uri.getFragment());
+  }
+
+  @Test
+  public void parseNoQuery() {
+    Uri uri = Uri.parse("http://apache.org/foo#blah");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertNull(uri.getQuery());
+    assertEquals(0, uri.getQueryParameters().size());
+    assertNull(uri.getQueryParameter("foo"));
+    assertEquals("blah", uri.getFragment());
+  }
+
+  @Test
+  public void parseNoFragment() {
+    Uri uri = Uri.parse("http://apache.org/foo?a=b&a=c&b=d+e");
+
+    assertEquals("http", uri.getScheme());
+    assertEquals("apache.org", uri.getAuthority());
+    assertEquals("/foo", uri.getPath());
+    assertEquals("a=b&a=c&b=d+e", uri.getQuery());
+    assertNull(uri.getFragment());
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void parseInvalidHost() {
+    Uri.parse("http://A&E%#%#%/foo?a=b#blah");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void parseInvalidScheme() {
+    Uri.parse("----://apache.org/foo?a=b#blah");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void parseInvalidPath() {
+    Uri.parse("http://apache.org/foo\\---(&%?a=b#blah");
+  }
+
+  @Test
+  public void toJavaUri() {
+    URI javaUri = URI.create("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri uri = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+
+    assertEquals(javaUri, uri.toJavaUri());
+  }
+
+  @Test
+  public void toJavaUriWithSpecialChars() {
+    URI javaUri = URI.create("http://example.org/foo/bar/baz?blah=bl%25ah#boo");
+    Uri uri = Uri.parse("http://example.org/foo/bar/baz?blah=bl%25ah#boo");
+
+    assertEquals(javaUri, uri.toJavaUri());
+  }
+
+  @Test
+  public void fromJavaUri() throws Exception {
+    URI javaUri = URI.create("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri uri = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+
+    assertEquals(uri, Uri.fromJavaUri(javaUri));
+  }
+
+  @Test
+  public void resolveFragment() throws Exception {
+    Uri base = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri other = Uri.parse("#bar");
+
+    assertEquals("http://example.org/foo/bar/baz?blah=blah#bar", base.resolve(other).toString());
+  }
+
+  @Test
+  public void resolveQuery() throws Exception {
+    Uri base = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri other = Uri.parse("?hello=world");
+
+    assertEquals("http://example.org/foo/bar/?hello=world", base.resolve(other).toString());
+  }
+
+  @Test
+  public void resolvePathIncludesSubdirs() throws Exception {
+    Uri base = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri other = Uri.parse("fez/../huey/./dewey/../louis");
+
+    assertEquals("http://example.org/foo/bar/huey/louis", base.resolve(other).toString());
+  }
+
+  // Ignore for now..
+  @Ignore
+  public void resolvePathSubdirsExtendsBeyondRoot() throws Exception {
+    Uri base = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri other = Uri.parse("../random/../../../../../home");
+
+    assertEquals("http://example.org/home", base.resolve(other).toString());
+  }
+
+  @Test
+  public void resolvePathRelative() throws Exception {
+    Uri base = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri other = Uri.parse("wee");
+
+    assertEquals("http://example.org/foo/bar/wee", base.resolve(other).toString());
+  }
+
+  @Test
+  public void resolvePathAbsolute() throws Exception {
+    Uri base = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri other = Uri.parse("/blah");
+
+    assertEquals("http://example.org/blah", base.resolve(other).toString());
+  }
+
+  @Test
+  public void resolveAuthority() throws Exception {
+    Uri base = Uri.parse("https://example.org/foo/bar/baz?blah=blah#boo");
+    Uri other = Uri.parse("//example.com/blah");
+
+    assertEquals("https://example.com/blah", base.resolve(other).toString());
+  }
+
+  @Test
+  public void resolveAbsolute() throws Exception {
+    Uri base = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri other = Uri.parse("http://www.ietf.org/rfc/rfc2396.txt");
+
+    assertEquals("http://www.ietf.org/rfc/rfc2396.txt", base.resolve(other).toString());
+  }
+
+  @Test
+  public void absoluteUrlIsAbsolute() {
+    assertTrue("Url with scheme not reported absolute.",
+        Uri.parse("http://example.org/foo").isAbsolute());
+  }
+
+  @Test
+  public void relativeUrlIsNotAbsolute() {
+    assertFalse("Url without scheme reported absolute.",
+        Uri.parse("//example.org/foo").isAbsolute());
+  }
+
+  @Test
+  public void parseWithSpecialCharacters() {
+    String original = "http://example.org/?foo%25pbar=baz+blah";
+
+    assertEquals(original, Uri.parse(original).toString());
+  }
+
+  @Test
+  public void equalsAndHashCodeOk() {
+    Uri uri = Uri.parse("http://example.org/foo/bar/baz?blah=blah#boo");
+    Uri uri2 = new UriBuilder()
+        .setScheme("http")
+        .setAuthority("example.org")
+        .setPath("/foo/bar/baz")
+        .addQueryParameter("blah", "blah")
+        .setFragment("boo")
+        .toUri();
+
+    assertEquals(uri, uri2);
+    assertEquals(uri2, uri);
+
+    assertEquals(uri.hashCode(), uri2.hashCode());
+  }
+}